| Previous | 15994 Revisions | Next |
| r11532 Thursday 12th May, 2011 at 22:56:22 UTC by Angelo Salese |
|---|
| More shuffling around, nw |
| [src/mame/drivers] | |
| [src/mame/includes] | |
| [src/mame/machine] | |
| [src/mame/video] | |
| [src/mess] | mess.mak |
| [src/mess/devices] | aescart.c* aescart.h* |
| [src/mess/drivers] | a3000.c* a310.c* a7000.c* ami1200.c* amiga.c* atari400.c* n64.c* nes.c* ng_aes.c* pce.c* snes.c* |
| [src/mess/includes] | nes.h* pce.h* |
| [src/mess/machine] | amigacd.c* amigacd.h* amigacrt.c* amigacrt.h* amigafdc.c* amigafdc.h* amigakbd.c* amigakbd.h* ataricrt.c* ataridev.h* atarifdc.c* nes.c* nes_ines.c* nes_mmc.c* nes_mmc.h* nes_pcb.c* nes_unif.c* pce.c* snescart.c* snescart.h* |
| [src/mess/video] | nes.c* |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | MESS specific Atari init and Cartridge code for Atari 8 bit systems | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #include "emu.h" | |
| 8 | #include "emuopts.h" | |
| 9 | #include "includes/atari.h" | |
| 10 | #include "ataridev.h" | |
| 11 | #include "machine/ram.h" | |
| 12 | #include "hashfile.h" | |
| 13 | ||
| 14 | #define LEFT_CARTSLOT_MOUNTED 1 | |
| 15 | #define RIGHT_CARTSLOT_MOUNTED 2 | |
| 16 | ||
| 17 | /* PCB */ | |
| 18 | enum | |
| 19 | { | |
| 20 | A800_UNKNOWN = 0, | |
| 21 | A800_4K, A800_8K, A800_12K, A800_16K, | |
| 22 | A800_RIGHT_4K, A800_RIGHT_8K, | |
| 23 | OSS_034M, OSS_M091, PHOENIX_8K, XEGS_32K, | |
| 24 | BBSB, DIAMOND_64K, WILLIAMS_64K, EXPRESS_64, | |
| 25 | SPARTADOS_X | |
| 26 | }; | |
| 27 | ||
| 28 | static int a800_cart_loaded = 0; | |
| 29 | static int atari = 0; | |
| 30 | static int a800_cart_type = A800_UNKNOWN; | |
| 31 | ||
| 32 | /************************************* | |
| 33 | * | |
| 34 | * Generic code | |
| 35 | * | |
| 36 | *************************************/ | |
| 37 | ||
| 38 | ||
| 39 | // Currently, the drivers have fixed 40k RAM, however the function here is ready for different sizes too | |
| 40 | static void a800_setbank(running_machine &machine, int cart_mounted) | |
| 41 | { | |
| 42 | offs_t ram_top; | |
| 43 | ||
| 44 | // take care of 0x0000-0x7fff: RAM or NOP | |
| 45 | ram_top = MIN(ram_get_size(machine.device(RAM_TAG)), 0x8000) - 1; | |
| 46 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x0000, ram_top, "0000"); | |
| 47 | memory_set_bankptr(machine, "0000", ram_get_ptr(machine.device(RAM_TAG))); | |
| 48 | ||
| 49 | // take care of 0x8000-0x9fff: A800 -> either right slot or RAM or NOP, others -> RAM or NOP | |
| 50 | // is there anything in the right slot? | |
| 51 | if (cart_mounted & RIGHT_CARTSLOT_MOUNTED) | |
| 52 | { | |
| 53 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x9fff, "8000"); | |
| 54 | memory_set_bankptr(machine, "8000", machine.region("rslot")->base()); | |
| 55 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0x9fff); | |
| 56 | } | |
| 57 | else if (a800_cart_type != BBSB) | |
| 58 | { | |
| 59 | ram_top = MIN(ram_get_size(machine.device(RAM_TAG)), 0xa000) - 1; | |
| 60 | if (ram_top > 0x8000) | |
| 61 | { | |
| 62 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x8000, ram_top, "8000"); | |
| 63 | memory_set_bankptr(machine, "8000", ram_get_ptr(machine.device(RAM_TAG)) + 0x8000); | |
| 64 | } | |
| 65 | } | |
| 66 | ||
| 67 | // take care of 0xa000-0xbfff: is there anything in the left slot? | |
| 68 | if (cart_mounted & LEFT_CARTSLOT_MOUNTED) | |
| 69 | { | |
| 70 | // FIXME: this is an hack to keep XL working until we clean up its memory map as well! | |
| 71 | if (atari == ATARI_800XL) | |
| 72 | { | |
| 73 | if (a800_cart_type == A800_16K) | |
| 74 | { | |
| 75 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x9fff, "8000"); | |
| 76 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base()); | |
| 77 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0x9fff); | |
| 78 | ||
| 79 | memcpy(machine.region("maincpu")->base() + 0x10000, machine.region("lslot")->base() + 0x2000, 0x2000); | |
| 80 | } | |
| 81 | else if (a800_cart_type == A800_8K) | |
| 82 | memcpy(machine.region("maincpu")->base() + 0x10000, machine.region("lslot")->base(), 0x2000); | |
| 83 | else | |
| 84 | fatalerror("This type of cart is not supported yet in this driver. Please use a400 or a800.\n"); | |
| 85 | } | |
| 86 | else if (a800_cart_type == A800_16K) | |
| 87 | { | |
| 88 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base()); | |
| 89 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base() + 0x2000); | |
| 90 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0xbfff); | |
| 91 | } | |
| 92 | else if (a800_cart_type == BBSB) | |
| 93 | { | |
| 94 | // this requires separate banking in 0x8000 & 0x9000! | |
| 95 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x8fff, "8000"); | |
| 96 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x9000, 0x9fff, "9000"); | |
| 97 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base() + 0x0000); | |
| 98 | memory_set_bankptr(machine, "9000", machine.region("lslot")->base() + 0x4000); | |
| 99 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base() + 0x8000); | |
| 100 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 101 | } | |
| 102 | else if (a800_cart_type == OSS_034M) | |
| 103 | { | |
| 104 | // this requires separate banking in 0xa000 & 0xb000! | |
| 105 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xafff, "a000"); | |
| 106 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xb000, 0xbfff, "b000"); | |
| 107 | memory_set_bankptr(machine, "b000", machine.region("lslot")->base() + 0x3000); | |
| 108 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 109 | } | |
| 110 | else if (a800_cart_type == OSS_M091) | |
| 111 | { | |
| 112 | // this requires separate banking in 0xa000 & 0xb000! | |
| 113 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xafff, "a000"); | |
| 114 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xb000, 0xbfff, "b000"); | |
| 115 | memory_set_bankptr(machine, "b000", machine.region("lslot")->base()); | |
| 116 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 117 | } | |
| 118 | else if (a800_cart_type == XEGS_32K) | |
| 119 | { | |
| 120 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base()); | |
| 121 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base() + 0x6000); | |
| 122 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0xbfff); | |
| 123 | } | |
| 124 | else | |
| 125 | { | |
| 126 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base()); | |
| 127 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 128 | } | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | /* MESS specific parts that have to be started */ | |
| 133 | static void ms_atari_machine_start(running_machine &machine, int type, int has_cart) | |
| 134 | { | |
| 135 | /* set atari type (temporarily not used) */ | |
| 136 | atari = type; | |
| 137 | a800_setbank(machine, a800_cart_loaded); | |
| 138 | } | |
| 139 | ||
| 140 | static void ms_atari800xl_machine_start(running_machine &machine, int type, int has_cart) | |
| 141 | { | |
| 142 | /* set atari type (temporarily not used) */ | |
| 143 | atari = type; | |
| 144 | a800_setbank(machine, a800_cart_loaded); | |
| 145 | } | |
| 146 | ||
| 147 | /************************************* | |
| 148 | * | |
| 149 | * Atari 400 | |
| 150 | * | |
| 151 | *************************************/ | |
| 152 | ||
| 153 | MACHINE_START( a400 ) | |
| 154 | { | |
| 155 | atari_machine_start(machine); | |
| 156 | ms_atari_machine_start(machine, ATARI_400, TRUE); | |
| 157 | } | |
| 158 | ||
| 159 | ||
| 160 | /************************************* | |
| 161 | * | |
| 162 | * Atari 800 | |
| 163 | * | |
| 164 | *************************************/ | |
| 165 | ||
| 166 | MACHINE_START( a800 ) | |
| 167 | { | |
| 168 | atari_machine_start(machine); | |
| 169 | ms_atari_machine_start(machine, ATARI_800, TRUE); | |
| 170 | } | |
| 171 | ||
| 172 | static WRITE8_HANDLER( x32_bank_w ) | |
| 173 | { | |
| 174 | // printf("written %x\n", data); | |
| 175 | int bank = data & 0x03; | |
| 176 | memory_set_bankptr(space->machine(), "8000", space->machine().region("lslot")->base() + bank * 0x2000); | |
| 177 | } | |
| 178 | ||
| 179 | static WRITE8_HANDLER( w64_bank_w ) | |
| 180 | { | |
| 181 | // printf("write to %x\n", offset); | |
| 182 | ||
| 183 | if (offset < 8) | |
| 184 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + offset * 0x2000); | |
| 185 | else | |
| 186 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base()); | |
| 187 | // FIXME: writes to 0x8-0xf should disable the cart | |
| 188 | } | |
| 189 | ||
| 190 | // this covers Express 64, Diamond 64 and SpartaDOS (same bankswitch, but at different addresses) | |
| 191 | static WRITE8_HANDLER( ex64_bank_w ) | |
| 192 | { | |
| 193 | // printf("write to %x\n", offset); | |
| 194 | ||
| 195 | if (offset < 8) | |
| 196 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + (7 - offset) * 0x2000); | |
| 197 | else | |
| 198 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base()); | |
| 199 | // FIXME: writes to 0x8-0xf should disable the cart | |
| 200 | } | |
| 201 | ||
| 202 | static WRITE8_HANDLER( bbsb_bankl_w ) | |
| 203 | { | |
| 204 | // printf("write to %x\n", 0x8000 + offset); | |
| 205 | if (offset >= 0xff6 && offset <= 0xff9) | |
| 206 | memory_set_bankptr(space->machine(), "8000", space->machine().region("lslot")->base() + 0x0000 + (offset - 0xff6) * 0x1000); | |
| 207 | } | |
| 208 | ||
| 209 | static WRITE8_HANDLER( bbsb_bankh_w ) | |
| 210 | { | |
| 211 | // printf("write to %x\n", 0x9000 + offset); | |
| 212 | if (offset >= 0xff6 && offset <= 0xff9) | |
| 213 | memory_set_bankptr(space->machine(), "9000", space->machine().region("lslot")->base() + 0x4000 + (offset - 0xff6) * 0x1000); | |
| 214 | } | |
| 215 | ||
| 216 | static WRITE8_HANDLER( oss_034m_w ) | |
| 217 | { | |
| 218 | switch (offset & 0x0f) | |
| 219 | { | |
| 220 | case 0: | |
| 221 | case 1: | |
| 222 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base()); | |
| 223 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 224 | break; | |
| 225 | case 2: | |
| 226 | case 6: | |
| 227 | // docs says this should put 0xff in the 0xa000 bank -> let's point to the end of the cart | |
| 228 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x4000); | |
| 229 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 230 | break; | |
| 231 | case 3: | |
| 232 | case 7: | |
| 233 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x1000); | |
| 234 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 235 | break; | |
| 236 | case 4: | |
| 237 | case 5: | |
| 238 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x2000); | |
| 239 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 240 | break; | |
| 241 | default: | |
| 242 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base() + 0xa000); | |
| 243 | memory_set_bankptr(space->machine(), "b000", space->machine().region("maincpu")->base() + 0xb000); | |
| 244 | break; | |
| 245 | } | |
| 246 | } | |
| 247 | ||
| 248 | static WRITE8_HANDLER( oss_m091_w ) | |
| 249 | { | |
| 250 | switch (offset & 0x09) | |
| 251 | { | |
| 252 | case 0: | |
| 253 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x1000); | |
| 254 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base()); | |
| 255 | break; | |
| 256 | case 1: | |
| 257 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x3000); | |
| 258 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base()); | |
| 259 | break; | |
| 260 | case 8: | |
| 261 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base() + 0xa000); | |
| 262 | memory_set_bankptr(space->machine(), "b000", space->machine().region("maincpu")->base() + 0xb000); | |
| 263 | break; | |
| 264 | case 9: | |
| 265 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x2000); | |
| 266 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base()); | |
| 267 | break; | |
| 268 | } | |
| 269 | } | |
| 270 | ||
| 271 | #if 0 | |
| 272 | static int bbsb_bankl = 0; | |
| 273 | static int bbsb_bankh = 0; | |
| 274 | ||
| 275 | static WRITE8_HANDLER( bbsb_bankl_w ) | |
| 276 | { | |
| 277 | bbsb_bankl = offset; // 0,1,2,3 | |
| 278 | } | |
| 279 | ||
| 280 | static WRITE8_HANDLER( bbsb_bankh_w ) | |
| 281 | { | |
| 282 | bbsb_bankh = offset; // 4,5,6,7 | |
| 283 | } | |
| 284 | ||
| 285 | static READ8_HANDLER( bbsb_bankl_r ) | |
| 286 | { | |
| 287 | // return data from the selected bank (0,1,2,3) | |
| 288 | UINT8 *mem = space->machine().region("lslot")->base(); | |
| 289 | return &mem[0x0000 + bbsb_bankl * 0x1000]; | |
| 290 | } | |
| 291 | ||
| 292 | static READ8_HANDLER( bbsb_bankh_r ) | |
| 293 | { | |
| 294 | // return data from the selected bank (4,5,6,7) | |
| 295 | UINT8 *mem = space->machine().region("lslot")->base(); | |
| 296 | return &mem[0x4000 + bbsb_bankh * 0x1000]; | |
| 297 | } | |
| 298 | #endif | |
| 299 | ||
| 300 | typedef struct _a800_pcb a800_pcb; | |
| 301 | struct _a800_pcb | |
| 302 | { | |
| 303 | const char *pcb_name; | |
| 304 | int pcb_id; | |
| 305 | }; | |
| 306 | ||
| 307 | // Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it | |
| 308 | // WARNING: most of these are still unsupported by the driver | |
| 309 | static const a800_pcb pcb_list[] = | |
| 310 | { | |
| 311 | {"standard 4k", A800_8K}, | |
| 312 | {"standard 8k", A800_8K}, | |
| 313 | {"standard 12k", A800_16K}, | |
| 314 | {"standard 16k", A800_16K}, | |
| 315 | {"right slot 4k", A800_RIGHT_4K}, | |
| 316 | {"right slot 8k", A800_RIGHT_8K}, | |
| 317 | ||
| 318 | {"oss 034m", OSS_034M}, | |
| 319 | {"oss m091", OSS_M091}, | |
| 320 | {"phoenix 8k", PHOENIX_8K}, | |
| 321 | {"xegs 32k", XEGS_32K}, | |
| 322 | {"bbsb", BBSB}, | |
| 323 | {"diamond 64k", DIAMOND_64K}, | |
| 324 | {"williams 64k", WILLIAMS_64K}, | |
| 325 | {"express 64", EXPRESS_64}, | |
| 326 | {"spartados x", SPARTADOS_X}, | |
| 327 | {"N/A", A800_UNKNOWN} | |
| 328 | }; | |
| 329 | ||
| 330 | static int a800_get_pcb_id(const char *pcb) | |
| 331 | { | |
| 332 | int i; | |
| 333 | ||
| 334 | for (i = 0; i < ARRAY_LENGTH(pcb_list); i++) | |
| 335 | { | |
| 336 | if (!mame_stricmp(pcb_list[i].pcb_name, pcb)) | |
| 337 | return pcb_list[i].pcb_id; | |
| 338 | } | |
| 339 | ||
| 340 | return A800_UNKNOWN; | |
| 341 | } | |
| 342 | ||
| 343 | // currently this does nothing, but it will eventually install the memory handlers required by the mappers | |
| 344 | static void a800_setup_mappers(running_machine &machine, int type) | |
| 345 | { | |
| 346 | switch (type) | |
| 347 | { | |
| 348 | case A800_4K: | |
| 349 | case A800_RIGHT_4K: | |
| 350 | case A800_12K: | |
| 351 | case A800_8K: | |
| 352 | case A800_16K: | |
| 353 | case A800_RIGHT_8K: | |
| 354 | case PHOENIX_8K: // as normal 8k cart, but it can be disabled by writing to 0xd500-0xdfff | |
| 355 | break; | |
| 356 | case XEGS_32K: | |
| 357 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(x32_bank_w)); | |
| 358 | break; | |
| 359 | case OSS_034M: | |
| 360 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(oss_034m_w)); | |
| 361 | break; | |
| 362 | case OSS_M091: | |
| 363 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(oss_m091_w)); | |
| 364 | break; | |
| 365 | case BBSB: | |
| 366 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x8000, 0x8fff, FUNC(bbsb_bankl_w)); | |
| 367 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x9000, 0x9fff, FUNC(bbsb_bankh_w)); | |
| 368 | break; | |
| 369 | case WILLIAMS_64K: | |
| 370 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd50f, FUNC(w64_bank_w)); | |
| 371 | break; | |
| 372 | case DIAMOND_64K: | |
| 373 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd5d0, 0xd5df, FUNC(ex64_bank_w)); | |
| 374 | break; | |
| 375 | case EXPRESS_64: | |
| 376 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd570, 0xd57f, FUNC(ex64_bank_w)); | |
| 377 | break; | |
| 378 | case SPARTADOS_X: | |
| 379 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd5e0, 0xd5ef, FUNC(ex64_bank_w)); | |
| 380 | break; | |
| 381 | default: | |
| 382 | break; | |
| 383 | } | |
| 384 | } | |
| 385 | ||
| 386 | static int a800_get_type(device_image_interface &image) | |
| 387 | { | |
| 388 | UINT8 header[16]; | |
| 389 | image.fread(header, 0x10); | |
| 390 | int hdr_type, cart_type = A800_UNKNOWN; | |
| 391 | ||
| 392 | // add check of CART format | |
| 393 | if (strncmp((const char *)header, "CART", 4)) | |
| 394 | fatalerror("Invalid header detected!\n"); | |
| 395 | ||
| 396 | hdr_type = (header[4] << 24) + (header[5] << 16) + (header[6] << 8) + (header[7] << 0); | |
| 397 | switch (hdr_type) | |
| 398 | { | |
| 399 | case 1: | |
| 400 | cart_type = A800_8K; | |
| 401 | break; | |
| 402 | case 2: | |
| 403 | cart_type = A800_16K; | |
| 404 | break; | |
| 405 | case 3: | |
| 406 | cart_type = OSS_034M; | |
| 407 | break; | |
| 408 | case 8: | |
| 409 | cart_type = WILLIAMS_64K; | |
| 410 | break; | |
| 411 | case 9: | |
| 412 | cart_type = DIAMOND_64K; | |
| 413 | break; | |
| 414 | case 10: | |
| 415 | cart_type = EXPRESS_64; | |
| 416 | break; | |
| 417 | case 11: | |
| 418 | cart_type = SPARTADOS_X; | |
| 419 | break; | |
| 420 | case 12: | |
| 421 | cart_type = XEGS_32K; | |
| 422 | break; | |
| 423 | case 15: | |
| 424 | cart_type = OSS_M091; | |
| 425 | break; | |
| 426 | case 18: | |
| 427 | cart_type = BBSB; | |
| 428 | break; | |
| 429 | case 21: | |
| 430 | cart_type = A800_RIGHT_8K; | |
| 431 | break; | |
| 432 | case 39: | |
| 433 | cart_type = PHOENIX_8K; | |
| 434 | break; | |
| 435 | case 4: | |
| 436 | case 6: | |
| 437 | case 7: | |
| 438 | case 16: | |
| 439 | case 19: | |
| 440 | case 20: | |
| 441 | fatalerror("Cart type \"%d\" means this is an Atari 5200 cart.\n", hdr_type); | |
| 442 | break; | |
| 443 | default: | |
| 444 | mame_printf_info("Cart type \"%d\" is currently unsupported.\n", hdr_type); | |
| 445 | break; | |
| 446 | } | |
| 447 | return cart_type; | |
| 448 | } | |
| 449 | ||
| 450 | static int a800_check_cart_type(device_image_interface &image) | |
| 451 | { | |
| 452 | const char *pcb_name; | |
| 453 | int type = A800_UNKNOWN; | |
| 454 | ||
| 455 | if (image.software_entry() == NULL) | |
| 456 | { | |
| 457 | UINT32 size = image.length(); | |
| 458 | ||
| 459 | // check if there is an header, if so extract cart_type from it, otherwise | |
| 460 | // try to guess the cart_type from the file size (notice that after the | |
| 461 | // a800_get_type call, we point at the start of the data) | |
| 462 | if ((size % 0x1000) == 0x10) | |
| 463 | type = a800_get_type(image); | |
| 464 | else if (size == 0x4000) | |
| 465 | type = A800_16K; | |
| 466 | else if (size == 0x2000) | |
| 467 | { | |
| 468 | if (strcmp(image.device().tag(),"cart2") == 0) | |
| 469 | type = A800_RIGHT_8K; | |
| 470 | else | |
| 471 | type = A800_8K; | |
| 472 | } | |
| 473 | } | |
| 474 | else | |
| 475 | { | |
| 476 | if ((pcb_name = image.get_feature("cart_type")) != NULL) | |
| 477 | type = a800_get_pcb_id(pcb_name); | |
| 478 | ||
| 479 | switch (type) | |
| 480 | { | |
| 481 | case A800_UNKNOWN: | |
| 482 | case A800_4K: | |
| 483 | case A800_RIGHT_4K: | |
| 484 | case A800_12K: | |
| 485 | case A800_8K: | |
| 486 | case A800_16K: | |
| 487 | case A800_RIGHT_8K: | |
| 488 | break; | |
| 489 | default: | |
| 490 | mame_printf_info("Cart type \"%s\" currently unsupported.\n", pcb_name); | |
| 491 | break; | |
| 492 | } | |
| 493 | } | |
| 494 | ||
| 495 | if ((strcmp(image.device().tag(),"cart2") == 0) && (type != A800_RIGHT_8K)) | |
| 496 | fatalerror("You cannot load this image '%s' in the right slot", image.filename()); | |
| 497 | ||
| 498 | return type; | |
| 499 | } | |
| 500 | ||
| 501 | DEVICE_IMAGE_LOAD( a800_cart ) | |
| 502 | { | |
| 503 | UINT32 size, start = 0; | |
| 504 | ||
| 505 | a800_cart_loaded = a800_cart_loaded & ~LEFT_CARTSLOT_MOUNTED; | |
| 506 | a800_cart_type = a800_check_cart_type(image); | |
| 507 | ||
| 508 | a800_setup_mappers(image.device().machine(), a800_cart_type); | |
| 509 | ||
| 510 | if (image.software_entry() == NULL) | |
| 511 | { | |
| 512 | size = image.length(); | |
| 513 | // if there is an header, skip it | |
| 514 | if ((size % 0x1000) == 0x10) | |
| 515 | { | |
| 516 | size -= 0x10; | |
| 517 | start = 0x10; | |
| 518 | } | |
| 519 | image.fread(image.device().machine().region("lslot")->base(), size - start); | |
| 520 | } | |
| 521 | else | |
| 522 | { | |
| 523 | size = image.get_software_region_length("rom"); | |
| 524 | memcpy(image.device().machine().region("lslot")->base(), image.get_software_region("rom"), size); | |
| 525 | } | |
| 526 | ||
| 527 | a800_cart_loaded |= (size > 0x0000) ? 1 : 0; | |
| 528 | ||
| 529 | logerror("%s loaded left cartridge '%s' size %dK\n", image.device().machine().system().name, image.filename(), size/1024); | |
| 530 | return IMAGE_INIT_PASS; | |
| 531 | } | |
| 532 | ||
| 533 | DEVICE_IMAGE_LOAD( a800_cart_right ) | |
| 534 | { | |
| 535 | UINT32 size, start = 0; | |
| 536 | ||
| 537 | a800_cart_loaded = a800_cart_loaded & ~RIGHT_CARTSLOT_MOUNTED; | |
| 538 | a800_cart_type = a800_check_cart_type(image); | |
| 539 | ||
| 540 | a800_setup_mappers(image.device().machine(), a800_cart_type); | |
| 541 | ||
| 542 | if (image.software_entry() == NULL) | |
| 543 | { | |
| 544 | size = image.length(); | |
| 545 | // if there is an header, skip it | |
| 546 | if ((size % 0x1000) == 0x10) | |
| 547 | { | |
| 548 | size -= 0x10; | |
| 549 | start = 0x10; | |
| 550 | } | |
| 551 | image.fread(image.device().machine().region("rslot")->base(), size - start); | |
| 552 | } | |
| 553 | else | |
| 554 | { | |
| 555 | size = image.get_software_region_length("rom"); | |
| 556 | memcpy(image.device().machine().region("rslot")->base(), image.get_software_region("rom"), size); | |
| 557 | } | |
| 558 | ||
| 559 | a800_cart_loaded |= (size > 0x0000) ? 2 : 0; | |
| 560 | ||
| 561 | logerror("%s loaded right cartridge '%s' size 8K\n", image.device().machine().system().name, image.filename()); | |
| 562 | return IMAGE_INIT_PASS; | |
| 563 | } | |
| 564 | ||
| 565 | DEVICE_IMAGE_UNLOAD( a800_cart ) | |
| 566 | { | |
| 567 | a800_cart_loaded = a800_cart_loaded & ~LEFT_CARTSLOT_MOUNTED; | |
| 568 | a800_cart_type = A800_UNKNOWN; | |
| 569 | a800_setbank(image.device().machine(), a800_cart_loaded); | |
| 570 | } | |
| 571 | ||
| 572 | DEVICE_IMAGE_UNLOAD( a800_cart_right ) | |
| 573 | { | |
| 574 | a800_cart_loaded = a800_cart_loaded & ~RIGHT_CARTSLOT_MOUNTED; | |
| 575 | a800_cart_type = A800_UNKNOWN; | |
| 576 | a800_setbank(image.device().machine(), a800_cart_loaded); | |
| 577 | } | |
| 578 | ||
| 579 | ||
| 580 | /************************************* | |
| 581 | * | |
| 582 | * Atari 800XL | |
| 583 | * | |
| 584 | *************************************/ | |
| 585 | ||
| 586 | MACHINE_START( a800xl ) | |
| 587 | { | |
| 588 | atari_machine_start(machine); | |
| 589 | ms_atari800xl_machine_start(machine, ATARI_800XL, TRUE); | |
| 590 | } | |
| 591 | ||
| 592 | /************************************* | |
| 593 | * | |
| 594 | * Atari 5200 console | |
| 595 | * | |
| 596 | *************************************/ | |
| 597 | ||
| 598 | MACHINE_START( a5200 ) | |
| 599 | { | |
| 600 | atari_machine_start(machine); | |
| 601 | ms_atari_machine_start(machine, ATARI_800XL, TRUE); | |
| 602 | } | |
| 603 | ||
| 604 | ||
| 605 | DEVICE_IMAGE_LOAD( a5200_cart ) | |
| 606 | { | |
| 607 | UINT8 *mem = image.device().machine().region("maincpu")->base(); | |
| 608 | UINT32 size; | |
| 609 | ||
| 610 | if (image.software_entry() == NULL) | |
| 611 | { | |
| 612 | /* load an optional (dual) cartidge */ | |
| 613 | size = image.fread(&mem[0x4000], 0x8000); | |
| 614 | } | |
| 615 | else | |
| 616 | { | |
| 617 | size = image.get_software_region_length("rom"); | |
| 618 | memcpy(mem + 0x4000, image.get_software_region("rom"), size); | |
| 619 | } | |
| 620 | ||
| 621 | if (size<0x8000) memmove(mem+0x4000+0x8000-size, mem+0x4000, size); | |
| 622 | // mirroring of smaller cartridges | |
| 623 | if (size <= 0x1000) memcpy(mem+0xa000, mem+0xb000, 0x1000); | |
| 624 | if (size <= 0x2000) memcpy(mem+0x8000, mem+0xa000, 0x2000); | |
| 625 | if (size <= 0x4000) | |
| 626 | { | |
| 627 | const char *info = hashfile_extrainfo(image); | |
| 628 | memcpy(&mem[0x4000], &mem[0x8000], 0x4000); | |
| 629 | if (info && !strcmp(info, "A13MIRRORING")) | |
| 630 | { | |
| 631 | memcpy(&mem[0x8000], &mem[0xa000], 0x2000); | |
| 632 | memcpy(&mem[0x6000], &mem[0x4000], 0x2000); | |
| 633 | } | |
| 634 | } | |
| 635 | logerror("A5200 loaded cartridge '%s' size %dK\n", image.filename() , size/1024); | |
| 636 | return IMAGE_INIT_PASS; | |
| 637 | } | |
| 638 | ||
| 639 | DEVICE_IMAGE_UNLOAD( a5200_cart ) | |
| 640 | { | |
| 641 | UINT8 *mem = image.device().machine().region("maincpu")->base(); | |
| 642 | /* zap the cartridge memory (again) */ | |
| 643 | memset(&mem[0x4000], 0x00, 0x8000); | |
| 644 | } | |
| 645 | ||
| 646 | /************************************* | |
| 647 | * | |
| 648 | * Atari XEGS | |
| 649 | * | |
| 650 | *************************************/ | |
| 651 | ||
| 652 | static UINT8 xegs_banks = 0; | |
| 653 | static UINT8 xegs_cart = 0; | |
| 654 | ||
| 655 | static WRITE8_HANDLER( xegs_bankswitch ) | |
| 656 | { | |
| 657 | UINT8 *cart = space->machine().region("user1")->base(); | |
| 658 | data &= xegs_banks - 1; | |
| 659 | memory_set_bankptr(space->machine(), "bank0", cart + data * 0x2000); | |
| 660 | } | |
| 661 | ||
| 662 | MACHINE_START( xegs ) | |
| 663 | { | |
| 664 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 665 | UINT8 *cart = space->machine().region("user1")->base(); | |
| 666 | UINT8 *cpu = space->machine().region("maincpu")->base(); | |
| 667 | ||
| 668 | atari_machine_start(machine); | |
| 669 | space->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(xegs_bankswitch)); | |
| 670 | ||
| 671 | if (xegs_cart) | |
| 672 | { | |
| 673 | memory_set_bankptr(machine, "bank0", cart); | |
| 674 | memory_set_bankptr(machine, "bank1", cart + (xegs_banks - 1) * 0x2000); | |
| 675 | } | |
| 676 | else | |
| 677 | { | |
| 678 | // point to built-in Missile Command (this does not work well, though... FIXME!!) | |
| 679 | memory_set_bankptr(machine, "bank0", cpu + 0x10000); | |
| 680 | memory_set_bankptr(machine, "bank1", cpu + 0x10000); | |
| 681 | } | |
| 682 | } | |
| 683 | ||
| 684 | DEVICE_IMAGE_LOAD( xegs_cart ) | |
| 685 | { | |
| 686 | UINT32 size; | |
| 687 | UINT8 *ptr = image.device().machine().region("user1")->base(); | |
| 688 | ||
| 689 | if (image.software_entry() == NULL) | |
| 690 | { | |
| 691 | // skip the header | |
| 692 | image.fseek(0x10, SEEK_SET); | |
| 693 | size = image.length() - 0x10; | |
| 694 | if (image.fread(ptr, size) != size) | |
| 695 | return IMAGE_INIT_FAIL; | |
| 696 | } | |
| 697 | else | |
| 698 | { | |
| 699 | size = image.get_software_region_length("rom"); | |
| 700 | memcpy(ptr, image.get_software_region("rom"), size); | |
| 701 | } | |
| 702 | ||
| 703 | xegs_banks = size / 0x2000; | |
| 704 | xegs_cart = 1; | |
| 705 | ||
| 706 | return IMAGE_INIT_PASS; | |
| 707 | } | |
| 708 | ||
| 709 | DEVICE_IMAGE_UNLOAD( xegs_cart ) | |
| 710 | { | |
| 711 | xegs_cart = 0; | |
| 712 | xegs_banks = 0; | |
| 713 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | ataridev.h | |
| 3 | ||
| 4 | */ | |
| 5 | ||
| 6 | #ifndef _ATARIDEV_H | |
| 7 | #define _ATARIDEV_H | |
| 8 | ||
| 9 | #define ATARI_5200 0 | |
| 10 | #define ATARI_400 1 | |
| 11 | #define ATARI_800 2 | |
| 12 | #define ATARI_600XL 3 | |
| 13 | #define ATARI_800XL 4 | |
| 14 | ||
| 15 | /*----------- defined in machine/ataricrt.c -----------*/ | |
| 16 | ||
| 17 | MACHINE_START( a400 ); | |
| 18 | MACHINE_START( a800 ); | |
| 19 | MACHINE_START( a800xl ); | |
| 20 | MACHINE_START( a5200 ); | |
| 21 | MACHINE_START( xegs ); | |
| 22 | ||
| 23 | DEVICE_IMAGE_LOAD( a800_cart ); | |
| 24 | DEVICE_IMAGE_UNLOAD( a800_cart ); | |
| 25 | ||
| 26 | DEVICE_IMAGE_LOAD( a800_cart_right ); | |
| 27 | DEVICE_IMAGE_UNLOAD( a800_cart_right ); | |
| 28 | ||
| 29 | DEVICE_IMAGE_LOAD( a5200_cart ); | |
| 30 | DEVICE_IMAGE_UNLOAD( a5200_cart ); | |
| 31 | ||
| 32 | DEVICE_IMAGE_LOAD( xegs_cart ); | |
| 33 | DEVICE_IMAGE_UNLOAD( xegs_cart ); | |
| 34 | ||
| 35 | ||
| 36 | /*----------- defined in machine/atarifdc.c -----------*/ | |
| 37 | /*************************************************************************** | |
| 38 | MACROS | |
| 39 | ***************************************************************************/ | |
| 40 | ||
| 41 | DECLARE_LEGACY_DEVICE(ATARI_FDC, atari_fdc); | |
| 42 | ||
| 43 | #define MCFG_ATARI_FDC_ADD(_tag) \ | |
| 44 | MCFG_DEVICE_ADD((_tag), ATARI_FDC, 0) | |
| 45 | ||
| 46 | ||
| 47 | /*************************************************************************** | |
| 48 | FUNCTION PROTOTYPES | |
| 49 | ***************************************************************************/ | |
| 50 | READ8_DEVICE_HANDLER( atari_serin_r ); | |
| 51 | WRITE8_DEVICE_HANDLER( atari_serout_w ); | |
| 52 | WRITE_LINE_DEVICE_HANDLER( atarifdc_pia_cb2_w ); | |
| 53 | ||
| 54 | #endif /* _ATARIDEV_H */ | |
| 55 |
| r11531 | r11532 | |
|---|---|---|
| 1 | /****************************************************f*********************** | |
| 2 | ||
| 3 | Amiga floppy disk controller emulation | |
| 4 | ||
| 5 | - The drive spins at 300 RPM = 1 Rev every 200ms | |
| 6 | - At 2usec per bit, that's 12500 bytes per track, or 6250 words per track | |
| 7 | - At 4usec per bit, that's 6250 bytes per track, or 3125 words per track | |
| 8 | - Each standard amiga sector has 544 words per sector, and 11 sectors per track = 11968 bytes | |
| 9 | - ( 12500(max) - 11968(actual) ) = 532 per track gap bytes | |
| 10 | ||
| 11 | ***************************************************************************/ | |
| 12 | ||
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | #include "includes/amiga.h" | |
| 16 | #include "imagedev/flopdrv.h" | |
| 17 | #include "formats/ami_dsk.h" | |
| 18 | #include "amigafdc.h" | |
| 19 | #include "machine/6526cia.h" | |
| 20 | ||
| 21 | ||
| 22 | #define MAX_TRACK_BYTES 12500 | |
| 23 | #define ACTUAL_TRACK_BYTES 11968 | |
| 24 | #define GAP_TRACK_BYTES ( MAX_TRACK_BYTES - ACTUAL_TRACK_BYTES ) | |
| 25 | #define ONE_SECTOR_BYTES (544*2) | |
| 26 | #define ONE_REV_TIME 200 /* ms */ | |
| 27 | #define MAX_WORDS_PER_DMA_CYCLE 32 /* 64 bytes per dma cycle */ | |
| 28 | #define DISK_DETECT_DELAY 1 | |
| 29 | #define MAX_TRACKS 160 | |
| 30 | #define MAX_MFM_TRACK_LEN 16384 | |
| 31 | ||
| 32 | #define NUM_DRIVES 2 | |
| 33 | ||
| 34 | /* required prototype */ | |
| 35 | static void setup_fdc_buffer( device_t *device,int drive ); | |
| 36 | ||
| 37 | /*************************************************************************** | |
| 38 | TYPE DEFINITIONS | |
| 39 | ***************************************************************************/ | |
| 40 | typedef struct { | |
| 41 | int motor_on; | |
| 42 | int side; | |
| 43 | int dir; | |
| 44 | int wprot; | |
| 45 | int disk_changed; | |
| 46 | device_image_interface *f; | |
| 47 | UINT32 extinfo[MAX_TRACKS]; | |
| 48 | UINT32 extoffs[MAX_TRACKS]; | |
| 49 | int is_ext_image; | |
| 50 | int cyl; | |
| 51 | int tracklen; | |
| 52 | UINT8 mfm[MAX_MFM_TRACK_LEN]; | |
| 53 | int cached; | |
| 54 | emu_timer *rev_timer; | |
| 55 | emu_timer *sync_timer; | |
| 56 | emu_timer *dma_timer; | |
| 57 | int rev_timer_started; | |
| 58 | int pos; | |
| 59 | int len; | |
| 60 | offs_t ptr; | |
| 61 | } fdc_def; | |
| 62 | ||
| 63 | typedef struct _amiga_fdc_t amiga_fdc_t; | |
| 64 | struct _amiga_fdc_t | |
| 65 | { | |
| 66 | fdc_def fdc_status[NUM_DRIVES]; | |
| 67 | ||
| 68 | /* signals */ | |
| 69 | int fdc_sel; | |
| 70 | int fdc_dir; | |
| 71 | int fdc_side; | |
| 72 | int fdc_step; | |
| 73 | int fdc_rdy; | |
| 74 | }; | |
| 75 | ||
| 76 | /***************************************************************************** | |
| 77 | INLINE FUNCTIONS | |
| 78 | *****************************************************************************/ | |
| 79 | INLINE amiga_fdc_t *get_safe_token(device_t *device) | |
| 80 | { | |
| 81 | assert(device != NULL); | |
| 82 | assert(device->type() == AMIGA_FDC); | |
| 83 | ||
| 84 | return (amiga_fdc_t *)downcast<legacy_device_base *>(device)->token(); | |
| 85 | } | |
| 86 | ||
| 87 | static TIMER_CALLBACK(fdc_rev_proc); | |
| 88 | static TIMER_CALLBACK(fdc_dma_proc); | |
| 89 | static TIMER_CALLBACK(fdc_sync_proc); | |
| 90 | static void check_extended_image( device_t *device, int id ); | |
| 91 | ||
| 92 | static void amiga_load_proc(device_image_interface &image) | |
| 93 | { | |
| 94 | amiga_fdc_t *fdc = get_safe_token(image.device().owner()); | |
| 95 | int id = floppy_get_drive(&image.device()); | |
| 96 | fdc->fdc_status[id].disk_changed = DISK_DETECT_DELAY; | |
| 97 | fdc->fdc_status[id].f = ℑ | |
| 98 | fdc->fdc_status[id].cached = -1; | |
| 99 | fdc->fdc_status[id].motor_on = 0; | |
| 100 | fdc->fdc_status[id].rev_timer_started = 0; | |
| 101 | fdc->fdc_status[id].rev_timer->reset( ); | |
| 102 | fdc->fdc_status[id].sync_timer->reset( ); | |
| 103 | fdc->fdc_status[id].dma_timer->reset( ); | |
| 104 | fdc->fdc_rdy = 0; | |
| 105 | ||
| 106 | check_extended_image( image.device().owner(), id ); | |
| 107 | } | |
| 108 | ||
| 109 | static void amiga_unload_proc(device_image_interface &image) | |
| 110 | { | |
| 111 | amiga_fdc_t *fdc = get_safe_token(image.device().owner()); | |
| 112 | int id = floppy_get_drive(&image.device()); | |
| 113 | fdc->fdc_status[id].disk_changed = DISK_DETECT_DELAY; | |
| 114 | fdc->fdc_status[id].f = NULL; | |
| 115 | fdc->fdc_status[id].cached = -1; | |
| 116 | fdc->fdc_status[id].motor_on = 0; | |
| 117 | fdc->fdc_status[id].rev_timer_started = 0; | |
| 118 | fdc->fdc_status[id].rev_timer->reset( ); | |
| 119 | fdc->fdc_status[id].sync_timer->reset( ); | |
| 120 | fdc->fdc_status[id].dma_timer->reset( ); | |
| 121 | fdc->fdc_rdy = 0; | |
| 122 | } | |
| 123 | ||
| 124 | /*------------------------------------------------- | |
| 125 | DEVICE_START(amiga_fdc) | |
| 126 | -------------------------------------------------*/ | |
| 127 | device_t *amiga_floppy_get_device_child(device_t *device,int drive) | |
| 128 | { | |
| 129 | switch(drive) { | |
| 130 | case 0 : return device->subdevice(FLOPPY_0); | |
| 131 | case 1 : return device->subdevice(FLOPPY_1); | |
| 132 | } | |
| 133 | return NULL; | |
| 134 | } | |
| 135 | ||
| 136 | static DEVICE_START(amiga_fdc) | |
| 137 | { | |
| 138 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 139 | int id; | |
| 140 | for(id=0;id<2;id++) | |
| 141 | { | |
| 142 | fdc->fdc_status[id].rev_timer = device->machine().scheduler().timer_alloc(FUNC(fdc_rev_proc), (void*)device); | |
| 143 | fdc->fdc_status[id].dma_timer = device->machine().scheduler().timer_alloc(FUNC(fdc_dma_proc), (void*)device); | |
| 144 | fdc->fdc_status[id].sync_timer = device->machine().scheduler().timer_alloc(FUNC(fdc_sync_proc), (void*)device); | |
| 145 | floppy_install_load_proc(amiga_floppy_get_device_child(device, id), amiga_load_proc); | |
| 146 | floppy_install_unload_proc(amiga_floppy_get_device_child(device, id), amiga_unload_proc); | |
| 147 | fdc->fdc_status[id].motor_on = 0; | |
| 148 | fdc->fdc_status[id].side = 0; | |
| 149 | fdc->fdc_status[id].dir = 0; | |
| 150 | fdc->fdc_status[id].wprot = 1; | |
| 151 | fdc->fdc_status[id].cyl = 0; | |
| 152 | fdc->fdc_status[id].rev_timer_started = 0; | |
| 153 | fdc->fdc_status[id].cached = -1; | |
| 154 | fdc->fdc_status[id].pos = 0; | |
| 155 | fdc->fdc_status[id].len = 0; | |
| 156 | fdc->fdc_status[id].ptr = 0; | |
| 157 | fdc->fdc_status[id].f = NULL; | |
| 158 | fdc->fdc_status[id].is_ext_image = 0; | |
| 159 | fdc->fdc_status[id].tracklen = MAX_TRACK_BYTES; | |
| 160 | fdc->fdc_status[id].disk_changed = DISK_DETECT_DELAY; | |
| 161 | fdc->fdc_status[id].rev_timer->reset( ); | |
| 162 | fdc->fdc_status[id].sync_timer->reset( ); | |
| 163 | fdc->fdc_status[id].dma_timer->reset( ); | |
| 164 | memset( fdc->fdc_status[id].mfm, 0xaa, MAX_MFM_TRACK_LEN ); | |
| 165 | } | |
| 166 | fdc->fdc_sel = 0x0f; | |
| 167 | fdc->fdc_dir = 0; | |
| 168 | fdc->fdc_side = 1; | |
| 169 | fdc->fdc_step = 1; | |
| 170 | fdc->fdc_rdy = 0; | |
| 171 | ||
| 172 | } | |
| 173 | ||
| 174 | ||
| 175 | /*------------------------------------------------- | |
| 176 | DEVICE_RESET(amiga_fdc) | |
| 177 | -------------------------------------------------*/ | |
| 178 | ||
| 179 | static DEVICE_RESET(amiga_fdc) | |
| 180 | { | |
| 181 | } | |
| 182 | ||
| 183 | static void check_extended_image( device_t *device, int id ) | |
| 184 | { | |
| 185 | UINT8 header[8], data[4]; | |
| 186 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 187 | ||
| 188 | fdc->fdc_status[id].is_ext_image = 0; | |
| 189 | ||
| 190 | if ( fdc->fdc_status[id].f->fseek( 0, SEEK_SET ) ) | |
| 191 | { | |
| 192 | logerror("FDC: image_fseek failed!\n" ); | |
| 193 | return; | |
| 194 | } | |
| 195 | ||
| 196 | fdc->fdc_status[id].f->fread( &header, sizeof( header ) ); | |
| 197 | ||
| 198 | if ( memcmp( header, "UAE--ADF", sizeof( header ) ) == 0 ) | |
| 199 | { | |
| 200 | int i; | |
| 201 | ||
| 202 | for( i = 0; i < MAX_TRACKS; i++ ) | |
| 203 | { | |
| 204 | fdc->fdc_status[id].f->fread( &data, sizeof( data ) ); | |
| 205 | ||
| 206 | /* data[0,1] = SYNC - data[2,3] = LEN */ | |
| 207 | ||
| 208 | fdc->fdc_status[id].extinfo[i] = data[0]; | |
| 209 | fdc->fdc_status[id].extinfo[i] <<= 8; | |
| 210 | fdc->fdc_status[id].extinfo[i] |= data[1]; | |
| 211 | fdc->fdc_status[id].extinfo[i] <<= 8; | |
| 212 | fdc->fdc_status[id].extinfo[i] |= data[2]; | |
| 213 | fdc->fdc_status[id].extinfo[i] <<= 8; | |
| 214 | fdc->fdc_status[id].extinfo[i] |= data[3]; | |
| 215 | ||
| 216 | if ( i == 0 ) | |
| 217 | fdc->fdc_status[id].extoffs[i] = sizeof( header ) + ( MAX_TRACKS * sizeof( data ) ); | |
| 218 | else | |
| 219 | fdc->fdc_status[id].extoffs[i] = fdc->fdc_status[id].extoffs[i-1] + ( fdc->fdc_status[id].extinfo[i-1] & 0xffff ); | |
| 220 | } | |
| 221 | ||
| 222 | fdc->fdc_status[id].is_ext_image = 1; | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | static int fdc_get_curpos( device_t *device, int drive ) | |
| 227 | { | |
| 228 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 229 | double elapsed; | |
| 230 | int speed; | |
| 231 | int bytes; | |
| 232 | int pos; | |
| 233 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 234 | ||
| 235 | if ( fdc->fdc_status[drive].rev_timer_started == 0 ) { | |
| 236 | logerror("Rev timer not started on drive %d, cant get position!\n", drive ); | |
| 237 | return 0; | |
| 238 | } | |
| 239 | ||
| 240 | elapsed = fdc->fdc_status[drive].rev_timer ->elapsed( ).as_double(); | |
| 241 | speed = ( CUSTOM_REG(REG_ADKCON) & 0x100 ) ? 2 : 4; | |
| 242 | ||
| 243 | bytes = elapsed / attotime::from_usec( speed * 8 ).as_double(); | |
| 244 | pos = bytes % ( fdc->fdc_status[drive].tracklen ); | |
| 245 | ||
| 246 | return pos; | |
| 247 | } | |
| 248 | ||
| 249 | UINT16 amiga_fdc_get_byte (device_t *device) | |
| 250 | { | |
| 251 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 252 | int pos; | |
| 253 | int i, drive = -1; | |
| 254 | UINT16 ret; | |
| 255 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 256 | ||
| 257 | ret = ( ( CUSTOM_REG(REG_DSKLEN) >> 1 ) & 0x4000 ) & ( ( CUSTOM_REG(REG_DMACON) << 10 ) & 0x4000 ); | |
| 258 | ret |= ( CUSTOM_REG(REG_DSKLEN) >> 1 ) & 0x2000; | |
| 259 | ||
| 260 | for ( i = 0; i < NUM_DRIVES; i++ ) { | |
| 261 | if ( !( fdc->fdc_sel & ( 1 << i ) ) ) | |
| 262 | drive = i; | |
| 263 | } | |
| 264 | ||
| 265 | if ( drive == -1 ) | |
| 266 | return ret; | |
| 267 | ||
| 268 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 269 | return ret; | |
| 270 | ||
| 271 | setup_fdc_buffer( device,drive ); | |
| 272 | ||
| 273 | pos = fdc_get_curpos( device, drive ); | |
| 274 | ||
| 275 | if ( fdc->fdc_status[drive].mfm[pos] == ( CUSTOM_REG(REG_DSRSYNC) >> 8 ) && | |
| 276 | fdc->fdc_status[drive].mfm[pos+1] == ( CUSTOM_REG(REG_DSRSYNC) & 0xff ) ) | |
| 277 | ret |= 0x1000; | |
| 278 | ||
| 279 | if ( pos != fdc->fdc_status[drive].pos ) { | |
| 280 | ret |= 0x8000; | |
| 281 | fdc->fdc_status[drive].pos = pos; | |
| 282 | } | |
| 283 | ||
| 284 | ret |= fdc->fdc_status[drive].mfm[pos]; | |
| 285 | ||
| 286 | return ret; | |
| 287 | } | |
| 288 | ||
| 289 | static TIMER_CALLBACK(fdc_sync_proc) | |
| 290 | { | |
| 291 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 292 | int drive = param; | |
| 293 | UINT16 sync = CUSTOM_REG(REG_DSRSYNC); | |
| 294 | int cur_pos; | |
| 295 | int sector; | |
| 296 | int time; | |
| 297 | amiga_fdc_t *fdc = get_safe_token((device_t*)ptr); | |
| 298 | ||
| 299 | /* if floppy got ejected, stop */ | |
| 300 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 301 | goto bail; | |
| 302 | ||
| 303 | if ( fdc->fdc_status[drive].motor_on == 0 ) | |
| 304 | goto bail; | |
| 305 | ||
| 306 | cur_pos = fdc_get_curpos( (device_t*)ptr, drive ); | |
| 307 | ||
| 308 | if ( cur_pos <= ( GAP_TRACK_BYTES + 6 ) ) | |
| 309 | { | |
| 310 | sector = 0; | |
| 311 | } | |
| 312 | else | |
| 313 | { | |
| 314 | sector = ( cur_pos - ( GAP_TRACK_BYTES + 6 ) ) / ONE_SECTOR_BYTES; | |
| 315 | } | |
| 316 | ||
| 317 | setup_fdc_buffer( (device_t*)ptr, drive ); | |
| 318 | ||
| 319 | if ( cur_pos < 2 ) | |
| 320 | cur_pos = 2; | |
| 321 | ||
| 322 | if ( fdc->fdc_status[drive].mfm[cur_pos-2] == ( ( sync >> 8 ) & 0xff ) && | |
| 323 | fdc->fdc_status[drive].mfm[cur_pos-1] == ( sync & 0xff ) ) | |
| 324 | { | |
| 325 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 326 | ||
| 327 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKSYN, 0xffff); | |
| 328 | } | |
| 329 | ||
| 330 | if ( sector < 10 ) | |
| 331 | { | |
| 332 | /* start the sync timer */ | |
| 333 | time = ONE_SECTOR_BYTES; | |
| 334 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 335 | time *= 8; | |
| 336 | fdc->fdc_status[drive].sync_timer->adjust(attotime::from_usec( time ), drive); | |
| 337 | return; | |
| 338 | } | |
| 339 | ||
| 340 | bail: | |
| 341 | fdc->fdc_status[drive].sync_timer->reset( ); | |
| 342 | } | |
| 343 | ||
| 344 | static TIMER_CALLBACK(fdc_dma_proc) | |
| 345 | { | |
| 346 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 347 | int drive = param; | |
| 348 | amiga_fdc_t *fdc = get_safe_token((device_t*)ptr); | |
| 349 | ||
| 350 | /* if DMA got disabled by the time we got here, stop operations */ | |
| 351 | if ( ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) == 0 ) | |
| 352 | goto bail; | |
| 353 | ||
| 354 | if ( ( CUSTOM_REG(REG_DMACON) & 0x0210 ) == 0 ) | |
| 355 | goto bail; | |
| 356 | ||
| 357 | /* if floppy got ejected, also stop */ | |
| 358 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 359 | goto bail; | |
| 360 | ||
| 361 | if ( fdc->fdc_status[drive].motor_on == 0 ) | |
| 362 | goto bail; | |
| 363 | ||
| 364 | setup_fdc_buffer( (device_t*)ptr, drive ); | |
| 365 | ||
| 366 | if ( CUSTOM_REG(REG_DSKLEN) & 0x4000 ) /* disk write case, unsupported yet */ | |
| 367 | { | |
| 368 | if ( fdc->fdc_status[drive].len > 0 ) | |
| 369 | { | |
| 370 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 371 | ||
| 372 | logerror("Write to disk unsupported yet\n" ); | |
| 373 | ||
| 374 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff); | |
| 375 | } | |
| 376 | } | |
| 377 | else | |
| 378 | { | |
| 379 | offs_t offset = fdc->fdc_status[drive].ptr; | |
| 380 | int cur_pos = fdc->fdc_status[drive].pos; | |
| 381 | int len = fdc->fdc_status[drive].len; | |
| 382 | ||
| 383 | if ( len > MAX_WORDS_PER_DMA_CYCLE ) len = MAX_WORDS_PER_DMA_CYCLE; | |
| 384 | ||
| 385 | fdc->fdc_status[drive].len -= len; | |
| 386 | ||
| 387 | while ( len-- ) | |
| 388 | { | |
| 389 | int dat = ( fdc->fdc_status[drive].mfm[cur_pos++] ) << 8; | |
| 390 | ||
| 391 | cur_pos %= ( fdc->fdc_status[drive].tracklen ); | |
| 392 | ||
| 393 | dat |= fdc->fdc_status[drive].mfm[cur_pos++]; | |
| 394 | ||
| 395 | cur_pos %= ( fdc->fdc_status[drive].tracklen ); | |
| 396 | ||
| 397 | (*state->m_chip_ram_w)(state, offset, dat); | |
| 398 | ||
| 399 | offset += 2; | |
| 400 | } | |
| 401 | ||
| 402 | fdc->fdc_status[drive].ptr = offset; | |
| 403 | fdc->fdc_status[drive].pos = cur_pos; | |
| 404 | ||
| 405 | if ( fdc->fdc_status[drive].len <= 0 ) | |
| 406 | { | |
| 407 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 408 | ||
| 409 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff); | |
| 410 | } | |
| 411 | else | |
| 412 | { | |
| 413 | int time; | |
| 414 | double len_words = fdc->fdc_status[drive].len; | |
| 415 | if ( len_words > MAX_WORDS_PER_DMA_CYCLE ) len_words = MAX_WORDS_PER_DMA_CYCLE; | |
| 416 | ||
| 417 | time = len_words * 2; | |
| 418 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 419 | time *= 8; | |
| 420 | fdc->fdc_status[drive].dma_timer->adjust(attotime::from_usec( time ), drive); | |
| 421 | return; | |
| 422 | } | |
| 423 | } | |
| 424 | ||
| 425 | bail: | |
| 426 | fdc->fdc_status[drive].dma_timer->reset( ); | |
| 427 | } | |
| 428 | ||
| 429 | void amiga_fdc_setup_dma( device_t *device ) { | |
| 430 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 431 | int i, cur_pos, drive = -1, len_words = 0; | |
| 432 | int time = 0; | |
| 433 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 434 | ||
| 435 | for ( i = 0; i < NUM_DRIVES; i++ ) { | |
| 436 | if ( !( fdc->fdc_sel & ( 1 << i ) ) ) | |
| 437 | drive = i; | |
| 438 | } | |
| 439 | ||
| 440 | if ( drive == -1 ) { | |
| 441 | address_space *space = device->machine().device("maincpu")->memory().space(AS_PROGRAM); | |
| 442 | ||
| 443 | logerror("Disk DMA started with no drive selected!\n" ); | |
| 444 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff); | |
| 445 | return; | |
| 446 | } | |
| 447 | ||
| 448 | if ( ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) == 0 ) | |
| 449 | goto bail; | |
| 450 | ||
| 451 | if ( ( CUSTOM_REG(REG_DMACON) & 0x0210 ) == 0 ) | |
| 452 | goto bail; | |
| 453 | ||
| 454 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 455 | goto bail; | |
| 456 | ||
| 457 | setup_fdc_buffer( device,drive ); | |
| 458 | ||
| 459 | fdc->fdc_status[drive].len = CUSTOM_REG(REG_DSKLEN) & 0x3fff; | |
| 460 | fdc->fdc_status[drive].ptr = CUSTOM_REG_LONG(REG_DSKPTH); | |
| 461 | fdc->fdc_status[drive].pos = cur_pos = fdc_get_curpos( device, drive ); | |
| 462 | ||
| 463 | /* we'll do a set amount at a time */ | |
| 464 | len_words = fdc->fdc_status[drive].len; | |
| 465 | if ( len_words > MAX_WORDS_PER_DMA_CYCLE ) len_words = MAX_WORDS_PER_DMA_CYCLE; | |
| 466 | ||
| 467 | if ( CUSTOM_REG(REG_ADKCON) & 0x0400 ) { /* Wait for sync */ | |
| 468 | if ( CUSTOM_REG(REG_DSRSYNC) != 0x4489 ) { | |
| 469 | logerror("Attempting to read a non-standard SYNC\n" ); | |
| 470 | } | |
| 471 | ||
| 472 | i = cur_pos; | |
| 473 | do { | |
| 474 | if ( fdc->fdc_status[drive].mfm[i] == ( CUSTOM_REG(REG_DSRSYNC) >> 8 ) && | |
| 475 | fdc->fdc_status[drive].mfm[i+1] == ( CUSTOM_REG(REG_DSRSYNC) & 0xff ) ) | |
| 476 | break; | |
| 477 | ||
| 478 | i++; | |
| 479 | i %= ( fdc->fdc_status[drive].tracklen ); | |
| 480 | time++; | |
| 481 | } while( i != cur_pos ); | |
| 482 | ||
| 483 | if ( i == cur_pos && time != 0 ) { | |
| 484 | logerror("SYNC not found on track!\n" ); | |
| 485 | return; | |
| 486 | } else { | |
| 487 | fdc->fdc_status[drive].pos = i + 2; | |
| 488 | time += 2; | |
| 489 | } | |
| 490 | } | |
| 491 | ||
| 492 | time += len_words * 2; | |
| 493 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 494 | time *= 8; | |
| 495 | fdc->fdc_status[drive].dma_timer->adjust(attotime::from_usec( time ), drive); | |
| 496 | ||
| 497 | return; | |
| 498 | ||
| 499 | bail: | |
| 500 | fdc->fdc_status[drive].dma_timer->reset( ); | |
| 501 | } | |
| 502 | ||
| 503 | static void setup_fdc_buffer( device_t *device,int drive ) | |
| 504 | { | |
| 505 | int sector, offset, len; | |
| 506 | UINT8 temp_cyl[512*11]; | |
| 507 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 508 | ||
| 509 | /* no disk in drive */ | |
| 510 | if ( fdc->fdc_status[drive].f == NULL ) { | |
| 511 | memset( &fdc->fdc_status[drive].mfm[0], 0xaa, 32 ); | |
| 512 | fdc->fdc_status[drive].disk_changed = DISK_DETECT_DELAY; | |
| 513 | return; | |
| 514 | } | |
| 515 | ||
| 516 | len = 512*11; | |
| 517 | ||
| 518 | offset = ( fdc->fdc_status[drive].cyl << 1 ) | fdc->fdc_side; | |
| 519 | ||
| 520 | if ( fdc->fdc_status[drive].cached == offset ) | |
| 521 | return; | |
| 522 | ||
| 523 | #if 0 | |
| 524 | popmessage("T:%d S:%d", fdc->fdc_status[drive].cyl, fdc_side ); | |
| 525 | #endif | |
| 526 | ||
| 527 | if ( fdc->fdc_status[drive].is_ext_image ) | |
| 528 | { | |
| 529 | len = fdc->fdc_status[drive].extinfo[offset] & 0xffff; | |
| 530 | ||
| 531 | if ( len > ( MAX_MFM_TRACK_LEN - 2 ) ) | |
| 532 | len = MAX_MFM_TRACK_LEN - 2; | |
| 533 | ||
| 534 | if ( fdc->fdc_status[drive].f->fseek( fdc->fdc_status[drive].extoffs[offset], SEEK_SET ) ) | |
| 535 | { | |
| 536 | logerror("FDC: image_fseek failed!\n" ); | |
| 537 | fdc->fdc_status[drive].f = NULL; | |
| 538 | fdc->fdc_status[drive].disk_changed = DISK_DETECT_DELAY; | |
| 539 | return; | |
| 540 | } | |
| 541 | ||
| 542 | /* if SYNC is 0000, then its a regular amiga dos track image */ | |
| 543 | if ( ( fdc->fdc_status[drive].extinfo[offset] >> 16 ) == 0x0000 ) | |
| 544 | { | |
| 545 | fdc->fdc_status[drive].f->fread( temp_cyl, len ); | |
| 546 | /* fall through to regular load */ | |
| 547 | } | |
| 548 | else /* otherwise, it's a raw track */ | |
| 549 | { | |
| 550 | fdc->fdc_status[drive].mfm[0] = ( fdc->fdc_status[drive].extinfo[offset] >> 24 ) & 0xff; | |
| 551 | fdc->fdc_status[drive].mfm[1] = ( fdc->fdc_status[drive].extinfo[offset] >> 16 ) & 0xff; | |
| 552 | fdc->fdc_status[drive].f->fread( &fdc->fdc_status[drive].mfm[2], len ); | |
| 553 | fdc->fdc_status[drive].tracklen = len + 2; | |
| 554 | fdc->fdc_status[drive].cached = offset; | |
| 555 | return; | |
| 556 | } | |
| 557 | } | |
| 558 | else | |
| 559 | { | |
| 560 | if ( fdc->fdc_status[drive].f->fseek( offset * len, SEEK_SET ) ) | |
| 561 | { | |
| 562 | logerror("FDC: image_fseek failed!\n" ); | |
| 563 | fdc->fdc_status[drive].f = NULL; | |
| 564 | fdc->fdc_status[drive].disk_changed = DISK_DETECT_DELAY; | |
| 565 | return; | |
| 566 | } | |
| 567 | ||
| 568 | fdc->fdc_status[drive].f->fread( temp_cyl, len ); | |
| 569 | } | |
| 570 | ||
| 571 | fdc->fdc_status[drive].tracklen = MAX_TRACK_BYTES; | |
| 572 | ||
| 573 | memset( &fdc->fdc_status[drive].mfm[ONE_SECTOR_BYTES*11], 0xaa, GAP_TRACK_BYTES ); | |
| 574 | ||
| 575 | for ( sector = 0; sector < 11; sector++ ) { | |
| 576 | int x; | |
| 577 | UINT8 *dest = ( &fdc->fdc_status[drive].mfm[(ONE_SECTOR_BYTES*sector)] ); | |
| 578 | UINT8 *src = &temp_cyl[sector*512]; | |
| 579 | UINT32 tmp; | |
| 580 | UINT32 even, odd; | |
| 581 | UINT32 hck = 0, dck = 0; | |
| 582 | ||
| 583 | /* Preamble and sync */ | |
| 584 | *(dest + 0) = 0xaa; | |
| 585 | *(dest + 1) = 0xaa; | |
| 586 | *(dest + 2) = 0xaa; | |
| 587 | *(dest + 3) = 0xaa; | |
| 588 | *(dest + 4) = 0x44; | |
| 589 | *(dest + 5) = 0x89; | |
| 590 | *(dest + 6) = 0x44; | |
| 591 | *(dest + 7) = 0x89; | |
| 592 | ||
| 593 | /* Track and sector info */ | |
| 594 | ||
| 595 | tmp = 0xff000000 | (offset<<16) | (sector<<8) | (11 - sector); | |
| 596 | odd = (tmp & 0x55555555) | 0xaaaaaaaa; | |
| 597 | even = ( ( tmp >> 1 ) & 0x55555555 ) | 0xaaaaaaaa; | |
| 598 | *(dest + 8) = (UINT8) ((even & 0xff000000)>>24); | |
| 599 | *(dest + 9) = (UINT8) ((even & 0xff0000)>>16); | |
| 600 | *(dest + 10) = (UINT8) ((even & 0xff00)>>8); | |
| 601 | *(dest + 11) = (UINT8) ((even & 0xff)); | |
| 602 | *(dest + 12) = (UINT8) ((odd & 0xff000000)>>24); | |
| 603 | *(dest + 13) = (UINT8) ((odd & 0xff0000)>>16); | |
| 604 | *(dest + 14) = (UINT8) ((odd & 0xff00)>>8); | |
| 605 | *(dest + 15) = (UINT8) ((odd & 0xff)); | |
| 606 | ||
| 607 | /* Fill unused space */ | |
| 608 | ||
| 609 | for (x = 16 ; x < 48; x++) | |
| 610 | *(dest + x) = 0xaa; | |
| 611 | ||
| 612 | /* Encode data section of sector */ | |
| 613 | ||
| 614 | for (x = 64 ; x < 576; x++) | |
| 615 | { | |
| 616 | tmp = *(src + x - 64); | |
| 617 | odd = (tmp & 0x55); | |
| 618 | even = (tmp>>1) & 0x55; | |
| 619 | *(dest + x) = (UINT8) (even | 0xaa); | |
| 620 | *(dest + x + 512) = (UINT8) (odd | 0xaa); | |
| 621 | } | |
| 622 | ||
| 623 | /* Calculate checksum for unused space */ | |
| 624 | ||
| 625 | for(x = 8; x < 48; x += 4) | |
| 626 | hck ^= (((UINT32) *(dest + x))<<24) | (((UINT32) *(dest + x + 1))<<16) | | |
| 627 | (((UINT32) *(dest + x + 2))<<8) | ((UINT32) *(dest + x + 3)); | |
| 628 | ||
| 629 | even = odd = hck; | |
| 630 | odd >>= 1; | |
| 631 | even |= 0xaaaaaaaa; | |
| 632 | odd |= 0xaaaaaaaa; | |
| 633 | ||
| 634 | *(dest + 48) = (UINT8) ((odd & 0xff000000)>>24); | |
| 635 | *(dest + 49) = (UINT8) ((odd & 0xff0000)>>16); | |
| 636 | *(dest + 50) = (UINT8) ((odd & 0xff00)>>8); | |
| 637 | *(dest + 51) = (UINT8) (odd & 0xff); | |
| 638 | *(dest + 52) = (UINT8) ((even & 0xff000000)>>24); | |
| 639 | *(dest + 53) = (UINT8) ((even & 0xff0000)>>16); | |
| 640 | *(dest + 54) = (UINT8) ((even & 0xff00)>>8); | |
| 641 | *(dest + 55) = (UINT8) (even & 0xff); | |
| 642 | ||
| 643 | /* Calculate checksum for data section */ | |
| 644 | ||
| 645 | for(x = 64; x < 1088; x += 4) | |
| 646 | dck ^= (((UINT32) *(dest + x))<<24) | (((UINT32) *(dest + x + 1))<<16) | | |
| 647 | (((UINT32) *(dest + x + 2))<< 8) | ((UINT32) *(dest + x + 3)); | |
| 648 | even = odd = dck; | |
| 649 | odd >>= 1; | |
| 650 | even |= 0xaaaaaaaa; | |
| 651 | odd |= 0xaaaaaaaa; | |
| 652 | *(dest + 56) = (UINT8) ((odd & 0xff000000)>>24); | |
| 653 | *(dest + 57) = (UINT8) ((odd & 0xff0000)>>16); | |
| 654 | *(dest + 58) = (UINT8) ((odd & 0xff00)>>8); | |
| 655 | *(dest + 59) = (UINT8) (odd & 0xff); | |
| 656 | *(dest + 60) = (UINT8) ((even & 0xff000000)>>24); | |
| 657 | *(dest + 61) = (UINT8) ((even & 0xff0000)>>16); | |
| 658 | *(dest + 62) = (UINT8) ((even & 0xff00)>>8); | |
| 659 | *(dest + 63) = (UINT8) (even & 0xff); | |
| 660 | } | |
| 661 | ||
| 662 | // update MFM data with proper CLK signal | |
| 663 | int lastbit= 0; | |
| 664 | for(int i=0;i<MAX_TRACK_BYTES ;i++) | |
| 665 | { | |
| 666 | UINT8 c=fdc->fdc_status[drive].mfm[i]; | |
| 667 | UINT8 dat = 0; | |
| 668 | for(int j=0;j<8;j=j+2) | |
| 669 | { | |
| 670 | UINT8 c1=(c>>(6-j))&0x3; | |
| 671 | if(c1&0x1) | |
| 672 | { | |
| 673 | dat |= (0x01<<(6-j)); | |
| 674 | lastbit=1; | |
| 675 | } | |
| 676 | else | |
| 677 | { | |
| 678 | if(lastbit==0 && (c1&0x2)) | |
| 679 | { | |
| 680 | dat |= (0x02<<(6-j)); | |
| 681 | } | |
| 682 | else | |
| 683 | { | |
| 684 | dat |= (0x00<<(6-j)); | |
| 685 | } | |
| 686 | lastbit=0; | |
| 687 | } | |
| 688 | } | |
| 689 | fdc->fdc_status[drive].mfm[i] = dat; | |
| 690 | } | |
| 691 | fdc->fdc_status[drive].cached = offset; | |
| 692 | } | |
| 693 | ||
| 694 | static TIMER_CALLBACK(fdc_rev_proc) | |
| 695 | { | |
| 696 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 697 | int drive = param; | |
| 698 | int time; | |
| 699 | device_t *cia; | |
| 700 | amiga_fdc_t *fdc = get_safe_token((device_t*)ptr); | |
| 701 | ||
| 702 | /* Issue a index pulse when a disk revolution completes */ | |
| 703 | cia = machine.device("cia_1"); | |
| 704 | mos6526_flag_w(cia, 0); | |
| 705 | mos6526_flag_w(cia, 1); | |
| 706 | ||
| 707 | fdc->fdc_status[drive].rev_timer->adjust(attotime::from_msec( ONE_REV_TIME ), drive); | |
| 708 | fdc->fdc_status[drive].rev_timer_started = 1; | |
| 709 | ||
| 710 | if ( fdc->fdc_status[drive].is_ext_image == 0 ) | |
| 711 | { | |
| 712 | /* also start the sync timer */ | |
| 713 | time = GAP_TRACK_BYTES + 6; | |
| 714 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 715 | time *= 8; | |
| 716 | fdc->fdc_status[drive].sync_timer->adjust(attotime::from_usec( time ), drive); | |
| 717 | } | |
| 718 | } | |
| 719 | ||
| 720 | static void start_rev_timer( device_t *device,int drive ) { | |
| 721 | // double time; | |
| 722 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 723 | ||
| 724 | if ( fdc->fdc_status[drive].rev_timer_started ) { | |
| 725 | logerror("Revolution timer started twice?!\n" ); | |
| 726 | return; | |
| 727 | } | |
| 728 | ||
| 729 | fdc->fdc_status[drive].rev_timer->adjust(attotime::from_msec( ONE_REV_TIME ), drive); | |
| 730 | fdc->fdc_status[drive].rev_timer_started = 1; | |
| 731 | } | |
| 732 | ||
| 733 | static void stop_rev_timer( device_t *device,int drive ) { | |
| 734 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 735 | ||
| 736 | if ( fdc->fdc_status[drive].rev_timer_started == 0 ) { | |
| 737 | logerror("Revolution timer never started?!\n" ); | |
| 738 | return; | |
| 739 | } | |
| 740 | ||
| 741 | fdc->fdc_status[drive].rev_timer->reset( ); | |
| 742 | fdc->fdc_status[drive].rev_timer_started = 0; | |
| 743 | fdc->fdc_status[drive].dma_timer->reset( ); | |
| 744 | fdc->fdc_status[drive].sync_timer->reset( ); | |
| 745 | } | |
| 746 | ||
| 747 | static void fdc_setup_leds(device_t *device, int drive ) { | |
| 748 | ||
| 749 | char portname[12]; | |
| 750 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 751 | sprintf(portname, "drive_%d_led", drive); | |
| 752 | output_set_value(portname, fdc->fdc_status[drive].motor_on == 0 ? 0 : 1); | |
| 753 | ||
| 754 | if ( drive == 0 ) | |
| 755 | set_led_status(device->machine(), 1, fdc->fdc_status[drive].motor_on ); /* update internal drive led */ | |
| 756 | ||
| 757 | if ( drive == 1 ) | |
| 758 | set_led_status(device->machine(), 2, fdc->fdc_status[drive].motor_on ); /* update external drive led */ | |
| 759 | } | |
| 760 | ||
| 761 | static void fdc_stepdrive( device_t *device,int drive ) { | |
| 762 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 763 | ||
| 764 | if ( fdc->fdc_dir ) { | |
| 765 | if ( fdc->fdc_status[drive].cyl ) | |
| 766 | fdc->fdc_status[drive].cyl--; | |
| 767 | } else { | |
| 768 | if ( fdc->fdc_status[drive].cyl < 79 ) | |
| 769 | fdc->fdc_status[drive].cyl++; | |
| 770 | } | |
| 771 | ||
| 772 | /* Update disk detection if applicable */ | |
| 773 | if ( fdc->fdc_status[drive].f != NULL ) | |
| 774 | { | |
| 775 | if ( fdc->fdc_status[drive].disk_changed > 0 ) | |
| 776 | fdc->fdc_status[drive].disk_changed--; | |
| 777 | } | |
| 778 | } | |
| 779 | ||
| 780 | static void fdc_motor( device_t *device,int drive, int off ) { | |
| 781 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 782 | int on = !off; | |
| 783 | ||
| 784 | if ( ( fdc->fdc_status[drive].motor_on == 0 ) && on ) { | |
| 785 | fdc->fdc_status[drive].pos = 0; | |
| 786 | ||
| 787 | start_rev_timer( device,drive ); | |
| 788 | ||
| 789 | } else { | |
| 790 | if ( fdc->fdc_status[drive].motor_on && off ) | |
| 791 | stop_rev_timer(device, drive ); | |
| 792 | } | |
| 793 | ||
| 794 | fdc->fdc_status[drive].motor_on = on; | |
| 795 | } | |
| 796 | ||
| 797 | WRITE8_DEVICE_HANDLER( amiga_fdc_control_w ) | |
| 798 | { | |
| 799 | int step_pulse; | |
| 800 | int drive; | |
| 801 | ||
| 802 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 803 | ||
| 804 | if ( fdc->fdc_sel != ( ( data >> 3 ) & 15 ) ) | |
| 805 | fdc->fdc_rdy = 0; | |
| 806 | ||
| 807 | fdc->fdc_sel = ( data >> 3 ) & 15; | |
| 808 | fdc->fdc_side = 1 - ( ( data >> 2 ) & 1 ); | |
| 809 | fdc->fdc_dir = ( data >> 1 ) & 1; | |
| 810 | ||
| 811 | step_pulse = data & 1; | |
| 812 | ||
| 813 | if ( fdc->fdc_step != step_pulse ) { | |
| 814 | fdc->fdc_step = step_pulse; | |
| 815 | ||
| 816 | if ( fdc->fdc_step == 0 ) { | |
| 817 | for ( drive = 0; drive < NUM_DRIVES; drive++ ) { | |
| 818 | if ( !( fdc->fdc_sel & ( 1 << drive ) ) ) | |
| 819 | fdc_stepdrive( device, drive ); | |
| 820 | } | |
| 821 | } | |
| 822 | } | |
| 823 | ||
| 824 | for ( drive = 0; drive < NUM_DRIVES; drive++ ) { | |
| 825 | if ( !( fdc->fdc_sel & ( 1 << drive ) ) ) { | |
| 826 | fdc_motor( device, drive, ( data >> 7 ) & 1 ); | |
| 827 | fdc_setup_leds( device,drive ); | |
| 828 | } | |
| 829 | } | |
| 830 | } | |
| 831 | ||
| 832 | UINT8 amiga_fdc_status_r (device_t *device) | |
| 833 | { | |
| 834 | int drive = -1, ret = 0x3c; | |
| 835 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 836 | for ( drive = 0; drive < NUM_DRIVES; drive++ ) { | |
| 837 | if ( !( fdc->fdc_sel & ( 1 << drive ) ) ) { | |
| 838 | ||
| 839 | if ( fdc->fdc_status[drive].motor_on ) { | |
| 840 | if ( fdc->fdc_rdy ) ret &= ~0x20; | |
| 841 | fdc->fdc_rdy = 1; | |
| 842 | } else { | |
| 843 | /* return drive id */ | |
| 844 | ret &= ~0x20; | |
| 845 | } | |
| 846 | ||
| 847 | if ( fdc->fdc_status[drive].cyl == 0 ) | |
| 848 | ret &= ~0x10; | |
| 849 | ||
| 850 | if ( fdc->fdc_status[drive].wprot ) | |
| 851 | ret &= ~0x08; | |
| 852 | ||
| 853 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 854 | ret &= ~0x04; | |
| 855 | ||
| 856 | return ret; | |
| 857 | } | |
| 858 | } | |
| 859 | ||
| 860 | return ret; | |
| 861 | } | |
| 862 | ||
| 863 | static const floppy_config amiga_floppy_config = | |
| 864 | { | |
| 865 | DEVCB_NULL, | |
| 866 | DEVCB_NULL, | |
| 867 | DEVCB_NULL, | |
| 868 | DEVCB_NULL, | |
| 869 | DEVCB_NULL, | |
| 870 | FLOPPY_STANDARD_3_5_DSHD, | |
| 871 | FLOPPY_OPTIONS_NAME(amiga_only), | |
| 872 | NULL | |
| 873 | }; | |
| 874 | ||
| 875 | static MACHINE_CONFIG_FRAGMENT( amiga_fdc ) | |
| 876 | MCFG_FLOPPY_2_DRIVES_ADD(amiga_floppy_config) | |
| 877 | MACHINE_CONFIG_END | |
| 878 | ||
| 879 | ||
| 880 | DEVICE_GET_INFO( amiga_fdc ) | |
| 881 | { | |
| 882 | switch (state) | |
| 883 | { | |
| 884 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 885 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; | |
| 886 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(amiga_fdc_t); break; | |
| 887 | ||
| 888 | /* --- the following bits of info are returned as pointers --- */ | |
| 889 | case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(amiga_fdc); break; | |
| 890 | ||
| 891 | /* --- the following bits of info are returned as pointers to data or functions --- */ | |
| 892 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(amiga_fdc); break; | |
| 893 | case DEVINFO_FCT_STOP: /* Nothing */ break; | |
| 894 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(amiga_fdc); break; | |
| 895 | ||
| 896 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 897 | case DEVINFO_STR_NAME: strcpy(info->s, "Amiga FDC"); break; | |
| 898 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Amiga FDC"); break; | |
| 899 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; | |
| 900 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; | |
| 901 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; | |
| 902 | } | |
| 903 | } | |
| 904 | ||
| 905 | DEFINE_LEGACY_DEVICE(AMIGA_FDC, amiga_fdc); |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Amiga keyboard controller emulation | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | ||
| 8 | #include "emu.h" | |
| 9 | #include "includes/amiga.h" | |
| 10 | #include "amigakbd.h" | |
| 11 | #include "machine/6526cia.h" | |
| 12 | ||
| 13 | ||
| 14 | #define KEYBOARD_BUFFER_SIZE 256 | |
| 15 | ||
| 16 | typedef struct | |
| 17 | { | |
| 18 | UINT8 *buf; | |
| 19 | int buf_pos; | |
| 20 | int cur_pos; | |
| 21 | emu_timer *timer; | |
| 22 | } amigakbd_t; | |
| 23 | static amigakbd_t kbd; | |
| 24 | ||
| 25 | static void kbd_sendscancode( running_machine &machine, UINT8 scancode ) | |
| 26 | { | |
| 27 | int j; | |
| 28 | device_t *cia = machine.device("cia_0"); | |
| 29 | ||
| 30 | /* send over to the cia A */ | |
| 31 | for( j = 0; j < 8; j++ ) | |
| 32 | { | |
| 33 | mos6526_cnt_w( cia, 0 ); /* lower cnt */ | |
| 34 | mos6526_sp_w( cia, BIT(scancode << j, 7) ); /* set the serial data */ | |
| 35 | mos6526_cnt_w( cia, 1 ); /* raise cnt */ | |
| 36 | } | |
| 37 | } | |
| 38 | ||
| 39 | static TIMER_CALLBACK( kbd_update_callback ) | |
| 40 | { | |
| 41 | UINT8 scancode; | |
| 42 | ||
| 43 | (void)param; | |
| 44 | ||
| 45 | /* if we don't have pending data, bail */ | |
| 46 | ||
| 47 | if ( kbd.buf_pos == kbd.cur_pos ) | |
| 48 | return; | |
| 49 | ||
| 50 | /* fetch the next scan code and send it to the Amiga */ | |
| 51 | scancode = kbd.buf[kbd.cur_pos++]; | |
| 52 | kbd.cur_pos %= KEYBOARD_BUFFER_SIZE; | |
| 53 | kbd_sendscancode( machine, scancode ); | |
| 54 | ||
| 55 | /* if we still have more data, schedule another update */ | |
| 56 | if ( kbd.buf_pos != kbd.cur_pos ) | |
| 57 | { | |
| 58 | kbd.timer->adjust(machine.primary_screen->frame_period() / 4); | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | static INPUT_CHANGED( kbd_update ) | |
| 63 | { | |
| 64 | int index = (int)(FPTR)param, i; | |
| 65 | UINT32 oldvalue = oldval * field.mask, newvalue = newval * field.mask; | |
| 66 | UINT32 delta = oldvalue ^ newvalue; | |
| 67 | ||
| 68 | /* Special case Page UP, which we will use as Action Replay button */ | |
| 69 | if ( (index == 3) && ( delta & 0x80000000 ) && ( newvalue & 0x80000000 ) ) | |
| 70 | { | |
| 71 | const amiga_machine_interface *amiga_intf = amiga_get_interface(field.machine()); | |
| 72 | ||
| 73 | if ( amiga_intf != NULL && amiga_intf->nmi_callback ) | |
| 74 | { | |
| 75 | (*amiga_intf->nmi_callback)(field.machine()); | |
| 76 | } | |
| 77 | } | |
| 78 | else | |
| 79 | { | |
| 80 | int key_buf_was_empty = ( kbd.buf_pos == kbd.cur_pos ) ? 1 : 0; | |
| 81 | ||
| 82 | for( i = 0; i < 32; i++ ) | |
| 83 | { | |
| 84 | if ( delta & ( 1 << i ) ) | |
| 85 | { | |
| 86 | int down = ( newvalue & ( 1 << i ) ) ? 0 : 1; | |
| 87 | int scancode = ( ( (index*32)+i ) << 1 ) | down; | |
| 88 | int amigacode = ~scancode; | |
| 89 | ||
| 90 | /* add the keycode to the buffer */ | |
| 91 | kbd.buf[kbd.buf_pos++] = amigacode & 0xff; | |
| 92 | kbd.buf_pos %= KEYBOARD_BUFFER_SIZE; | |
| 93 | } | |
| 94 | } | |
| 95 | ||
| 96 | /* if the buffer was empty and we have new data, start a timer to send the keystrokes */ | |
| 97 | if ( key_buf_was_empty && ( kbd.buf_pos != kbd.cur_pos ) ) | |
| 98 | { | |
| 99 | kbd.timer->adjust(field.machine().primary_screen->frame_period() / 4); | |
| 100 | } | |
| 101 | } | |
| 102 | } | |
| 103 | ||
| 104 | void amigakbd_init( running_machine &machine ) | |
| 105 | { | |
| 106 | /* allocate a keyboard buffer */ | |
| 107 | kbd.buf = auto_alloc_array(machine, UINT8, KEYBOARD_BUFFER_SIZE); | |
| 108 | kbd.buf_pos = 0; | |
| 109 | kbd.cur_pos = 0; | |
| 110 | kbd.timer = machine.scheduler().timer_alloc(FUNC(kbd_update_callback)); | |
| 111 | kbd.timer->reset(); | |
| 112 | } | |
| 113 | ||
| 114 | /*********************************************************************************************/ | |
| 115 | ||
| 116 | /* Layout is for the US A500 keyboard */ | |
| 117 | ||
| 118 | INPUT_PORTS_START( amiga_us_keyboard ) | |
| 119 | PORT_START("amiga_keyboard_0") | |
| 120 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // 00 | |
| 121 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 01 | |
| 122 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // 02 | |
| 123 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 03 | |
| 124 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 04 | |
| 125 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 05 | |
| 126 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // 06 | |
| 127 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // 07 | |
| 128 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // 08 | |
| 129 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // 09 | |
| 130 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // 0A | |
| 131 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 0B | |
| 132 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') // 0C | |
| 133 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') PORT_CHAR('\xA6') // 0D | |
| 134 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 0) // 0E | |
| 135 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 0F | |
| 136 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 10 | |
| 137 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 11 | |
| 138 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 12 | |
| 139 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 13 | |
| 140 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 14 | |
| 141 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 15 | |
| 142 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 16 | |
| 143 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 17 | |
| 144 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 18 | |
| 145 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // 19 | |
| 146 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') // 1A | |
| 147 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') // 1B | |
| 148 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 0) // 1C | |
| 149 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 1D | |
| 150 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 1E | |
| 151 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 1F | |
| 152 | ||
| 153 | PORT_START("amiga_keyboard_1") | |
| 154 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 20 | |
| 155 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 21 | |
| 156 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // 22 | |
| 157 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 23 | |
| 158 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 24 | |
| 159 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 25 | |
| 160 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // 26 | |
| 161 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 27 | |
| 162 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 28 | |
| 163 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // 29 | |
| 164 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') // 2A | |
| 165 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 2B | |
| 166 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 2C | |
| 167 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 2D | |
| 168 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 2E | |
| 169 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 2F | |
| 170 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 30 | |
| 171 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 31 | |
| 172 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // 32 | |
| 173 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 33 | |
| 174 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 34 | |
| 175 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 35 | |
| 176 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 36 | |
| 177 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 37 | |
| 178 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') // 38 | |
| 179 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') // 39 | |
| 180 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // 3A | |
| 181 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 3B | |
| 182 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))// 3C | |
| 183 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 3D | |
| 184 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 3E | |
| 185 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 3F | |
| 186 | ||
| 187 | PORT_START("amiga_keyboard_2") | |
| 188 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 40 | |
| 189 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) // 41 | |
| 190 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') // 42 | |
| 191 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // 43 | |
| 192 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // 44 | |
| 193 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) // 45 | |
| 194 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // 46 | |
| 195 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 47 | |
| 196 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 48 | |
| 197 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 49 | |
| 198 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 4A | |
| 199 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 4B | |
| 200 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) // 4C | |
| 201 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) // 4D | |
| 202 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // 4E | |
| 203 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // 4F | |
| 204 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // 50 | |
| 205 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // 51 | |
| 206 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 52 | |
| 207 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // 53 | |
| 208 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // 54 | |
| 209 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // 55 | |
| 210 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // 56 | |
| 211 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // 57 | |
| 212 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // 58 | |
| 213 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // 59 | |
| 214 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 5A | |
| 215 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 5B | |
| 216 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 5C | |
| 217 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 5D | |
| 218 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) // 5E | |
| 219 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // 5F | |
| 220 | ||
| 221 | PORT_START("amiga_keyboard_3") | |
| 222 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 60 | |
| 223 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 61 | |
| 224 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) // 62 | |
| 225 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))// 63 | |
| 226 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Alt (Left)") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // 64 | |
| 227 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Alt (Right)") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) // 65 | |
| 228 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Amiga A (Left)") PORT_CODE(KEYCODE_LWIN) // 66 | |
| 229 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Amiga A (Right)") PORT_CODE(KEYCODE_RWIN) // 67 | |
| 230 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 68 | |
| 231 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 69 | |
| 232 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6A | |
| 233 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6B | |
| 234 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6C | |
| 235 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6D | |
| 236 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6E | |
| 237 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6F | |
| 238 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 70 | |
| 239 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 71 | |
| 240 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 72 | |
| 241 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 73 | |
| 242 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 74 | |
| 243 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 75 | |
| 244 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 76 | |
| 245 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 77 | |
| 246 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 78 | |
| 247 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 79 | |
| 248 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7A | |
| 249 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7B | |
| 250 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7C | |
| 251 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7D | |
| 252 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7E | |
| 253 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_CODE(KEYCODE_PGUP) // 7F NMI button | |
| 254 | INPUT_PORTS_END |
| r11531 | r11532 | |
|---|---|---|
| 1 | #ifndef AMIGAFDC_H | |
| 2 | #define AMIGAFDC_H | |
| 3 | ||
| 4 | WRITE8_DEVICE_HANDLER( amiga_fdc_control_w ); | |
| 5 | UINT8 amiga_fdc_status_r (device_t *device); | |
| 6 | UINT16 amiga_fdc_get_byte (device_t *device); | |
| 7 | void amiga_fdc_setup_dma( device_t *device ); | |
| 8 | ||
| 9 | /*************************************************************************** | |
| 10 | MACROS | |
| 11 | ***************************************************************************/ | |
| 12 | ||
| 13 | DECLARE_LEGACY_DEVICE(AMIGA_FDC, amiga_fdc); | |
| 14 | ||
| 15 | #define MCFG_AMIGA_FDC_ADD(_tag) \ | |
| 16 | MCFG_DEVICE_ADD((_tag), AMIGA_FDC, 0) | |
| 17 | ||
| 18 | #endif /* AMIGAFDC_H */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | #ifndef AMIGAKBD_H | |
| 2 | #define AMIGAKBD_H | |
| 3 | ||
| 4 | void amigakbd_init( running_machine &machine ); | |
| 5 | ||
| 6 | INPUT_PORTS_EXTERN( amiga_us_keyboard ); | |
| 7 | ||
| 8 | #endif /* AMIGAKBD_H */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Amiga cartridge emulation | |
| 4 | ||
| 5 | TODO: | |
| 6 | - Investigate why the AR2/3 sometimes garble the video on exit from the cart | |
| 7 | - Add Nordic Power and similar carts | |
| 8 | - Add HRTMon A1200 cart | |
| 9 | ||
| 10 | ***************************************************************************/ | |
| 11 | ||
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "includes/amiga.h" | |
| 15 | #include "cpu/m68000/m68000.h" | |
| 16 | #include "machine/6526cia.h" | |
| 17 | #include "machine/amigacrt.h" | |
| 18 | ||
| 19 | enum | |
| 20 | { | |
| 21 | /* supported cartridges */ | |
| 22 | ACTION_REPLAY = 0, | |
| 23 | ACTION_REPLAY_MKII, | |
| 24 | ACTION_REPLAY_MKIII | |
| 25 | }; | |
| 26 | ||
| 27 | typedef struct | |
| 28 | { | |
| 29 | int cart_type; | |
| 30 | int ar1_spurious; | |
| 31 | UINT16 ar23_mode; | |
| 32 | } amigacrt_t; | |
| 33 | static amigacrt_t amigacrt; | |
| 34 | ||
| 35 | /*************************************************************************** | |
| 36 | ||
| 37 | Utilities | |
| 38 | ||
| 39 | ***************************************************************************/ | |
| 40 | ||
| 41 | static int check_kickstart_12_13( running_machine &machine, const char *cart_name ) | |
| 42 | { | |
| 43 | UINT16 * ksmem = (UINT16 *)machine.region( "user1" )->base(); | |
| 44 | ||
| 45 | if ( ksmem[2] == 0x00FC ) | |
| 46 | return 1; | |
| 47 | ||
| 48 | logerror( "%s requires Kickstart version 1.2 or 1.3 - Cart not installed\n", cart_name ); | |
| 49 | ||
| 50 | return 0; | |
| 51 | } | |
| 52 | ||
| 53 | /*************************************************************************** | |
| 54 | ||
| 55 | Amiga Action Replay 1 | |
| 56 | ||
| 57 | Whenever you push the button, an NMI interrupt is generated. | |
| 58 | ||
| 59 | The cartridge protects itself from being removed from memory by | |
| 60 | generating an interrupt whenever either the spurious interrupt | |
| 61 | vector is written at $60, or the nmi interrupt vector is written at | |
| 62 | $7c. If the spurious interrupt vector at $60 is written, then | |
| 63 | a NMI is generated, and the spurious irq vector is restored. If the | |
| 64 | NMI vector at $7c is written, then a spurious interrupt is generated, | |
| 65 | and the NMI vector is restored. | |
| 66 | ||
| 67 | When breakpoints are set, the target address is replaced by a trap | |
| 68 | instruction, and the original contents of the address are kept in | |
| 69 | the cartridge's RAM. A trap handler is installed pointing to $40 | |
| 70 | in RAM, where code that clears memory address $60 followed by two | |
| 71 | nops are written. There seems to be a small delay between the write | |
| 72 | to $60 and until the actual NMI is generated, since the cart expects | |
| 73 | the PC to be at $46 (at the second nop). | |
| 74 | ||
| 75 | ***************************************************************************/ | |
| 76 | ||
| 77 | static IRQ_CALLBACK(amiga_ar1_irqack) | |
| 78 | { | |
| 79 | if ( irqline == 7 && amigacrt.ar1_spurious ) | |
| 80 | { | |
| 81 | return M68K_INT_ACK_SPURIOUS; | |
| 82 | } | |
| 83 | ||
| 84 | return (24+irqline); | |
| 85 | } | |
| 86 | ||
| 87 | static TIMER_CALLBACK( amiga_ar1_delayed_nmi ) | |
| 88 | { | |
| 89 | (void)param; | |
| 90 | cputag_set_input_line(machine, "maincpu", 7, PULSE_LINE); | |
| 91 | } | |
| 92 | ||
| 93 | static void amiga_ar1_nmi( running_machine &machine ) | |
| 94 | { | |
| 95 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 96 | /* get the cart's built-in ram */ | |
| 97 | UINT16 *ar_ram = (UINT16 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_write_ptr(0x9fc000); | |
| 98 | ||
| 99 | if ( ar_ram != NULL ) | |
| 100 | { | |
| 101 | int i; | |
| 102 | ||
| 103 | /* copy custom register values */ | |
| 104 | for( i = 0; i < 256; i++ ) | |
| 105 | ar_ram[0x1800+i] = CUSTOM_REG(i); | |
| 106 | ||
| 107 | /* trigger NMI irq */ | |
| 108 | amigacrt.ar1_spurious = 0; | |
| 109 | machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(28), FUNC(amiga_ar1_delayed_nmi)); | |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | static WRITE16_HANDLER( amiga_ar1_chipmem_w ) | |
| 114 | { | |
| 115 | amiga_state *state = space->machine().driver_data<amiga_state>(); | |
| 116 | int pc = cpu_get_pc(&space->device()); | |
| 117 | ||
| 118 | /* see if we're inside the AR1 rom */ | |
| 119 | if ( ((pc >> 16) & 0xff ) != 0xf0 ) | |
| 120 | { | |
| 121 | /* if we're not, see if either the Spurious IRQ vector | |
| 122 | or the NMI vector are being overwritten */ | |
| 123 | if ( offset == (0x60/2) || offset == (0x7c/2) ) | |
| 124 | { | |
| 125 | /* trigger an NMI or spurious irq */ | |
| 126 | amigacrt.ar1_spurious = (offset == 0x60/2) ? 0 : 1; | |
| 127 | space->machine().scheduler().timer_set(space->machine().device<cpu_device>("maincpu")->cycles_to_attotime(28), FUNC(amiga_ar1_delayed_nmi)); | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | (*state->m_chip_ram_w)(state, offset * 2, data ); | |
| 132 | } | |
| 133 | ||
| 134 | static void amiga_ar1_check_overlay( running_machine &machine ) | |
| 135 | { | |
| 136 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, 0x00007f, FUNC(amiga_ar1_chipmem_w)); | |
| 137 | } | |
| 138 | ||
| 139 | static void amiga_ar1_init( running_machine &machine ) | |
| 140 | { | |
| 141 | void *ar_ram; | |
| 142 | ||
| 143 | /* check kickstart version */ | |
| 144 | if ( !check_kickstart_12_13( machine, "Amiga Action Replay" ) ) | |
| 145 | { | |
| 146 | amigacrt.cart_type = -1; | |
| 147 | return; | |
| 148 | } | |
| 149 | ||
| 150 | /* setup the cart ram */ | |
| 151 | ar_ram = auto_alloc_array(machine, UINT8, 0x4000); | |
| 152 | memset(ar_ram, 0, 0x4000); | |
| 153 | ||
| 154 | /* Install ROM */ | |
| 155 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xf00000, 0xf7ffff, "bank2"); | |
| 156 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xf00000, 0xf7ffff); | |
| 157 | ||
| 158 | /* Install RAM */ | |
| 159 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x9fc000, 0x9fffff, "bank3"); | |
| 160 | ||
| 161 | /* Configure Banks */ | |
| 162 | memory_set_bankptr(machine, "bank2", machine.region("user2")->base()); | |
| 163 | memory_set_bankptr(machine, "bank3", ar_ram); | |
| 164 | ||
| 165 | amigacrt.ar1_spurious = 0; | |
| 166 | ||
| 167 | /* Install IRQ ACK callback */ | |
| 168 | device_set_irq_callback(machine.device("maincpu"), amiga_ar1_irqack); | |
| 169 | } | |
| 170 | ||
| 171 | /*************************************************************************** | |
| 172 | ||
| 173 | Amiga Action Replay MKII/MKIII | |
| 174 | ||
| 175 | Whenever you push the button, an overlay of the cartridge appears | |
| 176 | in RAM and an NMI interrupt is generated. Only reads are overlayed. | |
| 177 | Writes go directly to chipmem (so that the CPU can write the stack | |
| 178 | information for the NMI). Once the interrupt is taken, the cart | |
| 179 | disables the ROM overlay and checks it's internal mode register | |
| 180 | to see why it was invoked. | |
| 181 | ||
| 182 | When a breakpoint is set the cart replaces the target instruction | |
| 183 | with a trap, and adds a trap handler that it locates in the $100-$120 | |
| 184 | area. The handler simply has one instruction: TST.B $BFE001. This cia | |
| 185 | access is monitored, and the conditions match (PC < 120 and a previous | |
| 186 | command requested the monitoring of the cia) then the cart is invoked. | |
| 187 | ||
| 188 | ***************************************************************************/ | |
| 189 | ||
| 190 | static void amiga_ar23_freeze( running_machine &machine ); | |
| 191 | ||
| 192 | static READ16_HANDLER( amiga_ar23_cia_r ) | |
| 193 | { | |
| 194 | int pc = cpu_get_pc(&space->device()); | |
| 195 | ||
| 196 | if ( ACCESSING_BITS_0_7 && offset == 2048 && pc >= 0x40 && pc < 0x120 ) | |
| 197 | { | |
| 198 | amiga_ar23_freeze(space->machine()); | |
| 199 | } | |
| 200 | ||
| 201 | return amiga_cia_r( space, offset, mem_mask ); | |
| 202 | } | |
| 203 | ||
| 204 | static WRITE16_HANDLER( amiga_ar23_mode_w ) | |
| 205 | { | |
| 206 | if ( data & 2 ) | |
| 207 | { | |
| 208 | space->install_legacy_read_handler(0xbfd000, 0xbfefff, FUNC(amiga_ar23_cia_r)); | |
| 209 | } | |
| 210 | else | |
| 211 | { | |
| 212 | space->install_legacy_read_handler(0xbfd000, 0xbfefff, FUNC(amiga_cia_r)); | |
| 213 | } | |
| 214 | ||
| 215 | amigacrt.ar23_mode = (data&0x3); | |
| 216 | if ( amigacrt.ar23_mode == 0 ) | |
| 217 | amigacrt.ar23_mode = 1; | |
| 218 | ||
| 219 | } | |
| 220 | ||
| 221 | static READ16_HANDLER( amiga_ar23_mode_r ) | |
| 222 | { | |
| 223 | amiga_state *state = space->machine().driver_data<amiga_state>(); | |
| 224 | UINT16 *mem = (UINT16 *)space->machine().region( "user2" )->base(); | |
| 225 | ||
| 226 | if ( ACCESSING_BITS_0_7 ) | |
| 227 | { | |
| 228 | if ( offset < 2 ) | |
| 229 | return (mem[offset] | (amigacrt.ar23_mode&3)); | |
| 230 | ||
| 231 | if ( offset == 0x03 ) /* disable cart oberlay on chip mem */ | |
| 232 | { | |
| 233 | UINT32 mirror_mask = state->m_chip_ram_size; | |
| 234 | ||
| 235 | memory_set_bank(space->machine(), "bank1", 0); | |
| 236 | ||
| 237 | while( (mirror_mask<<1) < 0x100000 ) | |
| 238 | { | |
| 239 | mirror_mask |= ( mirror_mask << 1 ); | |
| 240 | } | |
| 241 | ||
| 242 | /* overlay disabled, map RAM on 0x000000 */ | |
| 243 | space->install_write_bank(0x000000, state->m_chip_ram_size - 1, 0, mirror_mask, "bank1"); | |
| 244 | } | |
| 245 | } | |
| 246 | ||
| 247 | return mem[offset]; | |
| 248 | } | |
| 249 | ||
| 250 | static WRITE16_HANDLER( amiga_ar23_chipmem_w ) | |
| 251 | { | |
| 252 | amiga_state *state = space->machine().driver_data<amiga_state>(); | |
| 253 | if ( offset == (0x08/2) ) | |
| 254 | { | |
| 255 | if ( amigacrt.ar23_mode & 1 ) | |
| 256 | amiga_ar23_freeze(space->machine()); | |
| 257 | } | |
| 258 | ||
| 259 | (*state->m_chip_ram_w)(state, offset * 2, data ); | |
| 260 | } | |
| 261 | ||
| 262 | static void amiga_ar23_freeze( running_machine &machine ) | |
| 263 | { | |
| 264 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 265 | int pc = cpu_get_pc(machine.device("maincpu")); | |
| 266 | ||
| 267 | /* only freeze if we're not inside the cart's ROM */ | |
| 268 | if ( ((pc >> 16) & 0xfe ) != 0x40 ) | |
| 269 | { | |
| 270 | /* get the cart's built-in ram */ | |
| 271 | UINT16 *ar_ram = (UINT16 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_write_ptr(0x440000); | |
| 272 | ||
| 273 | if ( ar_ram != NULL ) | |
| 274 | { | |
| 275 | int i; | |
| 276 | ||
| 277 | for( i = 0; i < 0x100; i++ ) | |
| 278 | ar_ram[0x7800+i] = CUSTOM_REG(i); | |
| 279 | } | |
| 280 | ||
| 281 | /* overlay the cart rom's in chipram */ | |
| 282 | memory_set_bank(machine, "bank1", 2); | |
| 283 | ||
| 284 | /* writes go to chipram */ | |
| 285 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, state->m_chip_ram_size - 1, FUNC(amiga_ar23_chipmem_w)); | |
| 286 | ||
| 287 | /* trigger NMI irq */ | |
| 288 | cputag_set_input_line(machine, "maincpu", 7, PULSE_LINE); | |
| 289 | } | |
| 290 | } | |
| 291 | ||
| 292 | static void amiga_ar23_nmi( running_machine &machine ) | |
| 293 | { | |
| 294 | amigacrt.ar23_mode = 0; | |
| 295 | amiga_ar23_freeze(machine); | |
| 296 | } | |
| 297 | ||
| 298 | #if 0 | |
| 299 | static WRITE16_HANDLER( amiga_ar23_custom_w ) | |
| 300 | { | |
| 301 | int pc = cpu_get_pc(&space->device()); | |
| 302 | ||
| 303 | /* see if we're inside the AR2 rom */ | |
| 304 | if ( ((pc >> 16) & 0xfe ) != 0x40 ) | |
| 305 | { | |
| 306 | /* get the cart's built-in ram */ | |
| 307 | UINT16 *ar_ram = (UINT16 *)memory_get_write_ptr(0, AS_PROGRAM, 0x440000); | |
| 308 | ||
| 309 | if ( ar_ram != NULL ) | |
| 310 | { | |
| 311 | ar_ram[0x7800+offset] = data; | |
| 312 | } | |
| 313 | } | |
| 314 | ||
| 315 | amiga_custom_w( offset, data, mem_mask ); | |
| 316 | } | |
| 317 | ||
| 318 | static READ16_HANDLER( amiga_ar23_custom_r ) | |
| 319 | { | |
| 320 | UINT16 data = amiga_custom_r( offset, mem_mask ); | |
| 321 | ||
| 322 | int pc = cpu_get_pc(&space->device()); | |
| 323 | ||
| 324 | /* see if we're inside the AR2 rom */ | |
| 325 | if ( ((pc >> 16) & 0xfe ) != 0x40 ) | |
| 326 | { | |
| 327 | /* get the cart's built-in ram */ | |
| 328 | UINT16 *ar_ram = (UINT16 *)memory_get_write_ptr(0, AS_PROGRAM, 0x440000); | |
| 329 | ||
| 330 | if ( ar_ram != NULL ) | |
| 331 | { | |
| 332 | ar_ram[0x7800+offset] = data; | |
| 333 | } | |
| 334 | } | |
| 335 | ||
| 336 | return data; | |
| 337 | } | |
| 338 | #endif | |
| 339 | ||
| 340 | static void amiga_ar23_check_overlay( running_machine &machine ) | |
| 341 | { | |
| 342 | amigacrt.ar23_mode = 3; | |
| 343 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, 0x00000f, FUNC(amiga_ar23_chipmem_w)); | |
| 344 | } | |
| 345 | ||
| 346 | static void amiga_ar23_init( running_machine &machine, int ar3 ) | |
| 347 | { | |
| 348 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 349 | UINT32 mirror = 0x20000, size = 0x1ffff; | |
| 350 | void *ar_ram; | |
| 351 | ||
| 352 | /* check kickstart version */ | |
| 353 | if ( !check_kickstart_12_13( machine, "Action Replay MKII or MKIII" ) ) | |
| 354 | { | |
| 355 | amigacrt.cart_type = -1; | |
| 356 | return; | |
| 357 | } | |
| 358 | ||
| 359 | /* setup the cart ram */ | |
| 360 | ar_ram = auto_alloc_array_clear(machine, UINT8,0x10000); | |
| 361 | ||
| 362 | if ( ar3 ) | |
| 363 | { | |
| 364 | mirror = 0; | |
| 365 | size = 0x3ffff; | |
| 366 | } | |
| 367 | ||
| 368 | /* Install ROM */ | |
| 369 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x400000, 0x400000+size, 0, mirror, "bank2"); | |
| 370 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x400000, 0x400000+size, 0, mirror); | |
| 371 | ||
| 372 | /* Install RAM */ | |
| 373 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x440000, 0x44ffff, "bank3"); | |
| 374 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x440000, 0x44ffff, "bank3"); | |
| 375 | ||
| 376 | /* Install Custom chip monitor */ | |
| 377 | // machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xdff000, 0xdff1ff, FUNC(amiga_ar23_custom_r)); | |
| 378 | // machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xdff000, 0xdff1ff, FUNC(amiga_ar23_custom_w)); | |
| 379 | ||
| 380 | /* Install status/mode handlers */ | |
| 381 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400007, 0, mirror, FUNC(amiga_ar23_mode_r)); | |
| 382 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400000, 0x400003, 0, mirror, FUNC(amiga_ar23_mode_w)); | |
| 383 | ||
| 384 | /* Configure Banks */ | |
| 385 | memory_set_bankptr(machine, "bank2", machine.region("user2")->base()); | |
| 386 | memory_set_bankptr(machine, "bank3", ar_ram); | |
| 387 | ||
| 388 | memory_configure_bank(machine, "bank1", 0, 2, state->m_chip_ram, 0); | |
| 389 | memory_configure_bank(machine, "bank1", 1, 2, machine.region("user1")->base(), 0); | |
| 390 | memory_configure_bank(machine, "bank1", 2, 2, machine.region("user2")->base(), 0); | |
| 391 | ||
| 392 | amigacrt.ar23_mode = 3; | |
| 393 | } | |
| 394 | ||
| 395 | /*************************************************************************** | |
| 396 | ||
| 397 | MAME/MESS hooks | |
| 398 | ||
| 399 | ***************************************************************************/ | |
| 400 | ||
| 401 | void amiga_cart_init( running_machine &machine ) | |
| 402 | { | |
| 403 | /* see what is there */ | |
| 404 | UINT16 *mem = (UINT16 *)machine.region( "user2" )->base(); | |
| 405 | ||
| 406 | amigacrt.cart_type = -1; | |
| 407 | ||
| 408 | if ( mem != NULL ) | |
| 409 | { | |
| 410 | if ( mem[0x00] == 0x1111 ) | |
| 411 | { | |
| 412 | amigacrt.cart_type = ACTION_REPLAY; | |
| 413 | amiga_ar1_init(machine); | |
| 414 | } | |
| 415 | else if ( mem[0x0C] == 0x4D6B ) | |
| 416 | { | |
| 417 | amigacrt.cart_type = ACTION_REPLAY_MKII; | |
| 418 | amiga_ar23_init(machine, 0); | |
| 419 | } | |
| 420 | else if ( mem[0x0C] == 0x4D4B ) | |
| 421 | { | |
| 422 | amigacrt.cart_type = ACTION_REPLAY_MKIII; | |
| 423 | amiga_ar23_init(machine, 1); | |
| 424 | } | |
| 425 | } | |
| 426 | } | |
| 427 | ||
| 428 | void amiga_cart_check_overlay( running_machine &machine ) | |
| 429 | { | |
| 430 | if ( amigacrt.cart_type < 0 ) | |
| 431 | return; | |
| 432 | ||
| 433 | switch( amigacrt.cart_type ) | |
| 434 | { | |
| 435 | case ACTION_REPLAY: | |
| 436 | amiga_ar1_check_overlay(machine); | |
| 437 | break; | |
| 438 | ||
| 439 | case ACTION_REPLAY_MKII: | |
| 440 | case ACTION_REPLAY_MKIII: | |
| 441 | amiga_ar23_check_overlay(machine); | |
| 442 | break; | |
| 443 | } | |
| 444 | } | |
| 445 | ||
| 446 | void amiga_cart_nmi( running_machine &machine ) | |
| 447 | { | |
| 448 | if ( amigacrt.cart_type < 0 ) | |
| 449 | return; | |
| 450 | ||
| 451 | switch( amigacrt.cart_type ) | |
| 452 | { | |
| 453 | case ACTION_REPLAY: | |
| 454 | amiga_ar1_nmi(machine); | |
| 455 | break; | |
| 456 | ||
| 457 | case ACTION_REPLAY_MKII: | |
| 458 | case ACTION_REPLAY_MKIII: | |
| 459 | amiga_ar23_nmi(machine); | |
| 460 | break; | |
| 461 | } | |
| 462 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | #ifndef AMIGACRT_H | |
| 2 | #define AMIGACRT_H | |
| 3 | ||
| 4 | void amiga_cart_init( running_machine &machine ); | |
| 5 | void amiga_cart_check_overlay( running_machine &machine ); | |
| 6 | void amiga_cart_nmi( running_machine &machine ); | |
| 7 | ||
| 8 | #endif /* AMIGACRT_H */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES Cart PCBs Emulation | |
| 4 | ||
| 5 | ****************************************************************************************/ | |
| 6 | ||
| 7 | typedef struct _nes_pcb nes_pcb; | |
| 8 | struct _nes_pcb | |
| 9 | { | |
| 10 | const char *pcb_name; | |
| 11 | int pcb_id; | |
| 12 | }; | |
| 13 | ||
| 14 | // Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it | |
| 15 | static const nes_pcb pcb_list[] = | |
| 16 | { | |
| 17 | /* Nintendo HROM, NROM, RROM, SROM & STROM */ | |
| 18 | { "HVC-HROM", STD_NROM }, | |
| 19 | { "HVC-NROM", STD_NROM }, | |
| 20 | { "HVC-NROM-128", STD_NROM }, | |
| 21 | { "HVC-NROM-256", STD_NROM }, | |
| 22 | { "HVC-RROM", STD_NROM }, | |
| 23 | { "HVC-RROM-128", STD_NROM }, | |
| 24 | { "HVC-RTROM", STD_NROM }, | |
| 25 | { "HVC-SROM", STD_NROM }, | |
| 26 | { "HVC-STROM", STD_NROM }, | |
| 27 | { "NES-HROM", STD_NROM }, | |
| 28 | { "NES-NROM", STD_NROM }, | |
| 29 | { "NES-NROM-128", STD_NROM }, | |
| 30 | { "NES-NROM-256", STD_NROM }, | |
| 31 | { "NES-RROM", STD_NROM }, | |
| 32 | { "NES-RROM-128", STD_NROM }, | |
| 33 | { "NES-SROM", STD_NROM }, | |
| 34 | { "NES-STROM", STD_NROM }, | |
| 35 | /* "No mapper" boards by other manufacturer */ | |
| 36 | { "IREM-NROM-128", STD_NROM }, | |
| 37 | { "IREM-NROM-256", STD_NROM }, | |
| 38 | { "BANDAI-NROM-128", STD_NROM }, | |
| 39 | { "BANDAI-NROM-256", STD_NROM }, | |
| 40 | { "KONAMI-NROM-128", STD_NROM }, | |
| 41 | { "SETA-NROM-128", STD_NROM }, | |
| 42 | { "SUNSOFT-NROM-128", STD_NROM }, | |
| 43 | { "SUNSOFT-NROM-256", STD_NROM }, | |
| 44 | { "TAITO-NROM-128", STD_NROM }, | |
| 45 | { "TAITO-NROM-256", STD_NROM }, | |
| 46 | { "NAMCOT-3301", STD_NROM }, | |
| 47 | { "NAMCOT-3302", STD_NROM }, | |
| 48 | { "NAMCOT-3303", STD_NROM }, | |
| 49 | { "NAMCOT-3304", STD_NROM }, | |
| 50 | { "NAMCOT-3305", STD_NROM }, | |
| 51 | { "NAMCOT-3311", STD_NROM }, | |
| 52 | { "NAMCOT-3312", STD_NROM }, | |
| 53 | { "NAMCOT-3411", STD_NROM }, | |
| 54 | { "JALECO-JF-01", STD_NROM }, | |
| 55 | { "JALECO-JF-02", STD_NROM }, | |
| 56 | { "JALECO-JF-03", STD_NROM }, | |
| 57 | { "JALECO-JF-04", STD_NROM }, | |
| 58 | { "TENGEN-800003", STD_NROM }, | |
| 59 | { "SACHEN-NROM", STD_NROM }, | |
| 60 | /* Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) */ | |
| 61 | { "HVC-FAMILYBASIC", HVC_FAMBASIC }, | |
| 62 | /* Game Genie */ | |
| 63 | { "CAMERICA-GAMEGENIE", GG_NROM }, | |
| 64 | // | |
| 65 | /* Nintendo UNROM/UOROM */ | |
| 66 | { "HVC-UNROM", STD_UXROM }, | |
| 67 | { "HVC-UNEPROM", STD_UXROM }, | |
| 68 | { "HVC-UOROM", STD_UXROM }, | |
| 69 | { "NES-UNROM", STD_UXROM }, | |
| 70 | { "NES-UNEPROM", STD_UXROM }, | |
| 71 | { "NES-UOROM", STD_UXROM }, | |
| 72 | { "HVC-UNROM+74HC08", UXROM_CC }, | |
| 73 | /* UxROM boards by other manufacturer */ | |
| 74 | { "IREM-UNROM", STD_UXROM }, | |
| 75 | { "KONAMI-UNROM", STD_UXROM }, | |
| 76 | { "TAITO-UNROM", STD_UXROM }, | |
| 77 | { "JALECO-JF-15", STD_UXROM }, | |
| 78 | { "JALECO-JF-18", STD_UXROM }, | |
| 79 | { "JALECO-JF-39", STD_UXROM }, | |
| 80 | // | |
| 81 | /* Nintendo CNROM */ | |
| 82 | { "HVC-CNROM", STD_CNROM }, | |
| 83 | { "NES-CNROM", STD_CNROM }, | |
| 84 | /* CxROM boards by other manufacturer */ | |
| 85 | { "BANDAI-CNROM", STD_CNROM }, | |
| 86 | { "BANDAI-74*161/32", STD_CNROM }, | |
| 87 | { "KONAMI-CNROM", STD_CNROM }, | |
| 88 | { "NAMCOT-CNROM+WRAM", STD_CNROM }, | |
| 89 | { "TAITO-CNROM", STD_CNROM }, | |
| 90 | { "AVE-74*161", STD_CNROM }, | |
| 91 | { "NTDEC-N715061", STD_CNROM }, | |
| 92 | { "NTDEC-N715062", STD_CNROM }, | |
| 93 | { "SACHEN-CNROM", STD_CNROM }, | |
| 94 | /* Bandai Aerobics Studio (CNROM boards + special audio chip) */ | |
| 95 | { "BANDAI-PT-554", BANDAI_PT554 }, | |
| 96 | /* FIXME: Is this the same as mapper 3? */ | |
| 97 | { "TENGEN-800008", TENGEN_800008 }, | |
| 98 | // | |
| 99 | /* Nintendo AxROM */ | |
| 100 | { "HVC-AMROM", STD_AXROM }, | |
| 101 | { "HVC-AN1ROM", STD_AXROM }, | |
| 102 | { "HVC-ANROM", STD_AXROM }, | |
| 103 | { "HVC-AOROM", STD_AXROM }, | |
| 104 | { "NES-AMROM", STD_AXROM }, | |
| 105 | { "NES-AN1ROM", STD_AXROM }, | |
| 106 | { "NES-ANROM", STD_AXROM }, | |
| 107 | { "NES-AOROM", STD_AXROM }, | |
| 108 | /* AxROM boards by other manufacturer */ | |
| 109 | { "ACCLAIM-AOROM", STD_AXROM }, | |
| 110 | // | |
| 111 | /* Nintendo PxROM */ | |
| 112 | { "HVC-PEEOROM", STD_PXROM }, | |
| 113 | { "HVC-PNROM", STD_PXROM }, | |
| 114 | { "NES-PEEOROM", STD_PXROM }, | |
| 115 | { "NES-PNROM", STD_PXROM }, | |
| 116 | // | |
| 117 | /* Nintendo FxROM */ | |
| 118 | { "HVC-FJROM", STD_FXROM }, | |
| 119 | { "HVC-FKROM", STD_FXROM }, | |
| 120 | { "NES-FJROM", STD_FXROM }, | |
| 121 | { "NES-FKROM", STD_FXROM }, | |
| 122 | // | |
| 123 | /* Nintendo BXROM */ | |
| 124 | { "HVC-BNROM", STD_BXROM }, | |
| 125 | { "NES-BNROM", STD_BXROM }, | |
| 126 | /* BxROM boards by other manufacturer */ | |
| 127 | { "IREM-BNROM", STD_BXROM }, | |
| 128 | // | |
| 129 | /* Nintendo CPROM */ | |
| 130 | { "HVC-CPROM", STD_CPROM }, | |
| 131 | { "NES-CPROM", STD_CPROM }, | |
| 132 | // | |
| 133 | /* Nintendo GNROM & MHROM */ | |
| 134 | { "HVC-GNROM", STD_GXROM }, | |
| 135 | { "NES-GNROM", STD_GXROM }, | |
| 136 | { "HVC-MHROM", STD_MXROM }, | |
| 137 | { "NES-MHROM", STD_MXROM }, | |
| 138 | { "PAL-MH", STD_MXROM }, | |
| 139 | /* GxROM boards by other manufacturer */ | |
| 140 | { "BANDAI-GNROM", STD_GXROM }, | |
| 141 | // | |
| 142 | /* Nintendo NxROM */ | |
| 143 | { "HVC-NTBROM", STD_NXROM }, | |
| 144 | { "NES-NTBROM", STD_NXROM }, | |
| 145 | /* NxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */ | |
| 146 | { "SUNSOFT-4", STD_NXROM }, | |
| 147 | { "SUNSOFT-DCS", SUNSOFT_DCS }, | |
| 148 | { "TENGEN-800042", STD_NXROM }, | |
| 149 | // | |
| 150 | /* Nintendo JxROM */ | |
| 151 | { "HVC-JLROM", STD_JXROM }, | |
| 152 | { "HVC-JSROM", STD_JXROM }, | |
| 153 | { "NES-JLROM", STD_JXROM }, | |
| 154 | { "NES-JSROM", STD_JXROM }, | |
| 155 | { "NES-BTR", STD_JXROM }, | |
| 156 | /* JxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */ | |
| 157 | { "SUNSOFT-5A", STD_JXROM }, | |
| 158 | { "SUNSOFT-5B", STD_JXROM }, | |
| 159 | { "SUNSOFT-FME-7", STD_JXROM }, | |
| 160 | // | |
| 161 | /* Nintendo UN1ROM */ | |
| 162 | { "HVC-UN1ROM", STD_UN1ROM }, | |
| 163 | { "NES-UN1ROM", STD_UN1ROM }, | |
| 164 | // | |
| 165 | /* Nintendo SxROM */ | |
| 166 | { "HVC-SAROM", STD_SXROM }, | |
| 167 | { "HVC-SBROM", STD_SXROM }, | |
| 168 | { "HVC-SC1ROM", STD_SXROM }, | |
| 169 | { "HVC-SCROM", STD_SXROM }, | |
| 170 | { "HVC-SEROM", STD_SXROM }, | |
| 171 | { "HVC-SF1ROM", STD_SXROM }, | |
| 172 | { "HVC-SFROM", STD_SXROM }, | |
| 173 | { "HVC-SGROM", STD_SXROM }, | |
| 174 | { "HVC-SH1ROM", STD_SXROM }, | |
| 175 | { "HVC-SHROM", STD_SXROM }, | |
| 176 | { "HVC-SIROM", STD_SXROM }, | |
| 177 | { "HVC-SJROM", STD_SXROM }, | |
| 178 | { "HVC-SKROM", STD_SXROM }, | |
| 179 | { "HVC-SKEPROM", STD_SXROM }, | |
| 180 | { "HVC-SL1ROM", STD_SXROM }, | |
| 181 | { "HVC-SL2ROM", STD_SXROM }, | |
| 182 | { "HVC-SL3ROM", STD_SXROM }, | |
| 183 | { "HVC-SLROM", STD_SXROM }, | |
| 184 | { "HVC-SLRROM", STD_SXROM }, | |
| 185 | { "HVC-SMROM", STD_SXROM }, | |
| 186 | { "HVC-SNROM", STD_SXROM }, | |
| 187 | { "HVC-SUROM", STD_SXROM }, | |
| 188 | { "HVC-SXROM", STD_SXROM }, | |
| 189 | { "NES-SAROM", STD_SXROM }, | |
| 190 | { "NES-SBROM", STD_SXROM }, | |
| 191 | { "NES-SC1ROM", STD_SXROM }, | |
| 192 | { "NES-SCROM", STD_SXROM }, | |
| 193 | { "NES-SEROM", STD_SXROM }, | |
| 194 | { "NES-SF1ROM", STD_SXROM }, | |
| 195 | { "NES-SFROM", STD_SXROM }, | |
| 196 | { "NES-SGROM", STD_SXROM }, | |
| 197 | { "NES-SH1ROM", STD_SXROM }, | |
| 198 | { "NES-SHROM", STD_SXROM }, | |
| 199 | { "NES-SIROM", STD_SXROM }, | |
| 200 | { "NES-SJROM", STD_SXROM }, | |
| 201 | { "NES-SKROM", STD_SXROM }, | |
| 202 | { "NES-SKEPROM", STD_SXROM }, | |
| 203 | { "NES-SL1ROM", STD_SXROM }, | |
| 204 | { "NES-SL2ROM", STD_SXROM }, | |
| 205 | { "NES-SL3ROM", STD_SXROM }, | |
| 206 | { "NES-SLROM", STD_SXROM }, | |
| 207 | { "NES-SLRROM", STD_SXROM }, | |
| 208 | { "NES-SMROM", STD_SXROM }, | |
| 209 | { "NES-SNROM", STD_SXROM }, | |
| 210 | { "NES-SUROM", STD_SXROM }, | |
| 211 | { "NES-SXROM", STD_SXROM }, | |
| 212 | { "NES-WH", STD_SXROM }, | |
| 213 | { "NES-SOROM", STD_SOROM }, | |
| 214 | { "HVC-SOROM", STD_SOROM }, | |
| 215 | /* SxROM boards by other manufacturer */ | |
| 216 | { "KONAMI-SLROM", STD_SXROM }, | |
| 217 | { "VIRGIN-SNROM", STD_SXROM }, | |
| 218 | // | |
| 219 | /* Nintendo TxROM */ | |
| 220 | { "HVC-TBROM", STD_TXROM }, | |
| 221 | { "HVC-TEROM", STD_TXROM }, | |
| 222 | { "HVC-TFROM", STD_TXROM }, | |
| 223 | { "HVC-TGROM", STD_TXROM }, | |
| 224 | { "HVC-TKROM", STD_TXROM }, | |
| 225 | { "HVC-TL1ROM", STD_TXROM }, | |
| 226 | { "HVC-TL2ROM", STD_TXROM }, | |
| 227 | { "HVC-TLROM", STD_TXROM }, | |
| 228 | { "HVC-TNROM", STD_TXROM }, | |
| 229 | { "HVC-TR1ROM", STD_TVROM }, | |
| 230 | { "HVC-TSROM", STD_TXROM }, | |
| 231 | { "HVC-TVROM", STD_TVROM }, | |
| 232 | { "NES-B4", STD_TXROM }, | |
| 233 | { "NES-TBROM", STD_TXROM }, | |
| 234 | { "NES-TEROM", STD_TXROM }, | |
| 235 | { "NES-TFROM", STD_TXROM }, | |
| 236 | { "NES-TGROM", STD_TXROM }, | |
| 237 | { "NES-TKROM", STD_TXROM }, | |
| 238 | { "NES-TL1ROM", STD_TXROM }, | |
| 239 | { "NES-TL2ROM", STD_TXROM }, | |
| 240 | { "NES-TLROM", STD_TXROM }, | |
| 241 | { "NES-TNROM", STD_TXROM }, | |
| 242 | { "NES-TR1ROM", STD_TVROM }, | |
| 243 | { "NES-TSROM", STD_TXROM }, | |
| 244 | { "NES-TVROM", STD_TVROM }, | |
| 245 | /* TxROM boards by other manufacturer */ | |
| 246 | { "ACCLAIM-MC-ACC", STD_TXROM }, | |
| 247 | { "ACCLAIM-TLROM", STD_TXROM }, | |
| 248 | { "KONAMI-TLROM", STD_TXROM }, | |
| 249 | // | |
| 250 | /* Nintendo DxROM */ | |
| 251 | { "HVC-DE1ROM", STD_DXROM }, | |
| 252 | { "HVC-DEROM", STD_DXROM }, | |
| 253 | { "HVC-DRROM", STD_DRROM }, | |
| 254 | { "NES-DE1ROM", STD_DXROM }, | |
| 255 | { "NES-DEROM", STD_DXROM }, | |
| 256 | { "NES-DRROM", STD_DRROM }, | |
| 257 | /* DxROM boards by other manufacturer */ | |
| 258 | { "NAMCOT-3401", STD_DXROM }, | |
| 259 | { "NAMCOT-3405", STD_DXROM }, | |
| 260 | { "NAMCOT-3406", STD_DXROM }, | |
| 261 | { "NAMCOT-3407", STD_DXROM }, | |
| 262 | { "NAMCOT-3413", STD_DXROM }, | |
| 263 | { "NAMCOT-3414", STD_DXROM }, | |
| 264 | { "NAMCOT-3415", STD_DXROM }, | |
| 265 | { "NAMCOT-3416", STD_DXROM }, | |
| 266 | { "NAMCOT-3417", STD_DXROM }, | |
| 267 | { "NAMCOT-3451", STD_DXROM }, | |
| 268 | { "TENGEN-800002", STD_DXROM }, | |
| 269 | { "TENGEN-800004", STD_DRROM }, | |
| 270 | { "TENGEN-800030", STD_DXROM }, | |
| 271 | // | |
| 272 | /* Nintendo HKROM */ | |
| 273 | { "HVC-HKROM", STD_HKROM }, | |
| 274 | { "NES-HKROM", STD_HKROM }, | |
| 275 | // | |
| 276 | /* Nintendo BNROM */ | |
| 277 | { "HVC-TQROM", STD_TQROM }, | |
| 278 | { "NES-TQROM", STD_TQROM }, | |
| 279 | // | |
| 280 | /* Nintendo TxSROM */ | |
| 281 | { "HVC-TKSROM", STD_TXSROM }, | |
| 282 | { "HVC-TLSROM", STD_TXSROM }, | |
| 283 | { "NES-TKSROM", STD_TXSROM }, | |
| 284 | { "NES-TLSROM", STD_TXSROM }, | |
| 285 | // | |
| 286 | /* Nintendo ExROM */ | |
| 287 | { "HVC-EKROM", STD_EXROM }, | |
| 288 | { "HVC-ELROM", STD_EXROM }, | |
| 289 | { "HVC-ETROM", STD_EXROM }, | |
| 290 | { "HVC-EWROM", STD_EXROM }, | |
| 291 | { "NES-EKROM", STD_EXROM }, | |
| 292 | { "NES-ELROM", STD_EXROM }, | |
| 293 | { "NES-ETROM", STD_EXROM }, | |
| 294 | { "NES-EWROM", STD_EXROM }, | |
| 295 | // | |
| 296 | /* Nintendo Custom boards */ | |
| 297 | { "PAL-ZZ", PAL_ZZ }, | |
| 298 | { "NES-QJ", NES_QJ }, | |
| 299 | { "NES-EVENT", UNSUPPORTED_BOARD }, | |
| 300 | // | |
| 301 | /* Discrete board IC_74x139x74 */ | |
| 302 | { "JALECO-JF-05", DIS_74X139X74 }, | |
| 303 | { "JALECO-JF-06", DIS_74X139X74 }, | |
| 304 | { "JALECO-JF-07", DIS_74X139X74 }, | |
| 305 | { "JALECO-JF-08", DIS_74X139X74 }, | |
| 306 | { "JALECO-JF-09", DIS_74X139X74 }, | |
| 307 | { "JALECO-JF-10", DIS_74X139X74 }, | |
| 308 | { "KONAMI-74*139/74", DIS_74X139X74 }, | |
| 309 | { "TAITO-74*139/74", DIS_74X139X74 }, | |
| 310 | /* Discrete board IC_74x377 */ | |
| 311 | { "AGCI-47516", DIS_74X377 }, | |
| 312 | { "AVE-NINA-07", DIS_74X377 }, | |
| 313 | { "COLORDREAMS-74*377", DIS_74X377 }, | |
| 314 | /* Discrete board IC_74x161x161x32 */ | |
| 315 | { "BANDAI-74*161/161/32", DIS_74X161X161X32 }, | |
| 316 | { "TAITO-74*161/161/32", DIS_74X161X161X32 }, | |
| 317 | /* Discrete board IC_74x161x138 */ | |
| 318 | { "BIT-CORP-74*161/138", DIS_74X161X138 }, | |
| 319 | // | |
| 320 | { "BANDAI-LZ93D50", BANDAI_LZ93 }, | |
| 321 | { "BANDAI-LZ93D50+24C01", BANDAI_LZ93EX }, | |
| 322 | { "BANDAI-LZ93D50+24C02", BANDAI_LZ93EX }, | |
| 323 | { "BANDAI-FCG-1", BANDAI_FCG }, | |
| 324 | { "BANDAI-FCG-2", BANDAI_FCG }, | |
| 325 | { "BANDAI-JUMP2", BANDAI_JUMP2 }, | |
| 326 | { "BANDAI-DATACH", BANDAI_DATACH }, | |
| 327 | { "BANDAI-KARAOKE", BANDAI_KARAOKE }, | |
| 328 | { "BANDAI-OEKAKIDS", BANDAI_OEKAKIDS }, | |
| 329 | { "IREM-FCG-1", BANDAI_FCG }, | |
| 330 | // | |
| 331 | { "IREM-G101", IREM_G101 }, | |
| 332 | { "IREM-74*161/161/21/138", IREM_LROG017 }, | |
| 333 | { "IREM-H-3001", IREM_H3001 }, | |
| 334 | { "IREM-H3001", IREM_H3001 }, | |
| 335 | { "IREM-HOLYDIVER", IREM_HOLYDIV }, | |
| 336 | { "IREM-TAM-S1", IREM_TAM_S1 }, | |
| 337 | // | |
| 338 | { "JALECO-JF-23", JALECO_SS88006 }, | |
| 339 | { "JALECO-JF-24", JALECO_SS88006 }, | |
| 340 | { "JALECO-JF-25", JALECO_SS88006 }, | |
| 341 | { "JALECO-JF-27", JALECO_SS88006 }, | |
| 342 | { "JALECO-JF-29", JALECO_SS88006 }, | |
| 343 | { "JALECO-JF-30", JALECO_SS88006 }, | |
| 344 | { "JALECO-JF-31", JALECO_SS88006 }, | |
| 345 | { "JALECO-JF-32", JALECO_SS88006 }, | |
| 346 | { "JALECO-JF-33", JALECO_SS88006 }, | |
| 347 | { "JALECO-JF-34", JALECO_SS88006 }, | |
| 348 | { "JALECO-JF-35", JALECO_SS88006 }, | |
| 349 | { "JALECO-JF-36", JALECO_SS88006 }, | |
| 350 | { "JALECO-JF-37", JALECO_SS88006 }, | |
| 351 | { "JALECO-JF-38", JALECO_SS88006 }, | |
| 352 | { "JALECO-JF-40", JALECO_SS88006 }, | |
| 353 | { "JALECO-JF-41", JALECO_SS88006 }, | |
| 354 | { "JALECO-JF-11", JALECO_JF11 }, | |
| 355 | { "JALECO-JF-12", JALECO_JF11 }, | |
| 356 | { "JALECO-JF-14", JALECO_JF11 }, | |
| 357 | { "JALECO-JF-13", JALECO_JF13 }, | |
| 358 | { "JALECO-JF-16", JALECO_JF16 }, | |
| 359 | { "JALECO-JF-17", JALECO_JF17 }, | |
| 360 | { "JALECO-JF-26", JALECO_JF17 }, | |
| 361 | { "JALECO-JF-28", JALECO_JF17 }, | |
| 362 | { "JALECO-JF-19", JALECO_JF19 }, | |
| 363 | { "JALECO-JF-21", JALECO_JF19 }, | |
| 364 | // | |
| 365 | { "KONAMI-VRC-1", KONAMI_VRC1 }, | |
| 366 | { "JALECO-JF-20", KONAMI_VRC1 }, | |
| 367 | { "JALECO-JF-22", KONAMI_VRC1 }, | |
| 368 | { "KONAMI-VRC-2", KONAMI_VRC2 }, | |
| 369 | { "KONAMI-VRC-3", KONAMI_VRC3 }, | |
| 370 | { "KONAMI-VRC-4", KONAMI_VRC4 }, | |
| 371 | { "KONAMI-VRC-6", KONAMI_VRC6 }, | |
| 372 | { "KONAMI-VRC-7", KONAMI_VRC7 }, | |
| 373 | { "UNL-VRC7", KONAMI_VRC7 }, | |
| 374 | // | |
| 375 | { "NAMCOT-163", NAMCOT_163 }, | |
| 376 | { "NAMCOT-175", NAMCOT_163 }, | |
| 377 | { "NAMCOT-340", NAMCOT_163 }, | |
| 378 | { "NAMCOT-3425", NAMCOT_3425 }, | |
| 379 | { "NAMCOT-3433", NAMCOT_34X3 }, | |
| 380 | { "NAMCOT-3443", NAMCOT_34X3 }, | |
| 381 | { "NAMCOT-3446", NAMCOT_3446 }, | |
| 382 | { "NAMCOT-3453", NAMCOT_3453 }, | |
| 383 | // | |
| 384 | { "SUNSOFT-1", SUNSOFT_1 }, | |
| 385 | { "SUNSOFT-2", SUNSOFT_2 }, | |
| 386 | { "SUNSOFT-3", SUNSOFT_3 }, | |
| 387 | // | |
| 388 | { "TAITO-TC0190FMC", TAITO_TC0190FMC }, | |
| 389 | { "TAITO-TC0190FMC+PAL16R4", TAITO_TC0190FMCP }, | |
| 390 | { "TAITO-TC0350FMR", TAITO_TC0190FMC }, | |
| 391 | { "TAITO-X1-005", TAITO_X1_005 }, // two variants exist, depending on pin17 & pin31 connections | |
| 392 | { "TAITO-X1-017", TAITO_X1_017 }, | |
| 393 | // | |
| 394 | { "AGCI-50282", AGCI_50282 }, | |
| 395 | { "AVE-NINA-01", AVE_NINA01 }, | |
| 396 | { "AVE-NINA-02", AVE_NINA01 }, | |
| 397 | { "AVE-NINA-03", AVE_NINA06 }, | |
| 398 | { "AVE-NINA-06", AVE_NINA06 }, | |
| 399 | { "AVE-MB-91", AVE_NINA06 }, | |
| 400 | { "TXC-74*138/175", AVE_NINA06 }, | |
| 401 | { "UNL-SA-016-1M", AVE_NINA06 }, | |
| 402 | { "CAMERICA-ALGN", CAMERICA_BF9093 }, | |
| 403 | { "CAMERICA-BF9093", CAMERICA_BF9093 }, | |
| 404 | { "CAMERICA-BF9097", CAMERICA_BF9097 }, | |
| 405 | { "CAMERICA-ALGQ", CAMERICA_BF9096 }, | |
| 406 | { "CAMERICA-BF9096", CAMERICA_BF9096 }, | |
| 407 | { "CAMERICA-GOLDENFIVE", CAMERICA_GOLDENFIVE }, | |
| 408 | { "CNE-DECATHLON", CNE_DECATHLON }, | |
| 409 | { "CNE-PSB", CNE_FSB }, | |
| 410 | { "CNE-SHLZ", CNE_SHLZ }, | |
| 411 | { "JYCOMPANY-A", UNSUPPORTED_BOARD }, // mapper 90 | |
| 412 | { "JYCOMPANY-B", UNSUPPORTED_BOARD }, // mapper 209 | |
| 413 | { "JYCOMPANY-C", UNSUPPORTED_BOARD }, // mapper 211 | |
| 414 | { "NTDEC-112", NTDEC_ASDER }, // mapper 112 (better rename this board tag, to avoid confusion with TC-112!! | |
| 415 | { "NTDEC-TC-112", NTDEC_FIGHTINGHERO }, | |
| 416 | { "NTDEC-193", NTDEC_FIGHTINGHERO }, // mapper 193 | |
| 417 | { "UNL-TEK90", UNSUPPORTED_BOARD }, // related to JY Company? (i.e. mappers 90, 209, 211?) | |
| 418 | { "UNL-SA-002", SACHEN_TCU02 }, | |
| 419 | { "UNL-SA-009", SACHEN_SA009 }, | |
| 420 | { "UNL-SA-0036", SACHEN_SA0036 }, | |
| 421 | { "UNL-SA-0037", SACHEN_SA0037 }, | |
| 422 | { "UNL-SA-72007", SACHEN_SA72007 }, | |
| 423 | { "UNL-SA-72008", SACHEN_SA72008 }, | |
| 424 | { "UNL-SA-NROM", SACHEN_TCA01 }, | |
| 425 | { "UNL-SACHEN-TCA01", SACHEN_TCA01 }, | |
| 426 | { "SACHEN-8259A", SACHEN_8259A }, | |
| 427 | { "UNL-SACHEN-8259A", SACHEN_8259A }, | |
| 428 | { "SACHEN-8259B", SACHEN_8259B }, | |
| 429 | { "UNL-SACHEN-8259B", SACHEN_8259B }, | |
| 430 | { "SACHEN-8259C", SACHEN_8259C }, | |
| 431 | { "UNL-SACHEN-8259C", SACHEN_8259C }, | |
| 432 | { "SACHEN-8259D", SACHEN_8259D }, | |
| 433 | { "UNL-SACHEN-8259D", SACHEN_8259D }, | |
| 434 | { "UNL-SACHEN-74LS374N", SACHEN_74LS374 }, | |
| 435 | { "UNL-SACHEN-74LS374N-A", SACHEN_74LS374_A }, /* FIXME: Made up boards the different mirroring handling */ | |
| 436 | { "UNL-TC-U01-1.5M", SACHEN_TCU01 }, | |
| 437 | { "TENGEN-800032", TENGEN_800032 }, | |
| 438 | { "TENGEN-800037", TENGEN_800037 }, | |
| 439 | { "WAIXING-A", WAIXING_TYPE_A }, | |
| 440 | { "WAIXING-A-1", WAIXING_TYPE_A_1 }, /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi) */ | |
| 441 | { "WAIXING-B", WAIXING_TYPE_B }, | |
| 442 | { "WAIXING-C", WAIXING_TYPE_C }, | |
| 443 | { "WAIXING-D", WAIXING_TYPE_D }, | |
| 444 | { "WAIXING-E", WAIXING_TYPE_E }, | |
| 445 | { "WAIXING-F", WAIXING_TYPE_F }, | |
| 446 | { "WAIXING-G", WAIXING_TYPE_G }, | |
| 447 | { "WAIXING-H", WAIXING_TYPE_H }, | |
| 448 | { "WAIXING-I", WAIXING_TYPE_I }, | |
| 449 | { "WAIXING-J", WAIXING_TYPE_J }, | |
| 450 | { "WAIXING-SGZLZ", WAIXING_SGZLZ }, | |
| 451 | { "WAIXING-SEC", WAIXING_SECURITY }, | |
| 452 | { "WAIXING-SGZ", WAIXING_SGZ }, | |
| 453 | { "WAIXING-PS2", WAIXING_PS2 }, | |
| 454 | { "WAIXING-FFV", WAIXING_FFV }, | |
| 455 | { "WAIXING-ZS", WAIXING_ZS }, | |
| 456 | { "WAIXING-DQ8", WAIXING_DQ8 }, | |
| 457 | { "WAIXING-SH2", WAIXING_SH2 }, | |
| 458 | // | |
| 459 | { "TXC-TW", TXC_TW }, | |
| 460 | { "TXC-STRIKEWOLF", TXC_STRIKEWOLF }, | |
| 461 | { "TXC-MXMDHTWO", TXC_MXMDHTWO }, | |
| 462 | { "UNL-22211", TXC_22211A }, | |
| 463 | /* FIXME: Made up boards the different mirroring handling */ | |
| 464 | { "UNL-22211-A", TXC_22211A }, | |
| 465 | { "UNL-22211-B", TXC_22211B }, | |
| 466 | { "UNL-22211-C", TXC_22211C }, | |
| 467 | { "UNL-REXSOFT-DBZ5", REXSOFT_DBZ5 }, | |
| 468 | { "UNL-SL1632", REXSOFT_SL1632 }, | |
| 469 | { "SUBOR-BOARD-0", SUBOR_TYPE0 }, | |
| 470 | { "SUBOR-BOARD-1", SUBOR_TYPE1 }, | |
| 471 | { "SOMERITEAM-SL-12", SOMERI_SL12 }, // mapper 116 | |
| 472 | { "UNL-CONY", CONY_BOARD }, | |
| 473 | { "UNL-GOUDER", GOUDER_37017 }, | |
| 474 | { "UNL-NITRA", NITRA_TDA }, | |
| 475 | { "UNL-HOSENKAN", HOSENKAN_BOARD }, | |
| 476 | { "UNL-SUPERGAME", SUPERGAME_LIONKING }, | |
| 477 | { "UNL-PANDAPRINCE", KAY_PANDAPRINCE }, | |
| 478 | { "DREAMTECH01", DREAMTECH_BOARD }, | |
| 479 | { "DAOU-306", OPENCORP_DAOU306 }, | |
| 480 | { "HES", HES_BOARD }, | |
| 481 | /* FIXME: Made up boards the different mirroring handling? */ | |
| 482 | { "HES-6IN1", HES6IN1_BOARD }, | |
| 483 | { "SUPERGAME-BOOGERMAN", SUPERGAME_BOOGERMAN }, | |
| 484 | { "FUTUREMEDIA", FUTUREMEDIA_BOARD }, | |
| 485 | { "FUKUTAKE", FUKUTAKE_BOARD }, | |
| 486 | { "MAGICSERIES", MAGICSERIES_MD }, | |
| 487 | { "KASING", KASING_BOARD }, | |
| 488 | { "HENGGEDIANZI", HENGEDIANZI_BOARD }, | |
| 489 | { "HENGGEDIANZI-XJZB", HENGEDIANZI_XJZB }, | |
| 490 | { "KAISER-KS7058", KAISER_KS7058 }, | |
| 491 | { "KAISER-KS202", KAISER_KS202 },// mapper 56 | |
| 492 | { "KAISER-KS7022", KAISER_KS7022 },// mapper 175 | |
| 493 | { "UNL-KS7017", KAISER_KS7017 }, | |
| 494 | { "UNL-KS7032", KAISER_KS7032 }, // mapper 142 | |
| 495 | { "RCM-GS2015", RCM_GS2015 }, | |
| 496 | { "RCM-TETRISFAMILY", RCM_TETRISFAMILY }, | |
| 497 | { "UNL-NINJARYU", UNSUPPORTED_BOARD },// mapper 111 | |
| 498 | { "UNL-NANJING", NANJING_BOARD },// mapper 163 | |
| 499 | { "WHIRLWIND-2706", WHIRLWIND_2706 }, | |
| 500 | { "UNL-H2288", UNL_H2288 }, | |
| 501 | { "UNL-DANCE", UNSUPPORTED_BOARD }, | |
| 502 | { "UNL-EDU2000", UNL_EDU2K }, | |
| 503 | { "UNL-SHERO", UNSUPPORTED_BOARD /*SACHEN_SHERO*/ }, | |
| 504 | { "UNL-TF1201", UNSUPPORTED_BOARD /*UNL_TF1201*/ }, | |
| 505 | { "RUMBLESTATION", RUMBLESTATION_BOARD }, // mapper 46 | |
| 506 | { "UNL-WORLDHERO", UNSUPPORTED_BOARD },// mapper 27 | |
| 507 | { "UNL-A9746", UNSUPPORTED_BOARD },// mapper 219 | |
| 508 | { "UNL-603-5052", UNL_603_5052 },// mapper 238? | |
| 509 | { "UNL-SHJY3", UNL_SHJY3 },// mapper 253 | |
| 510 | { "UNL-RACERMATE", UNL_RACERMATE },// mapper 168 | |
| 511 | { "UNL-N625092", UNL_N625092 }, | |
| 512 | { "BMC-N625092", UNL_N625092 }, | |
| 513 | { "UNL-SC-127", UNL_SC127 }, | |
| 514 | { "UNL-SMB2J", UNL_SMB2J }, | |
| 515 | { "BTL-SMB2C", UNL_SMB2J }, | |
| 516 | { "UNL-MK2", UNL_MK2 }, | |
| 517 | { "UNL-XZY", UNL_XZY }, | |
| 518 | { "UNL-KOF96", UNL_KOF96 }, | |
| 519 | { "UNL-SUPERFIGHTER3", UNL_SUPERFIGHTER3 }, | |
| 520 | { "UNL-8237", UNL_8237 }, | |
| 521 | { "UNL-AX5705", UNL_AX5705 }, | |
| 522 | { "UNL-CC-21", UNL_CC21 }, | |
| 523 | { "UNL-KOF97", UNL_KOF97 }, | |
| 524 | { "UNL-T-230", UNL_T230 }, | |
| 525 | { "UNL-STUDYNGAME", UNL_STUDYNGAME }, // mapper 39 | |
| 526 | { "UNL-OneBus", UNSUPPORTED_BOARD }, | |
| 527 | // | |
| 528 | { "BTL-SMB2A", BTL_SMB2A }, | |
| 529 | { "BTL-MARIOBABY", BTL_MARIOBABY }, | |
| 530 | { "BTL-AISENSHINICOL", BTL_AISENSHINICOL }, | |
| 531 | { "BTL-SMB2B", BTL_SMB2B }, | |
| 532 | { "BTL-SMB3", BTL_SMB3 }, | |
| 533 | { "BTL-SUPERBROS11", BTL_SUPERBROS11 }, | |
| 534 | { "BTL-DRAGONNINJA", BTL_DRAGONNINJA }, | |
| 535 | { "BTL-MARIO1-MALEE2", UNSUPPORTED_BOARD }, // mapper 55? | |
| 536 | { "BTL-2708", UNSUPPORTED_BOARD },// mapper 103 | |
| 537 | { "BTL-TOBIDASEDAISAKUSEN", BTL_TOBIDASE },// mapper 120 | |
| 538 | { "BTL-SHUIGUANPIPE", UNSUPPORTED_BOARD },// mapper 183 | |
| 539 | { "BTL-PIKACHUY2K", BTL_PIKACHUY2K },// mapper 254 | |
| 540 | // | |
| 541 | { "BMC-190IN1", BMC_190IN1 }, | |
| 542 | { "BMC-64IN1NOREPEAT", BMC_64IN1NR }, | |
| 543 | { "BMC-A65AS", BMC_A65AS }, | |
| 544 | { "BMC-GS-2004", BMC_GS2004 }, | |
| 545 | { "BMC-GS-2013", BMC_GS2013 }, | |
| 546 | { "BMC-NOVELDIAMOND9999999IN1", BMC_NOVELDIAMOND }, | |
| 547 | { "BMC-9999999IN1", BMC_9999999IN1 }, // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 ?? | |
| 548 | { "BMC-SUPER24IN1SC03", BMC_S24IN1SC03 }, | |
| 549 | { "BMC-SUPERHIK8IN1", BMC_HIK8IN1 }, | |
| 550 | { "BMC-T-262", BMC_T262 }, | |
| 551 | { "BMC-WS", BMC_WS }, | |
| 552 | { "MLT-ACTION52", ACTENT_ACT52 }, | |
| 553 | { "MLT-CALTRON6IN1", CALTRON_6IN1 }, | |
| 554 | { "MLT-MAXI15", UNSUPPORTED_BOARD}, // mapper 234 | |
| 555 | { "BMC-SUPERBIG-7IN1", BMC_SUPERBIG_7IN1 }, | |
| 556 | { "BMC-SUPERHIK-4IN1", BMC_SUPERHIK_4IN1 }, | |
| 557 | { "BMC-BALLGAMES-11IN1", BMC_BALLGAMES_11IN1 }, | |
| 558 | { "BMC-MARIOPARTY-7IN1", BMC_MARIOPARTY_7IN1 }, | |
| 559 | { "BMC-GKA", BMC_GKA }, | |
| 560 | { "BMC-GKB", BMC_GKB }, | |
| 561 | { "BMC-SUPER700IN1", BMC_SUPER_700IN1 }, | |
| 562 | { "BMC-FAMILY-4646B", BMC_FAMILY_4646B }, | |
| 563 | { "BMC-36IN1", BMC_36IN1 }, | |
| 564 | { "BMC-21IN1", BMC_21IN1 }, | |
| 565 | { "BMC-150IN1", BMC_150IN1 }, | |
| 566 | { "BMC-35IN1", BMC_35IN1 }, | |
| 567 | { "BMC-64IN1", BMC_64IN1 }, | |
| 568 | { "BMC-15IN1", BMC_15IN1 }, | |
| 569 | { "BMC-SUPERHIK-300IN1", BMC_SUPERHIK_300IN1 }, | |
| 570 | { "BMC-SUPERGUN-20IN1", BMC_SUPERGUN_20IN1 }, | |
| 571 | { "BMC-GOLDENCARD-6IN1", BMC_GOLDENCARD_6IN1 }, | |
| 572 | { "BMC-72IN1", BMC_72IN1 }, | |
| 573 | { "BMC-76IN1", BMC_76IN1 }, | |
| 574 | { "BMC-SUPER42IN1", BMC_SUPER_42IN1 }, | |
| 575 | { "BMC-1200IN1", BMC_1200IN1 }, | |
| 576 | { "BMC-31IN1", BMC_31IN1 }, | |
| 577 | { "BMC-22GAMES", BMC_22GAMES }, | |
| 578 | { "BMC-20IN1", BMC_20IN1 }, | |
| 579 | { "BMC-110IN1", BMC_110IN1 }, | |
| 580 | { "BMC-810544-C-A1", BMC_810544 }, | |
| 581 | { "BMC-411120-C", UNSUPPORTED_BOARD }, | |
| 582 | { "BMC-830118C", UNSUPPORTED_BOARD }, | |
| 583 | { "BMC-12-IN-1", UNSUPPORTED_BOARD }, | |
| 584 | { "BMC-NTD-03", BMC_NTD_03 }, | |
| 585 | { "BMC-8157", UNSUPPORTED_BOARD /*BMC_8157*/ }, | |
| 586 | { "BMC-BS-5", BMC_BENSHENG_BS5 }, | |
| 587 | { "BMC-FK23C", BMC_FK23C }, | |
| 588 | { "BMC-FK23CA", BMC_FK23CA }, | |
| 589 | { "BMC-GHOSTBUSTERS63IN1", BMC_G63IN1 }, | |
| 590 | { "BMC-SUPERVISION16IN1", UNSUPPORTED_BOARD }, // mapper 53 | |
| 591 | { "BMC-RESETBASED-4IN1", UNSUPPORTED_BOARD },// mapper 60 with 64k prg and 32k chr | |
| 592 | { "BMC-VT5201", BMC_VT5201 },// mapper 60 otherwise | |
| 593 | { "BMC-D1038", BMC_VT5201 }, // mapper 60? | |
| 594 | { "BMC-42IN1RESETSWITCH", UNSUPPORTED_BOARD }, // mapper 60? | |
| 595 | { "BMC-SUPER22GAMES", UNSUPPORTED_BOARD },// mapper 233 | |
| 596 | { "BMC-GOLDENGAME-150IN1", UNSUPPORTED_BOARD },// mapper 235 with 2M PRG | |
| 597 | { "BMC-GOLDENGAME-260IN1", UNSUPPORTED_BOARD },// mapper 235 with 4M PRG | |
| 598 | { "BMC-70IN1", UNSUPPORTED_BOARD }, // mapper 236? | |
| 599 | { "BMC-70IN1B", UNSUPPORTED_BOARD }, // mapper 236? | |
| 600 | { "BMC-SUPERHIK-KOF", UNSUPPORTED_BOARD },// mapper 251 | |
| 601 | { "BMC-POWERJOY", BMC_PJOY84 }, | |
| 602 | // are there dumps of games with these boards? | |
| 603 | { "BMC-13IN1JY110", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 604 | { "BMC-GK-192", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 605 | { "KONAMI-QTAI", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 606 | { "UNL-3D-BLOCK", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 607 | { "UNL-C-N22M", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 608 | { "UNL-PEC-586", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 609 | // | |
| 610 | { "UNKNOWN", UNKNOWN_BOARD } // a few pirate dumps uses the wrong mapper... | |
| 611 | }; | |
| 612 | ||
| 613 | const nes_pcb *nes_pcb_lookup( const char *board ) | |
| 614 | { | |
| 615 | int i; | |
| 616 | for (i = 0; i < ARRAY_LENGTH(pcb_list); i++) | |
| 617 | { | |
| 618 | if (!mame_stricmp(pcb_list[i].pcb_name, board)) | |
| 619 | return &pcb_list[i]; | |
| 620 | } | |
| 621 | return NULL; | |
| 622 | } | |
| 623 | ||
| 624 | int nes_get_pcb_id( running_machine &machine, const char *feature ) | |
| 625 | { | |
| 626 | const nes_pcb *pcb = nes_pcb_lookup(feature); | |
| 627 | ||
| 628 | if (pcb == NULL) | |
| 629 | fatalerror("Unimplemented PCB type %s\n", feature); | |
| 630 | ||
| 631 | return pcb->pcb_id; | |
| 632 | } | |
| 633 | ||
| 634 | /************************************************ | |
| 635 | ||
| 636 | PCB Emulation (to be moved to MAME later) | |
| 637 | ||
| 638 | In the end, iNES, UNIF and xml should be | |
| 639 | simply handled through a look-up table | |
| 640 | which associates the mapper/board/feature | |
| 641 | to the correct pcb_id and then the core | |
| 642 | function pcb_handlers_setup should be called | |
| 643 | to set-up the expected handlers and callbacks | |
| 644 | ||
| 645 | Similarly, PC-10, VSNES and NES-based | |
| 646 | multigame boards, should simply call | |
| 647 | pcb_handlers_setup with the proper pcb_id | |
| 648 | at the beginning, rather than use ad hoc | |
| 649 | implementations. | |
| 650 | ||
| 651 | ************************************************/ | |
| 652 | ||
| 653 | // helper function for the few mappers reading from 0x8000-0xffff for protection | |
| 654 | INLINE UINT8 mmc_hi_access_rom( running_machine &machine, UINT32 offset ) | |
| 655 | { | |
| 656 | nes_state *state = machine.driver_data<nes_state>(); | |
| 657 | ||
| 658 | // usual ROM access | |
| 659 | switch (offset & 0x6000) | |
| 660 | { | |
| 661 | case 0x0000: | |
| 662 | return state->m_rom[0x10000 + state->m_prg_bank[0] * 0x2000 + (offset & 0x1fff)]; | |
| 663 | case 0x2000: | |
| 664 | return state->m_rom[0x10000 + state->m_prg_bank[1] * 0x2000 + (offset & 0x1fff)]; | |
| 665 | case 0x4000: | |
| 666 | return state->m_rom[0x10000 + state->m_prg_bank[2] * 0x2000 + (offset & 0x1fff)]; | |
| 667 | case 0x6000: | |
| 668 | return state->m_rom[0x10000 + state->m_prg_bank[3] * 0x2000 + (offset & 0x1fff)]; | |
| 669 | } | |
| 670 | return 0; | |
| 671 | } | |
| 672 | ||
| 673 | /************************************************************* | |
| 674 | ||
| 675 | NROM board emulation | |
| 676 | ||
| 677 | Games: Mario Bros., Super Mario Bros., Tennis and most of | |
| 678 | the first generation games | |
| 679 | ||
| 680 | iNES: mapper 0 | |
| 681 | ||
| 682 | In MESS: Supported, no need of specific handlers or IRQ | |
| 683 | ||
| 684 | *************************************************************/ | |
| 685 | ||
| 686 | /************************************************************* | |
| 687 | ||
| 688 | UxROM board emulation | |
| 689 | ||
| 690 | Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan, | |
| 691 | Metal Gear | |
| 692 | ||
| 693 | writes to 0x8000-0xffff change PRG 16K lower banks | |
| 694 | ||
| 695 | missing BC? | |
| 696 | ||
| 697 | iNES: mapper 2 | |
| 698 | ||
| 699 | In MESS: Supported. | |
| 700 | ||
| 701 | *************************************************************/ | |
| 702 | ||
| 703 | static WRITE8_HANDLER( uxrom_w ) | |
| 704 | { | |
| 705 | LOG_MMC(("uxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 706 | ||
| 707 | prg16_89ab(space->machine(), data); | |
| 708 | } | |
| 709 | ||
| 710 | /************************************************************* | |
| 711 | ||
| 712 | Nihon Bussan UNROM M5 | |
| 713 | ||
| 714 | Games: Crazy Climber Jpn | |
| 715 | ||
| 716 | Very simple mapper: prg16_89ab is always set to bank 0, | |
| 717 | while prg16_cdef is set by writes to 0x8000-0xffff. The game | |
| 718 | uses a custom controller. | |
| 719 | ||
| 720 | iNES: mapper 180 | |
| 721 | ||
| 722 | In MESS: Supported. | |
| 723 | ||
| 724 | *************************************************************/ | |
| 725 | ||
| 726 | static WRITE8_HANDLER( uxrom_cc_w ) | |
| 727 | { | |
| 728 | LOG_MMC(("uxrom_cc_w, offset: %04x, data: %02x\n", offset, data)); | |
| 729 | ||
| 730 | prg16_cdef(space->machine(), data); | |
| 731 | } | |
| 732 | ||
| 733 | /************************************************************* | |
| 734 | ||
| 735 | UN1ROM board emulation | |
| 736 | ||
| 737 | Games: Senjou no Okami | |
| 738 | ||
| 739 | writes to 0x8000-0xffff change PRG 16K lower banks | |
| 740 | ||
| 741 | missing BC? | |
| 742 | ||
| 743 | iNES: mapper 94 | |
| 744 | ||
| 745 | In MESS: Supported. | |
| 746 | ||
| 747 | *************************************************************/ | |
| 748 | ||
| 749 | static WRITE8_HANDLER( un1rom_w ) | |
| 750 | { | |
| 751 | LOG_MMC(("un1rom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 752 | ||
| 753 | prg16_89ab(space->machine(), data >> 2); | |
| 754 | } | |
| 755 | ||
| 756 | /************************************************************* | |
| 757 | ||
| 758 | CNROM board emulation | |
| 759 | ||
| 760 | Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy, | |
| 761 | Adventure Island, Flipull, Friday 13th, GeGeGe no | |
| 762 | Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's | |
| 763 | Secret Castle | |
| 764 | ||
| 765 | writes to 0x8000-0xffff change CHR 8K banks | |
| 766 | ||
| 767 | missing BC? | |
| 768 | ||
| 769 | iNES: mappers 3 & 185 (the latter for games using Pins as | |
| 770 | protection) | |
| 771 | ||
| 772 | Notice that BANDAI_PT554 board (Aerobics Studio) uses very | |
| 773 | similar hardware but with an additional sound chip which | |
| 774 | gets writes to 0x6000 (currently unemulated in MESS) | |
| 775 | ||
| 776 | In MESS: Supported | |
| 777 | ||
| 778 | *************************************************************/ | |
| 779 | ||
| 780 | static WRITE8_HANDLER( cnrom_w ) | |
| 781 | { | |
| 782 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 783 | LOG_MMC(("cnrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 784 | ||
| 785 | if (state->m_ce_mask) | |
| 786 | { | |
| 787 | chr8(space->machine(), data & ~state->m_ce_mask, CHRROM); | |
| 788 | ||
| 789 | if ((data & state->m_ce_mask) == state->m_ce_state) | |
| 790 | state->m_chr_open_bus = 0; | |
| 791 | else | |
| 792 | state->m_chr_open_bus = 1; | |
| 793 | } | |
| 794 | else | |
| 795 | chr8(space->machine(), data, CHRROM); | |
| 796 | } | |
| 797 | ||
| 798 | /************************************************************* | |
| 799 | ||
| 800 | Bandai PT-554 board emulation | |
| 801 | ||
| 802 | This is used by Aerobics Studio. It is basically a CNROM board | |
| 803 | with an additional sound chip which is not currently emulated by | |
| 804 | MESS | |
| 805 | ||
| 806 | iNES: mapper 3? | |
| 807 | ||
| 808 | *************************************************************/ | |
| 809 | ||
| 810 | static WRITE8_HANDLER( bandai_pt554_m_w ) | |
| 811 | { | |
| 812 | LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data)); | |
| 813 | ||
| 814 | // according to NEStopia, this is the effect | |
| 815 | if (!BIT(data, 6)) | |
| 816 | { | |
| 817 | // send command (data & 0x07) to sound chip | |
| 818 | } | |
| 819 | } | |
| 820 | ||
| 821 | /************************************************************* | |
| 822 | ||
| 823 | CPROM board emulation | |
| 824 | ||
| 825 | Games: Videomation | |
| 826 | ||
| 827 | writes to 0x8000-0xffff change CHR 4K lower banks | |
| 828 | ||
| 829 | iNES: mapper 13 | |
| 830 | ||
| 831 | In MESS: Supported | |
| 832 | ||
| 833 | *************************************************************/ | |
| 834 | ||
| 835 | static WRITE8_HANDLER( cprom_w ) | |
| 836 | { | |
| 837 | LOG_MMC(("cprom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 838 | chr4_4(space->machine(), data, CHRRAM); | |
| 839 | } | |
| 840 | ||
| 841 | /************************************************************* | |
| 842 | ||
| 843 | AxROM board emulation | |
| 844 | ||
| 845 | Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice | |
| 846 | ||
| 847 | writes to 0x8000-0xffff change PRG banks + sets mirroring | |
| 848 | ||
| 849 | missing BC for AMROM? | |
| 850 | ||
| 851 | iNES: mapper 7 | |
| 852 | ||
| 853 | In MESS: Supported | |
| 854 | ||
| 855 | *************************************************************/ | |
| 856 | ||
| 857 | static WRITE8_HANDLER( axrom_w ) | |
| 858 | { | |
| 859 | LOG_MMC(("axrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 860 | ||
| 861 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 862 | prg32(space->machine(), data); | |
| 863 | } | |
| 864 | ||
| 865 | /************************************************************* | |
| 866 | ||
| 867 | BxROM board emulation | |
| 868 | ||
| 869 | writes to 0x8000-0xffff change PRG banks | |
| 870 | ||
| 871 | missing BC? | |
| 872 | ||
| 873 | iNES: mapper 34 | |
| 874 | ||
| 875 | *************************************************************/ | |
| 876 | ||
| 877 | static WRITE8_HANDLER( bxrom_w ) | |
| 878 | { | |
| 879 | /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */ | |
| 880 | /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */ | |
| 881 | LOG_MMC(("bxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 882 | ||
| 883 | prg32(space->machine(), data); | |
| 884 | } | |
| 885 | ||
| 886 | /************************************************************* | |
| 887 | ||
| 888 | GxROM/MxROM board emulation | |
| 889 | ||
| 890 | writes to 0x8000-0xffff change PRG and CHR banks | |
| 891 | ||
| 892 | missing BC? | |
| 893 | ||
| 894 | iNES: mapper 66 | |
| 895 | ||
| 896 | *************************************************************/ | |
| 897 | ||
| 898 | static WRITE8_HANDLER( gxrom_w ) | |
| 899 | { | |
| 900 | LOG_MMC(("gxrom_w, offset %04x, data: %02x\n", offset, data)); | |
| 901 | ||
| 902 | prg32(space->machine(), (data & 0xf0) >> 4); | |
| 903 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 904 | } | |
| 905 | ||
| 906 | /************************************************************* | |
| 907 | ||
| 908 | SxROM (MMC1 based) board emulation | |
| 909 | ||
| 910 | iNES: mapper 1 (and 155 for the MMC1A variant which does not | |
| 911 | have WRAM disable bit) | |
| 912 | ||
| 913 | *************************************************************/ | |
| 914 | ||
| 915 | static TIMER_CALLBACK( mmc1_resync_callback ) | |
| 916 | { | |
| 917 | nes_state *state = machine.driver_data<nes_state>(); | |
| 918 | state->m_mmc1_reg_write_enable = 1; | |
| 919 | } | |
| 920 | ||
| 921 | ||
| 922 | static void mmc1_set_wram( address_space *space, int board ) | |
| 923 | { | |
| 924 | running_machine &machine = space->machine(); | |
| 925 | nes_state *state = machine.driver_data<nes_state>(); | |
| 926 | UINT8 bank = BIT(state->m_mmc_reg[0], 4) ? BIT(state->m_mmc_reg[1], 4) : BIT(state->m_mmc_reg[1], 3); | |
| 927 | ||
| 928 | switch (board) | |
| 929 | { | |
| 930 | case STD_SXROM: // here also reads are disabled! | |
| 931 | if (!BIT(state->m_mmc_reg[3], 4)) | |
| 932 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 933 | else | |
| 934 | { | |
| 935 | space->unmap_readwrite(0x6000, 0x7fff); | |
| 936 | break; | |
| 937 | } | |
| 938 | case STD_SXROM_A: // ignore WRAM enable bit | |
| 939 | if (state->m_battery_size > 0x2000) | |
| 940 | wram_bank(machine, ((state->m_mmc_reg[1] & 3) >> 2), NES_BATTERY); | |
| 941 | else if (state->m_battery_size) | |
| 942 | wram_bank(machine, 0, NES_BATTERY); | |
| 943 | break; | |
| 944 | case STD_SOROM: // there are 2 WRAM banks only and battery is bank 2 for the cart (hence, we invert bank, because we have battery first) | |
| 945 | if (!BIT(state->m_mmc_reg[3], 4)) | |
| 946 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 947 | else | |
| 948 | { | |
| 949 | space->unmap_readwrite(0x6000, 0x7fff); | |
| 950 | break; | |
| 951 | } | |
| 952 | case STD_SOROM_A: // ignore WRAM enable bit | |
| 953 | wram_bank(machine, 0, bank ? NES_BATTERY : NES_WRAM); | |
| 954 | break; | |
| 955 | } | |
| 956 | } | |
| 957 | ||
| 958 | static void mmc1_set_prg( running_machine &machine ) | |
| 959 | { | |
| 960 | nes_state *state = machine.driver_data<nes_state>(); | |
| 961 | UINT8 prg_mode, prg_offset; | |
| 962 | ||
| 963 | prg_mode = state->m_mmc_reg[0] & 0x0c; | |
| 964 | /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode, | |
| 965 | prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4, | |
| 966 | mmc_reg[3] sets banks at 0x8000; if it is 0, mmc_reg[3] sets banks at 0xc000. */ | |
| 967 | ||
| 968 | prg_offset = state->m_mmc_reg[1] & 0x10; | |
| 969 | /* In principle, mmc_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1. | |
| 970 | However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be | |
| 971 | set to the same value, or else pages will constantly be swapped as graphics render! | |
| 972 | Hence, we use only mmc_reg[1]&0x10 for prg_offset */ | |
| 973 | ||
| 974 | switch (prg_mode) | |
| 975 | { | |
| 976 | case 0x00: | |
| 977 | case 0x04: | |
| 978 | // printf("PRG 32 bank %d \n", (prg_offset + state->m_mmc_reg[3]) >> 1); | |
| 979 | prg32(machine, (prg_offset + state->m_mmc_reg[3]) >> 1); | |
| 980 | break; | |
| 981 | case 0x08: | |
| 982 | // printf("PRG 16 bank %d (high) \n", prg_offset + state->m_mmc_reg[3]); | |
| 983 | prg16_89ab(machine, prg_offset + 0); | |
| 984 | prg16_cdef(machine, prg_offset + state->m_mmc_reg[3]); | |
| 985 | break; | |
| 986 | case 0x0c: | |
| 987 | // printf("PRG 16 bank %d (low) \n", prg_offset + state->m_mmc_reg[3]); | |
| 988 | prg16_89ab(machine, prg_offset + state->m_mmc_reg[3]); | |
| 989 | prg16_cdef(machine, prg_offset + 0x0f); | |
| 990 | break; | |
| 991 | } | |
| 992 | } | |
| 993 | ||
| 994 | static void mmc1_set_prg_wram( address_space *space, int board ) | |
| 995 | { | |
| 996 | mmc1_set_prg(space->machine()); | |
| 997 | mmc1_set_wram(space, board); | |
| 998 | } | |
| 999 | ||
| 1000 | static void mmc1_set_chr( running_machine &machine ) | |
| 1001 | { | |
| 1002 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1003 | UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4); | |
| 1004 | ||
| 1005 | if (chr_mode) | |
| 1006 | { | |
| 1007 | chr4_0(machine, state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source); | |
| 1008 | chr4_4(machine, state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source); | |
| 1009 | } | |
| 1010 | else | |
| 1011 | chr8(machine, (state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source); | |
| 1012 | } | |
| 1013 | ||
| 1014 | static void common_sxrom_write_handler( address_space *space, offs_t offset, UINT8 data, int board ) | |
| 1015 | { | |
| 1016 | running_machine &machine = space->machine(); | |
| 1017 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1018 | /* Note that there is only one latch and shift counter, shared amongst the 4 regs */ | |
| 1019 | /* Space Shuttle will not work if they have independent variables. */ | |
| 1020 | ||
| 1021 | /* here we would need to add an if(cpu_cycles_passed>1) test, and | |
| 1022 | if requirement is not met simply return without writing anything. | |
| 1023 | Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic | |
| 1024 | Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on | |
| 1025 | this behavior!! */ | |
| 1026 | if (state->m_mmc1_reg_write_enable == 0) | |
| 1027 | { | |
| 1028 | return; | |
| 1029 | } | |
| 1030 | else | |
| 1031 | { | |
| 1032 | state->m_mmc1_reg_write_enable = 0; | |
| 1033 | space->machine().scheduler().synchronize(FUNC(mmc1_resync_callback)); | |
| 1034 | } | |
| 1035 | ||
| 1036 | if (data & 0x80) | |
| 1037 | { | |
| 1038 | state->m_mmc1_count = 0; | |
| 1039 | state->m_mmc1_latch = 0; | |
| 1040 | ||
| 1041 | /* Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars */ | |
| 1042 | state->m_mmc_reg[0] |= 0x0c; | |
| 1043 | mmc1_set_prg_wram(space, board); | |
| 1044 | return; | |
| 1045 | } | |
| 1046 | ||
| 1047 | if (state->m_mmc1_count < 5) | |
| 1048 | { | |
| 1049 | if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0; | |
| 1050 | state->m_mmc1_latch >>= 1; | |
| 1051 | state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; | |
| 1052 | state->m_mmc1_count++; | |
| 1053 | } | |
| 1054 | ||
| 1055 | if (state->m_mmc1_count == 5) | |
| 1056 | { | |
| 1057 | switch (offset & 0x6000) /* Which reg shall we write to? */ | |
| 1058 | { | |
| 1059 | case 0x0000: | |
| 1060 | state->m_mmc_reg[0] = state->m_mmc1_latch; | |
| 1061 | ||
| 1062 | switch (state->m_mmc_reg[0] & 0x03) | |
| 1063 | { | |
| 1064 | case 0: set_nt_mirroring(machine, PPU_MIRROR_LOW); break; | |
| 1065 | case 1: set_nt_mirroring(machine, PPU_MIRROR_HIGH); break; | |
| 1066 | case 2: set_nt_mirroring(machine, PPU_MIRROR_VERT); break; | |
| 1067 | case 3: set_nt_mirroring(machine, PPU_MIRROR_HORZ); break; | |
| 1068 | } | |
| 1069 | mmc1_set_chr(machine); | |
| 1070 | mmc1_set_prg_wram(space, board); | |
| 1071 | break; | |
| 1072 | case 0x2000: | |
| 1073 | state->m_mmc_reg[1] = state->m_mmc1_latch; | |
| 1074 | mmc1_set_chr(machine); | |
| 1075 | mmc1_set_prg_wram(space, board); | |
| 1076 | break; | |
| 1077 | case 0x4000: | |
| 1078 | state->m_mmc_reg[2] = state->m_mmc1_latch; | |
| 1079 | mmc1_set_chr(machine); | |
| 1080 | break; | |
| 1081 | case 0x6000: | |
| 1082 | state->m_mmc_reg[3] = state->m_mmc1_latch; | |
| 1083 | mmc1_set_prg_wram(space, board); | |
| 1084 | break; | |
| 1085 | } | |
| 1086 | state->m_mmc1_count = 0; | |
| 1087 | } | |
| 1088 | } | |
| 1089 | ||
| 1090 | static WRITE8_HANDLER( sxrom_w ) | |
| 1091 | { | |
| 1092 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1093 | ||
| 1094 | LOG_MMC(("sxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1095 | common_sxrom_write_handler(space, offset, data, state->m_pcb_id); | |
| 1096 | } | |
| 1097 | ||
| 1098 | /************************************************************* | |
| 1099 | ||
| 1100 | PxROM (MMC2 based) board emulation | |
| 1101 | ||
| 1102 | Games: Punch Out!!, Mike Tyson's Punch Out!! | |
| 1103 | ||
| 1104 | iNES: mapper 9 | |
| 1105 | ||
| 1106 | In MESS: Supported | |
| 1107 | ||
| 1108 | *************************************************************/ | |
| 1109 | ||
| 1110 | static void mmc2_latch( device_t *device, offs_t offset ) | |
| 1111 | { | |
| 1112 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1113 | if ((offset & 0x3ff0) == 0x0fd0) | |
| 1114 | { | |
| 1115 | LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", state->m_mmc_reg[0])); | |
| 1116 | state->m_mmc_latch1 = 0xfd; | |
| 1117 | chr4_0(device->machine(), state->m_mmc_reg[0], CHRROM); | |
| 1118 | } | |
| 1119 | else if ((offset & 0x3ff0) == 0x0fe0) | |
| 1120 | { | |
| 1121 | LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", state->m_mmc_reg[1])); | |
| 1122 | state->m_mmc_latch1 = 0xfe; | |
| 1123 | chr4_0(device->machine(), state->m_mmc_reg[1], CHRROM); | |
| 1124 | } | |
| 1125 | else if ((offset & 0x3ff0) == 0x1fd0) | |
| 1126 | { | |
| 1127 | LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", state->m_mmc_reg[2])); | |
| 1128 | state->m_mmc_latch2 = 0xfd; | |
| 1129 | chr4_4(device->machine(), state->m_mmc_reg[2], CHRROM); | |
| 1130 | } | |
| 1131 | else if ((offset & 0x3ff0) == 0x1fe0) | |
| 1132 | { | |
| 1133 | LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", state->m_mmc_reg[3])); | |
| 1134 | state->m_mmc_latch2 = 0xfe; | |
| 1135 | chr4_4(device->machine(), state->m_mmc_reg[3], CHRROM); | |
| 1136 | } | |
| 1137 | } | |
| 1138 | ||
| 1139 | static WRITE8_HANDLER( pxrom_w ) | |
| 1140 | { | |
| 1141 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1142 | LOG_MMC(("pxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1143 | switch (offset & 0x7000) | |
| 1144 | { | |
| 1145 | case 0x2000: | |
| 1146 | prg8_89(space->machine(), data); | |
| 1147 | break; | |
| 1148 | case 0x3000: | |
| 1149 | state->m_mmc_reg[0] = data; | |
| 1150 | if (state->m_mmc_latch1 == 0xfd) | |
| 1151 | chr4_0(space->machine(), state->m_mmc_reg[0], CHRROM); | |
| 1152 | break; | |
| 1153 | case 0x4000: | |
| 1154 | state->m_mmc_reg[1] = data; | |
| 1155 | if (state->m_mmc_latch1 == 0xfe) | |
| 1156 | chr4_0(space->machine(), state->m_mmc_reg[1], CHRROM); | |
| 1157 | break; | |
| 1158 | case 0x5000: | |
| 1159 | state->m_mmc_reg[2] = data; | |
| 1160 | if (state->m_mmc_latch2 == 0xfd) | |
| 1161 | chr4_4(space->machine(), state->m_mmc_reg[2], CHRROM); | |
| 1162 | break; | |
| 1163 | case 0x6000: | |
| 1164 | state->m_mmc_reg[3] = data; | |
| 1165 | if (state->m_mmc_latch2 == 0xfe) | |
| 1166 | chr4_4(space->machine(), state->m_mmc_reg[3], CHRROM); | |
| 1167 | break; | |
| 1168 | case 0x7000: | |
| 1169 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 1170 | break; | |
| 1171 | default: | |
| 1172 | LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data)); | |
| 1173 | break; | |
| 1174 | } | |
| 1175 | } | |
| 1176 | ||
| 1177 | /************************************************************* | |
| 1178 | ||
| 1179 | FxROM (MMC4 based) board emulation | |
| 1180 | ||
| 1181 | Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden | |
| 1182 | ||
| 1183 | iNES: mapper 10 | |
| 1184 | ||
| 1185 | In MESS: Supported | |
| 1186 | ||
| 1187 | *************************************************************/ | |
| 1188 | ||
| 1189 | static WRITE8_HANDLER( fxrom_w ) | |
| 1190 | { | |
| 1191 | LOG_MMC(("fxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1192 | switch (offset & 0x7000) | |
| 1193 | { | |
| 1194 | case 0x2000: | |
| 1195 | prg16_89ab(space->machine(), data); | |
| 1196 | break; | |
| 1197 | default: | |
| 1198 | pxrom_w(space, offset, data); | |
| 1199 | break; | |
| 1200 | } | |
| 1201 | } | |
| 1202 | ||
| 1203 | /************************************************************* | |
| 1204 | ||
| 1205 | TxROM (MMC3 based) board emulation | |
| 1206 | ||
| 1207 | iNES: mapper 4 | |
| 1208 | ||
| 1209 | *************************************************************/ | |
| 1210 | ||
| 1211 | static void mmc3_set_wram( address_space *space ) | |
| 1212 | { | |
| 1213 | running_machine &machine = space->machine(); | |
| 1214 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1215 | ||
| 1216 | // skip this function if we are emulating a MMC3 clone with mid writes | |
| 1217 | if (state->m_mmc_write_mid != NULL) | |
| 1218 | return; | |
| 1219 | ||
| 1220 | if (BIT(state->m_mmc3_wram_protect, 7)) | |
| 1221 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 1222 | else | |
| 1223 | { | |
| 1224 | space->unmap_readwrite(0x6000, 0x7fff); | |
| 1225 | return; | |
| 1226 | } | |
| 1227 | ||
| 1228 | if (!BIT(state->m_mmc3_wram_protect, 6)) | |
| 1229 | space->install_write_bank(0x6000, 0x7fff, "bank5"); | |
| 1230 | else | |
| 1231 | { | |
| 1232 | space->unmap_write(0x6000, 0x7fff); | |
| 1233 | return; | |
| 1234 | } | |
| 1235 | } | |
| 1236 | ||
| 1237 | static void mmc3_set_prg( running_machine &machine, int prg_base, int prg_mask ) | |
| 1238 | { | |
| 1239 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1240 | UINT8 prg_flip = (state->m_mmc3_latch & 0x40) ? 2 : 0; | |
| 1241 | ||
| 1242 | state->m_mmc3_prg_cb(machine, 0, prg_base | (state->m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); | |
| 1243 | state->m_mmc3_prg_cb(machine, 1, prg_base | (state->m_mmc_prg_bank[1] & prg_mask)); | |
| 1244 | state->m_mmc3_prg_cb(machine, 2, prg_base | (state->m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); | |
| 1245 | state->m_mmc3_prg_cb(machine, 3, prg_base | (state->m_mmc_prg_bank[3] & prg_mask)); | |
| 1246 | } | |
| 1247 | ||
| 1248 | static void mmc3_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask ) | |
| 1249 | { | |
| 1250 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1251 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 1252 | ||
| 1253 | state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); | |
| 1254 | state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); | |
| 1255 | state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); | |
| 1256 | state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); | |
| 1257 | state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr); | |
| 1258 | state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr); | |
| 1259 | state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr); | |
| 1260 | state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr); | |
| 1261 | } | |
| 1262 | ||
| 1263 | /* Here, IRQ counter decrements every scanline. */ | |
| 1264 | static void mmc3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 1265 | { | |
| 1266 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1267 | ||
| 1268 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 1269 | { | |
| 1270 | int priorCount = state->m_IRQ_count; | |
| 1271 | if ((state->m_IRQ_count == 0) || state->m_IRQ_clear) | |
| 1272 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 1273 | else | |
| 1274 | state->m_IRQ_count--; | |
| 1275 | ||
| 1276 | if (state->m_IRQ_enable && !blanked && (state->m_IRQ_count == 0) && (priorCount || state->m_IRQ_clear /*|| !state->m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq! | |
| 1277 | { | |
| 1278 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 1279 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 1280 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1281 | } | |
| 1282 | } | |
| 1283 | state->m_IRQ_clear = 0; | |
| 1284 | } | |
| 1285 | ||
| 1286 | static WRITE8_HANDLER( txrom_w ) | |
| 1287 | { | |
| 1288 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1289 | UINT8 mmc_helper, cmd; | |
| 1290 | ||
| 1291 | LOG_MMC(("txrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1292 | ||
| 1293 | switch (offset & 0x6001) | |
| 1294 | { | |
| 1295 | case 0x0000: | |
| 1296 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 1297 | state->m_mmc3_latch = data; | |
| 1298 | ||
| 1299 | /* Has PRG Mode changed? */ | |
| 1300 | if (mmc_helper & 0x40) | |
| 1301 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1302 | ||
| 1303 | /* Has CHR Mode changed? */ | |
| 1304 | if (mmc_helper & 0x80) | |
| 1305 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1306 | break; | |
| 1307 | ||
| 1308 | case 0x0001: | |
| 1309 | cmd = state->m_mmc3_latch & 0x07; | |
| 1310 | switch (cmd) | |
| 1311 | { | |
| 1312 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 1313 | case 2: case 3: case 4: case 5: | |
| 1314 | state->m_mmc_vrom_bank[cmd] = data; | |
| 1315 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1316 | break; | |
| 1317 | case 6: | |
| 1318 | case 7: | |
| 1319 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 1320 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1321 | break; | |
| 1322 | } | |
| 1323 | break; | |
| 1324 | ||
| 1325 | case 0x2000: | |
| 1326 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 1327 | break; | |
| 1328 | ||
| 1329 | case 0x2001: | |
| 1330 | state->m_mmc3_wram_protect = data; | |
| 1331 | mmc3_set_wram(space); | |
| 1332 | break; | |
| 1333 | ||
| 1334 | case 0x4000: | |
| 1335 | state->m_IRQ_count_latch = data; | |
| 1336 | break; | |
| 1337 | ||
| 1338 | case 0x4001: | |
| 1339 | state->m_IRQ_count = 0; | |
| 1340 | break; | |
| 1341 | ||
| 1342 | case 0x6000: | |
| 1343 | state->m_IRQ_enable = 0; | |
| 1344 | break; | |
| 1345 | ||
| 1346 | case 0x6001: | |
| 1347 | state->m_IRQ_enable = 1; | |
| 1348 | break; | |
| 1349 | ||
| 1350 | default: | |
| 1351 | logerror("txrom_w uncaught: %04x value: %02x\n", offset + 0x8000, data); | |
| 1352 | break; | |
| 1353 | } | |
| 1354 | } | |
| 1355 | ||
| 1356 | /************************************************************* | |
| 1357 | ||
| 1358 | HKROM (MMC6 based) board emulation | |
| 1359 | ||
| 1360 | iNES: mapper 4 | |
| 1361 | ||
| 1362 | *************************************************************/ | |
| 1363 | ||
| 1364 | static WRITE8_HANDLER( hkrom_m_w ) | |
| 1365 | { | |
| 1366 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1367 | UINT8 write_hi, write_lo; | |
| 1368 | LOG_MMC(("hkrom_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1369 | ||
| 1370 | if (offset < 0x1000) | |
| 1371 | return; | |
| 1372 | ||
| 1373 | // banks can be written only if both read & write is enabled! | |
| 1374 | write_hi = ((state->m_mmc6_reg & 0xc0) == 0xc0); | |
| 1375 | write_lo = ((state->m_mmc6_reg & 0x30) == 0x30); | |
| 1376 | ||
| 1377 | if (BIT(offset, 9) && write_hi) // access to upper 1k | |
| 1378 | state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data; | |
| 1379 | ||
| 1380 | if (!BIT(offset, 9) && write_lo) // access to lower 1k | |
| 1381 | state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data; | |
| 1382 | } | |
| 1383 | ||
| 1384 | static READ8_HANDLER( hkrom_m_r ) | |
| 1385 | { | |
| 1386 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1387 | LOG_MMC(("hkrom_m_r, offset: %04x\n", offset)); | |
| 1388 | ||
| 1389 | if (offset < 0x1000) | |
| 1390 | return 0xff; // here it should be open bus | |
| 1391 | ||
| 1392 | if (!(state->m_mmc6_reg & 0xa0)) | |
| 1393 | return 0xff; // here it should be open bus | |
| 1394 | ||
| 1395 | if (BIT(offset, 9) && BIT(state->m_mmc6_reg, 7)) // access to upper 1k when upper read is enabled | |
| 1396 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 1397 | ||
| 1398 | if (!BIT(offset, 9) && BIT(state->m_mmc6_reg, 5)) // access to lower 1k when lower read is enabled | |
| 1399 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 1400 | ||
| 1401 | // If only one bank is enabled for reading, the other reads back as zero | |
| 1402 | return 0x00; | |
| 1403 | } | |
| 1404 | ||
| 1405 | static WRITE8_HANDLER( hkrom_w ) | |
| 1406 | { | |
| 1407 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1408 | UINT8 mmc6_helper; | |
| 1409 | LOG_MMC(("hkrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1410 | ||
| 1411 | switch (offset & 0x6001) | |
| 1412 | { | |
| 1413 | case 0x0000: | |
| 1414 | mmc6_helper = state->m_mmc3_latch ^ data; | |
| 1415 | state->m_mmc3_latch = data; | |
| 1416 | ||
| 1417 | if (!state->m_mmc_latch2 && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write | |
| 1418 | state->m_mmc_latch2 = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game) | |
| 1419 | ||
| 1420 | /* Has PRG Mode changed? */ | |
| 1421 | if (BIT(mmc6_helper, 6)) | |
| 1422 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1423 | ||
| 1424 | /* Has CHR Mode changed? */ | |
| 1425 | if (BIT(mmc6_helper, 7)) | |
| 1426 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1427 | break; | |
| 1428 | ||
| 1429 | case 0x2001: | |
| 1430 | if (state->m_mmc_latch2) | |
| 1431 | state->m_mmc6_reg = data; | |
| 1432 | break; | |
| 1433 | ||
| 1434 | case 0x4001: | |
| 1435 | state->m_IRQ_count = 0; | |
| 1436 | state->m_IRQ_clear = 1; | |
| 1437 | break; | |
| 1438 | ||
| 1439 | default: | |
| 1440 | txrom_w(space, offset, data); | |
| 1441 | break; | |
| 1442 | } | |
| 1443 | } | |
| 1444 | ||
| 1445 | /************************************************************* | |
| 1446 | ||
| 1447 | TxSROM (MMC3 based) board emulation | |
| 1448 | ||
| 1449 | Games: Armadillo, Play Action Football, Pro Hockey, RPG | |
| 1450 | Jinsei Game, Y's 3 | |
| 1451 | ||
| 1452 | iNES: mapper 118 | |
| 1453 | ||
| 1454 | In MESS: Supported. It also uses mmc3_irq. | |
| 1455 | ||
| 1456 | *************************************************************/ | |
| 1457 | ||
| 1458 | static void txsrom_set_mirror( running_machine &machine ) | |
| 1459 | { | |
| 1460 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1461 | if (state->m_mmc3_latch & 0x80) | |
| 1462 | { | |
| 1463 | set_nt_page(machine, 0, CIRAM, (state->m_mmc_vrom_bank[2] & 0x80) >> 7, 1); | |
| 1464 | set_nt_page(machine, 1, CIRAM, (state->m_mmc_vrom_bank[3] & 0x80) >> 7, 1); | |
| 1465 | set_nt_page(machine, 2, CIRAM, (state->m_mmc_vrom_bank[4] & 0x80) >> 7, 1); | |
| 1466 | set_nt_page(machine, 3, CIRAM, (state->m_mmc_vrom_bank[5] & 0x80) >> 7, 1); | |
| 1467 | } | |
| 1468 | else | |
| 1469 | { | |
| 1470 | set_nt_page(machine, 0, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1); | |
| 1471 | set_nt_page(machine, 1, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1); | |
| 1472 | set_nt_page(machine, 2, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1); | |
| 1473 | set_nt_page(machine, 3, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1); | |
| 1474 | } | |
| 1475 | } | |
| 1476 | ||
| 1477 | static void txsrom_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 1478 | { | |
| 1479 | txsrom_set_mirror(machine); // we could probably update only for one (e.g. the first) call, to slightly optimize the code | |
| 1480 | chr1_x(machine, start, bank, source); | |
| 1481 | } | |
| 1482 | ||
| 1483 | static WRITE8_HANDLER( txsrom_w ) | |
| 1484 | { | |
| 1485 | LOG_MMC(("txsrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1486 | ||
| 1487 | switch (offset & 0x6001) | |
| 1488 | { | |
| 1489 | case 0x2000: | |
| 1490 | break; | |
| 1491 | ||
| 1492 | default: | |
| 1493 | txrom_w(space, offset, data); | |
| 1494 | break; | |
| 1495 | } | |
| 1496 | } | |
| 1497 | ||
| 1498 | /************************************************************* | |
| 1499 | ||
| 1500 | TQROM (MMC3 based) board emulation | |
| 1501 | ||
| 1502 | Games: Pin Bot, High Speed | |
| 1503 | ||
| 1504 | iNES: mapper 119 | |
| 1505 | ||
| 1506 | In MESS: Supported. It also uses mmc3_irq. | |
| 1507 | ||
| 1508 | *************************************************************/ | |
| 1509 | ||
| 1510 | static void tqrom_set_chr( running_machine &machine ) | |
| 1511 | { | |
| 1512 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1513 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 1514 | UINT8 chr_src[6], chr_mask[6]; | |
| 1515 | int i; | |
| 1516 | ||
| 1517 | for (i = 0; i < 6; i++) | |
| 1518 | { | |
| 1519 | chr_src[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM; | |
| 1520 | chr_mask[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f; | |
| 1521 | } | |
| 1522 | ||
| 1523 | chr1_x(machine, chr_page ^ 0, ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask[0]), chr_src[0]); | |
| 1524 | chr1_x(machine, chr_page ^ 1, ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask[0]), chr_src[0]); | |
| 1525 | chr1_x(machine, chr_page ^ 2, ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask[1]), chr_src[1]); | |
| 1526 | chr1_x(machine, chr_page ^ 3, ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask[1]), chr_src[1]); | |
| 1527 | chr1_x(machine, chr_page ^ 4, (state->m_mmc_vrom_bank[2] & chr_mask[2]), chr_src[2]); | |
| 1528 | chr1_x(machine, chr_page ^ 5, (state->m_mmc_vrom_bank[3] & chr_mask[3]), chr_src[3]); | |
| 1529 | chr1_x(machine, chr_page ^ 6, (state->m_mmc_vrom_bank[4] & chr_mask[4]), chr_src[4]); | |
| 1530 | chr1_x(machine, chr_page ^ 7, (state->m_mmc_vrom_bank[5] & chr_mask[5]), chr_src[5]); | |
| 1531 | } | |
| 1532 | ||
| 1533 | static WRITE8_HANDLER( tqrom_w ) | |
| 1534 | { | |
| 1535 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1536 | UINT8 mmc_helper, cmd; | |
| 1537 | LOG_MMC(("tqrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1538 | ||
| 1539 | switch (offset & 0x6001) | |
| 1540 | { | |
| 1541 | case 0x0000: | |
| 1542 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 1543 | state->m_mmc3_latch = data; | |
| 1544 | ||
| 1545 | /* Has PRG Mode changed? */ | |
| 1546 | if (mmc_helper & 0x40) | |
| 1547 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1548 | ||
| 1549 | /* Has CHR Mode changed? */ | |
| 1550 | if (mmc_helper & 0x80) | |
| 1551 | tqrom_set_chr(space->machine()); | |
| 1552 | break; | |
| 1553 | case 0x0001: /* $8001 */ | |
| 1554 | cmd = state->m_mmc3_latch & 0x07; | |
| 1555 | switch (cmd) | |
| 1556 | { | |
| 1557 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 1558 | case 2: case 3: case 4: case 5: | |
| 1559 | state->m_mmc_vrom_bank[cmd] = data; | |
| 1560 | tqrom_set_chr(space->machine()); | |
| 1561 | break; | |
| 1562 | case 6: | |
| 1563 | case 7: | |
| 1564 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 1565 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1566 | break; | |
| 1567 | } | |
| 1568 | break; | |
| 1569 | ||
| 1570 | default: | |
| 1571 | txrom_w(space, offset, data); | |
| 1572 | break; | |
| 1573 | } | |
| 1574 | } | |
| 1575 | ||
| 1576 | /************************************************************* | |
| 1577 | ||
| 1578 | PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart | |
| 1579 | Super Mario Bros. + Tetris + Nintendo World Cup) | |
| 1580 | ||
| 1581 | iNES: mapper 37 | |
| 1582 | ||
| 1583 | *************************************************************/ | |
| 1584 | ||
| 1585 | static WRITE8_HANDLER( zz_m_w ) | |
| 1586 | { | |
| 1587 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1588 | UINT8 mmc_helper = data & 0x07; | |
| 1589 | LOG_MMC(("zz_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1590 | ||
| 1591 | state->m_mmc_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0); | |
| 1592 | state->m_mmc_prg_mask = (mmc_helper << 1) | 0x07; | |
| 1593 | state->m_mmc_chr_base = BIT(mmc_helper, 2) << 7; | |
| 1594 | state->m_mmc_chr_mask = 0x7f; | |
| 1595 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1596 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1597 | } | |
| 1598 | ||
| 1599 | /************************************************************* | |
| 1600 | ||
| 1601 | NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart | |
| 1602 | Super Spike V'Ball + Nintendo World Cup) | |
| 1603 | ||
| 1604 | iNES: mapper 47 | |
| 1605 | ||
| 1606 | *************************************************************/ | |
| 1607 | ||
| 1608 | static WRITE8_HANDLER( qj_m_w ) | |
| 1609 | { | |
| 1610 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1611 | LOG_MMC(("qj_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1612 | ||
| 1613 | state->m_mmc_prg_base = BIT(data, 0) << 4; | |
| 1614 | state->m_mmc_prg_mask = 0x0f; | |
| 1615 | state->m_mmc_chr_base = BIT(data, 0) << 7; | |
| 1616 | state->m_mmc_chr_mask = 0x7f; | |
| 1617 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1618 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1619 | } | |
| 1620 | ||
| 1621 | /************************************************************* | |
| 1622 | ||
| 1623 | ExROM (MMC5 based) board emulation | |
| 1624 | ||
| 1625 | Games: Castlevania III, Just Breed, many Koei titles | |
| 1626 | ||
| 1627 | iNES: mapper 5 | |
| 1628 | ||
| 1629 | MESS status: Mostly Unsupported | |
| 1630 | ||
| 1631 | *************************************************************/ | |
| 1632 | ||
| 1633 | #if 0 | |
| 1634 | static void mmc5_update_chr_a( running_machine &machine ) | |
| 1635 | { | |
| 1636 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1637 | switch (state->m_mmc5_chr_mode) | |
| 1638 | { | |
| 1639 | case 0: // 8k banks | |
| 1640 | chr8(machine, state->m_mmc5_vrom_regA[7] & 0xff, CHRROM); | |
| 1641 | break; | |
| 1642 | ||
| 1643 | case 1: // 4k banks | |
| 1644 | chr4_0(machine, state->m_mmc5_vrom_regA[3] & 0xff, CHRROM); | |
| 1645 | chr4_4(machine, state->m_mmc5_vrom_regA[7] & 0xff, CHRROM); | |
| 1646 | break; | |
| 1647 | ||
| 1648 | case 2: // 2k banks | |
| 1649 | chr2_0(machine, state->m_mmc5_vrom_regA[1], CHRROM); | |
| 1650 | chr2_2(machine, state->m_mmc5_vrom_regA[3], CHRROM); | |
| 1651 | chr2_4(machine, state->m_mmc5_vrom_regA[5], CHRROM); | |
| 1652 | chr2_6(machine, state->m_mmc5_vrom_regA[7], CHRROM); | |
| 1653 | break; | |
| 1654 | ||
| 1655 | case 3: // 1k banks | |
| 1656 | chr1_0(machine, state->m_mmc5_vrom_regA[0], CHRROM); | |
| 1657 | chr1_1(machine, state->m_mmc5_vrom_regA[1], CHRROM); | |
| 1658 | chr1_2(machine, state->m_mmc5_vrom_regA[2], CHRROM); | |
| 1659 | chr1_3(machine, state->m_mmc5_vrom_regA[3], CHRROM); | |
| 1660 | chr1_4(machine, state->m_mmc5_vrom_regA[4], CHRROM); | |
| 1661 | chr1_5(machine, state->m_mmc5_vrom_regA[5], CHRROM); | |
| 1662 | chr1_6(machine, state->m_mmc5_vrom_regA[6], CHRROM); | |
| 1663 | chr1_7(machine, state->m_mmc5_vrom_regA[7], CHRROM); | |
| 1664 | break; | |
| 1665 | } | |
| 1666 | } | |
| 1667 | ||
| 1668 | static void mmc5_update_chr_b( running_machine &machine ) | |
| 1669 | { | |
| 1670 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1671 | switch (state->m_mmc5_chr_mode) | |
| 1672 | { | |
| 1673 | case 0: // 8k banks | |
| 1674 | chr8(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM); | |
| 1675 | break; | |
| 1676 | ||
| 1677 | case 1: // 4k banks | |
| 1678 | chr4_0(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM); | |
| 1679 | chr4_4(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM); | |
| 1680 | break; | |
| 1681 | ||
| 1682 | case 2: // 2k banks | |
| 1683 | chr2_0(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1684 | chr2_2(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1685 | chr2_4(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1686 | chr2_6(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1687 | break; | |
| 1688 | ||
| 1689 | case 3: // 1k banks | |
| 1690 | chr1_0(machine, state->m_mmc5_vrom_regB[0], CHRROM); | |
| 1691 | chr1_1(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1692 | chr1_2(machine, state->m_mmc5_vrom_regB[2], CHRROM); | |
| 1693 | chr1_3(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1694 | chr1_4(machine, state->m_mmc5_vrom_regB[0], CHRROM); | |
| 1695 | chr1_5(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1696 | chr1_6(machine, state->m_mmc5_vrom_regB[2], CHRROM); | |
| 1697 | chr1_7(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1698 | break; | |
| 1699 | } | |
| 1700 | } | |
| 1701 | #endif | |
| 1702 | ||
| 1703 | static void mmc5_update_prg( running_machine &machine ) | |
| 1704 | { | |
| 1705 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1706 | int bank1, bank2, bank3; | |
| 1707 | ||
| 1708 | switch (state->m_mmc5_prg_mode) | |
| 1709 | { | |
| 1710 | case 0: // 32k banks | |
| 1711 | prg32(machine, state->m_mmc5_prg_regs[3] >> 2); | |
| 1712 | break; | |
| 1713 | ||
| 1714 | case 1: // 16k banks | |
| 1715 | // printf("problema 1: %x\n", state->m_mmc5_prg_regs[1]); | |
| 1716 | bank1 = state->m_mmc5_prg_regs[1]; | |
| 1717 | ||
| 1718 | if (!BIT(bank1, 7)) | |
| 1719 | { | |
| 1720 | state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06); | |
| 1721 | state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1; | |
| 1722 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 1723 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 1724 | } | |
| 1725 | else | |
| 1726 | prg16_89ab(machine, bank1 >> 1); | |
| 1727 | ||
| 1728 | prg16_cdef(machine, state->m_mmc5_prg_regs[3] >> 1); | |
| 1729 | break; | |
| 1730 | ||
| 1731 | case 2: // 16k-8k banks | |
| 1732 | // printf("problema 2: %x %x\n", state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]); | |
| 1733 | bank1 = state->m_mmc5_prg_regs[1]; | |
| 1734 | bank3 = state->m_mmc5_prg_regs[2]; | |
| 1735 | ||
| 1736 | if (!BIT(bank1, 7)) | |
| 1737 | { | |
| 1738 | state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06); | |
| 1739 | state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1; | |
| 1740 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 1741 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 1742 | } | |
| 1743 | else | |
| 1744 | prg16_89ab(machine, (bank1 & 0x7f) >> 1); | |
| 1745 | ||
| 1746 | if (!BIT(bank3, 7)) | |
| 1747 | { | |
| 1748 | state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07); | |
| 1749 | memory_set_bank(machine, "bank3", state->m_prg_bank[2]); | |
| 1750 | } | |
| 1751 | else | |
| 1752 | prg8_cd(machine, bank3 & 0x7f); | |
| 1753 | ||
| 1754 | prg8_ef(machine, state->m_mmc5_prg_regs[3]); | |
| 1755 | break; | |
| 1756 | ||
| 1757 | case 3: // 8k banks | |
| 1758 | // printf("problema 3: %x %x %x\n", state->m_mmc5_prg_regs[0], state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]); | |
| 1759 | bank1 = state->m_mmc5_prg_regs[0]; | |
| 1760 | bank2 = state->m_mmc5_prg_regs[1]; | |
| 1761 | bank3 = state->m_mmc5_prg_regs[2]; | |
| 1762 | ||
| 1763 | if (!BIT(bank1, 7)) | |
| 1764 | { | |
| 1765 | state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x07); | |
| 1766 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 1767 | } | |
| 1768 | else | |
| 1769 | prg8_89(machine, bank1 & 0x7f); | |
| 1770 | ||
| 1771 | if (!BIT(bank2, 7)) | |
| 1772 | { | |
| 1773 | state->m_prg_bank[1] = state->m_prg_chunks + (bank2 & 0x07); | |
| 1774 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 1775 | } | |
| 1776 | else | |
| 1777 | prg8_ab(machine, bank2 & 0x7f); | |
| 1778 | ||
| 1779 | if (!BIT(bank3, 7)) | |
| 1780 | { | |
| 1781 | state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07); | |
| 1782 | memory_set_bank(machine, "bank3", state->m_prg_bank[2]); | |
| 1783 | } | |
| 1784 | else | |
| 1785 | prg8_cd(machine, bank3 & 0x7f); | |
| 1786 | ||
| 1787 | prg8_ef(machine, state->m_mmc5_prg_regs[3]); | |
| 1788 | break; | |
| 1789 | } | |
| 1790 | } | |
| 1791 | ||
| 1792 | static void mmc5_update_render_mode( running_machine &machine ) | |
| 1793 | { | |
| 1794 | } | |
| 1795 | ||
| 1796 | static void mmc5_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 1797 | { | |
| 1798 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1799 | ||
| 1800 | #if 1 | |
| 1801 | if (scanline == 0) | |
| 1802 | state->m_IRQ_status |= 0x40; | |
| 1803 | else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 1804 | state->m_IRQ_status &= ~0x40; | |
| 1805 | #endif | |
| 1806 | ||
| 1807 | if (scanline == state->m_IRQ_count) | |
| 1808 | { | |
| 1809 | if (state->m_IRQ_enable) | |
| 1810 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1811 | ||
| 1812 | state->m_IRQ_status = 0xff; | |
| 1813 | } | |
| 1814 | ||
| 1815 | /* FIXME: this is ok, but then we would need to update them again when we have the BG Hblank | |
| 1816 | I leave it commented out until the PPU is updated for this */ | |
| 1817 | // if (ppu2c0x_is_sprite_8x16(state->m_ppu) || state->m_mmc5_last_chr_a) | |
| 1818 | // mmc5_update_chr_a(device->machine()); | |
| 1819 | // else | |
| 1820 | // mmc5_update_chr_b(device->machine()); | |
| 1821 | } | |
| 1822 | ||
| 1823 | static void mmc5_ppu_mirror( running_machine &machine, int page, int src ) | |
| 1824 | { | |
| 1825 | switch (src) | |
| 1826 | { | |
| 1827 | case 0: /* CIRAM0 */ | |
| 1828 | set_nt_page(machine, page, CIRAM, 0, 1); | |
| 1829 | break; | |
| 1830 | case 1: /* CIRAM1 */ | |
| 1831 | set_nt_page(machine, page, CIRAM, 1, 1); | |
| 1832 | break; | |
| 1833 | case 2: /* ExRAM */ | |
| 1834 | set_nt_page(machine, page, EXRAM, 0, 1); // actually only works during rendering. | |
| 1835 | break; | |
| 1836 | case 3: /* Fill Registers */ | |
| 1837 | set_nt_page(machine, page, MMC5FILL, 0, 0); | |
| 1838 | break; | |
| 1839 | default: | |
| 1840 | fatalerror("This should never happen"); | |
| 1841 | break; | |
| 1842 | } | |
| 1843 | } | |
| 1844 | ||
| 1845 | static READ8_HANDLER( exrom_l_r ) | |
| 1846 | { | |
| 1847 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1848 | int retVal; | |
| 1849 | ||
| 1850 | /* $5c00 - $5fff: extended videoram attributes */ | |
| 1851 | if ((offset >= 0x1b00) && (offset <= 0x1eff)) | |
| 1852 | { | |
| 1853 | return state->m_mapper_ram[offset - 0x1b00]; | |
| 1854 | } | |
| 1855 | ||
| 1856 | switch (offset) | |
| 1857 | { | |
| 1858 | case 0x1104: /* $5204 */ | |
| 1859 | #if 0 | |
| 1860 | if (current_scanline == MMC5_scanline) | |
| 1861 | return 0x80; | |
| 1862 | else | |
| 1863 | return 0x00; | |
| 1864 | #else | |
| 1865 | retVal = state->m_IRQ_status; | |
| 1866 | state->m_IRQ_status &= ~0x80; | |
| 1867 | return retVal; | |
| 1868 | #endif | |
| 1869 | ||
| 1870 | case 0x1105: /* $5205 */ | |
| 1871 | return (state->m_mult1 * state->m_mult2) & 0xff; | |
| 1872 | case 0x1106: /* $5206 */ | |
| 1873 | return ((state->m_mult1 * state->m_mult2) & 0xff00) >> 8; | |
| 1874 | ||
| 1875 | default: | |
| 1876 | logerror("** MMC5 uncaught read, offset: %04x\n", offset + 0x4100); | |
| 1877 | return 0x00; | |
| 1878 | } | |
| 1879 | } | |
| 1880 | ||
| 1881 | ||
| 1882 | static WRITE8_HANDLER( exrom_l_w ) | |
| 1883 | { | |
| 1884 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1885 | ||
| 1886 | // LOG_MMC(("Mapper 5 write, offset: %04x, data: %02x\n", offset + 0x4100, data)); | |
| 1887 | /* Send $5000-$5015 to the sound chip */ | |
| 1888 | if ((offset >= 0xf00) && (offset <= 0xf15)) | |
| 1889 | { | |
| 1890 | nes_psg_w(state->m_sound, offset & 0x1f, data); | |
| 1891 | return; | |
| 1892 | } | |
| 1893 | ||
| 1894 | /* $5c00 - $5fff: extended videoram attributes */ | |
| 1895 | if ((offset >= 0x1b00) && (offset <= 0x1eff)) | |
| 1896 | { | |
| 1897 | if (state->m_MMC5_vram_protect == 0x03) | |
| 1898 | state->m_mapper_ram[offset - 0x1b00] = data; | |
| 1899 | return; | |
| 1900 | } | |
| 1901 | ||
| 1902 | switch (offset) | |
| 1903 | { | |
| 1904 | case 0x1000: /* $5100 */ | |
| 1905 | state->m_mmc5_prg_mode = data & 0x03; | |
| 1906 | // mmc5_update_prg(space->machine()); | |
| 1907 | LOG_MMC(("MMC5 rom bank mode: %02x\n", data)); | |
| 1908 | break; | |
| 1909 | ||
| 1910 | case 0x1001: /* $5101 */ | |
| 1911 | state->m_mmc5_chr_mode = data & 0x03; | |
| 1912 | // update chr | |
| 1913 | LOG_MMC(("MMC5 vrom bank mode: %02x\n", data)); | |
| 1914 | break; | |
| 1915 | ||
| 1916 | case 0x1002: /* $5102 */ | |
| 1917 | if (data == 0x02) | |
| 1918 | state->m_MMC5_vram_protect |= 1; | |
| 1919 | else | |
| 1920 | state->m_MMC5_vram_protect = 0; | |
| 1921 | LOG_MMC(("MMC5 vram protect 1: %02x\n", data)); | |
| 1922 | break; | |
| 1923 | case 0x1003: /* 5103 */ | |
| 1924 | if (data == 0x01) | |
| 1925 | state->m_MMC5_vram_protect |= 2; | |
| 1926 | else | |
| 1927 | state->m_MMC5_vram_protect = 0; | |
| 1928 | LOG_MMC(("MMC5 vram protect 2: %02x\n", data)); | |
| 1929 | break; | |
| 1930 | ||
| 1931 | case 0x1004: /* $5104 - Extra VRAM (EXRAM) control */ | |
| 1932 | state->m_mmc5_vram_control = data & 0x03; | |
| 1933 | // update render | |
| 1934 | mmc5_update_render_mode(space->machine()); | |
| 1935 | LOG_MMC(("MMC5 exram control: %02x\n", data)); | |
| 1936 | break; | |
| 1937 | ||
| 1938 | case 0x1005: /* $5105 */ | |
| 1939 | mmc5_ppu_mirror(space->machine(), 0, data & 0x03); | |
| 1940 | mmc5_ppu_mirror(space->machine(), 1, (data & 0x0c) >> 2); | |
| 1941 | mmc5_ppu_mirror(space->machine(), 2, (data & 0x30) >> 4); | |
| 1942 | mmc5_ppu_mirror(space->machine(), 3, (data & 0xc0) >> 6); | |
| 1943 | // update render | |
| 1944 | mmc5_update_render_mode(space->machine()); | |
| 1945 | break; | |
| 1946 | ||
| 1947 | /* tile data for MMC5 flood-fill NT mode */ | |
| 1948 | case 0x1006: | |
| 1949 | state->m_MMC5_floodtile = data; | |
| 1950 | break; | |
| 1951 | ||
| 1952 | /* attr data for MMC5 flood-fill NT mode */ | |
| 1953 | case 0x1007: | |
| 1954 | switch (data & 3) | |
| 1955 | { | |
| 1956 | default: | |
| 1957 | case 0: state->m_MMC5_floodattr = 0x00; break; | |
| 1958 | case 1: state->m_MMC5_floodattr = 0x55; break; | |
| 1959 | case 2: state->m_MMC5_floodattr = 0xaa; break; | |
| 1960 | case 3: state->m_MMC5_floodattr = 0xff; break; | |
| 1961 | } | |
| 1962 | break; | |
| 1963 | ||
| 1964 | case 0x1013: /* $5113 */ | |
| 1965 | LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07)); | |
| 1966 | // FIXME: a few Koei games have both WRAM & BWRAM but here we don't support this (yet) | |
| 1967 | if (state->m_battery) | |
| 1968 | wram_bank(space->machine(), data, NES_BATTERY); | |
| 1969 | else | |
| 1970 | wram_bank(space->machine(), data, NES_WRAM); | |
| 1971 | break; | |
| 1972 | ||
| 1973 | ||
| 1974 | case 0x1014: /* $5114 */ | |
| 1975 | case 0x1015: /* $5115 */ | |
| 1976 | case 0x1016: /* $5116 */ | |
| 1977 | case 0x1017: /* $5117 */ | |
| 1978 | state->m_mmc5_prg_regs[offset & 3] = data; | |
| 1979 | mmc5_update_prg(space->machine()); | |
| 1980 | break; | |
| 1981 | ||
| 1982 | #if 0 | |
| 1983 | // these do not work as expected... I guess we definitely need the bank update at proper times (with BG vs. sprite timing) | |
| 1984 | case 0x1020: /* $5120 */ | |
| 1985 | case 0x1021: /* $5121 */ | |
| 1986 | case 0x1022: /* $5122 */ | |
| 1987 | case 0x1023: /* $5123 */ | |
| 1988 | case 0x1024: /* $5124 */ | |
| 1989 | case 0x1025: /* $5125 */ | |
| 1990 | case 0x1026: /* $5126 */ | |
| 1991 | case 0x1027: /* $5127 */ | |
| 1992 | data |= (state->m_mmc5_chr_high << 8); | |
| 1993 | if (!state->m_mmc5_last_chr_a) | |
| 1994 | { | |
| 1995 | state->m_mmc5_vrom_regA[offset & 0x07] = data; | |
| 1996 | state->m_mmc5_last_chr_a = 1; | |
| 1997 | if (ppu2c0x_get_current_scanline(state->m_ppu) == 240 || !ppu2c0x_is_sprite_8x16(state->m_ppu)) | |
| 1998 | mmc5_update_chr_a(space->machine()); | |
| 1999 | } | |
| 2000 | break; | |
| 2001 | ||
| 2002 | ||
| 2003 | case 0x1028: /* $5128 */ | |
| 2004 | case 0x1029: /* $5129 */ | |
| 2005 | case 0x102a: /* $512a */ | |
| 2006 | case 0x102b: /* $512b */ | |
| 2007 | data |= (state->m_mmc5_chr_high << 8); | |
| 2008 | state->m_mmc5_vrom_regB[offset & 0x03] = data; | |
| 2009 | state->m_mmc5_last_chr_a = 0; | |
| 2010 | if (ppu2c0x_get_current_scanline(state->m_ppu) == 240 || !ppu2c0x_is_sprite_8x16(state->m_ppu)) | |
| 2011 | mmc5_update_chr_b(space->machine()); | |
| 2012 | break; | |
| 2013 | ||
| 2014 | case 0x1030: /* $5130 */ | |
| 2015 | state->m_mmc5_chr_high = data & 0x03; | |
| 2016 | if (state->m_mmc5_vram_control == 1) | |
| 2017 | { | |
| 2018 | // in this case state->m_mmc5_chr_high selects which 256KB of CHR ROM | |
| 2019 | // is to be used for all background tiles on the screen. | |
| 2020 | } | |
| 2021 | break; | |
| 2022 | ||
| 2023 | #endif | |
| 2024 | ||
| 2025 | case 0x1020: /* $5120 */ | |
| 2026 | LOG_MMC(("MMC5 $5120 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2027 | switch (state->m_mmc5_chr_mode) | |
| 2028 | { | |
| 2029 | case 0x03: | |
| 2030 | /* 1k switch */ | |
| 2031 | state->m_MMC5_vrom_bank[0] = data | (state->m_mmc5_high_chr << 8); | |
| 2032 | // mapper5_sync_vrom(0); | |
| 2033 | chr1_0(space->machine(), state->m_MMC5_vrom_bank[0], CHRROM); | |
| 2034 | // state->m_nes_vram_sprite[0] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2035 | // vrom_next[0] = 4; | |
| 2036 | // vrom_page_a = 1; | |
| 2037 | // vrom_page_b = 0; | |
| 2038 | break; | |
| 2039 | } | |
| 2040 | break; | |
| 2041 | case 0x1021: /* $5121 */ | |
| 2042 | LOG_MMC(("MMC5 $5121 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2043 | switch (state->m_mmc5_chr_mode) | |
| 2044 | { | |
| 2045 | case 0x02: | |
| 2046 | /* 2k switch */ | |
| 2047 | chr2_0(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2048 | break; | |
| 2049 | case 0x03: | |
| 2050 | /* 1k switch */ | |
| 2051 | state->m_MMC5_vrom_bank[1] = data | (state->m_mmc5_high_chr << 8); | |
| 2052 | // mapper5_sync_vrom(0); | |
| 2053 | chr1_1(space->machine(), state->m_MMC5_vrom_bank[1], CHRROM); | |
| 2054 | // state->m_nes_vram_sprite[1] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2055 | // vrom_next[1] = 5; | |
| 2056 | // vrom_page_a = 1; | |
| 2057 | // vrom_page_b = 0; | |
| 2058 | break; | |
| 2059 | } | |
| 2060 | break; | |
| 2061 | case 0x1022: /* $5122 */ | |
| 2062 | LOG_MMC(("MMC5 $5122 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2063 | switch (state->m_mmc5_chr_mode) | |
| 2064 | { | |
| 2065 | case 0x03: | |
| 2066 | /* 1k switch */ | |
| 2067 | state->m_MMC5_vrom_bank[2] = data | (state->m_mmc5_high_chr << 8); | |
| 2068 | // mapper5_sync_vrom(0); | |
| 2069 | chr1_2(space->machine(), state->m_MMC5_vrom_bank[2], CHRROM); | |
| 2070 | // state->m_nes_vram_sprite[2] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2071 | // vrom_next[2] = 6; | |
| 2072 | // vrom_page_a = 1; | |
| 2073 | // vrom_page_b = 0; | |
| 2074 | break; | |
| 2075 | } | |
| 2076 | break; | |
| 2077 | case 0x1023: /* $5123 */ | |
| 2078 | LOG_MMC(("MMC5 $5123 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2079 | switch (state->m_mmc5_chr_mode) | |
| 2080 | { | |
| 2081 | case 0x01: | |
| 2082 | chr4_0(space->machine(), data, CHRROM); | |
| 2083 | break; | |
| 2084 | case 0x02: | |
| 2085 | /* 2k switch */ | |
| 2086 | chr2_2(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2087 | break; | |
| 2088 | case 0x03: | |
| 2089 | /* 1k switch */ | |
| 2090 | state->m_MMC5_vrom_bank[3] = data | (state->m_mmc5_high_chr << 8); | |
| 2091 | // mapper5_sync_vrom(0); | |
| 2092 | chr1_3(space->machine(), state->m_MMC5_vrom_bank[3], CHRROM); | |
| 2093 | // state->m_nes_vram_sprite[3] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2094 | // vrom_next[3] = 7; | |
| 2095 | // vrom_page_a = 1; | |
| 2096 | // vrom_page_b = 0; | |
| 2097 | break; | |
| 2098 | } | |
| 2099 | break; | |
| 2100 | case 0x1024: /* $5124 */ | |
| 2101 | LOG_MMC(("MMC5 $5124 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2102 | switch (state->m_mmc5_chr_mode) | |
| 2103 | { | |
| 2104 | case 0x03: | |
| 2105 | /* 1k switch */ | |
| 2106 | state->m_MMC5_vrom_bank[4] = data | (state->m_mmc5_high_chr << 8); | |
| 2107 | // mapper5_sync_vrom(0); | |
| 2108 | chr1_4(space->machine(), state->m_MMC5_vrom_bank[4], CHRROM); | |
| 2109 | // state->m_nes_vram_sprite[4] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2110 | // vrom_next[0] = 0; | |
| 2111 | // vrom_page_a = 0; | |
| 2112 | // vrom_page_b = 0; | |
| 2113 | break; | |
| 2114 | } | |
| 2115 | break; | |
| 2116 | case 0x1025: /* $5125 */ | |
| 2117 | LOG_MMC(("MMC5 $5125 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2118 | switch (state->m_mmc5_chr_mode) | |
| 2119 | { | |
| 2120 | case 0x02: | |
| 2121 | /* 2k switch */ | |
| 2122 | chr2_4(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2123 | break; | |
| 2124 | case 0x03: | |
| 2125 | /* 1k switch */ | |
| 2126 | state->m_MMC5_vrom_bank[5] = data | (state->m_mmc5_high_chr << 8); | |
| 2127 | // mapper5_sync_vrom(0); | |
| 2128 | chr1_5(space->machine(), state->m_MMC5_vrom_bank[5], CHRROM); | |
| 2129 | // state->m_nes_vram_sprite[5] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2130 | // vrom_next[1] = 1; | |
| 2131 | // vrom_page_a = 0; | |
| 2132 | // vrom_page_b = 0; | |
| 2133 | break; | |
| 2134 | } | |
| 2135 | break; | |
| 2136 | case 0x1026: /* $5126 */ | |
| 2137 | LOG_MMC(("MMC5 $5126 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2138 | switch (state->m_mmc5_chr_mode) | |
| 2139 | { | |
| 2140 | case 0x03: | |
| 2141 | /* 1k switch */ | |
| 2142 | state->m_MMC5_vrom_bank[6] = data | (state->m_mmc5_high_chr << 8); | |
| 2143 | // mapper5_sync_vrom(0); | |
| 2144 | chr1_6(space->machine(), state->m_MMC5_vrom_bank[6], CHRROM); | |
| 2145 | // state->m_nes_vram_sprite[6] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2146 | // vrom_next[2] = 2; | |
| 2147 | // vrom_page_a = 0; | |
| 2148 | // vrom_page_b = 0; | |
| 2149 | break; | |
| 2150 | } | |
| 2151 | break; | |
| 2152 | case 0x1027: /* $5127 */ | |
| 2153 | LOG_MMC(("MMC5 $5127 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2154 | switch (state->m_mmc5_chr_mode) | |
| 2155 | { | |
| 2156 | case 0x00: | |
| 2157 | /* 8k switch */ | |
| 2158 | chr8(space->machine(), data, CHRROM); | |
| 2159 | break; | |
| 2160 | case 0x01: | |
| 2161 | /* 4k switch */ | |
| 2162 | chr4_4(space->machine(), data, CHRROM); | |
| 2163 | break; | |
| 2164 | case 0x02: | |
| 2165 | /* 2k switch */ | |
| 2166 | chr2_6(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2167 | break; | |
| 2168 | case 0x03: | |
| 2169 | /* 1k switch */ | |
| 2170 | state->m_MMC5_vrom_bank[7] = data | (state->m_mmc5_high_chr << 8); | |
| 2171 | // mapper5_sync_vrom(0); | |
| 2172 | chr1_7(space->machine(), state->m_MMC5_vrom_bank[7], CHRROM); | |
| 2173 | // state->m_nes_vram_sprite[7] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2174 | // vrom_next[3] = 3; | |
| 2175 | // vrom_page_a = 0; | |
| 2176 | // vrom_page_b = 0; | |
| 2177 | break; | |
| 2178 | } | |
| 2179 | break; | |
| 2180 | case 0x1028: /* $5128 */ | |
| 2181 | LOG_MMC(("MMC5 $5128 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2182 | switch (state->m_mmc5_chr_mode) | |
| 2183 | { | |
| 2184 | case 0x03: | |
| 2185 | /* 1k switch */ | |
| 2186 | state->m_MMC5_vrom_bank[8] = data | (state->m_mmc5_high_chr << 8); | |
| 2187 | // nes_vram[vrom_next[0]] = data * 64; | |
| 2188 | // nes_vram[0 + (vrom_page_a*4)] = data * 64; | |
| 2189 | // nes_vram[0] = data * 64; | |
| 2190 | chr1_4(space->machine(), state->m_MMC5_vrom_bank[8], CHRROM); | |
| 2191 | // mapper5_sync_vrom(1); | |
| 2192 | if (!state->m_vrom_page_b) | |
| 2193 | { | |
| 2194 | state->m_vrom_page_a ^= 0x01; | |
| 2195 | state->m_vrom_page_b = 1; | |
| 2196 | } | |
| 2197 | break; | |
| 2198 | } | |
| 2199 | break; | |
| 2200 | case 0x1029: /* $5129 */ | |
| 2201 | LOG_MMC(("MMC5 $5129 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2202 | switch (state->m_mmc5_chr_mode) | |
| 2203 | { | |
| 2204 | case 0x02: | |
| 2205 | /* 2k switch */ | |
| 2206 | chr2_0(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2207 | chr2_4(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2208 | break; | |
| 2209 | case 0x03: | |
| 2210 | /* 1k switch */ | |
| 2211 | state->m_MMC5_vrom_bank[9] = data | (state->m_mmc5_high_chr << 8); | |
| 2212 | // nes_vram[vrom_next[1]] = data * 64; | |
| 2213 | // nes_vram[1 + (vrom_page_a*4)] = data * 64; | |
| 2214 | // nes_vram[1] = data * 64; | |
| 2215 | chr1_5(space->machine(), state->m_MMC5_vrom_bank[9], CHRROM); | |
| 2216 | // mapper5_sync_vrom(1); | |
| 2217 | if (!state->m_vrom_page_b) | |
| 2218 | { | |
| 2219 | state->m_vrom_page_a ^= 0x01; | |
| 2220 | state->m_vrom_page_b = 1; | |
| 2221 | } | |
| 2222 | break; | |
| 2223 | } | |
| 2224 | break; | |
| 2225 | case 0x102a: /* $512a */ | |
| 2226 | LOG_MMC(("MMC5 $512a vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2227 | switch (state->m_mmc5_chr_mode) | |
| 2228 | { | |
| 2229 | case 0x03: | |
| 2230 | /* 1k switch */ | |
| 2231 | state->m_MMC5_vrom_bank[10] = data | (state->m_mmc5_high_chr << 8); | |
| 2232 | // nes_vram[vrom_next[2]] = data * 64; | |
| 2233 | // nes_vram[2 + (vrom_page_a*4)] = data * 64; | |
| 2234 | // nes_vram[2] = data * 64; | |
| 2235 | chr1_6(space->machine(), state->m_MMC5_vrom_bank[10], CHRROM); | |
| 2236 | // mapper5_sync_vrom(1); | |
| 2237 | if (!state->m_vrom_page_b) | |
| 2238 | { | |
| 2239 | state->m_vrom_page_a ^= 0x01; | |
| 2240 | state->m_vrom_page_b = 1; | |
| 2241 | } | |
| 2242 | break; | |
| 2243 | } | |
| 2244 | break; | |
| 2245 | case 0x102b: /* $512b */ | |
| 2246 | LOG_MMC(("MMC5 $512b vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2247 | switch (state->m_mmc5_chr_mode) | |
| 2248 | { | |
| 2249 | case 0x00: | |
| 2250 | /* 8k switch */ | |
| 2251 | /* switches in first half of an 8K bank!) */ | |
| 2252 | chr4_0(space->machine(), data << 1, CHRROM); | |
| 2253 | chr4_4(space->machine(), data << 1, CHRROM); | |
| 2254 | break; | |
| 2255 | case 0x01: | |
| 2256 | /* 4k switch */ | |
| 2257 | chr4_0(space->machine(), data, CHRROM); | |
| 2258 | chr4_4(space->machine(), data, CHRROM); | |
| 2259 | break; | |
| 2260 | case 0x02: | |
| 2261 | /* 2k switch */ | |
| 2262 | chr2_2(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2263 | chr2_6(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2264 | break; | |
| 2265 | case 0x03: | |
| 2266 | /* 1k switch */ | |
| 2267 | state->m_MMC5_vrom_bank[11] = data | (state->m_mmc5_high_chr << 8); | |
| 2268 | // nes_vram[vrom_next[3]] = data * 64; | |
| 2269 | // nes_vram[3 + (vrom_page_a*4)] = data * 64; | |
| 2270 | // nes_vram[3] = data * 64; | |
| 2271 | chr1_7(space->machine(), state->m_MMC5_vrom_bank[11], CHRROM); | |
| 2272 | // mapper5_sync_vrom(1); | |
| 2273 | if (!state->m_vrom_page_b) | |
| 2274 | { | |
| 2275 | state->m_vrom_page_a ^= 0x01; | |
| 2276 | state->m_vrom_page_b = 1; | |
| 2277 | } | |
| 2278 | break; | |
| 2279 | } | |
| 2280 | break; | |
| 2281 | ||
| 2282 | case 0x1030: /* $5130 */ | |
| 2283 | state->m_mmc5_high_chr = data & 0x03; | |
| 2284 | if (state->m_mmc5_vram_control == 1) | |
| 2285 | { | |
| 2286 | // in this case state->m_mmc5_high_chr selects which 256KB of CHR ROM | |
| 2287 | // is to be used for all background tiles on the screen. | |
| 2288 | } | |
| 2289 | break; | |
| 2290 | ||
| 2291 | ||
| 2292 | case 0x1100: /* $5200 */ | |
| 2293 | state->m_mmc5_split_scr = data; | |
| 2294 | // in EX2 and EX3 modes, no split screen | |
| 2295 | if (state->m_mmc5_vram_control & 0x02) | |
| 2296 | state->m_mmc5_split_scr &= 0x7f; | |
| 2297 | state->m_mmc5_split_ctrl = data; | |
| 2298 | break; | |
| 2299 | ||
| 2300 | case 0x1101: /* $5201 */ | |
| 2301 | state->m_mmc5_split_yst = (data >= 240) ? data - 16 : data; | |
| 2302 | break; | |
| 2303 | ||
| 2304 | case 0x1102: /* $5202 */ | |
| 2305 | state->m_mmc5_split_bank = data; | |
| 2306 | break; | |
| 2307 | ||
| 2308 | case 0x1103: /* $5203 */ | |
| 2309 | state->m_IRQ_count = data; | |
| 2310 | state->m_MMC5_scanline = data; | |
| 2311 | LOG_MMC(("MMC5 irq scanline: %d\n", state->m_IRQ_count)); | |
| 2312 | break; | |
| 2313 | case 0x1104: /* $5204 */ | |
| 2314 | state->m_IRQ_enable = data & 0x80; | |
| 2315 | LOG_MMC(("MMC5 irq enable: %02x\n", data)); | |
| 2316 | break; | |
| 2317 | case 0x1105: /* $5205 */ | |
| 2318 | state->m_mult1 = data; | |
| 2319 | break; | |
| 2320 | case 0x1106: /* $5206 */ | |
| 2321 | state->m_mult2 = data; | |
| 2322 | break; | |
| 2323 | ||
| 2324 | default: | |
| 2325 | logerror("** MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data); | |
| 2326 | break; | |
| 2327 | } | |
| 2328 | } | |
| 2329 | ||
| 2330 | /************************************************************* | |
| 2331 | ||
| 2332 | NTBROM & Sunsoft-4 board emulation | |
| 2333 | ||
| 2334 | Part of this can be used also for Sunsoft Double Cassette | |
| 2335 | System... which games use it? | |
| 2336 | ||
| 2337 | iNES: mapper 68 | |
| 2338 | ||
| 2339 | *************************************************************/ | |
| 2340 | ||
| 2341 | static void ntbrom_mirror( running_machine &machine, int mirror, int mirr0, int mirr1 ) | |
| 2342 | { | |
| 2343 | switch (mirror) | |
| 2344 | { | |
| 2345 | case 0x00: | |
| 2346 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 2347 | break; | |
| 2348 | case 0x01: | |
| 2349 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 2350 | break; | |
| 2351 | case 0x02: | |
| 2352 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 2353 | break; | |
| 2354 | case 0x03: | |
| 2355 | set_nt_mirroring(machine, PPU_MIRROR_HIGH); | |
| 2356 | break; | |
| 2357 | case 0x10: | |
| 2358 | set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0); | |
| 2359 | set_nt_page(machine, 1, ROM, mirr1 | 0x80, 0); | |
| 2360 | set_nt_page(machine, 2, ROM, mirr0 | 0x80, 0); | |
| 2361 | set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0); | |
| 2362 | break; | |
| 2363 | case 0x11: | |
| 2364 | set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0); | |
| 2365 | set_nt_page(machine, 1, ROM, mirr0 | 0x80, 0); | |
| 2366 | set_nt_page(machine, 2, ROM, mirr1 | 0x80, 0); | |
| 2367 | set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0); | |
| 2368 | break; | |
| 2369 | case 0x12: | |
| 2370 | set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0); | |
| 2371 | set_nt_page(machine, 1, ROM, mirr0 | 0x80, 0); | |
| 2372 | set_nt_page(machine, 2, ROM, mirr0 | 0x80, 0); | |
| 2373 | set_nt_page(machine, 3, ROM, mirr0 | 0x80, 0); | |
| 2374 | break; | |
| 2375 | case 0x13: | |
| 2376 | set_nt_page(machine, 0, ROM, mirr1 | 0x80, 0); | |
| 2377 | set_nt_page(machine, 1, ROM, mirr1 | 0x80, 0); | |
| 2378 | set_nt_page(machine, 2, ROM, mirr1 | 0x80, 0); | |
| 2379 | set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0); | |
| 2380 | break; | |
| 2381 | } | |
| 2382 | } | |
| 2383 | ||
| 2384 | static WRITE8_HANDLER( ntbrom_w ) | |
| 2385 | { | |
| 2386 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2387 | ||
| 2388 | LOG_MMC(("ntbrom_w, offset %04x, data: %02x\n", offset, data)); | |
| 2389 | ||
| 2390 | switch (offset & 0x7000) | |
| 2391 | { | |
| 2392 | case 0x0000: | |
| 2393 | chr2_0(space->machine(), data, CHRROM); | |
| 2394 | break; | |
| 2395 | case 0x1000: | |
| 2396 | chr2_2(space->machine(), data, CHRROM); | |
| 2397 | break; | |
| 2398 | case 0x2000: | |
| 2399 | chr2_4(space->machine(), data, CHRROM); | |
| 2400 | break; | |
| 2401 | case 0x3000: | |
| 2402 | chr2_6(space->machine(), data, CHRROM); | |
| 2403 | break; | |
| 2404 | case 0x4000: | |
| 2405 | state->m_mmc_latch1 = data & 0x7f; | |
| 2406 | ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2); | |
| 2407 | break; | |
| 2408 | case 0x5000: | |
| 2409 | state->m_mmc_latch2 = data & 0x7f; | |
| 2410 | ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2); | |
| 2411 | break; | |
| 2412 | case 0x6000: | |
| 2413 | state->m_mmc_reg[0] = data & 0x13; | |
| 2414 | ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2); | |
| 2415 | break; | |
| 2416 | case 0x7000: | |
| 2417 | prg16_89ab(space->machine(), data); | |
| 2418 | break; | |
| 2419 | default: | |
| 2420 | LOG_MMC(("ntbrom_w uncaught write, offset: %04x, data: %02x\n", offset, data)); | |
| 2421 | break; | |
| 2422 | } | |
| 2423 | } | |
| 2424 | ||
| 2425 | /************************************************************* | |
| 2426 | ||
| 2427 | JxROM & Sunsoft 5A / 5B / FME7 board emulation | |
| 2428 | ||
| 2429 | Notice that Sunsoft-5B = FME7 + sound chip (the latter being | |
| 2430 | currently unemulated in MESS) | |
| 2431 | ||
| 2432 | iNES: mapper 69 | |
| 2433 | ||
| 2434 | *************************************************************/ | |
| 2435 | ||
| 2436 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 2437 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 2438 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 2439 | static void jxrom_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 2440 | { | |
| 2441 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 2442 | ||
| 2443 | /* TODO: change to reflect the actual number of cycles spent */ | |
| 2444 | if ((state->m_IRQ_enable & 0x80) && (state->m_IRQ_enable & 0x01)) | |
| 2445 | { | |
| 2446 | if (state->m_IRQ_count <= 114) | |
| 2447 | { | |
| 2448 | state->m_IRQ_count = 0xffff; | |
| 2449 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 2450 | } | |
| 2451 | else | |
| 2452 | state->m_IRQ_count -= 114; | |
| 2453 | } | |
| 2454 | else if (state->m_IRQ_enable & 0x01) // if enable bit 7 is not set, only decrement the counter! | |
| 2455 | { | |
| 2456 | if (state->m_IRQ_count <= 114) | |
| 2457 | state->m_IRQ_count = 0xffff; | |
| 2458 | else | |
| 2459 | state->m_IRQ_count -= 114; | |
| 2460 | } | |
| 2461 | } | |
| 2462 | ||
| 2463 | static WRITE8_HANDLER( jxrom_w ) | |
| 2464 | { | |
| 2465 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2466 | LOG_MMC(("jxrom_w, offset %04x, data: %02x\n", offset, data)); | |
| 2467 | ||
| 2468 | switch (offset & 0x6000) | |
| 2469 | { | |
| 2470 | case 0x0000: | |
| 2471 | state->m_mmc_latch1 = data & 0x0f; | |
| 2472 | break; | |
| 2473 | ||
| 2474 | case 0x2000: | |
| 2475 | switch (state->m_mmc_latch1) | |
| 2476 | { | |
| 2477 | case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: | |
| 2478 | chr1_x(space->machine(), state->m_mmc_latch1, data, CHRROM); | |
| 2479 | break; | |
| 2480 | ||
| 2481 | case 8: | |
| 2482 | if (!(data & 0x40)) | |
| 2483 | { | |
| 2484 | // is PRG ROM | |
| 2485 | space->unmap_write(0x6000, 0x7fff); | |
| 2486 | prg8_67(space->machine(), data & 0x3f); | |
| 2487 | } | |
| 2488 | else if (data & 0x80) | |
| 2489 | { | |
| 2490 | // is PRG RAM | |
| 2491 | space->install_write_bank(0x6000, 0x7fff, "bank5"); | |
| 2492 | state->m_prg_bank[4] = state->m_battery_bank5_start + (data & 0x3f); | |
| 2493 | memory_set_bank(space->machine(), "bank5", state->m_prg_bank[4]); | |
| 2494 | } | |
| 2495 | break; | |
| 2496 | ||
| 2497 | case 9: | |
| 2498 | prg8_89(space->machine(), data); | |
| 2499 | break; | |
| 2500 | case 0x0a: | |
| 2501 | prg8_ab(space->machine(), data); | |
| 2502 | break; | |
| 2503 | case 0x0b: | |
| 2504 | prg8_cd(space->machine(), data); | |
| 2505 | break; | |
| 2506 | case 0x0c: | |
| 2507 | switch (data & 0x03) | |
| 2508 | { | |
| 2509 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 2510 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 2511 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 2512 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 2513 | } | |
| 2514 | break; | |
| 2515 | case 0x0d: | |
| 2516 | state->m_IRQ_enable = data; | |
| 2517 | break; | |
| 2518 | case 0x0e: | |
| 2519 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 2520 | break; | |
| 2521 | case 0x0f: | |
| 2522 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 2523 | break; | |
| 2524 | } | |
| 2525 | break; | |
| 2526 | ||
| 2527 | /* Here we would have sound command for Sunsoft 5b variant */ | |
| 2528 | // case 0x4000: | |
| 2529 | // case 0x6000: | |
| 2530 | ||
| 2531 | case 0x4000: | |
| 2532 | LOG_MMC(("Sunsoft-5B Sound: Register select write, data: %02x\n", data)); | |
| 2533 | break; | |
| 2534 | case 0x6000: | |
| 2535 | LOG_MMC(("Sunsoft-5B Sound: Register write, data: %02x\n", data)); | |
| 2536 | break; | |
| 2537 | default: | |
| 2538 | logerror("jxrom_w uncaught %04x value: %02x\n", offset + 0x8000, data); | |
| 2539 | break; | |
| 2540 | } | |
| 2541 | } | |
| 2542 | ||
| 2543 | /************************************************************* | |
| 2544 | ||
| 2545 | DxROM & Namcot 3433 - 3443 board emulation | |
| 2546 | ||
| 2547 | Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty | |
| 2548 | ||
| 2549 | These are the same board, but DRROM (and Tengen 800004) have | |
| 2550 | 4-screen mirroring | |
| 2551 | ||
| 2552 | iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring) | |
| 2553 | ||
| 2554 | *************************************************************/ | |
| 2555 | ||
| 2556 | static WRITE8_HANDLER( dxrom_w ) | |
| 2557 | { | |
| 2558 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2559 | LOG_MMC(("dxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2560 | ||
| 2561 | if (offset >= 0x2000) | |
| 2562 | return; | |
| 2563 | ||
| 2564 | switch (offset & 1) | |
| 2565 | { | |
| 2566 | case 1: | |
| 2567 | switch (state->m_mmc_latch1 & 0x07) | |
| 2568 | { | |
| 2569 | case 0: chr2_0(space->machine(), data >> 1, CHRROM); break; | |
| 2570 | case 1: chr2_2(space->machine(), data >> 1, CHRROM); break; | |
| 2571 | case 2: chr1_4(space->machine(), data | 0x40, CHRROM); break; | |
| 2572 | case 3: chr1_5(space->machine(), data | 0x40, CHRROM); break; | |
| 2573 | case 4: chr1_6(space->machine(), data | 0x40, CHRROM); break; | |
| 2574 | case 5: chr1_7(space->machine(), data | 0x40, CHRROM); break; | |
| 2575 | case 6: prg8_89(space->machine(), data); break; | |
| 2576 | case 7: prg8_ab(space->machine(), data); break; | |
| 2577 | } | |
| 2578 | break; | |
| 2579 | case 0: | |
| 2580 | state->m_mmc_latch1 = data; | |
| 2581 | break; | |
| 2582 | } | |
| 2583 | } | |
| 2584 | ||
| 2585 | ||
| 2586 | /************************************************************* | |
| 2587 | ||
| 2588 | Namcot 3453 board emulation | |
| 2589 | ||
| 2590 | Games: Devil Man | |
| 2591 | ||
| 2592 | These are the same as Namcot 34x3, but with additional mirroring | |
| 2593 | control | |
| 2594 | ||
| 2595 | iNES: mapper 154 | |
| 2596 | ||
| 2597 | *************************************************************/ | |
| 2598 | ||
| 2599 | static WRITE8_HANDLER( namcot3453_w ) | |
| 2600 | { | |
| 2601 | LOG_MMC(("namcot3453_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2602 | ||
| 2603 | // additional mirroring control when writing to even addresses | |
| 2604 | if (!(offset & 1)) | |
| 2605 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 2606 | ||
| 2607 | dxrom_w(space, offset, data); | |
| 2608 | } | |
| 2609 | ||
| 2610 | /************************************************************* | |
| 2611 | ||
| 2612 | Namcot 3446 board emulation | |
| 2613 | ||
| 2614 | Games: Digital Devil Monogatari - Megami Tensei | |
| 2615 | ||
| 2616 | These are similar Namcot 34x3, but different bankswitch capabilities | |
| 2617 | ||
| 2618 | iNES: mapper 76 | |
| 2619 | ||
| 2620 | *************************************************************/ | |
| 2621 | ||
| 2622 | static WRITE8_HANDLER( namcot3446_w ) | |
| 2623 | { | |
| 2624 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2625 | LOG_MMC(("namcot3446_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2626 | ||
| 2627 | // NEStopia does not have this! | |
| 2628 | if (offset >= 0x2000) | |
| 2629 | { | |
| 2630 | if (!(offset & 1)) | |
| 2631 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 2632 | return; | |
| 2633 | } | |
| 2634 | ||
| 2635 | switch (offset & 1) | |
| 2636 | { | |
| 2637 | case 1: | |
| 2638 | switch (state->m_mmc_latch1 & 0x07) | |
| 2639 | { | |
| 2640 | case 2: chr2_0(space->machine(), data, CHRROM); break; | |
| 2641 | case 3: chr2_2(space->machine(), data, CHRROM); break; | |
| 2642 | case 4: chr2_4(space->machine(), data, CHRROM); break; | |
| 2643 | case 5: chr2_6(space->machine(), data, CHRROM); break; | |
| 2644 | case 6: BIT(state->m_mmc_latch1, 6) ? prg8_cd(space->machine(), data) : prg8_89(space->machine(), data); break; | |
| 2645 | case 7: prg8_ab(space->machine(), data); break; | |
| 2646 | } | |
| 2647 | break; | |
| 2648 | case 0: | |
| 2649 | state->m_mmc_latch1 = data; | |
| 2650 | break; | |
| 2651 | } | |
| 2652 | } | |
| 2653 | ||
| 2654 | /************************************************************* | |
| 2655 | ||
| 2656 | Namcot 3425 board emulation | |
| 2657 | ||
| 2658 | Games: Dragon Buster | |
| 2659 | ||
| 2660 | These are similar Namcot 34x3, but with NT mirroring (two | |
| 2661 | different modes) | |
| 2662 | ||
| 2663 | iNES: mapper 95 | |
| 2664 | ||
| 2665 | *************************************************************/ | |
| 2666 | ||
| 2667 | static WRITE8_HANDLER( namcot3425_w ) | |
| 2668 | { | |
| 2669 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2670 | UINT8 mode; | |
| 2671 | LOG_MMC(("namcot3425_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2672 | if (offset >= 0x2000) | |
| 2673 | return; | |
| 2674 | ||
| 2675 | switch (offset & 1) | |
| 2676 | { | |
| 2677 | case 1: | |
| 2678 | mode = state->m_mmc_latch1 & 0x07; | |
| 2679 | switch (mode) | |
| 2680 | { | |
| 2681 | case 0: chr2_0(space->machine(), data >> 1, CHRROM); break; | |
| 2682 | case 1: chr2_2(space->machine(), data >> 1, CHRROM); break; | |
| 2683 | case 2: | |
| 2684 | case 3: | |
| 2685 | case 4: | |
| 2686 | case 5: | |
| 2687 | chr1_x(space->machine(), 2 + mode, data, CHRROM); | |
| 2688 | state->m_mmc_reg[mode - 2] = BIT(data, 5); | |
| 2689 | if (!BIT(state->m_mmc_latch1, 7)) | |
| 2690 | { | |
| 2691 | set_nt_page(space->machine(), 0, CIRAM, state->m_mmc_reg[0], 1); | |
| 2692 | set_nt_page(space->machine(), 1, CIRAM, state->m_mmc_reg[1], 1); | |
| 2693 | set_nt_page(space->machine(), 2, CIRAM, state->m_mmc_reg[2], 1); | |
| 2694 | set_nt_page(space->machine(), 3, CIRAM, state->m_mmc_reg[3], 1); | |
| 2695 | } | |
| 2696 | else | |
| 2697 | set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); | |
| 2698 | break; | |
| 2699 | case 6: prg8_89(space->machine(), data); break; | |
| 2700 | case 7: prg8_ab(space->machine(), data); break; | |
| 2701 | } | |
| 2702 | break; | |
| 2703 | case 0: | |
| 2704 | state->m_mmc_latch1 = data; | |
| 2705 | break; | |
| 2706 | } | |
| 2707 | } | |
| 2708 | ||
| 2709 | /************************************************************* | |
| 2710 | ||
| 2711 | Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation | |
| 2712 | ||
| 2713 | Games: many Color Dreams and Wisdom Tree titles | |
| 2714 | ||
| 2715 | iNES: mapper 11 | |
| 2716 | ||
| 2717 | In MESS: Supported | |
| 2718 | ||
| 2719 | *************************************************************/ | |
| 2720 | ||
| 2721 | static WRITE8_HANDLER( dis_74x377_w ) | |
| 2722 | { | |
| 2723 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2724 | LOG_MMC(("dis_74x377_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2725 | ||
| 2726 | chr8(space->machine(), data >> 4, state->m_mmc_chr_source); | |
| 2727 | prg32(space->machine(), data & 0x0f); | |
| 2728 | } | |
| 2729 | ||
| 2730 | /************************************************************* | |
| 2731 | ||
| 2732 | Discrete Logic board IC 74x139x74 by Konami & Jaleco | |
| 2733 | ||
| 2734 | iNES: mapper 87 | |
| 2735 | ||
| 2736 | *************************************************************/ | |
| 2737 | ||
| 2738 | static WRITE8_HANDLER( dis_74x139x74_m_w ) | |
| 2739 | { | |
| 2740 | LOG_MMC(("dis_74x139x74_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2741 | ||
| 2742 | chr8(space->machine(), ((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM); | |
| 2743 | } | |
| 2744 | ||
| 2745 | /************************************************************* | |
| 2746 | ||
| 2747 | Discrete Logic board IC 74x161x138 | |
| 2748 | ||
| 2749 | Games: Crime Busters | |
| 2750 | ||
| 2751 | iNES: mapper 38 | |
| 2752 | ||
| 2753 | *************************************************************/ | |
| 2754 | ||
| 2755 | static WRITE8_HANDLER( dis_74x161x138_m_w ) | |
| 2756 | { | |
| 2757 | LOG_MMC(("dis_74x161x138_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2758 | ||
| 2759 | chr8(space->machine(), data >> 2, CHRROM); | |
| 2760 | prg32(space->machine(), data); | |
| 2761 | } | |
| 2762 | ||
| 2763 | /************************************************************* | |
| 2764 | ||
| 2765 | Discrete Logic board IC 74x161x161x32 | |
| 2766 | ||
| 2767 | There are two variants (one with hardwired mirroring, the | |
| 2768 | other with a mirroring control), making necessary two distinct | |
| 2769 | mappers & pcb_id | |
| 2770 | ||
| 2771 | iNES: mappers 70 & 152 | |
| 2772 | ||
| 2773 | *************************************************************/ | |
| 2774 | ||
| 2775 | static WRITE8_HANDLER( dis_74x161x161x32_w ) | |
| 2776 | { | |
| 2777 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2778 | LOG_MMC(("dis_74x161x161x32_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2779 | ||
| 2780 | if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring | |
| 2781 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 2782 | chr8(space->machine(), data, CHRROM); | |
| 2783 | prg16_89ab(space->machine(), data >> 4); | |
| 2784 | } | |
| 2785 | ||
| 2786 | /************************************************************* | |
| 2787 | ||
| 2788 | Bandai LZ93D50 boards emulation | |
| 2789 | ||
| 2790 | There are several variants: plain board with or without SRAM, | |
| 2791 | board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode | |
| 2792 | Reader (DATACH). | |
| 2793 | We currently only emulate the base hardware. | |
| 2794 | ||
| 2795 | Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden, | |
| 2796 | Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam | |
| 2797 | Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam | |
| 2798 | Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump, | |
| 2799 | Famicom Jump II [no EEPROM], Datach Games | |
| 2800 | ||
| 2801 | At the moment, we don't support EEPROM I/O | |
| 2802 | ||
| 2803 | iNES: mappers 16, 153, 157 & 159 | |
| 2804 | ||
| 2805 | In MESS: Supported | |
| 2806 | ||
| 2807 | *************************************************************/ | |
| 2808 | ||
| 2809 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 2810 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 2811 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 2812 | static void bandai_lz_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 2813 | { | |
| 2814 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 2815 | ||
| 2816 | /* 114 is the number of cycles per scanline */ | |
| 2817 | /* TODO: change to reflect the actual number of cycles spent */ | |
| 2818 | if (state->m_IRQ_enable) | |
| 2819 | { | |
| 2820 | if (state->m_IRQ_count <= 114) | |
| 2821 | { | |
| 2822 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 2823 | state->m_IRQ_count = (0xffff - 114 + state->m_IRQ_count); // wrap around the 16 bits counter | |
| 2824 | } | |
| 2825 | state->m_IRQ_count -= 114; | |
| 2826 | } | |
| 2827 | } | |
| 2828 | ||
| 2829 | static WRITE8_HANDLER( lz93d50_w ) | |
| 2830 | { | |
| 2831 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2832 | LOG_MMC(("lz93d50_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2833 | ||
| 2834 | switch (offset & 0x000f) | |
| 2835 | { | |
| 2836 | case 0: case 1: case 2: case 3: | |
| 2837 | case 4: case 5: case 6: case 7: | |
| 2838 | chr1_x(space->machine(), offset & 0x07, data, state->m_mmc_chr_source); | |
| 2839 | break; | |
| 2840 | case 8: | |
| 2841 | prg16_89ab(space->machine(), data); | |
| 2842 | break; | |
| 2843 | case 9: | |
| 2844 | switch (data & 0x03) | |
| 2845 | { | |
| 2846 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 2847 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 2848 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 2849 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 2850 | } | |
| 2851 | break; | |
| 2852 | case 0x0a: | |
| 2853 | state->m_IRQ_enable = data & 0x01; | |
| 2854 | break; | |
| 2855 | case 0x0b: | |
| 2856 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 2857 | break; | |
| 2858 | case 0x0c: | |
| 2859 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 2860 | break; | |
| 2861 | default: | |
| 2862 | logerror("lz93d50_w uncaught write, offset: %04x, data: %02x\n", offset, data); | |
| 2863 | break; | |
| 2864 | } | |
| 2865 | } | |
| 2866 | ||
| 2867 | static WRITE8_HANDLER( lz93d50_m_w ) | |
| 2868 | { | |
| 2869 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2870 | LOG_MMC(("lz93d50_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2871 | ||
| 2872 | if (!state->m_battery && !state->m_wram) | |
| 2873 | lz93d50_w(space, offset & 0x0f, data); | |
| 2874 | else if (state->m_battery) | |
| 2875 | state->m_battery_ram[offset] = data; | |
| 2876 | else | |
| 2877 | state->m_wram[offset] = data; | |
| 2878 | } | |
| 2879 | ||
| 2880 | static void fjump2_set_prg( running_machine &machine ) | |
| 2881 | { | |
| 2882 | nes_state *state = machine.driver_data<nes_state>(); | |
| 2883 | UINT8 mmc_helper = 0; | |
| 2884 | int i; | |
| 2885 | ||
| 2886 | for (i = 0; i < 8; i++) | |
| 2887 | mmc_helper |= ((state->m_mmc_reg[i] & 0x01) << 4); | |
| 2888 | ||
| 2889 | prg16_89ab(machine, mmc_helper | state->m_mmc_latch1); | |
| 2890 | prg16_cdef(machine, mmc_helper | 0x0f); | |
| 2891 | } | |
| 2892 | ||
| 2893 | static WRITE8_HANDLER( fjump2_w ) | |
| 2894 | { | |
| 2895 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2896 | LOG_MMC(("fjump2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2897 | ||
| 2898 | switch (offset & 0x000f) | |
| 2899 | { | |
| 2900 | case 0: case 1: case 2: case 3: | |
| 2901 | case 4: case 5: case 6: case 7: | |
| 2902 | state->m_mmc_reg[offset & 0x000f] = data; | |
| 2903 | fjump2_set_prg(space->machine()); | |
| 2904 | break; | |
| 2905 | case 8: | |
| 2906 | state->m_mmc_latch1 = (data & 0x0f); | |
| 2907 | fjump2_set_prg(space->machine()); | |
| 2908 | break; | |
| 2909 | default: | |
| 2910 | lz93d50_m_w(space, offset & 0x0f, data); | |
| 2911 | break; | |
| 2912 | } | |
| 2913 | } | |
| 2914 | ||
| 2915 | /************************************************************* | |
| 2916 | ||
| 2917 | Bandai Karaoke Studio board emulation | |
| 2918 | ||
| 2919 | Games: Karaoke Studio | |
| 2920 | ||
| 2921 | Note: we currently do not emulate the mic | |
| 2922 | ||
| 2923 | iNES: mapper 188 | |
| 2924 | ||
| 2925 | *************************************************************/ | |
| 2926 | ||
| 2927 | static WRITE8_HANDLER( bandai_ks_w ) | |
| 2928 | { | |
| 2929 | LOG_MMC(("bandai_ks_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2930 | ||
| 2931 | prg16_89ab(space->machine(), data ^ 0x08); | |
| 2932 | } | |
| 2933 | ||
| 2934 | /************************************************************* | |
| 2935 | ||
| 2936 | Bandai Oeka Kids board emulation | |
| 2937 | ||
| 2938 | Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka | |
| 2939 | Kids - Anpanman to Oekaki Shiyou!! | |
| 2940 | ||
| 2941 | iNES: mapper 96 | |
| 2942 | ||
| 2943 | In MESS: Preliminary Support. | |
| 2944 | ||
| 2945 | *************************************************************/ | |
| 2946 | ||
| 2947 | static WRITE8_HANDLER( bandai_ok_w ) | |
| 2948 | { | |
| 2949 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2950 | UINT8 mmc_helper; | |
| 2951 | LOG_MMC(("mapper96_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2952 | ||
| 2953 | prg32(space->machine(), data); | |
| 2954 | ||
| 2955 | state->m_mmc_latch1 = data; | |
| 2956 | mmc_helper = (state->m_mmc_latch1 & 0x03) | (data & 0x04); | |
| 2957 | chr4_0(space->machine(), mmc_helper, CHRRAM); | |
| 2958 | chr4_4(space->machine(), 0x03 | (data & 0x04), CHRRAM); | |
| 2959 | } | |
| 2960 | ||
| 2961 | /************************************************************* | |
| 2962 | ||
| 2963 | Irem LROG017 - Discrete board emulation (74*161/161/21/138) | |
| 2964 | ||
| 2965 | Games: Napoleon Senki | |
| 2966 | ||
| 2967 | iNES: mapper 77 | |
| 2968 | ||
| 2969 | *************************************************************/ | |
| 2970 | ||
| 2971 | static WRITE8_HANDLER( lrog017_w ) | |
| 2972 | { | |
| 2973 | LOG_MMC(("lrog017_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2974 | ||
| 2975 | prg32(space->machine(), data); | |
| 2976 | chr2_0(space->machine(), (data >> 4), CHRROM); | |
| 2977 | } | |
| 2978 | ||
| 2979 | /************************************************************* | |
| 2980 | ||
| 2981 | Irem Holy Diver board emulation | |
| 2982 | ||
| 2983 | iNES: mapper 78 (shared with JF-16) | |
| 2984 | ||
| 2985 | *************************************************************/ | |
| 2986 | ||
| 2987 | static WRITE8_HANDLER( irem_hd_w ) | |
| 2988 | { | |
| 2989 | LOG_MMC(("irem_hd_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2990 | ||
| 2991 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 2992 | chr8(space->machine(), data >> 4, CHRROM); | |
| 2993 | prg16_89ab(space->machine(), data); | |
| 2994 | } | |
| 2995 | ||
| 2996 | /************************************************************* | |
| 2997 | ||
| 2998 | Irem TAM-S1 board emulation | |
| 2999 | ||
| 3000 | Games: Kaiketsu Yanchamaru | |
| 3001 | ||
| 3002 | iNES: mapper 97 | |
| 3003 | ||
| 3004 | In MESS: Supported. | |
| 3005 | ||
| 3006 | *************************************************************/ | |
| 3007 | ||
| 3008 | static WRITE8_HANDLER( tam_s1_w ) | |
| 3009 | { | |
| 3010 | LOG_MMC(("tam_s1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3011 | ||
| 3012 | if (offset < 0x4000) | |
| 3013 | { | |
| 3014 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 3015 | prg16_cdef(space->machine(), data); | |
| 3016 | } | |
| 3017 | } | |
| 3018 | ||
| 3019 | /************************************************************* | |
| 3020 | ||
| 3021 | Irem G-101 board emulation | |
| 3022 | ||
| 3023 | Major League uses hardwired mirroring | |
| 3024 | ||
| 3025 | iNES: mapper 32 | |
| 3026 | ||
| 3027 | *************************************************************/ | |
| 3028 | ||
| 3029 | static WRITE8_HANDLER( g101_w ) | |
| 3030 | { | |
| 3031 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3032 | LOG_MMC(("g101_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3033 | ||
| 3034 | switch (offset & 0x7000) | |
| 3035 | { | |
| 3036 | case 0x0000: | |
| 3037 | // NEStopia here differs a little bit | |
| 3038 | state->m_mmc_latch1 ? prg8_cd(space->machine(), data) : prg8_89(space->machine(), data); | |
| 3039 | break; | |
| 3040 | case 0x1000: | |
| 3041 | state->m_mmc_latch1 = BIT(data, 1); | |
| 3042 | if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring | |
| 3043 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 3044 | break; | |
| 3045 | case 0x2000: | |
| 3046 | prg8_ab(space->machine(), data); | |
| 3047 | break; | |
| 3048 | case 0x3000: | |
| 3049 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 3050 | break; | |
| 3051 | } | |
| 3052 | } | |
| 3053 | ||
| 3054 | /************************************************************* | |
| 3055 | ||
| 3056 | Irem H-3001 board emulation | |
| 3057 | ||
| 3058 | Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu, | |
| 3059 | Kaiketsu Yanchamaru 3, Spartan X 2 | |
| 3060 | ||
| 3061 | iNES: mapper 65 | |
| 3062 | ||
| 3063 | In MESS: Supported. | |
| 3064 | ||
| 3065 | *************************************************************/ | |
| 3066 | ||
| 3067 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 3068 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 3069 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 3070 | static void h3001_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3071 | { | |
| 3072 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3073 | if (state->m_IRQ_enable) | |
| 3074 | { | |
| 3075 | state->m_IRQ_count -= 114; | |
| 3076 | ||
| 3077 | if (state->m_IRQ_count <= 114) | |
| 3078 | { | |
| 3079 | state->m_IRQ_enable = 0; | |
| 3080 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3081 | } | |
| 3082 | } | |
| 3083 | } | |
| 3084 | ||
| 3085 | static WRITE8_HANDLER( h3001_w ) | |
| 3086 | { | |
| 3087 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3088 | LOG_MMC(("h3001_w, offset %04x, data: %02x\n", offset, data)); | |
| 3089 | ||
| 3090 | switch (offset & 0x7fff) | |
| 3091 | { | |
| 3092 | case 0x0000: | |
| 3093 | prg8_89(space->machine(), data); | |
| 3094 | break; | |
| 3095 | ||
| 3096 | case 0x1001: | |
| 3097 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 3098 | break; | |
| 3099 | ||
| 3100 | case 0x1003: | |
| 3101 | state->m_IRQ_enable = data & 0x80; | |
| 3102 | break; | |
| 3103 | ||
| 3104 | case 0x1004: | |
| 3105 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3106 | break; | |
| 3107 | ||
| 3108 | case 0x1005: | |
| 3109 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x00ff) | (data << 8); | |
| 3110 | break; | |
| 3111 | ||
| 3112 | case 0x1006: | |
| 3113 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff00) | data; | |
| 3114 | break; | |
| 3115 | ||
| 3116 | case 0x2000: | |
| 3117 | prg8_ab(space->machine(), data); | |
| 3118 | break; | |
| 3119 | ||
| 3120 | case 0x3000: case 0x3001: case 0x3002: case 0x3003: | |
| 3121 | case 0x3004: case 0x3005: case 0x3006: case 0x3007: | |
| 3122 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 3123 | break; | |
| 3124 | ||
| 3125 | case 0x4000: | |
| 3126 | prg8_cd(space->machine(), data); | |
| 3127 | break; | |
| 3128 | ||
| 3129 | default: | |
| 3130 | break; | |
| 3131 | } | |
| 3132 | } | |
| 3133 | ||
| 3134 | /************************************************************* | |
| 3135 | ||
| 3136 | Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ..., | |
| 3137 | JF-38, JF-40, JF-41 | |
| 3138 | ||
| 3139 | Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru, | |
| 3140 | Pizza Pop, Plasma Ball | |
| 3141 | ||
| 3142 | iNES: mapper 18 | |
| 3143 | ||
| 3144 | In MESS: Supported | |
| 3145 | ||
| 3146 | *************************************************************/ | |
| 3147 | ||
| 3148 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 3149 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 3150 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 3151 | static void ss88006_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3152 | { | |
| 3153 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3154 | ||
| 3155 | /* Increment & check the IRQ scanline counter */ | |
| 3156 | if (state->m_IRQ_enable) | |
| 3157 | { | |
| 3158 | LOG_MMC(("scanline: %d, irq count: %04x\n", scanline, state->m_IRQ_count)); | |
| 3159 | if (state->m_IRQ_mode & 0x08) | |
| 3160 | { | |
| 3161 | if ((state->m_IRQ_count & 0x000f) < 114) // always true, but we only update the IRQ once per scanlines so we cannot be more precise :( | |
| 3162 | { | |
| 3163 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3164 | state->m_IRQ_count = (state->m_IRQ_count & ~0x000f) | (0x0f - (114 & 0x0f) + (state->m_IRQ_count & 0x000f)); // sort of wrap around the counter | |
| 3165 | } | |
| 3166 | // decrements should not affect upper bits, so we don't do anything here (114 > 0x0f) | |
| 3167 | } | |
| 3168 | else if (state->m_IRQ_mode & 0x04) | |
| 3169 | { | |
| 3170 | if ((state->m_IRQ_count & 0x00ff) < 114) | |
| 3171 | { | |
| 3172 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3173 | state->m_IRQ_count = (state->m_IRQ_count & ~0x00ff) | (0xff - 114 + (state->m_IRQ_count & 0x00ff)); // wrap around the 8 bits counter | |
| 3174 | } | |
| 3175 | else | |
| 3176 | state->m_IRQ_count -= 114; | |
| 3177 | } | |
| 3178 | else if (state->m_IRQ_mode & 0x02) | |
| 3179 | { | |
| 3180 | if ((state->m_IRQ_count & 0x0fff) < 114) | |
| 3181 | { | |
| 3182 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3183 | state->m_IRQ_count = (state->m_IRQ_count & ~0x0fff) | (0xfff - 114 + (state->m_IRQ_count & 0x0fff)); // wrap around the 12 bits counter | |
| 3184 | } | |
| 3185 | else | |
| 3186 | state->m_IRQ_count -= 114; | |
| 3187 | } | |
| 3188 | else if (state->m_IRQ_count < 114) | |
| 3189 | { | |
| 3190 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3191 | state->m_IRQ_count = (0xffff - 114 + state->m_IRQ_count); // wrap around the 16 bits counter | |
| 3192 | } | |
| 3193 | else | |
| 3194 | state->m_IRQ_count -= 114; | |
| 3195 | } | |
| 3196 | } | |
| 3197 | ||
| 3198 | static WRITE8_HANDLER( ss88006_w ) | |
| 3199 | { | |
| 3200 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3201 | UINT8 bank; | |
| 3202 | LOG_MMC(("mapper18_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3203 | ||
| 3204 | switch (offset & 0x7003) | |
| 3205 | { | |
| 3206 | case 0x0000: | |
| 3207 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f); | |
| 3208 | prg8_89(space->machine(), state->m_mmc_prg_bank[0]); | |
| 3209 | break; | |
| 3210 | case 0x0001: | |
| 3211 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x0f) | (data << 4); | |
| 3212 | prg8_89(space->machine(), state->m_mmc_prg_bank[0]); | |
| 3213 | break; | |
| 3214 | case 0x0002: | |
| 3215 | state->m_mmc_prg_bank[1] = (state->m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f); | |
| 3216 | prg8_ab(space->machine(), state->m_mmc_prg_bank[1]); | |
| 3217 | break; | |
| 3218 | case 0x0003: | |
| 3219 | state->m_mmc_prg_bank[1] = (state->m_mmc_prg_bank[1] & 0x0f) | (data << 4); | |
| 3220 | prg8_ab(space->machine(), state->m_mmc_prg_bank[1]); | |
| 3221 | break; | |
| 3222 | case 0x1000: | |
| 3223 | state->m_mmc_prg_bank[2] = (state->m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f); | |
| 3224 | prg8_cd(space->machine(), state->m_mmc_prg_bank[2]); | |
| 3225 | break; | |
| 3226 | case 0x1001: | |
| 3227 | state->m_mmc_prg_bank[2] = (state->m_mmc_prg_bank[2] & 0x0f) | (data << 4); | |
| 3228 | prg8_cd(space->machine(), state->m_mmc_prg_bank[2]); | |
| 3229 | break; | |
| 3230 | ||
| 3231 | /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */ | |
| 3232 | /* believe it's related to battery-backed ram enable/disable */ | |
| 3233 | ||
| 3234 | case 0x2000: case 0x2001: case 0x2002: case 0x2003: | |
| 3235 | case 0x3000: case 0x3001: case 0x3002: case 0x3003: | |
| 3236 | case 0x4000: case 0x4001: case 0x4002: case 0x4003: | |
| 3237 | case 0x5000: case 0x5001: case 0x5002: case 0x5003: | |
| 3238 | bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1); | |
| 3239 | if (offset & 0x0001) | |
| 3240 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4); | |
| 3241 | else | |
| 3242 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 3243 | ||
| 3244 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 3245 | break; | |
| 3246 | ||
| 3247 | case 0x6000: | |
| 3248 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xfff0) | (data & 0x0f); | |
| 3249 | break; | |
| 3250 | case 0x6001: | |
| 3251 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff0f) | ((data & 0x0f) << 4); | |
| 3252 | break; | |
| 3253 | case 0x6002: | |
| 3254 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0ff) | ((data & 0x0f) << 8); | |
| 3255 | break; | |
| 3256 | case 0x6003: | |
| 3257 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0fff) | ((data & 0x0f) << 12); | |
| 3258 | break; | |
| 3259 | ||
| 3260 | case 0x7000: | |
| 3261 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3262 | break; | |
| 3263 | case 0x7001: | |
| 3264 | state->m_IRQ_enable = data & 0x01; | |
| 3265 | state->m_IRQ_mode = data & 0x0e; | |
| 3266 | break; | |
| 3267 | ||
| 3268 | case 0x7002: | |
| 3269 | switch (data & 0x03) | |
| 3270 | { | |
| 3271 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3272 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3273 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3274 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3275 | } | |
| 3276 | break; | |
| 3277 | ||
| 3278 | default: | |
| 3279 | logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data); | |
| 3280 | break; | |
| 3281 | } | |
| 3282 | } | |
| 3283 | ||
| 3284 | /************************************************************* | |
| 3285 | ||
| 3286 | Jaleco JF-11, JF-12 & JF-14 boards emulation | |
| 3287 | ||
| 3288 | Games: Bio Senshi Dan, Mississippi Satsujin Jiken | |
| 3289 | ||
| 3290 | iNES: mapper 140 | |
| 3291 | ||
| 3292 | In MESS: Supported. | |
| 3293 | ||
| 3294 | *************************************************************/ | |
| 3295 | ||
| 3296 | static WRITE8_HANDLER( jf11_m_w ) | |
| 3297 | { | |
| 3298 | LOG_MMC(("jf11_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3299 | chr8(space->machine(), data, CHRROM); | |
| 3300 | prg32(space->machine(), data >> 4); | |
| 3301 | } | |
| 3302 | ||
| 3303 | /************************************************************* | |
| 3304 | ||
| 3305 | Jaleco JF-13 board emulation | |
| 3306 | ||
| 3307 | Games: Moero Pro Yakyuu | |
| 3308 | ||
| 3309 | Note: we don't emulate the additional sound hardware. | |
| 3310 | ||
| 3311 | iNES: mapper 86 | |
| 3312 | ||
| 3313 | In MESS: Supported. | |
| 3314 | ||
| 3315 | *************************************************************/ | |
| 3316 | ||
| 3317 | static WRITE8_HANDLER( jf13_m_w ) | |
| 3318 | { | |
| 3319 | LOG_MMC(("jf13_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3320 | ||
| 3321 | if (offset == 0) | |
| 3322 | { | |
| 3323 | prg32(space->machine(), (data >> 4) & 0x03); | |
| 3324 | chr8(space->machine(), ((data >> 4) & 0x04) | (data & 0x03), CHRROM); | |
| 3325 | } | |
| 3326 | ||
| 3327 | if (offset == 0x1000) | |
| 3328 | { | |
| 3329 | LOG_MMC(("Jaleco JF-13 sound write, data: %02x\n", data)); | |
| 3330 | // according to NEStopia, this is the effect | |
| 3331 | if ((data & 0x30) == 0x20) | |
| 3332 | { | |
| 3333 | // send command (data & 0x1f) to sound chip | |
| 3334 | } | |
| 3335 | } | |
| 3336 | } | |
| 3337 | ||
| 3338 | /************************************************************* | |
| 3339 | ||
| 3340 | Jaleco JF-16 board emulation | |
| 3341 | ||
| 3342 | iNES: mapper 78 (shared with a diff Irem board) | |
| 3343 | ||
| 3344 | *************************************************************/ | |
| 3345 | ||
| 3346 | static WRITE8_HANDLER( jf16_w ) | |
| 3347 | { | |
| 3348 | LOG_MMC(("jf16_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3349 | ||
| 3350 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 3351 | chr8(space->machine(), data >> 4, CHRROM); | |
| 3352 | prg16_89ab(space->machine(), data); | |
| 3353 | } | |
| 3354 | ||
| 3355 | /************************************************************* | |
| 3356 | ||
| 3357 | Jaleco JF-17, JF-26 & JF-28 boards emulation | |
| 3358 | ||
| 3359 | Note: we don't emulate the additional sound hardware. | |
| 3360 | ||
| 3361 | Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball | |
| 3362 | Quest Jpn | |
| 3363 | ||
| 3364 | iNES: mapper 72 | |
| 3365 | ||
| 3366 | In MESS: Supported. | |
| 3367 | ||
| 3368 | *************************************************************/ | |
| 3369 | ||
| 3370 | static WRITE8_HANDLER( jf17_w ) | |
| 3371 | { | |
| 3372 | LOG_MMC(("jf17_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3373 | ||
| 3374 | if (BIT(data, 7)) | |
| 3375 | prg16_89ab(space->machine(), data & 0x0f); | |
| 3376 | if (BIT(data, 6)) | |
| 3377 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 3378 | if (BIT(data, 5) && !BIT(data,4)) | |
| 3379 | LOG_MMC(("Jaleco JF-17 sound write, data: %02x\n", data & 0x1f)); | |
| 3380 | } | |
| 3381 | ||
| 3382 | /************************************************************* | |
| 3383 | ||
| 3384 | Jaleco JF-19 & JF-21 boards emulation | |
| 3385 | ||
| 3386 | Note: we don't emulate the additional sound hardware. | |
| 3387 | ||
| 3388 | Games: Moero Pro Soccer, Moero Pro Yakyuu '88 | |
| 3389 | ||
| 3390 | iNES: mapper 92 | |
| 3391 | ||
| 3392 | In MESS: Supported (no samples). | |
| 3393 | ||
| 3394 | *************************************************************/ | |
| 3395 | ||
| 3396 | static WRITE8_HANDLER( jf19_w ) | |
| 3397 | { | |
| 3398 | LOG_MMC(("jf19_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3399 | ||
| 3400 | if (BIT(data, 7)) | |
| 3401 | prg16_cdef(space->machine(), data & 0x0f); | |
| 3402 | if (BIT(data, 6)) | |
| 3403 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 3404 | if (BIT(data, 5) && !BIT(data,4)) | |
| 3405 | LOG_MMC(("Jaleco JF-19 sound write, data: %02x\n", data & 0x1f)); | |
| 3406 | } | |
| 3407 | ||
| 3408 | /************************************************************* | |
| 3409 | ||
| 3410 | Konami VRC1 and Jaleco JF20, JF22 | |
| 3411 | ||
| 3412 | Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom | |
| 3413 | ||
| 3414 | iNES: mapper 75 | |
| 3415 | ||
| 3416 | In MESS: Supported. | |
| 3417 | ||
| 3418 | *************************************************************/ | |
| 3419 | ||
| 3420 | static WRITE8_HANDLER( konami_vrc1_w ) | |
| 3421 | { | |
| 3422 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3423 | LOG_MMC(("konami_vrc1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3424 | ||
| 3425 | switch (offset & 0x7000) | |
| 3426 | { | |
| 3427 | case 0x0000: | |
| 3428 | prg8_89(space->machine(), data); | |
| 3429 | break; | |
| 3430 | case 0x1000: | |
| 3431 | set_nt_mirroring(space->machine(), (data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 3432 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3); | |
| 3433 | state->m_mmc_vrom_bank[1] = (state->m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2); | |
| 3434 | chr4_0(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 3435 | chr4_4(space->machine(), state->m_mmc_vrom_bank[1], CHRROM); | |
| 3436 | break; | |
| 3437 | case 0x2000: | |
| 3438 | prg8_ab(space->machine(), data); | |
| 3439 | break; | |
| 3440 | case 0x4000: | |
| 3441 | prg8_cd(space->machine(), data); | |
| 3442 | break; | |
| 3443 | case 0x6000: | |
| 3444 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f); | |
| 3445 | chr4_0(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 3446 | break; | |
| 3447 | case 0x7000: | |
| 3448 | state->m_mmc_vrom_bank[1] = (state->m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f); | |
| 3449 | chr4_4(space->machine(), state->m_mmc_vrom_bank[1], CHRROM); | |
| 3450 | break; | |
| 3451 | } | |
| 3452 | } | |
| 3453 | ||
| 3454 | /************************************************************* | |
| 3455 | ||
| 3456 | Konami VRC-2 | |
| 3457 | ||
| 3458 | In MESS: Supported. | |
| 3459 | ||
| 3460 | *************************************************************/ | |
| 3461 | ||
| 3462 | static WRITE8_HANDLER( konami_vrc2_w ) | |
| 3463 | { | |
| 3464 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3465 | UINT8 bank, shift, mask; | |
| 3466 | UINT32 shifted_offs = (offset & 0x7000) | |
| 3467 | | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200) | |
| 3468 | | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100); | |
| 3469 | LOG_MMC(("konami_vrc2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3470 | ||
| 3471 | if (offset < 0x1000) | |
| 3472 | prg8_89(space->machine(), data); | |
| 3473 | else if (offset < 0x2000) | |
| 3474 | { | |
| 3475 | switch (data & 0x03) | |
| 3476 | { | |
| 3477 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3478 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3479 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3480 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3481 | } | |
| 3482 | } | |
| 3483 | else if (offset < 0x3000) | |
| 3484 | prg8_ab(space->machine(), data); | |
| 3485 | else if (offset < 0x7000) | |
| 3486 | { | |
| 3487 | bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9); | |
| 3488 | shift = BIT(shifted_offs, 8) * 4; | |
| 3489 | mask = (0xf0 >> shift); | |
| 3490 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & mask) | |
| 3491 | | (((data >> state->m_vrc_ls_chr) & 0x0f) << shift); | |
| 3492 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 3493 | } | |
| 3494 | else | |
| 3495 | logerror("konami_vrc2_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); | |
| 3496 | } | |
| 3497 | ||
| 3498 | /************************************************************* | |
| 3499 | ||
| 3500 | Konami VRC3 | |
| 3501 | ||
| 3502 | Games: Salamander | |
| 3503 | ||
| 3504 | iNES: mapper 73 | |
| 3505 | ||
| 3506 | In MESS: Supported. It also uses konami_irq. | |
| 3507 | ||
| 3508 | *************************************************************/ | |
| 3509 | ||
| 3510 | static WRITE8_HANDLER( konami_vrc3_w ) | |
| 3511 | { | |
| 3512 | LOG_MMC(("konami_vrc3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3513 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3514 | ||
| 3515 | switch (offset & 0x7000) | |
| 3516 | { | |
| 3517 | case 0x0000: | |
| 3518 | case 0x1000: | |
| 3519 | /* dunno which address controls these */ | |
| 3520 | state->m_IRQ_count_latch = data; | |
| 3521 | state->m_IRQ_enable_latch = data; | |
| 3522 | break; | |
| 3523 | case 0x2000: | |
| 3524 | state->m_IRQ_enable = data; | |
| 3525 | break; | |
| 3526 | case 0x3000: | |
| 3527 | state->m_IRQ_count &= ~0x0f; | |
| 3528 | state->m_IRQ_count |= data & 0x0f; | |
| 3529 | break; | |
| 3530 | case 0x4000: | |
| 3531 | state->m_IRQ_count &= ~0xf0; | |
| 3532 | state->m_IRQ_count |= (data & 0x0f) << 4; | |
| 3533 | break; | |
| 3534 | case 0x7000: | |
| 3535 | prg16_89ab(space->machine(), data); | |
| 3536 | break; | |
| 3537 | default: | |
| 3538 | logerror("konami_vrc3_w uncaught write, offset %04x, data: %02x\n", offset, data); | |
| 3539 | break; | |
| 3540 | } | |
| 3541 | } | |
| 3542 | ||
| 3543 | /************************************************************* | |
| 3544 | ||
| 3545 | Konami VRC-4 | |
| 3546 | ||
| 3547 | In MESS: Supported | |
| 3548 | ||
| 3549 | *************************************************************/ | |
| 3550 | ||
| 3551 | static void vrc4_set_prg( running_machine &machine ) | |
| 3552 | { | |
| 3553 | nes_state *state = machine.driver_data<nes_state>(); | |
| 3554 | if (state->m_mmc_latch1 & 0x02) | |
| 3555 | { | |
| 3556 | prg8_89(machine, 0xfe); | |
| 3557 | prg8_cd(machine, state->m_mmc_prg_bank[0]); | |
| 3558 | } | |
| 3559 | else | |
| 3560 | { | |
| 3561 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 3562 | prg8_cd(machine, 0xfe); | |
| 3563 | } | |
| 3564 | } | |
| 3565 | ||
| 3566 | static void konami_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3567 | { | |
| 3568 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3569 | /* Increment & check the IRQ scanline counter */ | |
| 3570 | if (state->m_IRQ_enable && (++state->m_IRQ_count == 0x100)) | |
| 3571 | { | |
| 3572 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3573 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3574 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3575 | } | |
| 3576 | } | |
| 3577 | ||
| 3578 | static WRITE8_HANDLER( konami_vrc4_w ) | |
| 3579 | { | |
| 3580 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3581 | UINT8 bank, shift, mask; | |
| 3582 | UINT32 shifted_offs = (offset & 0x7000) | |
| 3583 | | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200) | |
| 3584 | | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100); | |
| 3585 | LOG_MMC(("konami_vrc4_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3586 | ||
| 3587 | if (offset < 0x1000) | |
| 3588 | { | |
| 3589 | state->m_mmc_prg_bank[0] = data; | |
| 3590 | vrc4_set_prg(space->machine()); | |
| 3591 | } | |
| 3592 | else if (offset >= 0x2000 && offset < 0x3000) | |
| 3593 | prg8_ab(space->machine(), data); | |
| 3594 | else | |
| 3595 | { | |
| 3596 | switch (shifted_offs & 0x7300) | |
| 3597 | { | |
| 3598 | case 0x1000: | |
| 3599 | case 0x1100: | |
| 3600 | switch (data & 0x03) | |
| 3601 | { | |
| 3602 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3603 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3604 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3605 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3606 | } | |
| 3607 | break; | |
| 3608 | case 0x1200: | |
| 3609 | case 0x1300: | |
| 3610 | state->m_mmc_latch1 = data & 0x02; | |
| 3611 | vrc4_set_prg(space->machine()); | |
| 3612 | break; | |
| 3613 | case 0x3000: | |
| 3614 | case 0x3100: | |
| 3615 | case 0x3200: | |
| 3616 | case 0x3300: | |
| 3617 | case 0x4000: | |
| 3618 | case 0x4100: | |
| 3619 | case 0x4200: | |
| 3620 | case 0x4300: | |
| 3621 | case 0x5000: | |
| 3622 | case 0x5100: | |
| 3623 | case 0x5200: | |
| 3624 | case 0x5300: | |
| 3625 | case 0x6000: | |
| 3626 | case 0x6100: | |
| 3627 | case 0x6200: | |
| 3628 | case 0x6300: | |
| 3629 | bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9); | |
| 3630 | shift = BIT(shifted_offs, 8) * 4; | |
| 3631 | mask = (0xf0 >> shift); | |
| 3632 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift); | |
| 3633 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 3634 | break; | |
| 3635 | case 0x7000: | |
| 3636 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f); | |
| 3637 | break; | |
| 3638 | case 0x7100: | |
| 3639 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4); | |
| 3640 | break; | |
| 3641 | case 0x7200: | |
| 3642 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 3643 | state->m_IRQ_enable = data & 0x02; | |
| 3644 | state->m_IRQ_enable_latch = data & 0x01; | |
| 3645 | if (data & 0x02) | |
| 3646 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3647 | break; | |
| 3648 | case 0x7300: | |
| 3649 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3650 | break; | |
| 3651 | default: | |
| 3652 | logerror("konami_vrc4_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data); | |
| 3653 | break; | |
| 3654 | } | |
| 3655 | } | |
| 3656 | } | |
| 3657 | ||
| 3658 | /************************************************************* | |
| 3659 | ||
| 3660 | Konami VRC-6 | |
| 3661 | ||
| 3662 | In MESS: Supported. It also uses konami_irq (there are IRQ | |
| 3663 | issues though: see Akumajou Densetsu intro). | |
| 3664 | ||
| 3665 | *************************************************************/ | |
| 3666 | ||
| 3667 | static WRITE8_HANDLER( konami_vrc6_w ) | |
| 3668 | { | |
| 3669 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3670 | UINT8 bank; | |
| 3671 | UINT32 shifted_offs = (offset & 0x7000) | |
| 3672 | | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200) | |
| 3673 | | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100); | |
| 3674 | LOG_MMC(("konami_vrc6_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3675 | ||
| 3676 | if (offset < 0x1000) | |
| 3677 | prg16_89ab(space->machine(), data); | |
| 3678 | else if (offset >= 0x4000 && offset < 0x5000) | |
| 3679 | prg8_cd(space->machine(), data); | |
| 3680 | else | |
| 3681 | { | |
| 3682 | switch (shifted_offs & 0x7300) | |
| 3683 | { | |
| 3684 | case 0x1000: | |
| 3685 | case 0x1100: | |
| 3686 | case 0x1200: | |
| 3687 | case 0x2000: | |
| 3688 | case 0x2100: | |
| 3689 | case 0x2200: | |
| 3690 | case 0x3000: | |
| 3691 | case 0x3100: | |
| 3692 | case 0x3200: | |
| 3693 | LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", shifted_offs & 0x7300, data)); | |
| 3694 | break; | |
| 3695 | case 0x3300: | |
| 3696 | switch (data & 0x0c) | |
| 3697 | { | |
| 3698 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3699 | case 0x04: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3700 | case 0x08: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3701 | case 0x0c: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3702 | } | |
| 3703 | break; | |
| 3704 | case 0x5000: | |
| 3705 | case 0x5100: | |
| 3706 | case 0x5200: | |
| 3707 | case 0x5300: | |
| 3708 | case 0x6000: | |
| 3709 | case 0x6100: | |
| 3710 | case 0x6200: | |
| 3711 | case 0x6300: | |
| 3712 | bank = ((shifted_offs & 0x7000) - 0x5000) / 0x0400 + ((shifted_offs & 0x0300) >> 8); | |
| 3713 | chr1_x(space->machine(), bank, data, CHRROM); | |
| 3714 | break; | |
| 3715 | case 0x7000: | |
| 3716 | state->m_IRQ_count_latch = data; | |
| 3717 | break; | |
| 3718 | case 0x7100: | |
| 3719 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 3720 | state->m_IRQ_enable = data & 0x02; | |
| 3721 | state->m_IRQ_enable_latch = data & 0x01; | |
| 3722 | if (data & 0x02) | |
| 3723 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3724 | break; | |
| 3725 | case 0x7200: | |
| 3726 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3727 | break; | |
| 3728 | default: | |
| 3729 | logerror("konami_vrc6_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data); | |
| 3730 | break; | |
| 3731 | } | |
| 3732 | } | |
| 3733 | } | |
| 3734 | ||
| 3735 | /************************************************************* | |
| 3736 | ||
| 3737 | Konami VRC7 | |
| 3738 | ||
| 3739 | Games: Lagrange Point, Tiny Toon Adventures 2 | |
| 3740 | ||
| 3741 | iNES: mapper 85 | |
| 3742 | ||
| 3743 | In MESS: Supported. It also uses konami_irq. | |
| 3744 | ||
| 3745 | *************************************************************/ | |
| 3746 | ||
| 3747 | static WRITE8_HANDLER( konami_vrc7_w ) | |
| 3748 | { | |
| 3749 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3750 | UINT8 bank; | |
| 3751 | LOG_MMC(("konami_vrc7_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3752 | ||
| 3753 | switch (offset & 0x7018) | |
| 3754 | { | |
| 3755 | case 0x0000: | |
| 3756 | prg8_89(space->machine(), data); | |
| 3757 | break; | |
| 3758 | case 0x0008: | |
| 3759 | case 0x0010: | |
| 3760 | case 0x0018: | |
| 3761 | prg8_ab(space->machine(), data); | |
| 3762 | break; | |
| 3763 | ||
| 3764 | case 0x1000: | |
| 3765 | prg8_cd(space->machine(), data); | |
| 3766 | break; | |
| 3767 | ||
| 3768 | /* TODO: there are sound regs in here */ | |
| 3769 | ||
| 3770 | case 0x2000: | |
| 3771 | case 0x2008: | |
| 3772 | case 0x2010: | |
| 3773 | case 0x2018: | |
| 3774 | case 0x3000: | |
| 3775 | case 0x3008: | |
| 3776 | case 0x3010: | |
| 3777 | case 0x3018: | |
| 3778 | case 0x4000: | |
| 3779 | case 0x4008: | |
| 3780 | case 0x4010: | |
| 3781 | case 0x4018: | |
| 3782 | case 0x5000: | |
| 3783 | case 0x5008: | |
| 3784 | case 0x5010: | |
| 3785 | case 0x5018: | |
| 3786 | bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0); | |
| 3787 | chr1_x(space->machine(), bank, data, state->m_mmc_chr_source); | |
| 3788 | break; | |
| 3789 | ||
| 3790 | case 0x6000: | |
| 3791 | switch (data & 0x03) | |
| 3792 | { | |
| 3793 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3794 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3795 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3796 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3797 | } | |
| 3798 | break; | |
| 3799 | case 0x6008: case 0x6010: case 0x6018: | |
| 3800 | state->m_IRQ_count_latch = data; | |
| 3801 | break; | |
| 3802 | case 0x7000: | |
| 3803 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 3804 | state->m_IRQ_enable = data & 0x02; | |
| 3805 | state->m_IRQ_enable_latch = data & 0x01; | |
| 3806 | if (data & 0x02) | |
| 3807 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3808 | break; | |
| 3809 | case 0x7008: case 0x7010: case 0x7018: | |
| 3810 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3811 | break; | |
| 3812 | ||
| 3813 | default: | |
| 3814 | logerror("konami_vrc7_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); | |
| 3815 | break; | |
| 3816 | } | |
| 3817 | } | |
| 3818 | ||
| 3819 | /************************************************************* | |
| 3820 | ||
| 3821 | Namcot-163 board emulation | |
| 3822 | ||
| 3823 | Games: Battle Fleet, Family Circuit '91, Famista '90, '91, | |
| 3824 | '92 & '94, Megami Tensei II, Top Striker, Wagyan Land 2 & 3 | |
| 3825 | ||
| 3826 | iNES: mapper 19 | |
| 3827 | ||
| 3828 | In MESS: Supported | |
| 3829 | ||
| 3830 | *************************************************************/ | |
| 3831 | ||
| 3832 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 3833 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 3834 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 3835 | static void namcot_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3836 | { | |
| 3837 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3838 | ||
| 3839 | if (state->m_IRQ_enable) | |
| 3840 | { | |
| 3841 | if (state->m_IRQ_count >= (0x7fff - 114)) | |
| 3842 | { | |
| 3843 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3844 | state->m_IRQ_count = 0; | |
| 3845 | } | |
| 3846 | else | |
| 3847 | state->m_IRQ_count += 114; | |
| 3848 | } | |
| 3849 | } | |
| 3850 | ||
| 3851 | static WRITE8_HANDLER( namcot163_l_w ) | |
| 3852 | { | |
| 3853 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3854 | LOG_MMC(("namcot163_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3855 | offset += 0x100; | |
| 3856 | ||
| 3857 | switch (offset & 0x1800) | |
| 3858 | { | |
| 3859 | case 0x0800: | |
| 3860 | LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data)); | |
| 3861 | break; | |
| 3862 | case 0x1000: /* low byte of IRQ */ | |
| 3863 | state->m_IRQ_count = (state->m_IRQ_count & 0x7f00) | data; | |
| 3864 | break; | |
| 3865 | case 0x1800: /* high byte of IRQ, IRQ enable in high bit */ | |
| 3866 | state->m_IRQ_count = (state->m_IRQ_count & 0xff) | ((data & 0x7f) << 8); | |
| 3867 | state->m_IRQ_enable = data & 0x80; | |
| 3868 | break; | |
| 3869 | } | |
| 3870 | } | |
| 3871 | ||
| 3872 | static READ8_HANDLER( namcot163_l_r ) | |
| 3873 | { | |
| 3874 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3875 | LOG_MMC(("namcot163_l_r, offset: %04x\n", offset)); | |
| 3876 | offset += 0x100; | |
| 3877 | ||
| 3878 | switch (offset & 0x1800) | |
| 3879 | { | |
| 3880 | case 0x1000: | |
| 3881 | return state->m_IRQ_count & 0xff; | |
| 3882 | case 0x1800: | |
| 3883 | return (state->m_IRQ_count >> 8) & 0xff; | |
| 3884 | case 0x0800: | |
| 3885 | LOG_MMC(("Namcot-163 sound reg read\n")); | |
| 3886 | default: | |
| 3887 | return 0x00; | |
| 3888 | } | |
| 3889 | } | |
| 3890 | ||
| 3891 | static void namcot163_set_mirror( running_machine &machine, UINT8 page, UINT8 data ) | |
| 3892 | { | |
| 3893 | if (!(data < 0xe0)) | |
| 3894 | set_nt_page(machine, page, CIRAM, data & 0x01, 1); | |
| 3895 | else | |
| 3896 | set_nt_page(machine, page, ROM, data, 0); | |
| 3897 | } | |
| 3898 | ||
| 3899 | static WRITE8_HANDLER( namcot163_w ) | |
| 3900 | { | |
| 3901 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3902 | LOG_MMC(("namcot163_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3903 | switch (offset & 0x7800) | |
| 3904 | { | |
| 3905 | case 0x0000: case 0x0800: | |
| 3906 | case 0x1000: case 0x1800: | |
| 3907 | case 0x2000: case 0x2800: | |
| 3908 | case 0x3000: case 0x3800: | |
| 3909 | chr1_x(space->machine(), offset / 0x800, data, CHRROM); | |
| 3910 | break; | |
| 3911 | case 0x4000: | |
| 3912 | namcot163_set_mirror(space->machine(), 0, data); | |
| 3913 | break; | |
| 3914 | case 0x4800: | |
| 3915 | namcot163_set_mirror(space->machine(), 1, data); | |
| 3916 | break; | |
| 3917 | case 0x5000: | |
| 3918 | namcot163_set_mirror(space->machine(), 2, data); | |
| 3919 | break; | |
| 3920 | case 0x5800: | |
| 3921 | namcot163_set_mirror(space->machine(), 3, data); | |
| 3922 | break; | |
| 3923 | case 0x6000: | |
| 3924 | prg8_89(space->machine(), data & 0x3f); | |
| 3925 | break; | |
| 3926 | case 0x6800: | |
| 3927 | state->m_mmc_latch1 = data & 0xc0; // this should enable High CHRRAM, but we still have to properly implement it! | |
| 3928 | prg8_ab(space->machine(), data & 0x3f); | |
| 3929 | break; | |
| 3930 | case 0x7000: | |
| 3931 | prg8_cd(space->machine(), data & 0x3f); | |
| 3932 | break; | |
| 3933 | case 0x7800: | |
| 3934 | LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data)); | |
| 3935 | break; | |
| 3936 | } | |
| 3937 | } | |
| 3938 | ||
| 3939 | /************************************************************* | |
| 3940 | ||
| 3941 | Sunsoft-1 board emulation | |
| 3942 | ||
| 3943 | Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no | |
| 3944 | Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone | |
| 3945 | ||
| 3946 | iNES: mapper 184 (Fantasy Zone uses this board with no | |
| 3947 | CHRROM, and the register switches PRG banks) | |
| 3948 | ||
| 3949 | *************************************************************/ | |
| 3950 | ||
| 3951 | static WRITE8_HANDLER( sunsoft1_m_w ) | |
| 3952 | { | |
| 3953 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3954 | LOG_MMC(("sunsoft1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3955 | ||
| 3956 | if (state->m_chr_chunks) | |
| 3957 | { | |
| 3958 | chr4_0(space->machine(), data & 0x0f, CHRROM); | |
| 3959 | chr4_4(space->machine(), data >> 4, CHRROM); | |
| 3960 | } | |
| 3961 | else | |
| 3962 | prg16_89ab(space->machine(), data & 0x0f); | |
| 3963 | } | |
| 3964 | ||
| 3965 | /************************************************************* | |
| 3966 | ||
| 3967 | Sunsoft-2 board emulation | |
| 3968 | ||
| 3969 | The two games using this board have incompatible mirroring | |
| 3970 | wiring, making necessary two distinct mappers & pcb_id | |
| 3971 | ||
| 3972 | iNES: mapper 89 & 93 | |
| 3973 | ||
| 3974 | *************************************************************/ | |
| 3975 | ||
| 3976 | static WRITE8_HANDLER( sunsoft2_w ) | |
| 3977 | { | |
| 3978 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3979 | UINT8 sunsoft_helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00); | |
| 3980 | LOG_MMC(("sunsoft2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3981 | ||
| 3982 | if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring | |
| 3983 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 3984 | if (state->m_chr_chunks) | |
| 3985 | chr8(space->machine(), sunsoft_helper, CHRROM); | |
| 3986 | ||
| 3987 | prg16_89ab(space->machine(), data >> 4); | |
| 3988 | } | |
| 3989 | ||
| 3990 | /************************************************************* | |
| 3991 | ||
| 3992 | Sunsoft-3 board emulation | |
| 3993 | ||
| 3994 | The two games using this board have incompatible mirroring | |
| 3995 | wiring, making necessary two distinct mappers & pcb_id | |
| 3996 | ||
| 3997 | iNES: mapper 67 | |
| 3998 | ||
| 3999 | *************************************************************/ | |
| 4000 | ||
| 4001 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 4002 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 4003 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 4004 | static void sunsoft3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 4005 | { | |
| 4006 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 4007 | ||
| 4008 | /* TODO: change to reflect the actual number of cycles spent: both using 114 or cycling 114,114,113 | |
| 4009 | produces a 1-line glitch in Fantasy Zone 2: it really requires the counter to be updated each CPU cycle! */ | |
| 4010 | if (state->m_IRQ_enable) | |
| 4011 | { | |
| 4012 | if (state->m_IRQ_count <= 114) | |
| 4013 | { | |
| 4014 | state->m_IRQ_enable = 0; | |
| 4015 | state->m_IRQ_count = 0xffff; | |
| 4016 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 4017 | } | |
| 4018 | else | |
| 4019 | state->m_IRQ_count -= 114; | |
| 4020 | } | |
| 4021 | } | |
| 4022 | ||
| 4023 | static WRITE8_HANDLER( sunsoft3_w ) | |
| 4024 | { | |
| 4025 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4026 | LOG_MMC(("sunsoft3_w, offset %04x, data: %02x\n", offset, data)); | |
| 4027 | ||
| 4028 | switch (offset & 0x7800) | |
| 4029 | { | |
| 4030 | case 0x0800: | |
| 4031 | chr2_0(space->machine(), data, CHRROM); | |
| 4032 | break; | |
| 4033 | case 0x1800: | |
| 4034 | chr2_2(space->machine(), data, CHRROM); | |
| 4035 | break; | |
| 4036 | case 0x2800: | |
| 4037 | chr2_4(space->machine(), data, CHRROM); | |
| 4038 | break; | |
| 4039 | case 0x3800: | |
| 4040 | chr2_6(space->machine(), data, CHRROM); | |
| 4041 | break; | |
| 4042 | case 0x4000: | |
| 4043 | case 0x4800: | |
| 4044 | state->m_IRQ_toggle ^= 1; | |
| 4045 | if (state->m_IRQ_toggle) | |
| 4046 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 4047 | else | |
| 4048 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 4049 | break; | |
| 4050 | case 0x5800: | |
| 4051 | state->m_IRQ_enable = BIT(data, 4); | |
| 4052 | state->m_IRQ_toggle = 0; | |
| 4053 | break; | |
| 4054 | case 0x6800: | |
| 4055 | switch (data & 3) | |
| 4056 | { | |
| 4057 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 4058 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 4059 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 4060 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 4061 | } | |
| 4062 | break; | |
| 4063 | case 0x7800: | |
| 4064 | prg16_89ab(space->machine(), data); | |
| 4065 | break; | |
| 4066 | default: | |
| 4067 | LOG_MMC(("sunsoft3_w uncaught write, offset: %04x, data: %02x\n", offset, data)); | |
| 4068 | break; | |
| 4069 | } | |
| 4070 | } | |
| 4071 | ||
| 4072 | /************************************************************* | |
| 4073 | ||
| 4074 | Taito TC0190FMC + board emulation | |
| 4075 | ||
| 4076 | Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don, | |
| 4077 | Insector X, Operation Wolf, Power Blazer, Takeshi no | |
| 4078 | Sengoku Fuuunji | |
| 4079 | ||
| 4080 | iNES: mapper 33 | |
| 4081 | ||
| 4082 | In MESS: Supported. | |
| 4083 | ||
| 4084 | *************************************************************/ | |
| 4085 | ||
| 4086 | static WRITE8_HANDLER( tc0190fmc_w ) | |
| 4087 | { | |
| 4088 | LOG_MMC(("tc0190fmc_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4089 | ||
| 4090 | switch (offset & 0x7003) | |
| 4091 | { | |
| 4092 | case 0x0000: | |
| 4093 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4094 | prg8_89(space->machine(), data); | |
| 4095 | break; | |
| 4096 | case 0x0001: | |
| 4097 | prg8_ab(space->machine(), data); | |
| 4098 | break; | |
| 4099 | case 0x0002: | |
| 4100 | chr2_0(space->machine(), data, CHRROM); | |
| 4101 | break; | |
| 4102 | case 0x0003: | |
| 4103 | chr2_2(space->machine(), data, CHRROM); | |
| 4104 | break; | |
| 4105 | case 0x2000: | |
| 4106 | chr1_4(space->machine(), data, CHRROM); | |
| 4107 | break; | |
| 4108 | case 0x2001: | |
| 4109 | chr1_5(space->machine(), data, CHRROM); | |
| 4110 | break; | |
| 4111 | case 0x2002: | |
| 4112 | chr1_6(space->machine(), data, CHRROM); | |
| 4113 | break; | |
| 4114 | case 0x2003: | |
| 4115 | chr1_7(space->machine(), data, CHRROM); | |
| 4116 | break; | |
| 4117 | } | |
| 4118 | } | |
| 4119 | ||
| 4120 | /************************************************************* | |
| 4121 | ||
| 4122 | Taito TC0190FMC + PAL16R4 board emulation | |
| 4123 | ||
| 4124 | Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2, | |
| 4125 | Captain Saver, Don Doko Don 2, Flintstones, Jetsons | |
| 4126 | ||
| 4127 | This is basically Mapper 33 + IRQ. Notably, IRQ works the | |
| 4128 | same as MMC3 irq, BUT latch values are "inverted" (XOR'ed | |
| 4129 | with 0xff) and there is a little delay (not implemented yet) | |
| 4130 | We simply use MMC3 IRQ and XOR the value written in the | |
| 4131 | register 0xc000 below | |
| 4132 | ||
| 4133 | iNES: mapper 48 | |
| 4134 | ||
| 4135 | In MESS: Supported. | |
| 4136 | ||
| 4137 | *************************************************************/ | |
| 4138 | ||
| 4139 | static WRITE8_HANDLER( tc0190fmc_p16_w ) | |
| 4140 | { | |
| 4141 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4142 | LOG_MMC(("tc0190fmc_p16_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4143 | ||
| 4144 | switch (offset & 0x7003) | |
| 4145 | { | |
| 4146 | case 0x0000: | |
| 4147 | prg8_89(space->machine(), data); | |
| 4148 | break; | |
| 4149 | case 0x0001: | |
| 4150 | case 0x0002: | |
| 4151 | case 0x0003: | |
| 4152 | case 0x2000: | |
| 4153 | case 0x2001: | |
| 4154 | case 0x2002: | |
| 4155 | case 0x2003: | |
| 4156 | tc0190fmc_w(space, offset, data); | |
| 4157 | break; | |
| 4158 | case 0x4000: | |
| 4159 | state->m_IRQ_count_latch = (0x100 - data) & 0xff; | |
| 4160 | break; | |
| 4161 | case 0x4001: | |
| 4162 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 4163 | break; | |
| 4164 | case 0x4002: | |
| 4165 | state->m_IRQ_enable = 1; | |
| 4166 | break; | |
| 4167 | case 0x4003: | |
| 4168 | state->m_IRQ_enable = 0; | |
| 4169 | break; | |
| 4170 | case 0x6000: | |
| 4171 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4172 | break; | |
| 4173 | } | |
| 4174 | } | |
| 4175 | ||
| 4176 | /************************************************************* | |
| 4177 | ||
| 4178 | Taito X1-005 board emulation | |
| 4179 | ||
| 4180 | Actually, Fudou Myouou Den uses a variant of the board with | |
| 4181 | CIRAM, making necessary two distinct mappers & pcb_id. | |
| 4182 | ||
| 4183 | Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9 | |
| 4184 | and the 0x80 ram! | |
| 4185 | ||
| 4186 | iNES: mappers 80 & 207 | |
| 4187 | ||
| 4188 | *************************************************************/ | |
| 4189 | ||
| 4190 | static WRITE8_HANDLER( x1005_m_w ) | |
| 4191 | { | |
| 4192 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4193 | LOG_MMC(("x1005_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4194 | ||
| 4195 | switch (offset) | |
| 4196 | { | |
| 4197 | case 0x1ef0: | |
| 4198 | chr2_0(space->machine(), (data & 0x7f) >> 1, CHRROM); | |
| 4199 | break; | |
| 4200 | case 0x1ef1: | |
| 4201 | chr2_2(space->machine(), (data & 0x7f) >> 1, CHRROM); | |
| 4202 | break; | |
| 4203 | case 0x1ef2: | |
| 4204 | chr1_4(space->machine(), data, CHRROM); | |
| 4205 | break; | |
| 4206 | case 0x1ef3: | |
| 4207 | chr1_5(space->machine(), data, CHRROM); | |
| 4208 | break; | |
| 4209 | case 0x1ef4: | |
| 4210 | chr1_6(space->machine(), data, CHRROM); | |
| 4211 | break; | |
| 4212 | case 0x1ef5: | |
| 4213 | chr1_7(space->machine(), data, CHRROM); | |
| 4214 | break; | |
| 4215 | case 0x1ef6: | |
| 4216 | case 0x1ef7: | |
| 4217 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 4218 | break; | |
| 4219 | case 0x1ef8: | |
| 4220 | case 0x1ef9: | |
| 4221 | state->m_mmc_latch1 = data; | |
| 4222 | break; | |
| 4223 | case 0x1efa: | |
| 4224 | case 0x1efb: | |
| 4225 | prg8_89(space->machine(), data); | |
| 4226 | break; | |
| 4227 | case 0x1efc: | |
| 4228 | case 0x1efd: | |
| 4229 | prg8_ab(space->machine(), data); | |
| 4230 | break; | |
| 4231 | case 0x1efe: | |
| 4232 | case 0x1eff: | |
| 4233 | prg8_cd(space->machine(), data); | |
| 4234 | break; | |
| 4235 | default: | |
| 4236 | logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data); | |
| 4237 | break; | |
| 4238 | } | |
| 4239 | ||
| 4240 | if (offset >= 0x1f00 && state->m_mapper_ram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4241 | state->m_mapper_ram[offset & (state->m_mapper_ram_size - 1)] = data; | |
| 4242 | else if (offset >= 0x1f00 && state->m_mapper_bram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4243 | state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data; | |
| 4244 | } | |
| 4245 | ||
| 4246 | static READ8_HANDLER( x1005_m_r ) | |
| 4247 | { | |
| 4248 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4249 | LOG_MMC(("x1005a_m_r, offset: %04x\n", offset)); | |
| 4250 | ||
| 4251 | if (offset >= 0x1f00 && state->m_mapper_ram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4252 | return state->m_mapper_ram[offset & (state->m_mapper_ram_size - 1)]; | |
| 4253 | else if (offset >= 0x1f00 && state->m_mapper_bram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4254 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4255 | ||
| 4256 | return 0xff; | |
| 4257 | } | |
| 4258 | ||
| 4259 | static WRITE8_HANDLER( x1005a_m_w ) | |
| 4260 | { | |
| 4261 | LOG_MMC(("x1005a_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4262 | ||
| 4263 | // similar to x1005_m_w but mirroring is handled differently | |
| 4264 | if (offset == 0x1ef6 || offset == 0x1ef7) | |
| 4265 | return; | |
| 4266 | ||
| 4267 | switch (offset) | |
| 4268 | { | |
| 4269 | case 0x1ef0: | |
| 4270 | set_nt_page(space->machine(), 0, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4271 | set_nt_page(space->machine(), 1, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4272 | break; | |
| 4273 | case 0x1ef1: | |
| 4274 | set_nt_page(space->machine(), 2, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4275 | set_nt_page(space->machine(), 3, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4276 | break; | |
| 4277 | } | |
| 4278 | ||
| 4279 | x1005_m_w(space, offset, data); | |
| 4280 | } | |
| 4281 | ||
| 4282 | /************************************************************* | |
| 4283 | ||
| 4284 | Taito X1-017 board emulation | |
| 4285 | ||
| 4286 | We miss to emulate the security check at 0x6000-0x73ff | |
| 4287 | and the ram! | |
| 4288 | ||
| 4289 | Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri | |
| 4290 | Stadium, SD Keiji - Blader | |
| 4291 | ||
| 4292 | iNES: mapper 82 | |
| 4293 | ||
| 4294 | In MESS: Supported. | |
| 4295 | ||
| 4296 | *************************************************************/ | |
| 4297 | ||
| 4298 | static void x1017_set_chr( running_machine &machine ) | |
| 4299 | { | |
| 4300 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4301 | if (state->m_mmc_latch1) | |
| 4302 | { | |
| 4303 | chr2_4(machine, state->m_mmc_vrom_bank[0] >> 1, CHRROM); | |
| 4304 | chr2_6(machine, state->m_mmc_vrom_bank[1] >> 1, CHRROM); | |
| 4305 | } | |
| 4306 | else | |
| 4307 | { | |
| 4308 | chr2_0(machine, state->m_mmc_vrom_bank[0] >> 1, CHRROM); | |
| 4309 | chr2_2(machine, state->m_mmc_vrom_bank[1] >> 1, CHRROM); | |
| 4310 | } | |
| 4311 | chr1_x(machine, 4 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[2], CHRROM); | |
| 4312 | chr1_x(machine, 5 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[3], CHRROM); | |
| 4313 | chr1_x(machine, 6 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[4], CHRROM); | |
| 4314 | chr1_x(machine, 7 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[5], CHRROM); | |
| 4315 | } | |
| 4316 | ||
| 4317 | static WRITE8_HANDLER( x1017_m_w ) | |
| 4318 | { | |
| 4319 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4320 | UINT8 reg = offset & 0x07; | |
| 4321 | LOG_MMC(("x1017_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4322 | ||
| 4323 | switch (offset) | |
| 4324 | { | |
| 4325 | case 0x1ef0: | |
| 4326 | case 0x1ef1: | |
| 4327 | if (state->m_mmc_vrom_bank[reg] != data) | |
| 4328 | { | |
| 4329 | state->m_mmc_vrom_bank[reg] = data; | |
| 4330 | x1017_set_chr(space->machine()); | |
| 4331 | } | |
| 4332 | break; | |
| 4333 | case 0x1ef2: | |
| 4334 | case 0x1ef3: | |
| 4335 | case 0x1ef4: | |
| 4336 | case 0x1ef5: | |
| 4337 | if (state->m_mmc_vrom_bank[reg] != data) | |
| 4338 | { | |
| 4339 | state->m_mmc_vrom_bank[reg] = data; | |
| 4340 | x1017_set_chr(space->machine()); | |
| 4341 | } | |
| 4342 | break; | |
| 4343 | case 0x1ef6: | |
| 4344 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 4345 | state->m_mmc_latch1 = ((data & 0x02) << 1); | |
| 4346 | x1017_set_chr(space->machine()); | |
| 4347 | break; | |
| 4348 | case 0x1ef7: | |
| 4349 | case 0x1ef8: | |
| 4350 | case 0x1ef9: | |
| 4351 | state->m_mmc_reg[(offset & 0x0f) - 7] = data; | |
| 4352 | break; | |
| 4353 | case 0x1efa: | |
| 4354 | prg8_89(space->machine(), data >> 2); | |
| 4355 | break; | |
| 4356 | case 0x1efb: | |
| 4357 | prg8_ab(space->machine(), data >> 2); | |
| 4358 | break; | |
| 4359 | case 0x1efc: | |
| 4360 | prg8_cd(space->machine(), data >> 2); | |
| 4361 | break; | |
| 4362 | default: | |
| 4363 | logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data); | |
| 4364 | break; | |
| 4365 | } | |
| 4366 | } | |
| 4367 | ||
| 4368 | static READ8_HANDLER( x1017_m_r ) | |
| 4369 | { | |
| 4370 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4371 | LOG_MMC(("x1017_m_r, offset: %04x\n", offset)); | |
| 4372 | ||
| 4373 | // 2+2+1 KB of Internal RAM can be independently enabled/disabled! | |
| 4374 | if (offset < 0x0800 && state->m_mapper_bram != NULL && state->m_mmc_reg[0] == 0xca) | |
| 4375 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4376 | if (offset < 0x1000 && state->m_mapper_bram != NULL && state->m_mmc_reg[1] == 0x69) | |
| 4377 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4378 | if (offset < 0x1800 && state->m_mapper_bram != NULL && state->m_mmc_reg[2] == 0x84) | |
| 4379 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4380 | ||
| 4381 | return 0xff; | |
| 4382 | } | |
| 4383 | ||
| 4384 | /************************************************************* | |
| 4385 | ||
| 4386 | MISC UNLICENSED BOARDS | |
| 4387 | ||
| 4388 | *************************************************************/ | |
| 4389 | ||
| 4390 | /************************************************************* | |
| 4391 | ||
| 4392 | AGCI 50282 bootleg board emulation | |
| 4393 | ||
| 4394 | Games: Death Race | |
| 4395 | ||
| 4396 | iNES: mapper 144 | |
| 4397 | ||
| 4398 | In MESS: Supported. | |
| 4399 | ||
| 4400 | *************************************************************/ | |
| 4401 | ||
| 4402 | static WRITE8_HANDLER( agci_50282_w ) | |
| 4403 | { | |
| 4404 | LOG_MMC(("agci_50282_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4405 | ||
| 4406 | offset += 0x8000; | |
| 4407 | data |= (space->read_byte(offset) & 1); | |
| 4408 | ||
| 4409 | chr8(space->machine(), data >> 4, CHRROM); | |
| 4410 | prg32(space->machine(), data); | |
| 4411 | } | |
| 4412 | ||
| 4413 | /************************************************************* | |
| 4414 | ||
| 4415 | AVE NINA-001 board emulation | |
| 4416 | ||
| 4417 | iNES: mapper 34 | |
| 4418 | ||
| 4419 | *************************************************************/ | |
| 4420 | ||
| 4421 | static WRITE8_HANDLER( nina01_m_w ) | |
| 4422 | { | |
| 4423 | LOG_MMC(("nina01_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4424 | ||
| 4425 | switch (offset) | |
| 4426 | { | |
| 4427 | case 0x1ffd: | |
| 4428 | prg32(space->machine(), data); | |
| 4429 | break; | |
| 4430 | case 0x1ffe: | |
| 4431 | chr4_0(space->machine(), data, CHRROM); | |
| 4432 | break; | |
| 4433 | case 0x1fff: | |
| 4434 | chr4_4(space->machine(), data, CHRROM); | |
| 4435 | break; | |
| 4436 | } | |
| 4437 | } | |
| 4438 | ||
| 4439 | /************************************************************* | |
| 4440 | ||
| 4441 | AVE NINA-003, NINA-006 and MB-91 boards emulation | |
| 4442 | ||
| 4443 | Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid, | |
| 4444 | Solitaire, Ultimate League Soccer | |
| 4445 | ||
| 4446 | iNES: mapper 79 | |
| 4447 | ||
| 4448 | In MESS: Supported. | |
| 4449 | ||
| 4450 | *************************************************************/ | |
| 4451 | ||
| 4452 | static WRITE8_HANDLER( nina06_l_w ) | |
| 4453 | { | |
| 4454 | LOG_MMC(("nina06_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4455 | ||
| 4456 | if (!(offset & 0x0100)) | |
| 4457 | { | |
| 4458 | prg32(space->machine(), data >> 3); | |
| 4459 | chr8(space->machine(), data, CHRROM); | |
| 4460 | } | |
| 4461 | } | |
| 4462 | ||
| 4463 | /************************************************************* | |
| 4464 | ||
| 4465 | Active Entertainment Action 52 board emulation | |
| 4466 | ||
| 4467 | iNES: mapper 228 | |
| 4468 | ||
| 4469 | *************************************************************/ | |
| 4470 | ||
| 4471 | static WRITE8_HANDLER( ae_act52_w ) | |
| 4472 | { | |
| 4473 | int pbank, cbank; | |
| 4474 | UINT8 pmode; | |
| 4475 | LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4476 | ||
| 4477 | set_nt_mirroring(space->machine(), BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4478 | ||
| 4479 | cbank = (data & 0x03) | ((offset & 0x0f) << 2); | |
| 4480 | chr8(space->machine(), cbank, CHRROM); | |
| 4481 | ||
| 4482 | pmode = offset & 0x20; | |
| 4483 | pbank = (offset & 0x1fc0) >> 6; | |
| 4484 | if (pmode) | |
| 4485 | { | |
| 4486 | prg16_89ab(space->machine(), pbank); | |
| 4487 | prg16_cdef(space->machine(), pbank); | |
| 4488 | } | |
| 4489 | else | |
| 4490 | prg32(space->machine(), pbank >> 1); | |
| 4491 | } | |
| 4492 | ||
| 4493 | ||
| 4494 | /************************************************************* | |
| 4495 | ||
| 4496 | C & E Bootleg Board for Decathlon | |
| 4497 | ||
| 4498 | Games: Decathlon | |
| 4499 | ||
| 4500 | Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to | |
| 4501 | data & 3; writes to 0x80a5-0x80e4 set chr8 to data & 7 | |
| 4502 | ||
| 4503 | iNES: mapper 244 | |
| 4504 | ||
| 4505 | In MESS: Supported. | |
| 4506 | ||
| 4507 | *************************************************************/ | |
| 4508 | ||
| 4509 | static WRITE8_HANDLER( cne_decathl_w ) | |
| 4510 | { | |
| 4511 | LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4512 | ||
| 4513 | if (offset < 0x0065) | |
| 4514 | return; | |
| 4515 | if (offset < 0x00a5) | |
| 4516 | { | |
| 4517 | prg32(space->machine(), (offset - 0x0065) & 0x03); | |
| 4518 | return; | |
| 4519 | } | |
| 4520 | if (offset < 0x00e5) | |
| 4521 | { | |
| 4522 | chr8(space->machine(), (offset - 0x00a5) & 0x07, CHRROM); | |
| 4523 | } | |
| 4524 | } | |
| 4525 | ||
| 4526 | /************************************************************* | |
| 4527 | ||
| 4528 | C & E Bootleg Board for Fong Shen Bang | |
| 4529 | ||
| 4530 | Games: Fong Shen Bang - Zhu Lu Zhi Zhan | |
| 4531 | ||
| 4532 | Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks. | |
| 4533 | Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd | |
| 4534 | and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2, | |
| 4535 | chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM. | |
| 4536 | ||
| 4537 | iNES: mapper 246 | |
| 4538 | ||
| 4539 | In MESS: Supported. | |
| 4540 | ||
| 4541 | *************************************************************/ | |
| 4542 | ||
| 4543 | static WRITE8_HANDLER( cne_fsb_m_w ) | |
| 4544 | { | |
| 4545 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4546 | LOG_MMC(("cne_fsb_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4547 | ||
| 4548 | if (offset < 0x0800) | |
| 4549 | { | |
| 4550 | switch (offset & 0x0007) | |
| 4551 | { | |
| 4552 | case 0x0000: | |
| 4553 | prg8_89(space->machine(), data); | |
| 4554 | break; | |
| 4555 | case 0x0001: | |
| 4556 | prg8_ab(space->machine(), data); | |
| 4557 | break; | |
| 4558 | case 0x0002: | |
| 4559 | prg8_cd(space->machine(), data); | |
| 4560 | break; | |
| 4561 | case 0x0003: | |
| 4562 | prg8_ef(space->machine(), data); | |
| 4563 | break; | |
| 4564 | case 0x0004: | |
| 4565 | chr2_0(space->machine(), data, CHRROM); | |
| 4566 | break; | |
| 4567 | case 0x0005: | |
| 4568 | chr2_2(space->machine(), data, CHRROM); | |
| 4569 | break; | |
| 4570 | case 0x0006: | |
| 4571 | chr2_4(space->machine(), data, CHRROM); | |
| 4572 | break; | |
| 4573 | case 0x0007: | |
| 4574 | chr2_6(space->machine(), data, CHRROM); | |
| 4575 | break; | |
| 4576 | } | |
| 4577 | } | |
| 4578 | else | |
| 4579 | state->m_battery_ram[offset] = data; | |
| 4580 | } | |
| 4581 | ||
| 4582 | /************************************************************* | |
| 4583 | ||
| 4584 | C & E Bootleg Board for Sheng Huo Lie Zhuan | |
| 4585 | ||
| 4586 | Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan | |
| 4587 | ||
| 4588 | Simple Mapper: writes to 0x4020-0x5fff sets prg32 to | |
| 4589 | data>>4 and chr8 to data&f. We currently do not map | |
| 4590 | writes to 0x4020-0x40ff (to do: verify if this produces | |
| 4591 | issues) | |
| 4592 | ||
| 4593 | iNES: mapper 240 | |
| 4594 | ||
| 4595 | In MESS: Supported. | |
| 4596 | ||
| 4597 | *************************************************************/ | |
| 4598 | ||
| 4599 | static WRITE8_HANDLER( cne_shlz_l_w ) | |
| 4600 | { | |
| 4601 | LOG_MMC(("cne_shlz_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4602 | ||
| 4603 | prg32(space->machine(), data >> 4); | |
| 4604 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 4605 | } | |
| 4606 | ||
| 4607 | /************************************************************* | |
| 4608 | ||
| 4609 | Caltron 6 in 1 Board | |
| 4610 | ||
| 4611 | Games: 6 in 1 by Caltron | |
| 4612 | ||
| 4613 | iNES: mapper 41 | |
| 4614 | ||
| 4615 | In MESS: Supported. | |
| 4616 | ||
| 4617 | *************************************************************/ | |
| 4618 | ||
| 4619 | static WRITE8_HANDLER( caltron6in1_m_w ) | |
| 4620 | { | |
| 4621 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4622 | LOG_MMC(("caltron6in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4623 | ||
| 4624 | state->m_mmc_latch1 = offset & 0xff; | |
| 4625 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4626 | prg32(space->machine(), offset & 0x07); | |
| 4627 | } | |
| 4628 | ||
| 4629 | static WRITE8_HANDLER( caltron6in1_w ) | |
| 4630 | { | |
| 4631 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4632 | LOG_MMC(("caltron6in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4633 | ||
| 4634 | if (state->m_mmc_latch1 & 0x04) | |
| 4635 | chr8(space->machine(), ((state->m_mmc_latch1 & 0x18) >> 1) | (data & 0x03), CHRROM); | |
| 4636 | } | |
| 4637 | ||
| 4638 | /************************************************************* | |
| 4639 | ||
| 4640 | Camerica Boards (BF9093, BF9097, BF909X, ALGNV11) | |
| 4641 | ||
| 4642 | Games: Linus Spacehead's Cosmic Crusade, Micro Machines, | |
| 4643 | Mig-29, Stunt Kids | |
| 4644 | ||
| 4645 | To emulate NT mirroring for BF9097 board (missing in BF9093) | |
| 4646 | we use crc_hack, however Fire Hawk is broken (but without | |
| 4647 | mirroring there would be no helicopter graphics). | |
| 4648 | ||
| 4649 | iNES: mapper 71 | |
| 4650 | ||
| 4651 | In MESS: Partially Supported. | |
| 4652 | ||
| 4653 | *************************************************************/ | |
| 4654 | ||
| 4655 | static WRITE8_HANDLER( bf9093_w ) | |
| 4656 | { | |
| 4657 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4658 | LOG_MMC(("bf9093_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4659 | ||
| 4660 | switch (offset & 0x7000) | |
| 4661 | { | |
| 4662 | case 0x0000: | |
| 4663 | case 0x1000: | |
| 4664 | if (!state->m_hard_mirroring) | |
| 4665 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 4666 | break; | |
| 4667 | case 0x4000: | |
| 4668 | case 0x5000: | |
| 4669 | case 0x6000: | |
| 4670 | case 0x7000: | |
| 4671 | prg16_89ab(space->machine(), data); | |
| 4672 | break; | |
| 4673 | } | |
| 4674 | } | |
| 4675 | ||
| 4676 | /************************************************************* | |
| 4677 | ||
| 4678 | Camerica BF9096 & ALGQV11 Boards | |
| 4679 | ||
| 4680 | Games: Quattro Adventure, Quattro Arcade, Quattro Sports | |
| 4681 | ||
| 4682 | Writes to 0x8000-0x9fff set prg block to (data&0x18)>>1, | |
| 4683 | writes to 0xa000-0xbfff set prg page to data&3. selected | |
| 4684 | prg are: prg16_89ab = block|page, prg_cdef = 3|page. | |
| 4685 | For more info on the hardware to bypass the NES lockout, see | |
| 4686 | Kevtris' Camerica Mappers documentation. | |
| 4687 | ||
| 4688 | iNES: mapper 232 | |
| 4689 | ||
| 4690 | In MESS: Supported. | |
| 4691 | ||
| 4692 | *************************************************************/ | |
| 4693 | ||
| 4694 | static void bf9096_set_prg( running_machine &machine ) | |
| 4695 | { | |
| 4696 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4697 | prg16_89ab(machine, (state->m_mmc_latch2 & 0x03) | ((state->m_mmc_latch1 & 0x18) >> 1)); | |
| 4698 | prg16_cdef(machine, 0x03 | ((state->m_mmc_latch1 & 0x18) >> 1)); | |
| 4699 | } | |
| 4700 | ||
| 4701 | static WRITE8_HANDLER( bf9096_w ) | |
| 4702 | { | |
| 4703 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4704 | LOG_MMC(("bf9096_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4705 | ||
| 4706 | if (offset < 0x2000) | |
| 4707 | state->m_mmc_latch1 = data; | |
| 4708 | else | |
| 4709 | state->m_mmc_latch2 = data; | |
| 4710 | ||
| 4711 | bf9096_set_prg(space->machine()); | |
| 4712 | } | |
| 4713 | ||
| 4714 | /************************************************************* | |
| 4715 | ||
| 4716 | Camerica Golden Five board | |
| 4717 | ||
| 4718 | Games: Pegasus 5 in 1 | |
| 4719 | ||
| 4720 | iNES: mapper 104 | |
| 4721 | ||
| 4722 | In MESS: Supported. | |
| 4723 | ||
| 4724 | *************************************************************/ | |
| 4725 | ||
| 4726 | static WRITE8_HANDLER( golden5_w ) | |
| 4727 | { | |
| 4728 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4729 | LOG_MMC(("golden5_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4730 | ||
| 4731 | if (offset < 0x4000) | |
| 4732 | { | |
| 4733 | if (data & 0x08) | |
| 4734 | { | |
| 4735 | state->m_mmc_prg_bank[0] = ((data & 0x07) << 4) | (state->m_mmc_prg_bank[0] & 0x0f); | |
| 4736 | prg16_89ab(space->machine(), state->m_mmc_prg_bank[0]); | |
| 4737 | prg16_cdef(space->machine(), ((data & 0x07) << 4) | 0x0f); | |
| 4738 | } | |
| 4739 | ||
| 4740 | } | |
| 4741 | else | |
| 4742 | { | |
| 4743 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x70) | (data & 0x0f); | |
| 4744 | prg16_89ab(space->machine(), state->m_mmc_prg_bank[0]); | |
| 4745 | } | |
| 4746 | } | |
| 4747 | ||
| 4748 | /************************************************************* | |
| 4749 | ||
| 4750 | Cony Bootleg Board | |
| 4751 | ||
| 4752 | Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II | |
| 4753 | Pro, World Heroes 2 | |
| 4754 | ||
| 4755 | iNES: mapper 83 | |
| 4756 | ||
| 4757 | In MESS: Supported. | |
| 4758 | ||
| 4759 | *************************************************************/ | |
| 4760 | ||
| 4761 | static WRITE8_HANDLER( cony_l_w ) | |
| 4762 | { | |
| 4763 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4764 | LOG_MMC(("cony_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4765 | ||
| 4766 | if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff | |
| 4767 | state->m_mapper83_low_reg[offset & 0x03] = data; | |
| 4768 | } | |
| 4769 | ||
| 4770 | static READ8_HANDLER( cony_l_r ) | |
| 4771 | { | |
| 4772 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4773 | LOG_MMC(("cony_l_r, offset: %04x\n", offset)); | |
| 4774 | ||
| 4775 | if (offset == 0x0f00) // 0x5000 | |
| 4776 | { | |
| 4777 | // read dipswitch bit! - currently unimplemented | |
| 4778 | } | |
| 4779 | if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff | |
| 4780 | return state->m_mapper83_low_reg[offset & 0x03]; | |
| 4781 | else | |
| 4782 | return 0x00; | |
| 4783 | } | |
| 4784 | ||
| 4785 | static void cony_set_prg( running_machine &machine ) | |
| 4786 | { | |
| 4787 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4788 | prg16_89ab(machine, state->m_mapper83_reg[8] & 0x3f); | |
| 4789 | prg16_cdef(machine, (state->m_mapper83_reg[8] & 0x30) | 0x0f); | |
| 4790 | } | |
| 4791 | ||
| 4792 | static void cony_set_chr( running_machine &machine ) | |
| 4793 | { | |
| 4794 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4795 | // FIXME: here we emulate at least 3 different boards!!! | |
| 4796 | // one board switches 1k VROM banks only | |
| 4797 | // one writes to 0x8000 and then switches 2k VROM banks only | |
| 4798 | // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only | |
| 4799 | // we should split them and possibly document the proper behavior of each variant | |
| 4800 | if (state->m_mmc_latch1 && !state->m_mmc_latch2) | |
| 4801 | { | |
| 4802 | chr2_0(machine, state->m_mapper83_reg[0], CHRROM); | |
| 4803 | chr2_2(machine, state->m_mapper83_reg[1], CHRROM); | |
| 4804 | chr2_4(machine, state->m_mapper83_reg[6], CHRROM); | |
| 4805 | chr2_6(machine, state->m_mapper83_reg[7], CHRROM); | |
| 4806 | } | |
| 4807 | else | |
| 4808 | { | |
| 4809 | chr1_0(machine, state->m_mapper83_reg[0] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4810 | chr1_1(machine, state->m_mapper83_reg[1] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4811 | chr1_2(machine, state->m_mapper83_reg[2] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4812 | chr1_3(machine, state->m_mapper83_reg[3] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4813 | chr1_4(machine, state->m_mapper83_reg[4] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4814 | chr1_5(machine, state->m_mapper83_reg[5] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4815 | chr1_6(machine, state->m_mapper83_reg[6] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4816 | chr1_7(machine, state->m_mapper83_reg[7] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4817 | } | |
| 4818 | } | |
| 4819 | ||
| 4820 | static WRITE8_HANDLER( cony_w ) | |
| 4821 | { | |
| 4822 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4823 | LOG_MMC(("cony_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4824 | ||
| 4825 | switch (offset) | |
| 4826 | { | |
| 4827 | case 0x0000: | |
| 4828 | state->m_mmc_latch1 = 1; | |
| 4829 | case 0x3000: | |
| 4830 | case 0x30ff: | |
| 4831 | case 0x31ff: | |
| 4832 | state->m_mapper83_reg[8] = data; | |
| 4833 | cony_set_prg(space->machine()); | |
| 4834 | cony_set_chr(space->machine()); | |
| 4835 | break; | |
| 4836 | case 0x0100: | |
| 4837 | state->m_mmc_reg[0] = data & 0x80; | |
| 4838 | switch (data & 0x03) | |
| 4839 | { | |
| 4840 | case 0: | |
| 4841 | set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); | |
| 4842 | break; | |
| 4843 | case 1: | |
| 4844 | set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); | |
| 4845 | break; | |
| 4846 | case 2: | |
| 4847 | set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); | |
| 4848 | break; | |
| 4849 | case 3: | |
| 4850 | set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); | |
| 4851 | break; | |
| 4852 | } | |
| 4853 | break; | |
| 4854 | case 0x0200: | |
| 4855 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 4856 | break; | |
| 4857 | case 0x0201: | |
| 4858 | state->m_IRQ_enable = state->m_mmc_reg[0]; | |
| 4859 | state->m_IRQ_count = (data << 8) | (state->m_IRQ_count & 0xff); | |
| 4860 | break; | |
| 4861 | case 0x0300: | |
| 4862 | prg8_89(space->machine(), data); | |
| 4863 | break; | |
| 4864 | case 0x0301: | |
| 4865 | prg8_ab(space->machine(), data); | |
| 4866 | break; | |
| 4867 | case 0x0302: | |
| 4868 | prg8_cd(space->machine(), data); | |
| 4869 | break; | |
| 4870 | case 0x0312: | |
| 4871 | case 0x0313: | |
| 4872 | case 0x0314: | |
| 4873 | case 0x0315: | |
| 4874 | state->m_mmc_latch2 = 1; | |
| 4875 | case 0x0310: | |
| 4876 | case 0x0311: | |
| 4877 | case 0x0316: | |
| 4878 | case 0x0317: | |
| 4879 | state->m_mapper83_reg[offset - 0x0310] = data; | |
| 4880 | cony_set_chr(space->machine()); | |
| 4881 | break; | |
| 4882 | case 0x0318: | |
| 4883 | state->m_mapper83_reg[9] = data; | |
| 4884 | cony_set_prg(space->machine()); | |
| 4885 | break; | |
| 4886 | } | |
| 4887 | } | |
| 4888 | ||
| 4889 | /************************************************************* | |
| 4890 | ||
| 4891 | Board DREAMTECH01 | |
| 4892 | ||
| 4893 | Games: Korean Igo | |
| 4894 | ||
| 4895 | In MESS: Supported | |
| 4896 | ||
| 4897 | *************************************************************/ | |
| 4898 | ||
| 4899 | static WRITE8_HANDLER( dreamtech_l_w ) | |
| 4900 | { | |
| 4901 | LOG_MMC(("dreamtech_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 4902 | offset += 0x100; | |
| 4903 | ||
| 4904 | if (offset == 0x1020) /* 0x5020 */ | |
| 4905 | prg16_89ab(space->machine(), data); | |
| 4906 | } | |
| 4907 | ||
| 4908 | /************************************************************* | |
| 4909 | ||
| 4910 | Bootleg Board by Fukutake | |
| 4911 | ||
| 4912 | Games: Study Box | |
| 4913 | ||
| 4914 | iNES: mapper 186 | |
| 4915 | ||
| 4916 | In MESS: Unsupported. | |
| 4917 | ||
| 4918 | ||
| 4919 | *************************************************************/ | |
| 4920 | ||
| 4921 | static WRITE8_HANDLER( fukutake_l_w ) | |
| 4922 | { | |
| 4923 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4924 | LOG_MMC(("fukutake_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 4925 | offset += 0x100; | |
| 4926 | ||
| 4927 | if (offset >= 0x200 && offset < 0x400) | |
| 4928 | { | |
| 4929 | if (offset & 1) | |
| 4930 | prg16_89ab(space->machine(), data); | |
| 4931 | else | |
| 4932 | wram_bank(space->machine(), data >> 6, NES_WRAM); | |
| 4933 | } | |
| 4934 | else if (offset >= 0x400 && offset < 0xf00) | |
| 4935 | state->m_mapper_ram[offset - 0x400] = data; | |
| 4936 | } | |
| 4937 | ||
| 4938 | static READ8_HANDLER( fukutake_l_r ) | |
| 4939 | { | |
| 4940 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4941 | LOG_MMC(("fukutake_l_r offset: %04x\n", offset)); | |
| 4942 | offset += 0x100; | |
| 4943 | ||
| 4944 | if (offset >= 0x200 && offset < 0x400) | |
| 4945 | { | |
| 4946 | if (offset == 0x200 || offset == 0x201 || offset == 0x203) | |
| 4947 | return 0x00; | |
| 4948 | else if (offset == 0x202) | |
| 4949 | return 0x40; | |
| 4950 | else | |
| 4951 | return 0xff; | |
| 4952 | } | |
| 4953 | else if (offset >= 0x400 && offset < 0xf00) | |
| 4954 | return state->m_mapper_ram[offset - 0x400]; | |
| 4955 | ||
| 4956 | return 0; | |
| 4957 | } | |
| 4958 | ||
| 4959 | /************************************************************* | |
| 4960 | ||
| 4961 | Bootleg Board by Future Media | |
| 4962 | ||
| 4963 | Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun | |
| 4964 | ||
| 4965 | iNES: mapper 117 | |
| 4966 | ||
| 4967 | In MESS: Unsupported. | |
| 4968 | ||
| 4969 | *************************************************************/ | |
| 4970 | ||
| 4971 | static void futuremedia_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 4972 | { | |
| 4973 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 4974 | // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 4975 | { | |
| 4976 | if (state->m_IRQ_enable && state->m_IRQ_count) | |
| 4977 | { | |
| 4978 | state->m_IRQ_count--; | |
| 4979 | if (!state->m_IRQ_count) | |
| 4980 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 4981 | } | |
| 4982 | } | |
| 4983 | } | |
| 4984 | ||
| 4985 | static WRITE8_HANDLER( futuremedia_w ) | |
| 4986 | { | |
| 4987 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4988 | LOG_MMC(("futuremedia_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4989 | ||
| 4990 | switch (offset) | |
| 4991 | { | |
| 4992 | case 0x0000: | |
| 4993 | prg8_89(space->machine(), data); | |
| 4994 | break; | |
| 4995 | case 0x0001: | |
| 4996 | prg8_ab(space->machine(), data); | |
| 4997 | break; | |
| 4998 | case 0x0002: | |
| 4999 | prg8_cd(space->machine(), data); | |
| 5000 | break; | |
| 5001 | case 0x0003: | |
| 5002 | prg8_ef(space->machine(), data); | |
| 5003 | break; | |
| 5004 | case 0x2000: | |
| 5005 | case 0x2001: | |
| 5006 | case 0x2002: | |
| 5007 | case 0x2003: | |
| 5008 | case 0x2004: | |
| 5009 | case 0x2005: | |
| 5010 | case 0x2006: | |
| 5011 | case 0x2007: | |
| 5012 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 5013 | break; | |
| 5014 | ||
| 5015 | case 0x5000: | |
| 5016 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5017 | break; | |
| 5018 | ||
| 5019 | case 0x4001: | |
| 5020 | state->m_IRQ_count_latch = data; | |
| 5021 | break; | |
| 5022 | case 0x4002: | |
| 5023 | // IRQ cleared | |
| 5024 | break; | |
| 5025 | case 0x4003: | |
| 5026 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 5027 | break; | |
| 5028 | case 0x6000: | |
| 5029 | state->m_IRQ_enable = data & 0x01; | |
| 5030 | break; | |
| 5031 | } | |
| 5032 | } | |
| 5033 | ||
| 5034 | /************************************************************* | |
| 5035 | ||
| 5036 | Bootleg Board 37017 (?) by Gouder | |
| 5037 | ||
| 5038 | Games: Street Fighter IV | |
| 5039 | ||
| 5040 | MMC3 clone. It also requires reads from 0x5000-0x7fff. | |
| 5041 | ||
| 5042 | iNES: mapper 208 | |
| 5043 | ||
| 5044 | In MESS: Preliminary Support. | |
| 5045 | ||
| 5046 | *************************************************************/ | |
| 5047 | ||
| 5048 | static WRITE8_HANDLER( gouder_sf4_l_w ) | |
| 5049 | { | |
| 5050 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5051 | static const UINT8 conv_table[256] = | |
| 5052 | { | |
| 5053 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, | |
| 5054 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, | |
| 5055 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, | |
| 5056 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, | |
| 5057 | 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5058 | 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5059 | 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5060 | 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5061 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, | |
| 5062 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, | |
| 5063 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, | |
| 5064 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, | |
| 5065 | 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5066 | 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5067 | 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5068 | 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
| 5069 | }; | |
| 5070 | ||
| 5071 | LOG_MMC(("gouder_sf4_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5072 | ||
| 5073 | if (!(offset < 0x1700)) | |
| 5074 | state->m_mmc_reg[offset & 0x03] = data ^ conv_table[state->m_mmc_reg[4]]; | |
| 5075 | else if (!(offset < 0xf00)) | |
| 5076 | state->m_mmc_reg[4] = data; | |
| 5077 | else if (!(offset < 0x700)) | |
| 5078 | prg32(space->machine(), ((data >> 3) & 0x02) | (data & 0x01)); | |
| 5079 | } | |
| 5080 | ||
| 5081 | static READ8_HANDLER( gouder_sf4_l_r ) | |
| 5082 | { | |
| 5083 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5084 | LOG_MMC(("gouder_sf4_l_r, offset: %04x\n", offset)); | |
| 5085 | ||
| 5086 | if (!(offset < 0x1700)) | |
| 5087 | return state->m_mmc_reg[offset & 0x03]; | |
| 5088 | ||
| 5089 | return 0x00; | |
| 5090 | } | |
| 5091 | ||
| 5092 | /* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ | |
| 5093 | static void gouder_sf4_prg_cb( running_machine &machine, int start, int bank ) | |
| 5094 | { | |
| 5095 | return; | |
| 5096 | } | |
| 5097 | ||
| 5098 | ||
| 5099 | /************************************************************* | |
| 5100 | ||
| 5101 | Bootleg Board by Henggedianzi | |
| 5102 | ||
| 5103 | Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu | |
| 5104 | Chou Ji | |
| 5105 | ||
| 5106 | Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets | |
| 5107 | NT mirroring. | |
| 5108 | ||
| 5109 | iNES: mapper 177 | |
| 5110 | ||
| 5111 | In MESS: Supported. | |
| 5112 | ||
| 5113 | *************************************************************/ | |
| 5114 | ||
| 5115 | static WRITE8_HANDLER( henggedianzi_w ) | |
| 5116 | { | |
| 5117 | LOG_MMC(("henggedianzi_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5118 | ||
| 5119 | prg32(space->machine(), data); | |
| 5120 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5121 | } | |
| 5122 | ||
| 5123 | /************************************************************* | |
| 5124 | ||
| 5125 | Bootleg Board by Henggedianzi | |
| 5126 | ||
| 5127 | Games: Xing He Zhan Shi | |
| 5128 | ||
| 5129 | Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000- | |
| 5130 | 0xffff set NT mirroring | |
| 5131 | ||
| 5132 | iNES: mapper 179 | |
| 5133 | ||
| 5134 | In MESS: Supported. | |
| 5135 | ||
| 5136 | *************************************************************/ | |
| 5137 | ||
| 5138 | static WRITE8_HANDLER( heng_xjzb_l_w ) | |
| 5139 | { | |
| 5140 | LOG_MMC(("heng_xjzb_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5141 | offset += 0x4100; | |
| 5142 | ||
| 5143 | if (offset & 0x5000) | |
| 5144 | prg32(space->machine(), data >> 1); | |
| 5145 | } | |
| 5146 | ||
| 5147 | static WRITE8_HANDLER( heng_xjzb_w ) | |
| 5148 | { | |
| 5149 | LOG_MMC(("heng_xjzb_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5150 | ||
| 5151 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5152 | } | |
| 5153 | ||
| 5154 | /************************************************************* | |
| 5155 | ||
| 5156 | Bootleg Board by HES (also used by others) | |
| 5157 | ||
| 5158 | Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder, | |
| 5159 | Total Funpack | |
| 5160 | ||
| 5161 | Actually, two variant: one for HES 6-in-1 with mirroring control | |
| 5162 | and one for AV Soccer and others with hardwired mirroring | |
| 5163 | ||
| 5164 | iNES: mapper 113 | |
| 5165 | ||
| 5166 | In MESS: Supported. | |
| 5167 | ||
| 5168 | *************************************************************/ | |
| 5169 | ||
| 5170 | static WRITE8_HANDLER( hes6in1_l_w ) | |
| 5171 | { | |
| 5172 | LOG_MMC(("hes6in1_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5173 | ||
| 5174 | if (!(offset & 0x100)) | |
| 5175 | { | |
| 5176 | prg32(space->machine(), (data & 0x38) >> 3); | |
| 5177 | chr8(space->machine(), (data & 0x07) | ((data & 0x40) >> 3), CHRROM); | |
| 5178 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 5179 | } | |
| 5180 | } | |
| 5181 | ||
| 5182 | static WRITE8_HANDLER( hes_l_w ) | |
| 5183 | { | |
| 5184 | LOG_MMC(("hes_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5185 | ||
| 5186 | if (!(offset & 0x100)) | |
| 5187 | { | |
| 5188 | prg32(space->machine(), (data & 0x38) >> 3); | |
| 5189 | chr8(space->machine(), (data & 0x07) | ((data & 0x40) >> 3), CHRROM); | |
| 5190 | } | |
| 5191 | } | |
| 5192 | ||
| 5193 | /************************************************************* | |
| 5194 | ||
| 5195 | Bootleg Board by Hosenkan | |
| 5196 | ||
| 5197 | Games: Pocahontas, Super Donkey Kong | |
| 5198 | ||
| 5199 | iNES: mapper 182 | |
| 5200 | ||
| 5201 | In MESS: Supported. | |
| 5202 | ||
| 5203 | *************************************************************/ | |
| 5204 | ||
| 5205 | static WRITE8_HANDLER( hosenkan_w ) | |
| 5206 | { | |
| 5207 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5208 | LOG_MMC(("hosenkan_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5209 | ||
| 5210 | switch (offset & 0x7003) | |
| 5211 | { | |
| 5212 | case 0x0001: | |
| 5213 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5214 | break; | |
| 5215 | case 0x2000: | |
| 5216 | state->m_mmc_latch1 = data; | |
| 5217 | break; | |
| 5218 | case 0x4000: | |
| 5219 | switch (state->m_mmc_latch1) | |
| 5220 | { | |
| 5221 | case 0: | |
| 5222 | chr2_0(space->machine(), data >> 1, CHRROM); | |
| 5223 | break; | |
| 5224 | case 1: | |
| 5225 | chr1_5(space->machine(), data, CHRROM); | |
| 5226 | break; | |
| 5227 | case 2: | |
| 5228 | chr2_2(space->machine(), data >> 1, CHRROM); | |
| 5229 | break; | |
| 5230 | case 3: | |
| 5231 | chr1_7(space->machine(), data, CHRROM); | |
| 5232 | break; | |
| 5233 | case 4: | |
| 5234 | prg8_89(space->machine(), data); | |
| 5235 | break; | |
| 5236 | case 5: | |
| 5237 | prg8_ab(space->machine(), data); | |
| 5238 | break; | |
| 5239 | case 6: | |
| 5240 | chr1_4(space->machine(), data, CHRROM); | |
| 5241 | break; | |
| 5242 | case 7: | |
| 5243 | chr1_6(space->machine(), data, CHRROM); | |
| 5244 | break; | |
| 5245 | } | |
| 5246 | break; | |
| 5247 | case 0x6003: | |
| 5248 | if (data) | |
| 5249 | { | |
| 5250 | state->m_IRQ_count = data; | |
| 5251 | state->m_IRQ_enable = 1; | |
| 5252 | } | |
| 5253 | else | |
| 5254 | state->m_IRQ_enable = 0; | |
| 5255 | break; | |
| 5256 | } | |
| 5257 | } | |
| 5258 | ||
| 5259 | /************************************************************* | |
| 5260 | ||
| 5261 | Kaiser Board KS7058 | |
| 5262 | ||
| 5263 | Games: Tui Do Woo Ma Jeung | |
| 5264 | ||
| 5265 | Writes to 0xf000-0xffff set 4k chr banks. Namely, if | |
| 5266 | offset&0x80 is 0 the lower 4k are set, if it is 1 the | |
| 5267 | upper 4k are set. | |
| 5268 | ||
| 5269 | iNES: mapper 171 | |
| 5270 | ||
| 5271 | In MESS: Supported. | |
| 5272 | ||
| 5273 | *************************************************************/ | |
| 5274 | ||
| 5275 | static WRITE8_HANDLER( ks7058_w ) | |
| 5276 | { | |
| 5277 | LOG_MMC(("ks7058_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5278 | ||
| 5279 | switch (offset & 0x7080) | |
| 5280 | { | |
| 5281 | case 0x7000: | |
| 5282 | chr4_0(space->machine(), data, CHRROM); | |
| 5283 | break; | |
| 5284 | case 0x7080: | |
| 5285 | chr4_4(space->machine(), data, CHRROM); | |
| 5286 | break; | |
| 5287 | } | |
| 5288 | } | |
| 5289 | ||
| 5290 | /************************************************************* | |
| 5291 | ||
| 5292 | Kaiser Board KS7022 | |
| 5293 | ||
| 5294 | Games: 15 in 1 | |
| 5295 | ||
| 5296 | iNES: mapper 175 | |
| 5297 | ||
| 5298 | In MESS: Supported? | |
| 5299 | ||
| 5300 | *************************************************************/ | |
| 5301 | ||
| 5302 | static WRITE8_HANDLER( ks7022_w ) | |
| 5303 | { | |
| 5304 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5305 | LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5306 | ||
| 5307 | if (offset == 0) | |
| 5308 | set_nt_mirroring(space->machine(), BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5309 | ||
| 5310 | if (offset == 0x2000) | |
| 5311 | state->m_mmc_latch1 = data & 0x0f; | |
| 5312 | } | |
| 5313 | ||
| 5314 | static READ8_HANDLER( ks7022_r ) | |
| 5315 | { | |
| 5316 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5317 | LOG_MMC(("ks7022_r, offset: %04x\n", offset)); | |
| 5318 | ||
| 5319 | if (offset == 0x7ffc) | |
| 5320 | { | |
| 5321 | chr8(space->machine(), state->m_mmc_latch1, CHRROM); | |
| 5322 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 5323 | prg16_cdef(space->machine(), state->m_mmc_latch1); | |
| 5324 | } | |
| 5325 | ||
| 5326 | return mmc_hi_access_rom(space->machine(), offset); | |
| 5327 | } | |
| 5328 | ||
| 5329 | /************************************************************* | |
| 5330 | ||
| 5331 | Kaiser Board KS7032 | |
| 5332 | ||
| 5333 | Games: | |
| 5334 | ||
| 5335 | iNES: | |
| 5336 | ||
| 5337 | In MESS: | |
| 5338 | ||
| 5339 | *************************************************************/ | |
| 5340 | ||
| 5341 | static void ks7032_prg_update( running_machine &machine ) | |
| 5342 | { | |
| 5343 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5344 | ||
| 5345 | prg8_67(machine, state->m_mmc_reg[4]); | |
| 5346 | prg8_89(machine, state->m_mmc_reg[1]); | |
| 5347 | prg8_ab(machine, state->m_mmc_reg[2]); | |
| 5348 | prg8_cd(machine, state->m_mmc_reg[3]); | |
| 5349 | } | |
| 5350 | ||
| 5351 | static void ks7032_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 5352 | { | |
| 5353 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 5354 | ||
| 5355 | if (state->m_IRQ_enable) | |
| 5356 | { | |
| 5357 | if (state->m_IRQ_count >= (0xffff - 114)) | |
| 5358 | { | |
| 5359 | state->m_IRQ_enable = 0; | |
| 5360 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 5361 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 5362 | } | |
| 5363 | else | |
| 5364 | state->m_IRQ_count += 114; | |
| 5365 | } | |
| 5366 | } | |
| 5367 | ||
| 5368 | static WRITE8_HANDLER( ks7032_w ) | |
| 5369 | { | |
| 5370 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5371 | LOG_MMC(("ks7032_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5372 | ||
| 5373 | switch (offset & 0x7000) | |
| 5374 | { | |
| 5375 | case 0x0000: | |
| 5376 | state->m_IRQ_count = (state->m_IRQ_count & 0xfff0) | (data & 0x0f); | |
| 5377 | break; | |
| 5378 | case 0x1000: | |
| 5379 | state->m_IRQ_count = (state->m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4); | |
| 5380 | break; | |
| 5381 | case 0x2000: | |
| 5382 | state->m_IRQ_count = (state->m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8); | |
| 5383 | break; | |
| 5384 | case 0x3000: | |
| 5385 | state->m_IRQ_count = (state->m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12); | |
| 5386 | break; | |
| 5387 | case 0x4000: | |
| 5388 | state->m_IRQ_enable = 1; | |
| 5389 | break; | |
| 5390 | case 0x6000: | |
| 5391 | state->m_mmc_latch1 = data & 0x07; | |
| 5392 | break; | |
| 5393 | case 0x7000: | |
| 5394 | state->m_mmc_reg[state->m_mmc_latch1] = data; | |
| 5395 | ks7032_prg_update(space->machine()); | |
| 5396 | break; | |
| 5397 | } | |
| 5398 | } | |
| 5399 | ||
| 5400 | /************************************************************* | |
| 5401 | ||
| 5402 | Kaiser Board KS202 | |
| 5403 | ||
| 5404 | Games: | |
| 5405 | ||
| 5406 | iNES: | |
| 5407 | ||
| 5408 | In MESS: Supported? | |
| 5409 | ||
| 5410 | *************************************************************/ | |
| 5411 | ||
| 5412 | ||
| 5413 | static WRITE8_HANDLER( ks202_w ) | |
| 5414 | { | |
| 5415 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5416 | LOG_MMC(("ks202_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5417 | ||
| 5418 | switch (offset & 0x7000) | |
| 5419 | { | |
| 5420 | case 0x0000: | |
| 5421 | state->m_IRQ_count = (state->m_IRQ_count & 0xfff0) | (data & 0x0f); | |
| 5422 | break; | |
| 5423 | case 0x1000: | |
| 5424 | state->m_IRQ_count = (state->m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4); | |
| 5425 | break; | |
| 5426 | case 0x2000: | |
| 5427 | state->m_IRQ_count = (state->m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8); | |
| 5428 | break; | |
| 5429 | case 0x3000: | |
| 5430 | state->m_IRQ_count = (state->m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12); | |
| 5431 | break; | |
| 5432 | case 0x4000: | |
| 5433 | state->m_IRQ_enable = 1; | |
| 5434 | break; | |
| 5435 | case 0x6000: | |
| 5436 | state->m_mmc_latch1 = data & 0x07; | |
| 5437 | break; | |
| 5438 | case 0x7000: | |
| 5439 | state->m_mmc_reg[state->m_mmc_latch1] = data; | |
| 5440 | ks7032_prg_update(space->machine()); | |
| 5441 | switch (offset & 0xc00) | |
| 5442 | { | |
| 5443 | case 0x800: | |
| 5444 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 5445 | break; | |
| 5446 | case 0xc00: | |
| 5447 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 5448 | break; | |
| 5449 | } | |
| 5450 | break; | |
| 5451 | } | |
| 5452 | } | |
| 5453 | ||
| 5454 | /************************************************************* | |
| 5455 | ||
| 5456 | Kaiser Board KS7017 | |
| 5457 | ||
| 5458 | Games: | |
| 5459 | ||
| 5460 | iNES: | |
| 5461 | ||
| 5462 | In MESS: Not working | |
| 5463 | ||
| 5464 | *************************************************************/ | |
| 5465 | ||
| 5466 | static void mmc_fds_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 5467 | { | |
| 5468 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 5469 | ||
| 5470 | if (state->m_IRQ_enable) | |
| 5471 | { | |
| 5472 | if (state->m_IRQ_count <= 114) | |
| 5473 | { | |
| 5474 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 5475 | state->m_IRQ_enable = 0; | |
| 5476 | state->m_IRQ_status |= 0x01; | |
| 5477 | } | |
| 5478 | else | |
| 5479 | state->m_IRQ_count -= 114; | |
| 5480 | } | |
| 5481 | } | |
| 5482 | ||
| 5483 | static WRITE8_HANDLER( ks7017_l_w ) | |
| 5484 | { | |
| 5485 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5486 | LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5487 | ||
| 5488 | offset += 0x100; | |
| 5489 | ||
| 5490 | if (offset >= 0xa00 && offset < 0xb00) | |
| 5491 | state->m_mmc_latch1 = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04); | |
| 5492 | ||
| 5493 | if (offset >= 0x1000 && offset < 0x1100) | |
| 5494 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 5495 | } | |
| 5496 | ||
| 5497 | WRITE8_HANDLER( ks7017_extra_w ) | |
| 5498 | { | |
| 5499 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5500 | LOG_MMC(("ks7017_extra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5501 | ||
| 5502 | offset += 0x20; | |
| 5503 | ||
| 5504 | if (offset == 0x0020) /* 0x4020 */ | |
| 5505 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 5506 | ||
| 5507 | if (offset == 0x0021) /* 0x4021 */ | |
| 5508 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 5509 | ||
| 5510 | if (offset == 0x0025) /* 0x4025 */ | |
| 5511 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5512 | } | |
| 5513 | ||
| 5514 | READ8_HANDLER( ks7017_extra_r ) | |
| 5515 | { | |
| 5516 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5517 | LOG_MMC(("ks7017_extra_r, offset: %04x\n", offset)); | |
| 5518 | ||
| 5519 | state->m_IRQ_status &= ~0x01; | |
| 5520 | return state->m_IRQ_status; | |
| 5521 | } | |
| 5522 | ||
| 5523 | /************************************************************* | |
| 5524 | ||
| 5525 | Bootleg Board by Kay (for Panda Prince) | |
| 5526 | ||
| 5527 | Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97 | |
| 5528 | (and its title hack MK6), UMK3, Super Lion King 2 | |
| 5529 | ||
| 5530 | MMC3 clone. This is basically KOF96 board + protection | |
| 5531 | ||
| 5532 | iNES: mapper 121 | |
| 5533 | ||
| 5534 | In MESS: Most game works, with some graphical issues. | |
| 5535 | ||
| 5536 | *************************************************************/ | |
| 5537 | ||
| 5538 | static WRITE8_HANDLER( kay_pp_l_w ) | |
| 5539 | { | |
| 5540 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5541 | LOG_MMC(("kay_pp_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5542 | offset += 0x100; | |
| 5543 | ||
| 5544 | if (offset >= 0x1000) | |
| 5545 | { | |
| 5546 | switch (data & 0x03) | |
| 5547 | { | |
| 5548 | case 0x00: | |
| 5549 | case 0x01: | |
| 5550 | state->m_mmc_reg[0] = 0x83; | |
| 5551 | break; | |
| 5552 | case 0x02: | |
| 5553 | state->m_mmc_reg[0] = 0x42; | |
| 5554 | break; | |
| 5555 | case 0x03: | |
| 5556 | state->m_mmc_reg[0] = 0x00; | |
| 5557 | break; | |
| 5558 | } | |
| 5559 | } | |
| 5560 | } | |
| 5561 | ||
| 5562 | static READ8_HANDLER( kay_pp_l_r ) | |
| 5563 | { | |
| 5564 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5565 | LOG_MMC(("kay_pp_l_r, offset: %04x\n", offset)); | |
| 5566 | offset += 0x100; | |
| 5567 | ||
| 5568 | if (offset >= 0x1000) | |
| 5569 | return state->m_mmc_reg[0]; | |
| 5570 | else | |
| 5571 | return 0xff; | |
| 5572 | } | |
| 5573 | ||
| 5574 | static void kay_pp_update_regs( running_machine &machine ) | |
| 5575 | { | |
| 5576 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5577 | ||
| 5578 | switch (state->m_mmc_reg[5] & 0x3f) | |
| 5579 | { | |
| 5580 | case 0x20: | |
| 5581 | case 0x29: | |
| 5582 | case 0x2b: | |
| 5583 | case 0x3f: | |
| 5584 | state->m_mmc_reg[7] = 1; | |
| 5585 | state->m_mmc_reg[1] = state->m_mmc_reg[6]; | |
| 5586 | break; | |
| 5587 | case 0x26: | |
| 5588 | state->m_mmc_reg[7] = 0; | |
| 5589 | state->m_mmc_reg[1] = state->m_mmc_reg[6]; | |
| 5590 | break; | |
| 5591 | case 0x2c: | |
| 5592 | state->m_mmc_reg[7] = 1; | |
| 5593 | if (state->m_mmc_reg[6]) | |
| 5594 | state->m_mmc_reg[1] = state->m_mmc_reg[6]; | |
| 5595 | break; | |
| 5596 | ||
| 5597 | case 0x28: | |
| 5598 | state->m_mmc_reg[7] = 0; | |
| 5599 | state->m_mmc_reg[2] = state->m_mmc_reg[6]; | |
| 5600 | break; | |
| 5601 | ||
| 5602 | case 0x2a: | |
| 5603 | state->m_mmc_reg[7] = 0; | |
| 5604 | state->m_mmc_reg[3] = state->m_mmc_reg[6]; | |
| 5605 | break; | |
| 5606 | ||
| 5607 | case 0x2f: | |
| 5608 | break; | |
| 5609 | ||
| 5610 | default: | |
| 5611 | state->m_mmc_reg[5] = 0; | |
| 5612 | break; | |
| 5613 | } | |
| 5614 | } | |
| 5615 | ||
| 5616 | static void kay_pp_prg_cb( running_machine &machine, int start, int bank ) | |
| 5617 | { | |
| 5618 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5619 | ||
| 5620 | if (state->m_mmc_reg[5] & 0x3f) | |
| 5621 | { | |
| 5622 | prg8_x(machine, start, bank & 0x3f); | |
| 5623 | prg8_ef(machine, state->m_mmc_reg[1]); | |
| 5624 | prg8_cd(machine, state->m_mmc_reg[2]); | |
| 5625 | prg8_ab(machine, state->m_mmc_reg[3]); | |
| 5626 | } | |
| 5627 | else | |
| 5628 | prg8_x(machine, start, bank & 0x3f); | |
| 5629 | } | |
| 5630 | ||
| 5631 | static void kay_pp_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 5632 | { | |
| 5633 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5634 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 5635 | ||
| 5636 | if ((start & 0x04) == chr_page) | |
| 5637 | bank |= 0x100; | |
| 5638 | ||
| 5639 | chr1_x(machine, start, bank, source); | |
| 5640 | } | |
| 5641 | ||
| 5642 | static WRITE8_HANDLER( kay_pp_w ) | |
| 5643 | { | |
| 5644 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5645 | LOG_MMC(("kay_pp_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5646 | ||
| 5647 | switch (offset & 0x6003) | |
| 5648 | { | |
| 5649 | case 0x0000: | |
| 5650 | txrom_w(space, offset, data); | |
| 5651 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5652 | break; | |
| 5653 | ||
| 5654 | case 0x0001: | |
| 5655 | state->m_mmc_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3) | |
| 5656 | | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5); | |
| 5657 | if (!state->m_mmc_reg[7]) | |
| 5658 | kay_pp_update_regs(space->machine()); | |
| 5659 | txrom_w(space, offset, data); | |
| 5660 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5661 | break; | |
| 5662 | ||
| 5663 | case 0x0003: | |
| 5664 | state->m_mmc_reg[5] = data; | |
| 5665 | kay_pp_update_regs(space->machine()); | |
| 5666 | txrom_w(space, 0x0000, data); | |
| 5667 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5668 | break; | |
| 5669 | ||
| 5670 | default: | |
| 5671 | txrom_w(space, offset, data); | |
| 5672 | break; | |
| 5673 | } | |
| 5674 | } | |
| 5675 | ||
| 5676 | /************************************************************* | |
| 5677 | ||
| 5678 | Bootleg Board by Kasing | |
| 5679 | ||
| 5680 | Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2, | |
| 5681 | Shisen Mahjong 2 | |
| 5682 | ||
| 5683 | MMC3 clone | |
| 5684 | ||
| 5685 | iNES: mapper 115 | |
| 5686 | ||
| 5687 | In MESS: Supported | |
| 5688 | ||
| 5689 | *************************************************************/ | |
| 5690 | ||
| 5691 | static void kasing_prg_cb( running_machine &machine, int start, int bank ) | |
| 5692 | { | |
| 5693 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5694 | if (BIT(state->m_mmc_reg[0], 7)) | |
| 5695 | prg32(machine, state->m_mmc_reg[0] >> 1); | |
| 5696 | else | |
| 5697 | prg8_x(machine, start, bank); | |
| 5698 | } | |
| 5699 | ||
| 5700 | static WRITE8_HANDLER( kasing_m_w ) | |
| 5701 | { | |
| 5702 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5703 | LOG_MMC(("kasing_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5704 | ||
| 5705 | switch (offset & 0x01) | |
| 5706 | { | |
| 5707 | case 0x00: | |
| 5708 | state->m_mmc_reg[0] = data; | |
| 5709 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5710 | break; | |
| 5711 | case 0x01: | |
| 5712 | state->m_mmc_chr_base = (data & 0x01) ? 0x100 : 0x000; | |
| 5713 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 5714 | break; | |
| 5715 | } | |
| 5716 | } | |
| 5717 | ||
| 5718 | /************************************************************* | |
| 5719 | ||
| 5720 | Bootleg Board by Magic Series | |
| 5721 | ||
| 5722 | Games: Magic Dragon | |
| 5723 | ||
| 5724 | Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8 | |
| 5725 | banks | |
| 5726 | ||
| 5727 | iNES: mapper 107 | |
| 5728 | ||
| 5729 | In MESS: Supported. | |
| 5730 | ||
| 5731 | *************************************************************/ | |
| 5732 | ||
| 5733 | static WRITE8_HANDLER( magics_md_w ) | |
| 5734 | { | |
| 5735 | LOG_MMC(("magics_md_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5736 | ||
| 5737 | prg32(space->machine(), data >> 1); | |
| 5738 | chr8(space->machine(), data, CHRROM); | |
| 5739 | } | |
| 5740 | ||
| 5741 | /************************************************************* | |
| 5742 | ||
| 5743 | Bootleg Board by Nanjing | |
| 5744 | ||
| 5745 | Games: A lot of pirate originals | |
| 5746 | ||
| 5747 | iNES: mapper 163 | |
| 5748 | ||
| 5749 | In MESS: Unsupported. | |
| 5750 | ||
| 5751 | *************************************************************/ | |
| 5752 | ||
| 5753 | static void nanjing_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 5754 | { | |
| 5755 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 5756 | ||
| 5757 | if (BIT(state->m_mmc_reg[0], 7)) | |
| 5758 | { | |
| 5759 | if (scanline == 127) | |
| 5760 | { | |
| 5761 | chr4_0(device->machine(), 1, CHRRAM); | |
| 5762 | chr4_4(device->machine(), 1, CHRRAM); | |
| 5763 | } | |
| 5764 | ||
| 5765 | if (scanline == 239) | |
| 5766 | { | |
| 5767 | chr4_0(device->machine(), 0, CHRRAM); | |
| 5768 | chr4_4(device->machine(), 0, CHRRAM); | |
| 5769 | } | |
| 5770 | } | |
| 5771 | ||
| 5772 | } | |
| 5773 | ||
| 5774 | static WRITE8_HANDLER( nanjing_l_w ) | |
| 5775 | { | |
| 5776 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5777 | LOG_MMC(("nanjing_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5778 | ||
| 5779 | offset += 0x100; | |
| 5780 | ||
| 5781 | if (offset < 0x1000) | |
| 5782 | return; | |
| 5783 | ||
| 5784 | if (offset == 0x1100) // 0x5100 | |
| 5785 | { | |
| 5786 | if (data == 6) | |
| 5787 | prg32(space->machine(), 3); | |
| 5788 | return; | |
| 5789 | } | |
| 5790 | ||
| 5791 | if (offset == 0x1101) // 0x5101 | |
| 5792 | { | |
| 5793 | UINT8 temp = state->m_mmc_count; | |
| 5794 | state->m_mmc_count = data; | |
| 5795 | ||
| 5796 | if (temp & !data) | |
| 5797 | state->m_mmc_latch2 ^= 0xff; | |
| 5798 | } | |
| 5799 | ||
| 5800 | switch (offset & 0x300) | |
| 5801 | { | |
| 5802 | case 0x000: | |
| 5803 | case 0x200: | |
| 5804 | state->m_mmc_reg[BIT(offset, 9)] = data; | |
| 5805 | if (!BIT(state->m_mmc_reg[0], 7) && ppu2c0x_get_current_scanline(state->m_ppu) <= 127) | |
| 5806 | chr8(space->machine(), 0, CHRRAM); | |
| 5807 | break; | |
| 5808 | case 0x300: | |
| 5809 | state->m_mmc_latch1 = data; | |
| 5810 | break; | |
| 5811 | } | |
| 5812 | ||
| 5813 | prg32(space->machine(), (state->m_mmc_reg[0] & 0x0f) | ((state->m_mmc_reg[1] & 0x0f) << 4)); | |
| 5814 | } | |
| 5815 | ||
| 5816 | static READ8_HANDLER( nanjing_l_r ) | |
| 5817 | { | |
| 5818 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5819 | UINT8 value = 0; | |
| 5820 | LOG_MMC(("nanjing_l_r, offset: %04x\n", offset)); | |
| 5821 | ||
| 5822 | offset += 0x100; | |
| 5823 | ||
| 5824 | if (offset < 0x1000) | |
| 5825 | return 0; | |
| 5826 | ||
| 5827 | switch (offset & 0x700) | |
| 5828 | { | |
| 5829 | case 0x100: | |
| 5830 | value = state->m_mmc_latch1; | |
| 5831 | break; | |
| 5832 | case 0x500: | |
| 5833 | value = state->m_mmc_latch2 & state->m_mmc_latch1; | |
| 5834 | break; | |
| 5835 | case 0x000: | |
| 5836 | case 0x200: | |
| 5837 | case 0x300: | |
| 5838 | case 0x400: | |
| 5839 | case 0x600: | |
| 5840 | case 0x700: | |
| 5841 | value = 4; | |
| 5842 | break; | |
| 5843 | } | |
| 5844 | return value; | |
| 5845 | } | |
| 5846 | ||
| 5847 | /************************************************************* | |
| 5848 | ||
| 5849 | Bootleg Board by Nitra | |
| 5850 | ||
| 5851 | Games: Time Diver Avenger | |
| 5852 | ||
| 5853 | This acts basically like a MMC3 with different use of write | |
| 5854 | address. | |
| 5855 | ||
| 5856 | iNES: mapper 250 | |
| 5857 | ||
| 5858 | In MESS: Supported. | |
| 5859 | ||
| 5860 | *************************************************************/ | |
| 5861 | ||
| 5862 | static WRITE8_HANDLER( nitra_w ) | |
| 5863 | { | |
| 5864 | LOG_MMC(("nitra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5865 | ||
| 5866 | txrom_w(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff); | |
| 5867 | } | |
| 5868 | ||
| 5869 | /************************************************************* | |
| 5870 | ||
| 5871 | NTDEC ASDER Bootleg Board | |
| 5872 | ||
| 5873 | Games: Cobra Mission, Fighting Hero III, Huang Di, Master | |
| 5874 | Shooter | |
| 5875 | ||
| 5876 | iNES: mapper 112 | |
| 5877 | ||
| 5878 | In MESS: Supported. | |
| 5879 | ||
| 5880 | *************************************************************/ | |
| 5881 | ||
| 5882 | static WRITE8_HANDLER( ntdec_asder_w ) | |
| 5883 | { | |
| 5884 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5885 | LOG_MMC(("ntdec_asder_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5886 | ||
| 5887 | switch (offset) | |
| 5888 | { | |
| 5889 | case 0x0000: | |
| 5890 | state->m_mmc_latch1 = data & 0x07; | |
| 5891 | break; | |
| 5892 | case 0x2000: | |
| 5893 | switch (state->m_mmc_latch1) | |
| 5894 | { | |
| 5895 | case 0: | |
| 5896 | prg8_89(space->machine(), data); | |
| 5897 | break; | |
| 5898 | case 1: | |
| 5899 | prg8_ab(space->machine(), data); | |
| 5900 | break; | |
| 5901 | case 2: | |
| 5902 | data &= 0xfe; | |
| 5903 | chr1_0(space->machine(), data, CHRROM); | |
| 5904 | chr1_1(space->machine(), data + 1, CHRROM); | |
| 5905 | break; | |
| 5906 | case 3: | |
| 5907 | data &= 0xfe; | |
| 5908 | chr1_2(space->machine(), data, CHRROM); | |
| 5909 | chr1_3(space->machine(), data + 1, CHRROM); | |
| 5910 | break; | |
| 5911 | case 4: | |
| 5912 | chr1_4(space->machine(), data, CHRROM); | |
| 5913 | break; | |
| 5914 | case 5: | |
| 5915 | chr1_5(space->machine(), data, CHRROM); | |
| 5916 | break; | |
| 5917 | case 6: | |
| 5918 | chr1_6(space->machine(), data, CHRROM); | |
| 5919 | break; | |
| 5920 | case 7: | |
| 5921 | chr1_7(space->machine(), data, CHRROM); | |
| 5922 | break; | |
| 5923 | } | |
| 5924 | break; | |
| 5925 | case 0x6000: | |
| 5926 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5927 | break; | |
| 5928 | } | |
| 5929 | } | |
| 5930 | ||
| 5931 | /************************************************************* | |
| 5932 | ||
| 5933 | Bootleg Board by NTDEC for Fighting Hero | |
| 5934 | ||
| 5935 | Games: Fighting Hero | |
| 5936 | ||
| 5937 | Very simple mapper: writes to 0x6000-0x7fff swap PRG and | |
| 5938 | CHR banks. | |
| 5939 | ||
| 5940 | iNES: mapper 193 | |
| 5941 | ||
| 5942 | In MESS: Supported. | |
| 5943 | ||
| 5944 | *************************************************************/ | |
| 5945 | ||
| 5946 | static WRITE8_HANDLER( ntdec_fh_m_w ) | |
| 5947 | { | |
| 5948 | LOG_MMC(("ntdec_fh_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5949 | ||
| 5950 | switch (offset & 0x03) | |
| 5951 | { | |
| 5952 | case 0: | |
| 5953 | chr4_0(space->machine(), data >> 2, CHRROM); | |
| 5954 | break; | |
| 5955 | case 1: | |
| 5956 | chr2_4(space->machine(), data >> 1, CHRROM); | |
| 5957 | break; | |
| 5958 | case 2: | |
| 5959 | chr2_6(space->machine(), data >> 1 , CHRROM); | |
| 5960 | break; | |
| 5961 | case 3: | |
| 5962 | prg8_89(space->machine(), data); | |
| 5963 | break; | |
| 5964 | } | |
| 5965 | } | |
| 5966 | ||
| 5967 | /************************************************************* | |
| 5968 | ||
| 5969 | Open Corp DAOU306 board | |
| 5970 | ||
| 5971 | Games: Metal Force (K) | |
| 5972 | ||
| 5973 | iNES: mapper 156 | |
| 5974 | ||
| 5975 | In MESS: Supported. | |
| 5976 | ||
| 5977 | *************************************************************/ | |
| 5978 | ||
| 5979 | static WRITE8_HANDLER( daou306_w ) | |
| 5980 | { | |
| 5981 | LOG_MMC(("daou306_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5982 | ||
| 5983 | switch (offset) | |
| 5984 | { | |
| 5985 | case 0x4000: | |
| 5986 | chr1_0(space->machine(), data, CHRROM); | |
| 5987 | break; | |
| 5988 | case 0x4001: | |
| 5989 | chr1_1(space->machine(), data, CHRROM); | |
| 5990 | break; | |
| 5991 | case 0x4002: | |
| 5992 | chr1_2(space->machine(), data, CHRROM); | |
| 5993 | break; | |
| 5994 | case 0x4003: | |
| 5995 | chr1_3(space->machine(), data, CHRROM); | |
| 5996 | break; | |
| 5997 | case 0x4008: | |
| 5998 | chr1_4(space->machine(), data, CHRROM); | |
| 5999 | break; | |
| 6000 | case 0x4009: | |
| 6001 | chr1_5(space->machine(), data, CHRROM); | |
| 6002 | break; | |
| 6003 | case 0x400a: | |
| 6004 | chr1_6(space->machine(), data, CHRROM); | |
| 6005 | break; | |
| 6006 | case 0x400b: | |
| 6007 | chr1_7(space->machine(), data, CHRROM); | |
| 6008 | break; | |
| 6009 | case 0x4010: | |
| 6010 | prg16_89ab(space->machine(), data); | |
| 6011 | break; | |
| 6012 | } | |
| 6013 | } | |
| 6014 | ||
| 6015 | /************************************************************* | |
| 6016 | ||
| 6017 | RCM GS2015 Board | |
| 6018 | ||
| 6019 | Games: Bonza, Magic Jewelry 2 | |
| 6020 | ||
| 6021 | Very simple mapper: writes to 0x8000-0xffff sets prg32 | |
| 6022 | to offset and chr8 to offset>>1 (when chrrom is present) | |
| 6023 | ||
| 6024 | iNES: mapper 216 | |
| 6025 | ||
| 6026 | In MESS: Supported. | |
| 6027 | ||
| 6028 | *************************************************************/ | |
| 6029 | ||
| 6030 | static WRITE8_HANDLER( gs2015_w ) | |
| 6031 | { | |
| 6032 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6033 | LOG_MMC(("gs2015_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6034 | ||
| 6035 | prg32(space->machine(), offset); | |
| 6036 | chr8(space->machine(), offset >> 1, state->m_mmc_chr_source); | |
| 6037 | } | |
| 6038 | ||
| 6039 | /************************************************************* | |
| 6040 | ||
| 6041 | Bootleg Board by RCM for Tetris Family | |
| 6042 | ||
| 6043 | Games: Tetris Family 9 in 1, 20 in 1 | |
| 6044 | ||
| 6045 | Simple Mapper: prg/chr/nt are swapped depending on the offset | |
| 6046 | of writes in 0x8000-0xffff. offset&0x80 set NT mirroring, | |
| 6047 | when (offset&0x30) is 0,3 prg32 is set; when it is 1,2 | |
| 6048 | two 16k prg banks are set. See below for the values used in | |
| 6049 | these banks. | |
| 6050 | ||
| 6051 | iNES: mapper 61 | |
| 6052 | ||
| 6053 | In MESS: Supported. | |
| 6054 | ||
| 6055 | *************************************************************/ | |
| 6056 | ||
| 6057 | static WRITE8_HANDLER( rcm_tf_w ) | |
| 6058 | { | |
| 6059 | LOG_MMC(("rcm_tf_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6060 | ||
| 6061 | switch (offset & 0x30) | |
| 6062 | { | |
| 6063 | case 0x00: | |
| 6064 | case 0x30: | |
| 6065 | prg32(space->machine(), offset & 0x0f); | |
| 6066 | break; | |
| 6067 | case 0x10: | |
| 6068 | case 0x20: | |
| 6069 | prg16_89ab(space->machine(), ((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); | |
| 6070 | prg16_cdef(space->machine(), ((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); | |
| 6071 | break; | |
| 6072 | } | |
| 6073 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6074 | } | |
| 6075 | ||
| 6076 | /************************************************************* | |
| 6077 | ||
| 6078 | Bootleg Board by Rex Soft | |
| 6079 | ||
| 6080 | Games: Dragon Ball Z 5, Dragon Ball Z Super | |
| 6081 | ||
| 6082 | MMC3 clone | |
| 6083 | ||
| 6084 | iNES: mapper 12 | |
| 6085 | ||
| 6086 | In MESS: Supported | |
| 6087 | ||
| 6088 | *************************************************************/ | |
| 6089 | ||
| 6090 | static WRITE8_HANDLER( rex_dbz_l_w ) | |
| 6091 | { | |
| 6092 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6093 | LOG_MMC(("rex_dbz_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6094 | ||
| 6095 | state->m_mmc_reg[0] = data; | |
| 6096 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6097 | } | |
| 6098 | ||
| 6099 | /* we would need to use this read handler in 0x6000-0x7fff as well */ | |
| 6100 | static READ8_HANDLER( rex_dbz_l_r ) | |
| 6101 | { | |
| 6102 | LOG_MMC(("rex_dbz_l_r, offset: %04x\n", offset)); | |
| 6103 | return 0x01; | |
| 6104 | } | |
| 6105 | ||
| 6106 | static void rex_dbz_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 6107 | { | |
| 6108 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6109 | int shift = (start < 4) ? 8 : 4; | |
| 6110 | ||
| 6111 | bank |= ((state->m_mmc_reg[0] << shift) & 0x100); | |
| 6112 | chr1_x(machine, start, bank, source); | |
| 6113 | } | |
| 6114 | ||
| 6115 | /************************************************************* | |
| 6116 | ||
| 6117 | Rex Soft SL1632 Board | |
| 6118 | ||
| 6119 | Games: Samurai Spirits | |
| 6120 | ||
| 6121 | MMC3 clone | |
| 6122 | ||
| 6123 | iNES: mapper 14 | |
| 6124 | ||
| 6125 | In MESS: Supported | |
| 6126 | ||
| 6127 | *************************************************************/ | |
| 6128 | ||
| 6129 | static void rex_sl1632_set_prg( running_machine &machine, int prg_base, int prg_mask ) | |
| 6130 | { | |
| 6131 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6132 | ||
| 6133 | if (state->m_mmc_reg[0] & 0x02) | |
| 6134 | { | |
| 6135 | mmc3_set_prg(machine, prg_base, prg_mask); | |
| 6136 | } | |
| 6137 | else | |
| 6138 | { | |
| 6139 | prg8_89(machine, state->m_mmc_extra_bank[0]); | |
| 6140 | prg8_ab(machine, state->m_mmc_extra_bank[1]); | |
| 6141 | prg8_cd(machine, state->m_mmc_extra_bank[2]); | |
| 6142 | prg8_ef(machine, state->m_mmc_extra_bank[3]); | |
| 6143 | } | |
| 6144 | } | |
| 6145 | ||
| 6146 | static void rex_sl1632_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask ) | |
| 6147 | { | |
| 6148 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6149 | static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1}; | |
| 6150 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 6151 | UINT8 bank[8]; | |
| 6152 | UINT8 chr_base2[8]; | |
| 6153 | int i; | |
| 6154 | ||
| 6155 | if (state->m_mmc_reg[0] & 0x02) | |
| 6156 | { | |
| 6157 | for(i = 0; i < 8; i++) | |
| 6158 | { | |
| 6159 | bank[i] = state->m_mmc_vrom_bank[i]; | |
| 6160 | chr_base2[i] = chr_base | ((state->m_mmc_reg[0] << conv_table[i]) & 0x100); | |
| 6161 | } | |
| 6162 | } | |
| 6163 | else | |
| 6164 | { | |
| 6165 | for(i = 0; i < 8; i++) | |
| 6166 | { | |
| 6167 | bank[i] = state->m_mmc_extra_bank[i + 4]; // first 4 state->m_mmc_extra_banks are PRG | |
| 6168 | chr_base2[i] = chr_base; | |
| 6169 | } | |
| 6170 | } | |
| 6171 | ||
| 6172 | chr1_x(machine, chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr); | |
| 6173 | chr1_x(machine, chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr); | |
| 6174 | chr1_x(machine, chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr); | |
| 6175 | chr1_x(machine, chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr); | |
| 6176 | chr1_x(machine, chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr); | |
| 6177 | chr1_x(machine, chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr); | |
| 6178 | chr1_x(machine, chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr); | |
| 6179 | chr1_x(machine, chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr); | |
| 6180 | } | |
| 6181 | ||
| 6182 | static WRITE8_HANDLER( rex_sl1632_w ) | |
| 6183 | { | |
| 6184 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6185 | UINT8 map14_helper1, map14_helper2, mmc_helper, cmd; | |
| 6186 | LOG_MMC(("rex_sl1632_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6187 | ||
| 6188 | if (offset == 0x2131) | |
| 6189 | { | |
| 6190 | state->m_mmc_reg[0] = data; | |
| 6191 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6192 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6193 | ||
| 6194 | if (!(state->m_mmc_reg[0] & 0x02)) | |
| 6195 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6196 | } | |
| 6197 | ||
| 6198 | if (state->m_mmc_reg[0] & 0x02) | |
| 6199 | { | |
| 6200 | switch (offset & 0x6001) | |
| 6201 | { | |
| 6202 | case 0x0000: | |
| 6203 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 6204 | state->m_mmc3_latch = data; | |
| 6205 | ||
| 6206 | /* Has PRG Mode changed? */ | |
| 6207 | if (mmc_helper & 0x40) | |
| 6208 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6209 | ||
| 6210 | /* Has CHR Mode changed? */ | |
| 6211 | if (mmc_helper & 0x80) | |
| 6212 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6213 | break; | |
| 6214 | ||
| 6215 | case 0x0001: | |
| 6216 | cmd = state->m_mmc3_latch & 0x07; | |
| 6217 | switch (cmd) | |
| 6218 | { | |
| 6219 | case 0: case 1: // these have to be changed due to the different way rex_sl1632_set_chr works (it handles 1k banks)! | |
| 6220 | state->m_mmc_vrom_bank[2 * cmd] = data; | |
| 6221 | state->m_mmc_vrom_bank[2 * cmd + 1] = data; | |
| 6222 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6223 | break; | |
| 6224 | case 2: case 3: case 4: case 5: | |
| 6225 | state->m_mmc_vrom_bank[cmd + 2] = data; | |
| 6226 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6227 | break; | |
| 6228 | case 6: | |
| 6229 | case 7: | |
| 6230 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 6231 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6232 | break; | |
| 6233 | } | |
| 6234 | break; | |
| 6235 | ||
| 6236 | case 0x2000: | |
| 6237 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 6238 | break; | |
| 6239 | ||
| 6240 | default: | |
| 6241 | txrom_w(space, offset, data); | |
| 6242 | break; | |
| 6243 | } | |
| 6244 | } | |
| 6245 | else if (offset >= 0x3000 && offset <= 0x6003 ) | |
| 6246 | { | |
| 6247 | map14_helper1 = (offset & 0x01) << 2; | |
| 6248 | offset = ((offset & 0x02) | (offset >> 10)) >> 1; | |
| 6249 | map14_helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 state->m_mmc_extra_banks are for PRG! | |
| 6250 | state->m_mmc_extra_bank[map14_helper2] = (state->m_mmc_extra_bank[map14_helper2] & (0xf0 >> map14_helper1)) | ((data & 0x0f) << map14_helper1); | |
| 6251 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6252 | } | |
| 6253 | else | |
| 6254 | { | |
| 6255 | switch (offset & 0x7003) | |
| 6256 | { | |
| 6257 | case 0x0000: | |
| 6258 | case 0x2000: | |
| 6259 | state->m_mmc_extra_bank[offset >> 13] = data; | |
| 6260 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6261 | break; | |
| 6262 | ||
| 6263 | case 0x1000: | |
| 6264 | state->m_mmc_reg[1] = data; | |
| 6265 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6266 | break; | |
| 6267 | } | |
| 6268 | } | |
| 6269 | } | |
| 6270 | ||
| 6271 | /************************************************************* | |
| 6272 | ||
| 6273 | Rumblestation Board | |
| 6274 | ||
| 6275 | Games: Rumblestation 15 in 1 | |
| 6276 | ||
| 6277 | iNES: mapper 46 | |
| 6278 | ||
| 6279 | In MESS: Supported. | |
| 6280 | ||
| 6281 | *************************************************************/ | |
| 6282 | ||
| 6283 | static WRITE8_HANDLER( rumblestation_m_w ) | |
| 6284 | { | |
| 6285 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6286 | LOG_MMC(("rumblestation_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6287 | ||
| 6288 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x01) | ((data & 0x0f) << 1); | |
| 6289 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x07) | ((data & 0xf0) >> 1); | |
| 6290 | prg32(space->machine(), state->m_mmc_prg_bank[0]); | |
| 6291 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6292 | } | |
| 6293 | ||
| 6294 | static WRITE8_HANDLER( rumblestation_w ) | |
| 6295 | { | |
| 6296 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6297 | LOG_MMC(("rumblestation_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6298 | ||
| 6299 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & ~0x01) | (data & 0x01); | |
| 6300 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x07) | ((data & 0x70) >> 4); | |
| 6301 | prg32(space->machine(), state->m_mmc_prg_bank[0]); | |
| 6302 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6303 | } | |
| 6304 | ||
| 6305 | /************************************************************* | |
| 6306 | ||
| 6307 | Sachen 74x374 bootleg boards | |
| 6308 | ||
| 6309 | Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy, | |
| 6310 | Olympic IQ, Poker II, Tasac [150], Poker III [243] | |
| 6311 | ||
| 6312 | iNES: mappers 150 & 243 | |
| 6313 | ||
| 6314 | *************************************************************/ | |
| 6315 | ||
| 6316 | static void sachen_set_mirror( running_machine &machine, UINT8 nt ) // used by mappers 137, 138, 139, 141 | |
| 6317 | { | |
| 6318 | switch (nt) | |
| 6319 | { | |
| 6320 | case 0: | |
| 6321 | case 1: | |
| 6322 | set_nt_mirroring(machine, nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6323 | break; | |
| 6324 | case 2: | |
| 6325 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 6326 | set_nt_page(machine, 1, CIRAM, 1, 1); | |
| 6327 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 6328 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 6329 | break; | |
| 6330 | case 3: | |
| 6331 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 6332 | break; | |
| 6333 | default: | |
| 6334 | LOG_MMC(("Mapper set NT to invalid value %02x", nt)); | |
| 6335 | break; | |
| 6336 | } | |
| 6337 | } | |
| 6338 | ||
| 6339 | static WRITE8_HANDLER( sachen_74x374_l_w ) | |
| 6340 | { | |
| 6341 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6342 | LOG_MMC(("sachen_74x374_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6343 | ||
| 6344 | /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6345 | if (!(offset & 0x100)) | |
| 6346 | { | |
| 6347 | if (!(offset & 0x01)) | |
| 6348 | state->m_mmc_latch1 = data & 0x07; | |
| 6349 | else | |
| 6350 | { | |
| 6351 | switch (state->m_mmc_latch1) | |
| 6352 | { | |
| 6353 | case 0x02: | |
| 6354 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08); | |
| 6355 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6356 | prg32(space->machine(), data & 0x01); | |
| 6357 | break; | |
| 6358 | case 0x04: | |
| 6359 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x04) | ((data << 2) & 0x04); | |
| 6360 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6361 | break; | |
| 6362 | case 0x05: | |
| 6363 | prg32(space->machine(), data & 0x07); | |
| 6364 | break; | |
| 6365 | case 0x06: | |
| 6366 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x03) | ((data << 0) & 0x03); | |
| 6367 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6368 | break; | |
| 6369 | case 0x07: | |
| 6370 | sachen_set_mirror(space->machine(), (data >> 1) & 0x03); | |
| 6371 | break; | |
| 6372 | default: | |
| 6373 | break; | |
| 6374 | } | |
| 6375 | } | |
| 6376 | } | |
| 6377 | } | |
| 6378 | ||
| 6379 | static READ8_HANDLER( sachen_74x374_l_r ) | |
| 6380 | { | |
| 6381 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6382 | LOG_MMC(("sachen_74x374_l_r, offset: %04x", offset)); | |
| 6383 | ||
| 6384 | /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6385 | if (!(offset & 0x100)) | |
| 6386 | return (~state->m_mmc_latch1 & 0x3f) /* ^ dips*/; // we would need to check the Dips here | |
| 6387 | else | |
| 6388 | return 0; | |
| 6389 | } | |
| 6390 | ||
| 6391 | static WRITE8_HANDLER( sachen_74x374a_l_w ) | |
| 6392 | { | |
| 6393 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6394 | LOG_MMC(("sachen_74x374a_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6395 | ||
| 6396 | /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6397 | if (!(offset & 0x100)) | |
| 6398 | { | |
| 6399 | if (!(offset & 0x01)) | |
| 6400 | state->m_mmc_latch1 = data; | |
| 6401 | else | |
| 6402 | { | |
| 6403 | switch (state->m_mmc_latch1 & 0x07) | |
| 6404 | { | |
| 6405 | case 0x00: | |
| 6406 | prg32(space->machine(), 0); | |
| 6407 | chr8(space->machine(), 3, CHRROM); | |
| 6408 | break; | |
| 6409 | case 0x02: | |
| 6410 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08); | |
| 6411 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6412 | break; | |
| 6413 | case 0x04: | |
| 6414 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x01) | ((data << 0) & 0x01); | |
| 6415 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6416 | break; | |
| 6417 | case 0x05: | |
| 6418 | prg32(space->machine(), data & 0x01); | |
| 6419 | break; | |
| 6420 | case 0x06: | |
| 6421 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x06) | ((data << 1) & 0x06); | |
| 6422 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6423 | break; | |
| 6424 | case 0x07: | |
| 6425 | sachen_set_mirror(space->machine(), BIT(data, 0)); | |
| 6426 | break; | |
| 6427 | default: | |
| 6428 | break; | |
| 6429 | } | |
| 6430 | } | |
| 6431 | } | |
| 6432 | } | |
| 6433 | ||
| 6434 | /************************************************************* | |
| 6435 | ||
| 6436 | Sachen S8259 bootleg boards | |
| 6437 | ||
| 6438 | iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D) | |
| 6439 | ||
| 6440 | *************************************************************/ | |
| 6441 | ||
| 6442 | static void common_s8259_write_handler( address_space *space, offs_t offset, UINT8 data, int board ) | |
| 6443 | { | |
| 6444 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6445 | UINT8 bank_helper1, bank_helper2, shift, add1, add2, add3; | |
| 6446 | ||
| 6447 | /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6448 | if (!(offset & 0x100)) | |
| 6449 | { | |
| 6450 | if (!(offset & 0x01)) | |
| 6451 | state->m_mmc_latch1 = data & 0x07; | |
| 6452 | else | |
| 6453 | { | |
| 6454 | state->m_sachen_reg[state->m_mmc_latch1] = data; | |
| 6455 | ||
| 6456 | switch (state->m_mmc_latch1) | |
| 6457 | { | |
| 6458 | case 0x05: | |
| 6459 | prg32(space->machine(), data); | |
| 6460 | break; | |
| 6461 | case 0x07: | |
| 6462 | sachen_set_mirror(space->machine(), BIT(data, 0) ? 0 : (data >> 1) & 0x03); | |
| 6463 | break; | |
| 6464 | default: | |
| 6465 | if (board == SACHEN_8259D) | |
| 6466 | { | |
| 6467 | if (state->m_mmc_chr_source == CHRROM) | |
| 6468 | { | |
| 6469 | chr1_0(space->machine(), (state->m_sachen_reg[0] & 0x07), CHRROM); | |
| 6470 | chr1_1(space->machine(), (state->m_sachen_reg[1] & 0x07) | (state->m_sachen_reg[4] << 4 & 0x10), CHRROM); | |
| 6471 | chr1_2(space->machine(), (state->m_sachen_reg[2] & 0x07) | (state->m_sachen_reg[4] << 3 & 0x10), CHRROM); | |
| 6472 | chr1_3(space->machine(), (state->m_sachen_reg[3] & 0x07) | (state->m_sachen_reg[4] << 2 & 0x10) | (state->m_sachen_reg[6] << 3 & 0x08), CHRROM); | |
| 6473 | } | |
| 6474 | } | |
| 6475 | else | |
| 6476 | { | |
| 6477 | bank_helper1 = state->m_sachen_reg[7] & 0x01; | |
| 6478 | bank_helper2 = (state->m_sachen_reg[4] & 0x07) << 3; | |
| 6479 | shift = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 2 : 0; | |
| 6480 | add1 = (board == SACHEN_8259B) ? 0 : 1; | |
| 6481 | add2 = (board == SACHEN_8259C) ? 2 : 0; | |
| 6482 | add3 = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 3 : 0; | |
| 6483 | ||
| 6484 | if (state->m_mmc_chr_source == CHRROM) | |
| 6485 | { | |
| 6486 | chr2_0(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << shift, CHRROM); | |
| 6487 | chr2_2(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << shift | add1, CHRROM); | |
| 6488 | chr2_4(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << shift | add2, CHRROM); | |
| 6489 | chr2_6(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << shift | add3, CHRROM); | |
| 6490 | } | |
| 6491 | } | |
| 6492 | break; | |
| 6493 | } | |
| 6494 | } | |
| 6495 | } | |
| 6496 | } | |
| 6497 | ||
| 6498 | static WRITE8_HANDLER( s8259_l_w ) | |
| 6499 | { | |
| 6500 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6501 | LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", state->m_pcb_id, offset, data)); | |
| 6502 | ||
| 6503 | common_s8259_write_handler(space, offset, data, state->m_pcb_id); | |
| 6504 | } | |
| 6505 | ||
| 6506 | static WRITE8_HANDLER( s8259_m_w ) | |
| 6507 | { | |
| 6508 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6509 | LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", state->m_pcb_id, offset, data)); | |
| 6510 | ||
| 6511 | common_s8259_write_handler(space, (offset + 0x100) & 0xfff, data, state->m_pcb_id); | |
| 6512 | } | |
| 6513 | ||
| 6514 | ||
| 6515 | /************************************************************* | |
| 6516 | ||
| 6517 | Sachen SA009 bootleg boards | |
| 6518 | ||
| 6519 | Games: Pipe 5 | |
| 6520 | ||
| 6521 | iNES: mapper 160 | |
| 6522 | ||
| 6523 | In MESS: Supported. | |
| 6524 | ||
| 6525 | *************************************************************/ | |
| 6526 | ||
| 6527 | static WRITE8_HANDLER( sa009_l_w ) | |
| 6528 | { | |
| 6529 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6530 | LOG_MMC(("sa009_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6531 | ||
| 6532 | chr8(space->machine(), data, state->m_mmc_chr_source); | |
| 6533 | } | |
| 6534 | ||
| 6535 | /************************************************************* | |
| 6536 | ||
| 6537 | Sachen SA0036 bootleg boards | |
| 6538 | ||
| 6539 | Games: Taiwan Mahjong 16 | |
| 6540 | ||
| 6541 | iNES: mapper 149 | |
| 6542 | ||
| 6543 | In MESS: Supported. | |
| 6544 | ||
| 6545 | *************************************************************/ | |
| 6546 | ||
| 6547 | static WRITE8_HANDLER( sa0036_w ) | |
| 6548 | { | |
| 6549 | LOG_MMC(("sa0036_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6550 | ||
| 6551 | chr8(space->machine(), data >> 7, CHRROM); | |
| 6552 | } | |
| 6553 | ||
| 6554 | /************************************************************* | |
| 6555 | ||
| 6556 | Sachen SA0037 bootleg boards | |
| 6557 | ||
| 6558 | Games: Mahjong World, Shisen Mahjong | |
| 6559 | ||
| 6560 | iNES: mapper 148 | |
| 6561 | ||
| 6562 | In MESS: Supported. | |
| 6563 | ||
| 6564 | *************************************************************/ | |
| 6565 | ||
| 6566 | static WRITE8_HANDLER( sa0037_w ) | |
| 6567 | { | |
| 6568 | LOG_MMC(("sa0037_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6569 | ||
| 6570 | prg32(space->machine(), data >> 3); | |
| 6571 | chr8(space->machine(), data, CHRROM); | |
| 6572 | } | |
| 6573 | ||
| 6574 | /************************************************************* | |
| 6575 | ||
| 6576 | Sachen SA72007 bootleg boards | |
| 6577 | ||
| 6578 | Games: Sidewinder | |
| 6579 | ||
| 6580 | iNES: mapper 145 | |
| 6581 | ||
| 6582 | In MESS: Supported. | |
| 6583 | ||
| 6584 | *************************************************************/ | |
| 6585 | ||
| 6586 | static WRITE8_HANDLER( sa72007_l_w ) | |
| 6587 | { | |
| 6588 | LOG_MMC(("sa72007_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6589 | ||
| 6590 | /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6591 | if (!(offset & 0x100)) | |
| 6592 | chr8(space->machine(), data >> 7, CHRROM); | |
| 6593 | } | |
| 6594 | ||
| 6595 | /************************************************************* | |
| 6596 | ||
| 6597 | Sachen SA72008 bootleg boards | |
| 6598 | ||
| 6599 | Games: Jovial Race, Qi Wang | |
| 6600 | ||
| 6601 | iNES: mapper 133 | |
| 6602 | ||
| 6603 | In MESS: Supported. | |
| 6604 | ||
| 6605 | *************************************************************/ | |
| 6606 | ||
| 6607 | static WRITE8_HANDLER( sa72008_l_w ) | |
| 6608 | { | |
| 6609 | LOG_MMC(("sa72008_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6610 | ||
| 6611 | prg32(space->machine(), data >> 2); | |
| 6612 | chr8(space->machine(), data, CHRROM); | |
| 6613 | } | |
| 6614 | ||
| 6615 | /************************************************************* | |
| 6616 | ||
| 6617 | Sachen TCA-01 bootleg boards | |
| 6618 | ||
| 6619 | iNES: mapper 143 | |
| 6620 | ||
| 6621 | Games: Dancing Blocks, Magic Mathematic | |
| 6622 | ||
| 6623 | In MESS: Supported. | |
| 6624 | ||
| 6625 | *************************************************************/ | |
| 6626 | ||
| 6627 | static READ8_HANDLER( tca01_l_r ) | |
| 6628 | { | |
| 6629 | LOG_MMC(("tca01_l_r, offset: %04x\n", offset)); | |
| 6630 | ||
| 6631 | /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6632 | if (!(offset & 0x100)) | |
| 6633 | return (~offset & 0x3f) | 0x40; | |
| 6634 | else | |
| 6635 | return 0x00; | |
| 6636 | } | |
| 6637 | ||
| 6638 | /************************************************************* | |
| 6639 | ||
| 6640 | Sachen TCU-01 bootleg boards | |
| 6641 | ||
| 6642 | Games: Challenge of the Dragon, Chinese Kungfu | |
| 6643 | ||
| 6644 | iNES: mapper 147 | |
| 6645 | ||
| 6646 | In MESS: Supported. | |
| 6647 | ||
| 6648 | *************************************************************/ | |
| 6649 | ||
| 6650 | static WRITE8_HANDLER( tcu01_l_w ) | |
| 6651 | { | |
| 6652 | LOG_MMC(("tcu01_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6653 | ||
| 6654 | if ((offset & 0x103) == 0x002) | |
| 6655 | { | |
| 6656 | prg32(space->machine(), ((data >> 6) & 0x02) | ((data >> 2) & 0x01)); | |
| 6657 | chr8(space->machine(), data >> 3, CHRROM); | |
| 6658 | } | |
| 6659 | } | |
| 6660 | ||
| 6661 | static WRITE8_HANDLER( tcu01_m_w ) | |
| 6662 | { | |
| 6663 | LOG_MMC(("tcu01_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6664 | ||
| 6665 | tcu01_l_w(space, (offset + 0x100) & 0xfff, data); | |
| 6666 | } | |
| 6667 | ||
| 6668 | static WRITE8_HANDLER( tcu01_w ) | |
| 6669 | { | |
| 6670 | LOG_MMC(("tcu01_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6671 | ||
| 6672 | tcu01_l_w(space, (offset + 0x100) & 0xfff, data); | |
| 6673 | } | |
| 6674 | ||
| 6675 | /************************************************************* | |
| 6676 | ||
| 6677 | Sachen TCU-02 bootleg boards | |
| 6678 | ||
| 6679 | Games: Mei Loi Siu Ji | |
| 6680 | ||
| 6681 | iNES: mapper 136 | |
| 6682 | ||
| 6683 | In MESS: Supported. | |
| 6684 | ||
| 6685 | *************************************************************/ | |
| 6686 | ||
| 6687 | static WRITE8_HANDLER( tcu02_l_w ) | |
| 6688 | { | |
| 6689 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6690 | LOG_MMC(("tcu02_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6691 | ||
| 6692 | if ((offset & 0x103) == 0x002) | |
| 6693 | { | |
| 6694 | state->m_mmc_latch1 = (data & 0x30) | ((data + 3) & 0x0f); | |
| 6695 | chr8(space->machine(), state->m_mmc_latch1, CHRROM); | |
| 6696 | } | |
| 6697 | } | |
| 6698 | ||
| 6699 | static READ8_HANDLER( tcu02_l_r ) | |
| 6700 | { | |
| 6701 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6702 | LOG_MMC(("tcu02_l_r, offset: %04x\n", offset)); | |
| 6703 | ||
| 6704 | if ((offset & 0x103) == 0x000) | |
| 6705 | return state->m_mmc_latch1 | 0x40; | |
| 6706 | else | |
| 6707 | return 0x00; | |
| 6708 | } | |
| 6709 | ||
| 6710 | ||
| 6711 | /************************************************************* | |
| 6712 | ||
| 6713 | Subor bootleg board Type 0 | |
| 6714 | ||
| 6715 | iNES: mapper 167 | |
| 6716 | ||
| 6717 | *************************************************************/ | |
| 6718 | ||
| 6719 | static WRITE8_HANDLER( subor0_w ) | |
| 6720 | { | |
| 6721 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6722 | UINT8 subor_helper1, subor_helper2; | |
| 6723 | LOG_MMC(("subor0_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6724 | ||
| 6725 | state->m_subor_reg[(offset >> 13) & 0x03] = data; | |
| 6726 | subor_helper1 = ((state->m_subor_reg[0] ^ state->m_subor_reg[1]) << 1) & 0x20; | |
| 6727 | subor_helper2 = ((state->m_subor_reg[2] ^ state->m_subor_reg[3]) << 0) & 0x1f; | |
| 6728 | ||
| 6729 | if (state->m_subor_reg[1] & 0x08) | |
| 6730 | { | |
| 6731 | subor_helper1 += subor_helper2 & 0xfe; | |
| 6732 | subor_helper2 = subor_helper1; | |
| 6733 | subor_helper1 += 1; | |
| 6734 | } | |
| 6735 | else if (state->m_subor_reg[1] & 0x04) | |
| 6736 | { | |
| 6737 | subor_helper2 += subor_helper1; | |
| 6738 | subor_helper1 = 0x1f; | |
| 6739 | } | |
| 6740 | else | |
| 6741 | { | |
| 6742 | subor_helper1 += subor_helper2; | |
| 6743 | subor_helper2 = 0x20; | |
| 6744 | } | |
| 6745 | ||
| 6746 | prg16_89ab(space->machine(), subor_helper1); | |
| 6747 | prg16_cdef(space->machine(), subor_helper2); | |
| 6748 | } | |
| 6749 | ||
| 6750 | /************************************************************* | |
| 6751 | ||
| 6752 | Subor bootleg board Type 1 | |
| 6753 | ||
| 6754 | iNES: mapper 166 | |
| 6755 | ||
| 6756 | *************************************************************/ | |
| 6757 | ||
| 6758 | static WRITE8_HANDLER( subor1_w ) | |
| 6759 | { | |
| 6760 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6761 | UINT8 subor_helper1, subor_helper2; | |
| 6762 | LOG_MMC(("subor1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6763 | ||
| 6764 | state->m_subor_reg[(offset >> 13) & 0x03] = data; | |
| 6765 | subor_helper1 = ((state->m_subor_reg[0] ^ state->m_subor_reg[1]) << 1) & 0x20; | |
| 6766 | subor_helper2 = ((state->m_subor_reg[2] ^ state->m_subor_reg[3]) << 0) & 0x1f; | |
| 6767 | ||
| 6768 | if (state->m_subor_reg[1] & 0x08) | |
| 6769 | { | |
| 6770 | subor_helper1 += subor_helper2 & 0xfe; | |
| 6771 | subor_helper2 = subor_helper1; | |
| 6772 | subor_helper2 += 1; | |
| 6773 | } | |
| 6774 | else if (state->m_subor_reg[1] & 0x04) | |
| 6775 | { | |
| 6776 | subor_helper2 += subor_helper1; | |
| 6777 | subor_helper1 = 0x1f; | |
| 6778 | } | |
| 6779 | else | |
| 6780 | { | |
| 6781 | subor_helper1 += subor_helper2; | |
| 6782 | subor_helper2 = 0x07; | |
| 6783 | } | |
| 6784 | ||
| 6785 | prg16_89ab(space->machine(), subor_helper1); | |
| 6786 | prg16_cdef(space->machine(), subor_helper2); | |
| 6787 | } | |
| 6788 | ||
| 6789 | /************************************************************* | |
| 6790 | ||
| 6791 | Bootleg Board by Super Game | |
| 6792 | ||
| 6793 | Games: Boogerman, Mortal Kombat III | |
| 6794 | ||
| 6795 | MMC3 clone. Also, it probably needs a hack to support both | |
| 6796 | variants (Boogerman & MK3). | |
| 6797 | ||
| 6798 | iNES: mapper 215 | |
| 6799 | ||
| 6800 | In MESS: Preliminary support. | |
| 6801 | ||
| 6802 | *************************************************************/ | |
| 6803 | ||
| 6804 | static void sgame_boog_prg_cb( running_machine &machine, int start, int bank ) | |
| 6805 | { | |
| 6806 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6807 | if (!(state->m_mmc_reg[0] & 0x80)) // if this is != 0 we should never even arrive here | |
| 6808 | { | |
| 6809 | if (state->m_mmc_reg[1] & 0x08) | |
| 6810 | bank = (bank & 0x1f) | 0x20; | |
| 6811 | else | |
| 6812 | bank = (bank & 0x0f) | (state->m_mmc_reg[1] & 0x10); | |
| 6813 | ||
| 6814 | prg8_x(machine, start, bank); | |
| 6815 | } | |
| 6816 | } | |
| 6817 | ||
| 6818 | static void sgame_boog_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 6819 | { | |
| 6820 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6821 | ||
| 6822 | if ((state->m_mmc_reg[1] & 0x04)) | |
| 6823 | bank |= 0x100; | |
| 6824 | else | |
| 6825 | bank = (bank & 0x7f) | ((state->m_mmc_reg[1] & 0x10) << 3); | |
| 6826 | ||
| 6827 | chr1_x(machine, start, bank, source); | |
| 6828 | } | |
| 6829 | ||
| 6830 | static void sgame_boog_set_prg( running_machine &machine ) | |
| 6831 | { | |
| 6832 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6833 | if (state->m_mmc_reg[0] & 0x80) | |
| 6834 | { | |
| 6835 | prg16_89ab(machine, (state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10)); | |
| 6836 | prg16_cdef(machine, (state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10)); | |
| 6837 | } | |
| 6838 | else | |
| 6839 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6840 | } | |
| 6841 | ||
| 6842 | static WRITE8_HANDLER( sgame_boog_l_w ) | |
| 6843 | { | |
| 6844 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6845 | LOG_MMC(("sgame_boog_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6846 | offset += 0x100; | |
| 6847 | ||
| 6848 | if (offset == 0x1000) | |
| 6849 | { | |
| 6850 | state->m_mmc_reg[0] = data; | |
| 6851 | sgame_boog_set_prg(space->machine()); | |
| 6852 | } | |
| 6853 | else if (offset == 0x1001) | |
| 6854 | { | |
| 6855 | state->m_mmc_reg[1] = data; | |
| 6856 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6857 | } | |
| 6858 | else if (offset == 0x1007) | |
| 6859 | { | |
| 6860 | state->m_mmc3_latch = 0; | |
| 6861 | state->m_mmc_reg[2] = data; | |
| 6862 | sgame_boog_set_prg(space->machine()); | |
| 6863 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6864 | } | |
| 6865 | } | |
| 6866 | ||
| 6867 | static WRITE8_HANDLER( sgame_boog_m_w ) | |
| 6868 | { | |
| 6869 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6870 | LOG_MMC(("sgame_boog_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6871 | ||
| 6872 | if (offset == 0x0000) | |
| 6873 | { | |
| 6874 | state->m_mmc_reg[0] = data; | |
| 6875 | sgame_boog_set_prg(space->machine()); | |
| 6876 | } | |
| 6877 | else if (offset == 0x0001) | |
| 6878 | { | |
| 6879 | state->m_mmc_reg[1] = data; | |
| 6880 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6881 | } | |
| 6882 | else if (offset == 0x0007) | |
| 6883 | { | |
| 6884 | state->m_mmc3_latch = 0; | |
| 6885 | state->m_mmc_reg[2] = data; | |
| 6886 | sgame_boog_set_prg(space->machine()); | |
| 6887 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6888 | } | |
| 6889 | } | |
| 6890 | ||
| 6891 | static WRITE8_HANDLER( sgame_boog_w ) | |
| 6892 | { | |
| 6893 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6894 | static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4}; | |
| 6895 | LOG_MMC(("sgame_boog_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6896 | ||
| 6897 | switch (offset & 0x6001) | |
| 6898 | { | |
| 6899 | case 0x0000: | |
| 6900 | if (!state->m_mmc_reg[2]) | |
| 6901 | txrom_w(space, 0x0000, data); | |
| 6902 | break; | |
| 6903 | ||
| 6904 | case 0x0001: | |
| 6905 | if (!state->m_mmc_reg[2]) | |
| 6906 | txrom_w(space, 0x0001, data); | |
| 6907 | else if (state->m_mmc_reg[3] && ((state->m_mmc_reg[0] & 0x80) == 0 || (state->m_mmc_latch1 & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter! | |
| 6908 | { | |
| 6909 | state->m_mmc_reg[3] = 0; | |
| 6910 | txrom_w(space, 0x0001, data); | |
| 6911 | } | |
| 6912 | break; | |
| 6913 | ||
| 6914 | case 0x2000: | |
| 6915 | if (!state->m_mmc_reg[2]) | |
| 6916 | txrom_w(space, 0x2000, data); | |
| 6917 | else | |
| 6918 | { | |
| 6919 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 6920 | state->m_mmc_reg[3] = 1; | |
| 6921 | txrom_w(space, 0x0000, data); | |
| 6922 | break; | |
| 6923 | } | |
| 6924 | break; | |
| 6925 | ||
| 6926 | case 0x4000: | |
| 6927 | if (!state->m_mmc_reg[2]) | |
| 6928 | txrom_w(space, 0x4000, data); | |
| 6929 | else | |
| 6930 | set_nt_mirroring(space->machine(), ((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6931 | break; | |
| 6932 | ||
| 6933 | case 0x4001: | |
| 6934 | if (!state->m_mmc_reg[2]) | |
| 6935 | txrom_w(space, 0x4001, data); | |
| 6936 | else | |
| 6937 | txrom_w(space, 0x6001, data); | |
| 6938 | break; | |
| 6939 | ||
| 6940 | case 0x6001: | |
| 6941 | if (!state->m_mmc_reg[2]) | |
| 6942 | txrom_w(space, 0x6001, data); | |
| 6943 | else | |
| 6944 | { | |
| 6945 | txrom_w(space, 0x4000, data); | |
| 6946 | txrom_w(space, 0x4001, data); | |
| 6947 | } | |
| 6948 | break; | |
| 6949 | ||
| 6950 | default: | |
| 6951 | txrom_w(space, offset, data); | |
| 6952 | break; | |
| 6953 | } | |
| 6954 | } | |
| 6955 | ||
| 6956 | /************************************************************* | |
| 6957 | ||
| 6958 | Bootleg Board by Super Game | |
| 6959 | ||
| 6960 | Games: The Lion King | |
| 6961 | ||
| 6962 | MMC3 clone. | |
| 6963 | ||
| 6964 | iNES: mapper 114 | |
| 6965 | ||
| 6966 | In MESS: Supported. | |
| 6967 | ||
| 6968 | *************************************************************/ | |
| 6969 | ||
| 6970 | static WRITE8_HANDLER( sgame_lion_m_w ) | |
| 6971 | { | |
| 6972 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6973 | LOG_MMC(("sgame_lion_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6974 | ||
| 6975 | state->m_map114_reg = data; | |
| 6976 | ||
| 6977 | if (state->m_map114_reg & 0x80) | |
| 6978 | { | |
| 6979 | prg16_89ab(space->machine(), data & 0x1f); | |
| 6980 | prg16_cdef(space->machine(), data & 0x1f); | |
| 6981 | } | |
| 6982 | else | |
| 6983 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6984 | ||
| 6985 | } | |
| 6986 | ||
| 6987 | static WRITE8_HANDLER( sgame_lion_w ) | |
| 6988 | { | |
| 6989 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6990 | static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; | |
| 6991 | LOG_MMC(("sgame_lion_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6992 | ||
| 6993 | if (offset < 0x6000) | |
| 6994 | { | |
| 6995 | switch (offset & 0x6000) | |
| 6996 | { | |
| 6997 | case 0x0000: | |
| 6998 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6999 | break; | |
| 7000 | case 0x2000: | |
| 7001 | state->m_map114_reg_enabled = 1; | |
| 7002 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 7003 | txrom_w(space, 0x0000, data); | |
| 7004 | break; | |
| 7005 | case 0x4000: | |
| 7006 | if (state->m_map114_reg_enabled && (state->m_map114_reg & 0x80) == 0) | |
| 7007 | { | |
| 7008 | state->m_map114_reg_enabled = 0; | |
| 7009 | txrom_w(space, 0x0001, data); | |
| 7010 | } | |
| 7011 | break; | |
| 7012 | } | |
| 7013 | } | |
| 7014 | else | |
| 7015 | { | |
| 7016 | switch (offset & 0x03) | |
| 7017 | { | |
| 7018 | case 0x02: | |
| 7019 | txrom_w(space, 0x6000, data); | |
| 7020 | break; | |
| 7021 | case 0x03: | |
| 7022 | txrom_w(space, 0x6001, data); | |
| 7023 | txrom_w(space, 0x4000, data); | |
| 7024 | txrom_w(space, 0x4001, data); | |
| 7025 | break; | |
| 7026 | } | |
| 7027 | } | |
| 7028 | } | |
| 7029 | ||
| 7030 | /************************************************************* | |
| 7031 | ||
| 7032 | Tengen 800008 Board | |
| 7033 | ||
| 7034 | iNES: mapper 3? | |
| 7035 | ||
| 7036 | In MESS: Supported. | |
| 7037 | ||
| 7038 | *************************************************************/ | |
| 7039 | ||
| 7040 | static WRITE8_HANDLER( tengen_800008_w ) | |
| 7041 | { | |
| 7042 | LOG_MMC(("tengen_800008_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7043 | ||
| 7044 | prg32(space->machine(), data >> 3); | |
| 7045 | chr8(space->machine(), data, CHRROM); | |
| 7046 | } | |
| 7047 | ||
| 7048 | /************************************************************* | |
| 7049 | ||
| 7050 | Tengen 800032 Board | |
| 7051 | ||
| 7052 | Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls | |
| 7053 | & Croosbones, Xybots | |
| 7054 | ||
| 7055 | iNES: mapper 64 | |
| 7056 | ||
| 7057 | In MESS: Partially Supported. | |
| 7058 | ||
| 7059 | *************************************************************/ | |
| 7060 | ||
| 7061 | static void tengen_800032_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 7062 | { | |
| 7063 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 7064 | if (!state->m_IRQ_mode) // we are in scanline mode! | |
| 7065 | { | |
| 7066 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 7067 | { | |
| 7068 | if (!state->m_IRQ_reset) | |
| 7069 | { | |
| 7070 | if (!state->m_IRQ_count) | |
| 7071 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 7072 | else | |
| 7073 | { | |
| 7074 | state->m_IRQ_count--; | |
| 7075 | if (state->m_IRQ_enable && !blanked && !state->m_IRQ_count) | |
| 7076 | { | |
| 7077 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 7078 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 7079 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 7080 | } | |
| 7081 | } | |
| 7082 | } | |
| 7083 | else | |
| 7084 | { | |
| 7085 | state->m_IRQ_reset = 0; | |
| 7086 | state->m_IRQ_count = state->m_IRQ_count_latch + 1; | |
| 7087 | } | |
| 7088 | } | |
| 7089 | } | |
| 7090 | /* otherwise, we are in CPU cycles mode --> decrement count of 114 every scanline | |
| 7091 | --> in the meanwhile anything can have happened to IRQ_reset and we would not know | |
| 7092 | --> Skulls and Crossbones does not show anything!! */ | |
| 7093 | else | |
| 7094 | { | |
| 7095 | // if (!state->m_IRQ_reset) | |
| 7096 | { | |
| 7097 | if (state->m_IRQ_count <= 114) | |
| 7098 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 7099 | else | |
| 7100 | { | |
| 7101 | state->m_IRQ_count -= 114; | |
| 7102 | if (state->m_IRQ_enable && !blanked && (state->m_IRQ_count <= 114)) | |
| 7103 | { | |
| 7104 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 7105 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 7106 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 7107 | } | |
| 7108 | } | |
| 7109 | } | |
| 7110 | // else | |
| 7111 | // { | |
| 7112 | // state->m_IRQ_reset = 0; | |
| 7113 | // state->m_IRQ_count = state->m_IRQ_count_latch + 1; | |
| 7114 | // } | |
| 7115 | } | |
| 7116 | } | |
| 7117 | ||
| 7118 | static void tengen_800032_set_prg( running_machine &machine ) | |
| 7119 | { | |
| 7120 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7121 | UINT8 prg_mode = state->m_mmc_latch1 & 0x40; | |
| 7122 | ||
| 7123 | prg8_89(machine, state->m_mmc_prg_bank[prg_mode ? 2: 0]); | |
| 7124 | prg8_ab(machine, state->m_mmc_prg_bank[prg_mode ? 0: 1]); | |
| 7125 | prg8_cd(machine, state->m_mmc_prg_bank[prg_mode ? 1: 2]); | |
| 7126 | } | |
| 7127 | ||
| 7128 | static void tengen_800032_set_chr( running_machine &machine ) | |
| 7129 | { | |
| 7130 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7131 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 7132 | ||
| 7133 | if (state->m_mmc_latch1 & 0x20) | |
| 7134 | { | |
| 7135 | chr1_x(machine, 0 ^ chr_page, state->m_mmc_vrom_bank[0], CHRROM); | |
| 7136 | chr1_x(machine, 1 ^ chr_page, state->m_mmc_vrom_bank[8], CHRROM); | |
| 7137 | chr1_x(machine, 2 ^ chr_page, state->m_mmc_vrom_bank[1], CHRROM); | |
| 7138 | chr1_x(machine, 3 ^ chr_page, state->m_mmc_vrom_bank[9], CHRROM); | |
| 7139 | } | |
| 7140 | else | |
| 7141 | { | |
| 7142 | chr1_x(machine, 0 ^ chr_page, state->m_mmc_vrom_bank[0] & ~0x01, CHRROM); | |
| 7143 | chr1_x(machine, 1 ^ chr_page, state->m_mmc_vrom_bank[0] | 0x01, CHRROM); | |
| 7144 | chr1_x(machine, 2 ^ chr_page, state->m_mmc_vrom_bank[1] & ~0x01, CHRROM); | |
| 7145 | chr1_x(machine, 3 ^ chr_page, state->m_mmc_vrom_bank[1] | 0x01, CHRROM); | |
| 7146 | } | |
| 7147 | ||
| 7148 | chr1_x(machine, 4 ^ chr_page, state->m_mmc_vrom_bank[2], CHRROM); | |
| 7149 | chr1_x(machine, 5 ^ chr_page, state->m_mmc_vrom_bank[3], CHRROM); | |
| 7150 | chr1_x(machine, 6 ^ chr_page, state->m_mmc_vrom_bank[4], CHRROM); | |
| 7151 | chr1_x(machine, 7 ^ chr_page, state->m_mmc_vrom_bank[5], CHRROM); | |
| 7152 | } | |
| 7153 | ||
| 7154 | static WRITE8_HANDLER( tengen_800032_w ) | |
| 7155 | { | |
| 7156 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7157 | UINT8 map64_helper, cmd; | |
| 7158 | LOG_MMC(("tengen_800032_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7159 | ||
| 7160 | switch (offset & 0x6001) | |
| 7161 | { | |
| 7162 | case 0x0000: | |
| 7163 | map64_helper = state->m_mmc_latch1 ^ data; | |
| 7164 | state->m_mmc_latch1 = data; | |
| 7165 | ||
| 7166 | /* Has PRG Mode changed? */ | |
| 7167 | if (map64_helper & 0x40) | |
| 7168 | tengen_800032_set_prg(space->machine()); | |
| 7169 | ||
| 7170 | /* Has CHR Mode changed? */ | |
| 7171 | if (map64_helper & 0xa0) | |
| 7172 | tengen_800032_set_chr(space->machine()); | |
| 7173 | break; | |
| 7174 | ||
| 7175 | case 0x0001: | |
| 7176 | cmd = state->m_mmc_latch1 & 0x0f; | |
| 7177 | switch (cmd) | |
| 7178 | { | |
| 7179 | case 0: case 1: | |
| 7180 | case 2: case 3: | |
| 7181 | case 4: case 5: | |
| 7182 | state->m_mmc_vrom_bank[cmd] = data; | |
| 7183 | tengen_800032_set_chr(space->machine()); | |
| 7184 | break; | |
| 7185 | case 6: case 7: | |
| 7186 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 7187 | tengen_800032_set_prg(space->machine()); | |
| 7188 | break; | |
| 7189 | case 8: case 9: | |
| 7190 | state->m_mmc_vrom_bank[cmd - 2] = data; | |
| 7191 | tengen_800032_set_chr(space->machine()); | |
| 7192 | break; | |
| 7193 | case 0x0f: | |
| 7194 | state->m_mmc_prg_bank[2] = data; | |
| 7195 | tengen_800032_set_prg(space->machine()); | |
| 7196 | break; | |
| 7197 | } | |
| 7198 | break; | |
| 7199 | ||
| 7200 | case 0x2000: | |
| 7201 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 7202 | break; | |
| 7203 | ||
| 7204 | case 0x4000: | |
| 7205 | state->m_IRQ_count_latch = data; | |
| 7206 | break; | |
| 7207 | ||
| 7208 | case 0x4001: /* $c001 - IRQ scanline latch */ | |
| 7209 | state->m_IRQ_mode = data & 0x01; | |
| 7210 | state->m_IRQ_reset = 1; | |
| 7211 | break; | |
| 7212 | ||
| 7213 | case 0x6000: | |
| 7214 | state->m_IRQ_enable = 0; | |
| 7215 | break; | |
| 7216 | ||
| 7217 | case 0x6001: | |
| 7218 | state->m_IRQ_enable = 1; | |
| 7219 | break; | |
| 7220 | ||
| 7221 | default: | |
| 7222 | LOG_MMC(("Mapper 64 write. addr: %04x value: %02x\n", offset + 0x8000, data)); | |
| 7223 | break; | |
| 7224 | } | |
| 7225 | } | |
| 7226 | ||
| 7227 | /************************************************************* | |
| 7228 | ||
| 7229 | Tengen 800037 Board | |
| 7230 | ||
| 7231 | Games: Alien Syndrome | |
| 7232 | ||
| 7233 | iNES: mapper 158 | |
| 7234 | ||
| 7235 | In MESS: Very preliminary support. | |
| 7236 | ||
| 7237 | *************************************************************/ | |
| 7238 | ||
| 7239 | // probably wrong... | |
| 7240 | static void tengen_800037_set_mirror( running_machine &machine ) | |
| 7241 | { | |
| 7242 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7243 | UINT8 nt_mode = state->m_mmc_latch1 & 0x80; | |
| 7244 | ||
| 7245 | set_nt_page(machine, 0, ROM, state->m_mmc_vrom_bank[nt_mode ? 2 : 0], 0); | |
| 7246 | set_nt_page(machine, 1, ROM, state->m_mmc_vrom_bank[nt_mode ? 3 : 0], 0); | |
| 7247 | set_nt_page(machine, 2, ROM, state->m_mmc_vrom_bank[nt_mode ? 4 : 1], 0); | |
| 7248 | set_nt_page(machine, 3, ROM, state->m_mmc_vrom_bank[nt_mode ? 5 : 1], 0); | |
| 7249 | } | |
| 7250 | ||
| 7251 | static WRITE8_HANDLER( tengen_800037_w ) | |
| 7252 | { | |
| 7253 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7254 | UINT8 map158_helper, cmd; | |
| 7255 | LOG_MMC(("tengen_800037_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7256 | ||
| 7257 | switch (offset & 0x6001) | |
| 7258 | { | |
| 7259 | case 0x0000: | |
| 7260 | map158_helper = state->m_mmc_latch1 ^ data; | |
| 7261 | state->m_mmc_latch1 = data; | |
| 7262 | ||
| 7263 | /* Has PRG Mode changed? */ | |
| 7264 | if (map158_helper & 0x40) | |
| 7265 | tengen_800032_set_prg(space->machine()); | |
| 7266 | ||
| 7267 | /* Has CHR Mode changed? */ | |
| 7268 | if (map158_helper & 0xa0) | |
| 7269 | { | |
| 7270 | tengen_800032_set_chr(space->machine()); | |
| 7271 | tengen_800037_set_mirror(space->machine()); | |
| 7272 | } | |
| 7273 | break; | |
| 7274 | ||
| 7275 | case 0x0001: | |
| 7276 | cmd = state->m_mmc_latch1 & 0x0f; | |
| 7277 | switch (cmd) | |
| 7278 | { | |
| 7279 | case 0: case 1: | |
| 7280 | case 2: case 3: | |
| 7281 | case 4: case 5: | |
| 7282 | state->m_mmc_vrom_bank[cmd] = data; | |
| 7283 | tengen_800032_set_chr(space->machine()); | |
| 7284 | tengen_800037_set_mirror(space->machine()); | |
| 7285 | break; | |
| 7286 | case 6: case 7: | |
| 7287 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 7288 | tengen_800032_set_prg(space->machine()); | |
| 7289 | break; | |
| 7290 | case 8: case 9: | |
| 7291 | state->m_mmc_vrom_bank[cmd - 2] = data; | |
| 7292 | tengen_800032_set_chr(space->machine()); | |
| 7293 | tengen_800037_set_mirror(space->machine()); | |
| 7294 | break; | |
| 7295 | case 0x0f: | |
| 7296 | state->m_mmc_prg_bank[2] = data; | |
| 7297 | tengen_800032_set_prg(space->machine()); | |
| 7298 | break; | |
| 7299 | } | |
| 7300 | break; | |
| 7301 | ||
| 7302 | case 0x2000: | |
| 7303 | break; | |
| 7304 | ||
| 7305 | default: | |
| 7306 | tengen_800032_w(space, offset, data); | |
| 7307 | break; | |
| 7308 | } | |
| 7309 | } | |
| 7310 | ||
| 7311 | /************************************************************* | |
| 7312 | ||
| 7313 | Bootleg Board 22211 by TXC (Type A) | |
| 7314 | ||
| 7315 | Games: Creatom | |
| 7316 | ||
| 7317 | Info from NEStopia: this mapper features write to four | |
| 7318 | registers (0x4100-0x4103). The third one is used to select | |
| 7319 | PRG and CHR banks. | |
| 7320 | ||
| 7321 | iNES: mapper 132 | |
| 7322 | ||
| 7323 | In MESS: Supported. | |
| 7324 | ||
| 7325 | *************************************************************/ | |
| 7326 | ||
| 7327 | static WRITE8_HANDLER( txc_22211_l_w ) | |
| 7328 | { | |
| 7329 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7330 | LOG_MMC(("txc_22211_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7331 | ||
| 7332 | if (offset < 4) | |
| 7333 | state->m_txc_reg[offset & 0x03] = data; | |
| 7334 | } | |
| 7335 | ||
| 7336 | static READ8_HANDLER( txc_22211_l_r ) | |
| 7337 | { | |
| 7338 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7339 | LOG_MMC(("txc_22211_l_r, offset: %04x\n", offset)); | |
| 7340 | ||
| 7341 | if (offset == 0x0000) | |
| 7342 | return (state->m_txc_reg[1] ^ state->m_txc_reg[2]) | 0x40; | |
| 7343 | else | |
| 7344 | return 0x00; | |
| 7345 | } | |
| 7346 | ||
| 7347 | static WRITE8_HANDLER( txc_22211_w ) | |
| 7348 | { | |
| 7349 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7350 | LOG_MMC(("txc_22211_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7351 | ||
| 7352 | prg32(space->machine(), state->m_txc_reg[2] >> 2); | |
| 7353 | chr8(space->machine(), state->m_txc_reg[2], CHRROM); | |
| 7354 | } | |
| 7355 | ||
| 7356 | /************************************************************* | |
| 7357 | ||
| 7358 | Bootleg Board 22211 by TXC (Type B) | |
| 7359 | ||
| 7360 | Games: 1991 Du Ma Racing | |
| 7361 | ||
| 7362 | This mapper is basically the same as Type A. Only difference is | |
| 7363 | in the way CHR banks are selected (see below) | |
| 7364 | ||
| 7365 | iNES: mapper 172 | |
| 7366 | ||
| 7367 | In MESS: Supported. | |
| 7368 | ||
| 7369 | *************************************************************/ | |
| 7370 | ||
| 7371 | static WRITE8_HANDLER( txc_22211b_w ) | |
| 7372 | { | |
| 7373 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7374 | LOG_MMC(("txc_22211b_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7375 | ||
| 7376 | prg32(space->machine(), state->m_txc_reg[2] >> 2); | |
| 7377 | chr8(space->machine(), (((data ^ state->m_txc_reg[2]) >> 3) & 0x02) | (((data ^ state->m_txc_reg[2]) >> 5) & 0x01), CHRROM); | |
| 7378 | } | |
| 7379 | ||
| 7380 | /************************************************************* | |
| 7381 | ||
| 7382 | Bootleg Board 22211 by TXC (Type C) | |
| 7383 | ||
| 7384 | Games: Mahjong Block, Xiao Ma Li | |
| 7385 | ||
| 7386 | This mapper is basically the same as 132 too. Only difference is | |
| 7387 | in 0x4100 reads which expect also bit 0 to be set | |
| 7388 | ||
| 7389 | iNES: mapper 172 | |
| 7390 | ||
| 7391 | In MESS: Supported. | |
| 7392 | ||
| 7393 | *************************************************************/ | |
| 7394 | ||
| 7395 | static READ8_HANDLER( txc_22211c_l_r ) | |
| 7396 | { | |
| 7397 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7398 | LOG_MMC(("txc_22211c_l_r, offset: %04x\n", offset)); | |
| 7399 | ||
| 7400 | if (offset == 0x0000) | |
| 7401 | return (state->m_txc_reg[1] ^ state->m_txc_reg[2]) | 0x41; | |
| 7402 | else | |
| 7403 | return 0x00; | |
| 7404 | } | |
| 7405 | ||
| 7406 | /************************************************************* | |
| 7407 | ||
| 7408 | Bootleg Board 'Thunder Warrior' by TXC | |
| 7409 | ||
| 7410 | Games: Master Fighter II, Master Fighter 3, Thunder Warrior | |
| 7411 | ||
| 7412 | MMC3 clone | |
| 7413 | ||
| 7414 | iNES: mapper 189 | |
| 7415 | ||
| 7416 | In MESS: Supported. | |
| 7417 | ||
| 7418 | *************************************************************/ | |
| 7419 | ||
| 7420 | static WRITE8_HANDLER( txc_tw_l_w ) | |
| 7421 | { | |
| 7422 | LOG_MMC(("txctw_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7423 | ||
| 7424 | prg32(space->machine(), (data >> 4) | data); | |
| 7425 | } | |
| 7426 | ||
| 7427 | static WRITE8_HANDLER( txc_tw_m_w ) | |
| 7428 | { | |
| 7429 | LOG_MMC(("txctw_m_w, offset: %04x, data: %04x\n", offset, data)); | |
| 7430 | ||
| 7431 | txc_tw_l_w(space, offset & 0xff, data); // offset does not really count for this mapper | |
| 7432 | } | |
| 7433 | ||
| 7434 | /* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ | |
| 7435 | static void txc_tw_prg_cb( running_machine &machine, int start, int bank ) | |
| 7436 | { | |
| 7437 | return; | |
| 7438 | } | |
| 7439 | ||
| 7440 | /************************************************************* | |
| 7441 | ||
| 7442 | Bootleg Board 'Strike Wolf' by TXC | |
| 7443 | ||
| 7444 | Games: Strike Wolf (also Policeman?? according to Nestopia) | |
| 7445 | ||
| 7446 | iNES: mapper 36 | |
| 7447 | ||
| 7448 | Known Boards: Bootleg Board by TXC | |
| 7449 | ||
| 7450 | In MESS: Supported. | |
| 7451 | ||
| 7452 | *************************************************************/ | |
| 7453 | ||
| 7454 | static WRITE8_HANDLER( txc_strikewolf_w ) | |
| 7455 | { | |
| 7456 | LOG_MMC(("txc_strikewolf_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7457 | ||
| 7458 | if ((offset >= 0x400) && (offset < 0x7fff)) | |
| 7459 | { | |
| 7460 | prg32(space->machine(), data >> 4); | |
| 7461 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 7462 | } | |
| 7463 | } | |
| 7464 | ||
| 7465 | /************************************************************* | |
| 7466 | ||
| 7467 | Bootleg Board MXMDHTWO by TXC | |
| 7468 | ||
| 7469 | Games: Commandos, Journey to the West, Ma Bu Mi Zhen & | |
| 7470 | Qu Wei Cheng Yu Wu, Si Lu Chuan Qi | |
| 7471 | ||
| 7472 | Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank. | |
| 7473 | Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct. | |
| 7474 | ||
| 7475 | iNES: mapper 241 | |
| 7476 | ||
| 7477 | In MESS: Supported. | |
| 7478 | ||
| 7479 | *************************************************************/ | |
| 7480 | ||
| 7481 | static READ8_HANDLER( txc_mxmdhtwo_l_r ) | |
| 7482 | { | |
| 7483 | return 0x50; | |
| 7484 | } | |
| 7485 | ||
| 7486 | static WRITE8_HANDLER( txc_mxmdhtwo_w ) | |
| 7487 | { | |
| 7488 | LOG_MMC(("txc_mxmdhtwo_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7489 | ||
| 7490 | prg32(space->machine(), data); | |
| 7491 | } | |
| 7492 | ||
| 7493 | /************************************************************* | |
| 7494 | ||
| 7495 | Waixing Board Type A | |
| 7496 | ||
| 7497 | Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi, | |
| 7498 | Jia A Fung Yun, Wei Luo Chuan Qi | |
| 7499 | ||
| 7500 | This mapper is quite similar to MMC3, but with two differences: | |
| 7501 | mirroring is not the same, and when VROM banks 8,9 are accessed | |
| 7502 | they point to CHRRAM and not CHRROM. | |
| 7503 | ||
| 7504 | iNES: mapper 74 | |
| 7505 | ||
| 7506 | In MESS: Supported | |
| 7507 | ||
| 7508 | *************************************************************/ | |
| 7509 | ||
| 7510 | /* MIRROR_LOW and MIRROR_HIGH are swapped! */ | |
| 7511 | static void waixing_set_mirror( running_machine &machine, UINT8 nt ) | |
| 7512 | { | |
| 7513 | switch (nt) | |
| 7514 | { | |
| 7515 | case 0: | |
| 7516 | case 1: | |
| 7517 | set_nt_mirroring(machine, nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 7518 | break; | |
| 7519 | case 2: | |
| 7520 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 7521 | break; | |
| 7522 | case 3: | |
| 7523 | set_nt_mirroring(machine, PPU_MIRROR_HIGH); | |
| 7524 | break; | |
| 7525 | default: | |
| 7526 | LOG_MMC(("Mapper set NT to invalid value %02x", nt)); | |
| 7527 | break; | |
| 7528 | } | |
| 7529 | } | |
| 7530 | ||
| 7531 | /* Luo Ke Ren X only works with this */ | |
| 7532 | static void waixing_a_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7533 | { | |
| 7534 | int chr_src = (bank <= 9) ? CHRRAM : CHRROM; | |
| 7535 | chr1_x(machine, start, bank, chr_src); | |
| 7536 | } | |
| 7537 | ||
| 7538 | /* Ji Jia Zhan Shi only works with this */ | |
| 7539 | static void waixing_a1_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7540 | { | |
| 7541 | int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM; | |
| 7542 | chr1_x(machine, start, bank, chr_src); | |
| 7543 | } | |
| 7544 | ||
| 7545 | static WRITE8_HANDLER( waixing_a_w ) | |
| 7546 | { | |
| 7547 | LOG_MMC(("waixing_a_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7548 | ||
| 7549 | switch (offset & 0x6001) | |
| 7550 | { | |
| 7551 | case 0x2000: | |
| 7552 | waixing_set_mirror(space->machine(), data); //maybe data & 0x03? | |
| 7553 | break; | |
| 7554 | ||
| 7555 | case 0x2001: | |
| 7556 | break; | |
| 7557 | ||
| 7558 | default: | |
| 7559 | txrom_w(space, offset, data); | |
| 7560 | break; | |
| 7561 | } | |
| 7562 | } | |
| 7563 | ||
| 7564 | /************************************************************* | |
| 7565 | ||
| 7566 | Waixing Board Type B | |
| 7567 | ||
| 7568 | Games: Sugoro Quest (C) | |
| 7569 | ||
| 7570 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7571 | in the sense that it is the same board except for the | |
| 7572 | CHRRAM pages. | |
| 7573 | ||
| 7574 | iNES: mapper 191 | |
| 7575 | ||
| 7576 | In MESS: Supported. | |
| 7577 | ||
| 7578 | *************************************************************/ | |
| 7579 | ||
| 7580 | static void waixing_b_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7581 | { | |
| 7582 | int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM; | |
| 7583 | chr1_x(machine, start, bank, chr_src); | |
| 7584 | } | |
| 7585 | ||
| 7586 | /************************************************************* | |
| 7587 | ||
| 7588 | Waixing Board Type C | |
| 7589 | ||
| 7590 | Games: Ying Lie Qun Xia Zhuan, Young Chivalry | |
| 7591 | ||
| 7592 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7593 | in the sense that it is the same board except for the | |
| 7594 | CHRRAM pages. | |
| 7595 | ||
| 7596 | iNES: mapper 192 | |
| 7597 | ||
| 7598 | In MESS: Supported. | |
| 7599 | ||
| 7600 | *************************************************************/ | |
| 7601 | ||
| 7602 | static void waixing_c_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7603 | { | |
| 7604 | int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM; | |
| 7605 | chr1_x(machine, start, bank, chr_src); | |
| 7606 | } | |
| 7607 | ||
| 7608 | /************************************************************* | |
| 7609 | ||
| 7610 | Waixing Board Type D | |
| 7611 | ||
| 7612 | Games: Super Robot Taisen (C) | |
| 7613 | ||
| 7614 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7615 | in the sense that it is the same board except for the | |
| 7616 | CHRRAM pages. | |
| 7617 | ||
| 7618 | iNES: mapper 194 | |
| 7619 | ||
| 7620 | In MESS: Supported. | |
| 7621 | ||
| 7622 | *************************************************************/ | |
| 7623 | ||
| 7624 | static void waixing_d_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7625 | { | |
| 7626 | int chr_src = (bank < 0x02) ? CHRRAM : CHRROM; | |
| 7627 | chr1_x(machine, start, bank, chr_src); | |
| 7628 | } | |
| 7629 | ||
| 7630 | /************************************************************* | |
| 7631 | ||
| 7632 | Waixing Board Type E | |
| 7633 | ||
| 7634 | Games: Captain Tsubasa Vol. II (C), Chaos World, God | |
| 7635 | Slayer (C), Zu Qiu Xiao Jiang | |
| 7636 | ||
| 7637 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7638 | in the sense that it is the same board except for the | |
| 7639 | CHRRAM pages. | |
| 7640 | ||
| 7641 | iNES: mapper 195 | |
| 7642 | ||
| 7643 | In MESS: Supported. | |
| 7644 | ||
| 7645 | *************************************************************/ | |
| 7646 | ||
| 7647 | static void waixing_e_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7648 | { | |
| 7649 | int chr_src = (bank < 0x04) ? CHRRAM : CHRROM; | |
| 7650 | chr1_x(machine, start, bank, chr_src); | |
| 7651 | } | |
| 7652 | ||
| 7653 | /************************************************************* | |
| 7654 | ||
| 7655 | Waixing Board Type F | |
| 7656 | ||
| 7657 | Games: Tenchi wo Kurau II (C) | |
| 7658 | ||
| 7659 | MMC3 clone. | |
| 7660 | ||
| 7661 | iNES: mapper 198 | |
| 7662 | ||
| 7663 | In MESS: Preliminary support. | |
| 7664 | ||
| 7665 | *************************************************************/ | |
| 7666 | ||
| 7667 | static WRITE8_HANDLER( waixing_f_w ) | |
| 7668 | { | |
| 7669 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7670 | UINT8 cmd; | |
| 7671 | LOG_MMC(("waixing_f_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7672 | ||
| 7673 | switch (offset & 0x6001) | |
| 7674 | { | |
| 7675 | case 0x0001: | |
| 7676 | cmd = state->m_mmc_latch1 & 0x07; | |
| 7677 | if (cmd >= 6) | |
| 7678 | { | |
| 7679 | state->m_mmc_prg_bank[cmd - 6] = data & ((data > 0x3f) ? 0x4f : 0x3f); | |
| 7680 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7681 | } | |
| 7682 | else | |
| 7683 | waixing_a_w(space, offset, data); | |
| 7684 | break; | |
| 7685 | ||
| 7686 | default: | |
| 7687 | waixing_a_w(space, offset, data); | |
| 7688 | break; | |
| 7689 | } | |
| 7690 | } | |
| 7691 | ||
| 7692 | /************************************************************* | |
| 7693 | ||
| 7694 | Waixing Board Type G | |
| 7695 | ||
| 7696 | Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon | |
| 7697 | Ball Z II (C) | |
| 7698 | ||
| 7699 | MMC3 clone | |
| 7700 | ||
| 7701 | iNES: mapper 199 | |
| 7702 | ||
| 7703 | In MESS: Supported. | |
| 7704 | ||
| 7705 | *************************************************************/ | |
| 7706 | ||
| 7707 | static void waixing_g_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7708 | { | |
| 7709 | int chr_src = (bank < 0x08) ? CHRRAM : CHRROM; | |
| 7710 | chr1_x(machine, start, bank, chr_src); | |
| 7711 | } | |
| 7712 | ||
| 7713 | static void waixing_g_set_chr( running_machine &machine, int chr_base, int chr_mask ) | |
| 7714 | { | |
| 7715 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7716 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 7717 | ||
| 7718 | state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | (state->m_mmc_vrom_bank[0] & chr_mask), state->m_mmc_chr_source); | |
| 7719 | state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | (state->m_mmc_vrom_bank[6] & chr_mask), state->m_mmc_chr_source); | |
| 7720 | state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), state->m_mmc_chr_source); | |
| 7721 | state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | (state->m_mmc_vrom_bank[7] & chr_mask), state->m_mmc_chr_source); | |
| 7722 | state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), state->m_mmc_chr_source); | |
| 7723 | state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), state->m_mmc_chr_source); | |
| 7724 | state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), state->m_mmc_chr_source); | |
| 7725 | state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), state->m_mmc_chr_source); | |
| 7726 | } | |
| 7727 | ||
| 7728 | static WRITE8_HANDLER( waixing_g_w ) | |
| 7729 | { | |
| 7730 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7731 | UINT8 MMC3_helper, cmd; | |
| 7732 | LOG_MMC(("waixing_g_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7733 | ||
| 7734 | switch (offset & 0x6001) | |
| 7735 | { | |
| 7736 | case 0x0000: | |
| 7737 | MMC3_helper = state->m_mmc_latch1 ^ data; | |
| 7738 | state->m_mmc_latch1 = data; | |
| 7739 | ||
| 7740 | /* Has PRG Mode changed? */ | |
| 7741 | if (MMC3_helper & 0x40) | |
| 7742 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7743 | ||
| 7744 | /* Has CHR Mode changed? */ | |
| 7745 | if (MMC3_helper & 0x80) | |
| 7746 | waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 7747 | break; | |
| 7748 | ||
| 7749 | case 0x0001: | |
| 7750 | cmd = state->m_mmc_latch1 & 0x0f; | |
| 7751 | switch (cmd) | |
| 7752 | { | |
| 7753 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 7754 | case 2: case 3: case 4: case 5: | |
| 7755 | state->m_mmc_vrom_bank[cmd] = data; | |
| 7756 | waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 7757 | break; | |
| 7758 | case 6: | |
| 7759 | case 7: | |
| 7760 | case 8: | |
| 7761 | case 9: | |
| 7762 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 7763 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7764 | break; | |
| 7765 | case 0x0a: case 0x0b: | |
| 7766 | state->m_mmc_vrom_bank[cmd - 4] = data; | |
| 7767 | waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 7768 | break; | |
| 7769 | } | |
| 7770 | break; | |
| 7771 | ||
| 7772 | default: | |
| 7773 | waixing_a_w(space, offset, data); | |
| 7774 | break; | |
| 7775 | } | |
| 7776 | } | |
| 7777 | ||
| 7778 | /************************************************************* | |
| 7779 | ||
| 7780 | Waixing Board Type H | |
| 7781 | ||
| 7782 | Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E | |
| 7783 | Long - Dragon Quest VII | |
| 7784 | ||
| 7785 | MMC3 clone. More info to come. | |
| 7786 | ||
| 7787 | iNES: mapper 245 | |
| 7788 | ||
| 7789 | In MESS: Supported. | |
| 7790 | ||
| 7791 | *************************************************************/ | |
| 7792 | ||
| 7793 | static void waixing_h_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7794 | { | |
| 7795 | if (source == CHRROM) | |
| 7796 | chr1_x(machine, start, bank, source); | |
| 7797 | } | |
| 7798 | ||
| 7799 | static WRITE8_HANDLER( waixing_h_w ) | |
| 7800 | { | |
| 7801 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7802 | UINT8 cmd; | |
| 7803 | LOG_MMC(("waixing_h_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7804 | ||
| 7805 | switch (offset & 0x6001) | |
| 7806 | { | |
| 7807 | case 0x0001: | |
| 7808 | cmd = state->m_mmc3_latch & 0x07; | |
| 7809 | switch (cmd) | |
| 7810 | { | |
| 7811 | case 0: // in this case we set prg_base in addition to state->m_mmc_vrom_bank! | |
| 7812 | state->m_mmc_prg_base = (data << 5) & 0x40; | |
| 7813 | state->m_mmc_prg_mask = 0x3f; | |
| 7814 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7815 | txrom_w(space, offset, data); | |
| 7816 | default: | |
| 7817 | txrom_w(space, offset, data); | |
| 7818 | break; | |
| 7819 | } | |
| 7820 | break; | |
| 7821 | ||
| 7822 | case 0x2001: | |
| 7823 | break; | |
| 7824 | ||
| 7825 | default: | |
| 7826 | txrom_w(space, offset, data); | |
| 7827 | break; | |
| 7828 | } | |
| 7829 | } | |
| 7830 | ||
| 7831 | /************************************************************* | |
| 7832 | ||
| 7833 | Waixing San Guo Zhi Board | |
| 7834 | ||
| 7835 | Games: San Guo Zhi | |
| 7836 | ||
| 7837 | This board uses Konami IRQ | |
| 7838 | ||
| 7839 | iNES: mapper 252 | |
| 7840 | ||
| 7841 | In MESS: Unsupported. | |
| 7842 | ||
| 7843 | *************************************************************/ | |
| 7844 | ||
| 7845 | static WRITE8_HANDLER( waixing_sgz_w ) | |
| 7846 | { | |
| 7847 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7848 | UINT8 mmc_helper, bank; | |
| 7849 | LOG_MMC(("waixing_sgz_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7850 | ||
| 7851 | switch (offset & 0x7000) | |
| 7852 | { | |
| 7853 | case 0x0000: | |
| 7854 | prg8_89(space->machine(), data); | |
| 7855 | break; | |
| 7856 | case 0x2000: | |
| 7857 | prg8_ab(space->machine(), data); | |
| 7858 | break; | |
| 7859 | case 0x3000: | |
| 7860 | case 0x4000: | |
| 7861 | case 0x5000: | |
| 7862 | case 0x6000: | |
| 7863 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3); | |
| 7864 | mmc_helper = offset & 0x04; | |
| 7865 | if (mmc_helper) | |
| 7866 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); | |
| 7867 | else | |
| 7868 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 7869 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 7870 | break; | |
| 7871 | case 0x7000: | |
| 7872 | switch (offset & 0x0c) | |
| 7873 | { | |
| 7874 | case 0x00: | |
| 7875 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f); | |
| 7876 | break; | |
| 7877 | case 0x04: | |
| 7878 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4); | |
| 7879 | break; | |
| 7880 | case 0x08: | |
| 7881 | state->m_IRQ_enable = data & 0x02; | |
| 7882 | state->m_IRQ_enable_latch = data & 0x01; | |
| 7883 | if (data & 0x02) | |
| 7884 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 7885 | break; | |
| 7886 | case 0x0c: | |
| 7887 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 7888 | break; | |
| 7889 | } | |
| 7890 | break; | |
| 7891 | } | |
| 7892 | } | |
| 7893 | ||
| 7894 | ||
| 7895 | /************************************************************* | |
| 7896 | ||
| 7897 | Waixing San Guo Zhong Lie Zhuan Board | |
| 7898 | ||
| 7899 | Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing | |
| 7900 | Ji Zheng Ba | |
| 7901 | ||
| 7902 | iNES: mapper 178 | |
| 7903 | ||
| 7904 | In MESS: Supported. | |
| 7905 | ||
| 7906 | *************************************************************/ | |
| 7907 | ||
| 7908 | static WRITE8_HANDLER( waixing_sgzlz_l_w ) | |
| 7909 | { | |
| 7910 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7911 | LOG_MMC(("waixing_sgzlz_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7912 | ||
| 7913 | switch (offset) | |
| 7914 | { | |
| 7915 | case 0x700: | |
| 7916 | set_nt_mirroring(space->machine(), data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 7917 | break; | |
| 7918 | case 0x701: | |
| 7919 | state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x0c) | ((data >> 1) & 0x03); | |
| 7920 | prg32(space->machine(), state->m_mmc_latch1); | |
| 7921 | break; | |
| 7922 | case 0x702: | |
| 7923 | state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x03) | ((data << 2) & 0x0c); | |
| 7924 | break; | |
| 7925 | } | |
| 7926 | } | |
| 7927 | ||
| 7928 | /************************************************************* | |
| 7929 | ||
| 7930 | Waixing Final Fantasy V Board | |
| 7931 | ||
| 7932 | Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket | |
| 7933 | Monster Red | |
| 7934 | ||
| 7935 | iNES: mapper 164 | |
| 7936 | ||
| 7937 | In MESS: Supported. | |
| 7938 | ||
| 7939 | *************************************************************/ | |
| 7940 | ||
| 7941 | static WRITE8_HANDLER( waixing_ffv_l_w ) | |
| 7942 | { | |
| 7943 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7944 | UINT8 mmc_helper; | |
| 7945 | LOG_MMC(("waixing_ffv_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7946 | offset += 0x100; /* the checks work better on addresses */ | |
| 7947 | ||
| 7948 | if (0x1000 == (offset & 0x1200)) | |
| 7949 | { | |
| 7950 | state->m_mmc_reg[BIT(offset, 8)] = data; | |
| 7951 | mmc_helper = BIT(state->m_mmc_reg[1], 0) << 5; | |
| 7952 | switch (state->m_mmc_reg[0] & 0x70) | |
| 7953 | { | |
| 7954 | case 0x00: | |
| 7955 | case 0x20: | |
| 7956 | case 0x40: | |
| 7957 | case 0x60: | |
| 7958 | prg16_89ab(space->machine(), mmc_helper | ((state->m_mmc_reg[0] >> 1) & 0x10) | (state->m_mmc_reg[0] & 0x0f)); | |
| 7959 | prg16_cdef(space->machine(), mmc_helper & 0x1f); | |
| 7960 | break; | |
| 7961 | case 0x50: | |
| 7962 | prg32(space->machine(), (mmc_helper >> 1) | (state->m_mmc_reg[0] & 0x0f)); | |
| 7963 | break; | |
| 7964 | case 0x70: | |
| 7965 | prg16_89ab(space->machine(), mmc_helper | ((state->m_mmc_reg[0] << 1) & 0x10) | (state->m_mmc_reg[0] & 0x0f)); | |
| 7966 | prg16_cdef(space->machine(), mmc_helper & 0x1f); | |
| 7967 | break; | |
| 7968 | } | |
| 7969 | } | |
| 7970 | } | |
| 7971 | ||
| 7972 | /************************************************************* | |
| 7973 | ||
| 7974 | Waixing Zhan Shi Board | |
| 7975 | ||
| 7976 | Games: Wai Xing Zhan Shi | |
| 7977 | ||
| 7978 | Simple mapper: writes to 0x8000-0xffff sets prg32 banks to | |
| 7979 | (offset>>3)&f. written data&3 sets the mirroring (with | |
| 7980 | switched high/low compared to the standard one). | |
| 7981 | ||
| 7982 | A crc check is required to support Dragon Quest VIII (which | |
| 7983 | uses a slightly different board) | |
| 7984 | ||
| 7985 | iNES: mapper 242 | |
| 7986 | ||
| 7987 | In MESS: Supported. | |
| 7988 | ||
| 7989 | *************************************************************/ | |
| 7990 | ||
| 7991 | static WRITE8_HANDLER( waixing_zs_w ) | |
| 7992 | { | |
| 7993 | LOG_MMC(("waixing_zs_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7994 | ||
| 7995 | prg32(space->machine(), offset >> 3); | |
| 7996 | ||
| 7997 | switch (data & 0x03) | |
| 7998 | { | |
| 7999 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 8000 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 8001 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 8002 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 8003 | } | |
| 8004 | } | |
| 8005 | ||
| 8006 | /************************************************************* | |
| 8007 | ||
| 8008 | Waixing Dragon Quest VIII Board | |
| 8009 | ||
| 8010 | Games: Dragon Quest VIII | |
| 8011 | ||
| 8012 | Simple mapper: writes to 0x8000-0xffff sets prg32 banks to | |
| 8013 | (offset>>3)&f. | |
| 8014 | ||
| 8015 | iNES: mapper 242 | |
| 8016 | ||
| 8017 | In MESS: Supported. | |
| 8018 | ||
| 8019 | *************************************************************/ | |
| 8020 | ||
| 8021 | static WRITE8_HANDLER( waixing_dq8_w ) | |
| 8022 | { | |
| 8023 | LOG_MMC(("waixing_dq8_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8024 | ||
| 8025 | prg32(space->machine(), offset >> 3); | |
| 8026 | } | |
| 8027 | ||
| 8028 | ||
| 8029 | /************************************************************* | |
| 8030 | ||
| 8031 | Waixing PS2 board | |
| 8032 | ||
| 8033 | Games: Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R) | |
| 8034 | ||
| 8035 | iNES: mapper 15 | |
| 8036 | ||
| 8037 | In MESS: Supported | |
| 8038 | ||
| 8039 | *************************************************************/ | |
| 8040 | ||
| 8041 | static WRITE8_HANDLER( waixing_ps2_w ) | |
| 8042 | { | |
| 8043 | UINT8 map15_flip = (data & 0x80) >> 7; | |
| 8044 | UINT8 map15_helper = (data & 0x7f) << 1; | |
| 8045 | ||
| 8046 | LOG_MMC(("waixing_ps2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8047 | ||
| 8048 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8049 | ||
| 8050 | switch (offset & 0x0fff) | |
| 8051 | { | |
| 8052 | case 0x000: | |
| 8053 | prg8_89(space->machine(), (map15_helper + 0) ^ map15_flip); | |
| 8054 | prg8_ab(space->machine(), (map15_helper + 1) ^ map15_flip); | |
| 8055 | prg8_cd(space->machine(), (map15_helper + 2) ^ map15_flip); | |
| 8056 | prg8_ef(space->machine(), (map15_helper + 3) ^ map15_flip); | |
| 8057 | break; | |
| 8058 | case 0x001: | |
| 8059 | map15_helper |= map15_flip; | |
| 8060 | prg8_89(space->machine(), map15_helper); | |
| 8061 | prg8_ab(space->machine(), map15_helper + 1); | |
| 8062 | prg8_cd(space->machine(), map15_helper + 1); | |
| 8063 | prg8_ef(space->machine(), map15_helper + 1); | |
| 8064 | break; | |
| 8065 | case 0x002: | |
| 8066 | map15_helper |= map15_flip; | |
| 8067 | prg8_89(space->machine(), map15_helper); | |
| 8068 | prg8_ab(space->machine(), map15_helper); | |
| 8069 | prg8_cd(space->machine(), map15_helper); | |
| 8070 | prg8_ef(space->machine(), map15_helper); | |
| 8071 | break; | |
| 8072 | case 0x003: | |
| 8073 | map15_helper |= map15_flip; | |
| 8074 | prg8_89(space->machine(), map15_helper); | |
| 8075 | prg8_ab(space->machine(), map15_helper + 1); | |
| 8076 | prg8_cd(space->machine(), map15_helper); | |
| 8077 | prg8_ef(space->machine(), map15_helper + 1); | |
| 8078 | break; | |
| 8079 | } | |
| 8080 | } | |
| 8081 | ||
| 8082 | /************************************************************* | |
| 8083 | ||
| 8084 | Waixing Board with Security Chip | |
| 8085 | ||
| 8086 | Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo, | |
| 8087 | Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan | |
| 8088 | ||
| 8089 | MMC3 clone | |
| 8090 | ||
| 8091 | iNES: mapper 249 | |
| 8092 | ||
| 8093 | In MESS: Partially Supported. | |
| 8094 | ||
| 8095 | *************************************************************/ | |
| 8096 | ||
| 8097 | static void waixing_sec_prg_cb( running_machine &machine, int start, int bank ) | |
| 8098 | { | |
| 8099 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8100 | ||
| 8101 | if (state->m_mmc_reg[0]) | |
| 8102 | bank = ((bank & 0x01)) | ((bank >> 3) & 0x02) | ((bank >> 1) & 0x04) | ((bank << 2) & 0x18); | |
| 8103 | ||
| 8104 | prg8_x(machine, start, bank); | |
| 8105 | } | |
| 8106 | ||
| 8107 | static void waixing_sec_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8108 | { | |
| 8109 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8110 | ||
| 8111 | if (state->m_mmc_reg[0]) | |
| 8112 | bank = ((bank & 0x03)) | ((bank >> 1) & 0x04) | ((bank >> 4) & 0x08) | | |
| 8113 | ((bank >> 2) & 0x10) | ((bank << 3) & 0x20) | ((bank << 2) & 0xc0); | |
| 8114 | ||
| 8115 | chr1_x(machine, start, bank, source); | |
| 8116 | } | |
| 8117 | ||
| 8118 | static WRITE8_HANDLER( waixing_sec_l_w ) | |
| 8119 | { | |
| 8120 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8121 | LOG_MMC(("waixing_sec_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8122 | ||
| 8123 | offset += 0x100; | |
| 8124 | ||
| 8125 | if (offset == 0x1000) | |
| 8126 | { | |
| 8127 | state->m_mmc_reg[0] = data & 0x02; | |
| 8128 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8129 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8130 | } | |
| 8131 | } | |
| 8132 | ||
| 8133 | /************************************************************* | |
| 8134 | ||
| 8135 | Waixing SH2 Board | |
| 8136 | ||
| 8137 | Games: Fire Emblem (C) and Fire Emblem Gaiden (C) | |
| 8138 | ||
| 8139 | MMC3 clone with different access to CHR | |
| 8140 | ||
| 8141 | iNES: mapper 165 | |
| 8142 | ||
| 8143 | In MESS: Partially Supported. | |
| 8144 | ||
| 8145 | *************************************************************/ | |
| 8146 | ||
| 8147 | static void waixing_sh2_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8148 | { | |
| 8149 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8150 | ||
| 8151 | chr4_0(machine, state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM); | |
| 8152 | chr4_4(machine, state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM); | |
| 8153 | } | |
| 8154 | ||
| 8155 | READ8_HANDLER( waixing_sh2_chr_r ) | |
| 8156 | { | |
| 8157 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8158 | int bank = offset >> 10; | |
| 8159 | UINT8 val = state->m_chr_map[bank].access[offset & 0x3ff]; // this would be usual return value | |
| 8160 | int chr_helper; | |
| 8161 | ||
| 8162 | switch (offset & 0xff8) | |
| 8163 | { | |
| 8164 | case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break; | |
| 8165 | case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break; | |
| 8166 | default: return val; | |
| 8167 | } | |
| 8168 | ||
| 8169 | state->m_mmc_reg[offset >> 12] = chr_helper; | |
| 8170 | if (offset & 0x1000) | |
| 8171 | chr4_4(space->machine(), state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM); | |
| 8172 | else | |
| 8173 | chr4_0(space->machine(), state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM); | |
| 8174 | ||
| 8175 | return val; | |
| 8176 | } | |
| 8177 | ||
| 8178 | /************************************************************* | |
| 8179 | ||
| 8180 | Board UNL-8237 | |
| 8181 | ||
| 8182 | Games: Pocahontas 2 | |
| 8183 | ||
| 8184 | MMC3 clone | |
| 8185 | ||
| 8186 | In MESS: Supported | |
| 8187 | ||
| 8188 | *************************************************************/ | |
| 8189 | ||
| 8190 | static void unl_8237_prg_cb( running_machine &machine, int start, int bank ) | |
| 8191 | { | |
| 8192 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8193 | ||
| 8194 | if (!(state->m_mmc_reg[0] & 0x80)) | |
| 8195 | prg8_x(machine, start, bank); | |
| 8196 | } | |
| 8197 | ||
| 8198 | static void unl_8237_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8199 | { | |
| 8200 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8201 | bank |= ((state->m_mmc_reg[1] << 6) & 0x100); | |
| 8202 | ||
| 8203 | chr1_x(machine, start, bank, source); | |
| 8204 | } | |
| 8205 | ||
| 8206 | static WRITE8_HANDLER( unl_8237_l_w ) | |
| 8207 | { | |
| 8208 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8209 | LOG_MMC(("unl_8237_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 8210 | offset += 0x100; | |
| 8211 | ||
| 8212 | if (offset == 0x1000) | |
| 8213 | { | |
| 8214 | state->m_mmc_reg[0] = data; | |
| 8215 | if (state->m_mmc_reg[0] & 0x80) | |
| 8216 | { | |
| 8217 | if (state->m_mmc_reg[0] & 0x20) | |
| 8218 | prg32(space->machine(), (state->m_mmc_reg[0] & 0x0f) >> 1); | |
| 8219 | else | |
| 8220 | { | |
| 8221 | prg16_89ab(space->machine(), state->m_mmc_reg[0] & 0x1f); | |
| 8222 | prg16_cdef(space->machine(), state->m_mmc_reg[0] & 0x1f); | |
| 8223 | } | |
| 8224 | } | |
| 8225 | else | |
| 8226 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8227 | } | |
| 8228 | ||
| 8229 | if (offset == 0x1001) | |
| 8230 | { | |
| 8231 | state->m_mmc_reg[1] = data; | |
| 8232 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8233 | } | |
| 8234 | } | |
| 8235 | ||
| 8236 | static WRITE8_HANDLER( unl_8237_w ) | |
| 8237 | { | |
| 8238 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8239 | static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5}; | |
| 8240 | LOG_MMC(("unl_8237_w offset: %04x, data: %02x\n", offset, data)); | |
| 8241 | ||
| 8242 | switch (offset & 0x7000) | |
| 8243 | { | |
| 8244 | case 0x0000: | |
| 8245 | case 0x1000: | |
| 8246 | set_nt_mirroring(space->machine(), (data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8247 | break; | |
| 8248 | ||
| 8249 | case 0x2000: | |
| 8250 | case 0x3000: | |
| 8251 | state->m_mmc_reg[2] = 1; | |
| 8252 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 8253 | txrom_w(space, 0x0000, data); | |
| 8254 | break; | |
| 8255 | ||
| 8256 | case 0x4000: | |
| 8257 | case 0x5000: | |
| 8258 | if (state->m_mmc_reg[2]) | |
| 8259 | { | |
| 8260 | state->m_mmc_reg[2] = 0; | |
| 8261 | txrom_w(space, 0x0001, data); | |
| 8262 | } | |
| 8263 | break; | |
| 8264 | ||
| 8265 | case 0x6000: | |
| 8266 | break; | |
| 8267 | ||
| 8268 | case 0x7000: | |
| 8269 | txrom_w(space, 0x6001, data); | |
| 8270 | txrom_w(space, 0x4000, data); | |
| 8271 | txrom_w(space, 0x4001, data); | |
| 8272 | break; | |
| 8273 | } | |
| 8274 | } | |
| 8275 | ||
| 8276 | /************************************************************* | |
| 8277 | ||
| 8278 | Board UNL-AX5705 | |
| 8279 | ||
| 8280 | Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack) | |
| 8281 | ||
| 8282 | In MESS: Supported | |
| 8283 | ||
| 8284 | *************************************************************/ | |
| 8285 | ||
| 8286 | static void unl_ax5705_set_prg( running_machine &machine ) | |
| 8287 | { | |
| 8288 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8289 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 8290 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 8291 | } | |
| 8292 | ||
| 8293 | static WRITE8_HANDLER( unl_ax5705_w ) | |
| 8294 | { | |
| 8295 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8296 | UINT8 bank; | |
| 8297 | LOG_MMC(("unl_ax5705_w offset: %04x, data: %02x\n", offset, data)); | |
| 8298 | ||
| 8299 | switch (offset & 0x700f) | |
| 8300 | { | |
| 8301 | case 0x0000: | |
| 8302 | state->m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); | |
| 8303 | unl_ax5705_set_prg(space->machine()); | |
| 8304 | break; | |
| 8305 | case 0x0008: | |
| 8306 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8307 | break; | |
| 8308 | case 0x2000: | |
| 8309 | state->m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); | |
| 8310 | unl_ax5705_set_prg(space->machine()); | |
| 8311 | break; | |
| 8312 | /* CHR banks 0, 1, 4, 5 */ | |
| 8313 | case 0x2008: | |
| 8314 | case 0x200a: | |
| 8315 | case 0x4008: | |
| 8316 | case 0x400a: | |
| 8317 | bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8318 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 8319 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8320 | break; | |
| 8321 | case 0x2009: | |
| 8322 | case 0x200b: | |
| 8323 | case 0x4009: | |
| 8324 | case 0x400b: | |
| 8325 | bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8326 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); | |
| 8327 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8328 | break; | |
| 8329 | /* CHR banks 2, 3, 6, 7 */ | |
| 8330 | case 0x4000: | |
| 8331 | case 0x4002: | |
| 8332 | case 0x6000: | |
| 8333 | case 0x6002: | |
| 8334 | bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8335 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 8336 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8337 | break; | |
| 8338 | case 0x4001: | |
| 8339 | case 0x4003: | |
| 8340 | case 0x6001: | |
| 8341 | case 0x6003: | |
| 8342 | bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8343 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); | |
| 8344 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8345 | break; | |
| 8346 | } | |
| 8347 | } | |
| 8348 | ||
| 8349 | /************************************************************* | |
| 8350 | ||
| 8351 | Board UNL-CC-21 | |
| 8352 | ||
| 8353 | Games: Mi Hun Che | |
| 8354 | ||
| 8355 | In MESS: Supported | |
| 8356 | ||
| 8357 | *************************************************************/ | |
| 8358 | ||
| 8359 | static WRITE8_HANDLER( unl_cc21_w ) | |
| 8360 | { | |
| 8361 | LOG_MMC(("unl_cc21_w offset: %04x, data: %02x\n", offset, data)); | |
| 8362 | ||
| 8363 | set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 8364 | chr8(space->machine(), (offset & 0x01), CHRROM); | |
| 8365 | } | |
| 8366 | ||
| 8367 | /************************************************************* | |
| 8368 | ||
| 8369 | Board UNL-KOF97 | |
| 8370 | ||
| 8371 | Games: King of Fighters 97 (Rex Soft) | |
| 8372 | ||
| 8373 | MMC3 clone | |
| 8374 | ||
| 8375 | In MESS: Not working | |
| 8376 | ||
| 8377 | *************************************************************/ | |
| 8378 | ||
| 8379 | static UINT8 unl_kof97_unscramble( UINT8 data ) | |
| 8380 | { | |
| 8381 | return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20); | |
| 8382 | } | |
| 8383 | ||
| 8384 | static WRITE8_HANDLER( unl_kof97_w ) | |
| 8385 | { | |
| 8386 | LOG_MMC(("unl_kof97_w offset: %04x, data: %02x\n", offset, data)); | |
| 8387 | ||
| 8388 | /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */ | |
| 8389 | if (offset == 0x1000) | |
| 8390 | { | |
| 8391 | data = unl_kof97_unscramble(data); | |
| 8392 | txrom_w(space, 0x0001, data); | |
| 8393 | } | |
| 8394 | else if (offset == 0x2000) | |
| 8395 | { | |
| 8396 | data = unl_kof97_unscramble(data); | |
| 8397 | txrom_w(space, 0x0000, data); | |
| 8398 | } | |
| 8399 | else if (offset == 0x5000) | |
| 8400 | { | |
| 8401 | data = unl_kof97_unscramble(data); | |
| 8402 | txrom_w(space, 0x4001, data); | |
| 8403 | } | |
| 8404 | else if (offset == 0x7000) | |
| 8405 | { | |
| 8406 | data = unl_kof97_unscramble(data); | |
| 8407 | txrom_w(space, 0x6001, data); | |
| 8408 | } | |
| 8409 | else /* Other addresses behaves like MMC3, up to unscrambling data */ | |
| 8410 | { | |
| 8411 | switch (offset & 0x6001) | |
| 8412 | { | |
| 8413 | case 0x0000: | |
| 8414 | case 0x0001: | |
| 8415 | case 0x4000: | |
| 8416 | case 0x4001: | |
| 8417 | case 0x6000: | |
| 8418 | case 0x6001: | |
| 8419 | case 0x2000: /* are these ever called?!? */ | |
| 8420 | case 0x2001: | |
| 8421 | data = unl_kof97_unscramble(data); | |
| 8422 | txrom_w(space, offset, data); | |
| 8423 | break; | |
| 8424 | } | |
| 8425 | } | |
| 8426 | } | |
| 8427 | ||
| 8428 | /************************************************************* | |
| 8429 | ||
| 8430 | Board UNL-T-230 | |
| 8431 | ||
| 8432 | Games: Dragon Ball Z IV (Unl) | |
| 8433 | ||
| 8434 | In MESS: Supported | |
| 8435 | ||
| 8436 | *************************************************************/ | |
| 8437 | ||
| 8438 | static WRITE8_HANDLER( unl_t230_w ) | |
| 8439 | { | |
| 8440 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8441 | UINT8 bank; | |
| 8442 | LOG_MMC(("unl_t230_w offset: %04x, data: %02x\n", offset, data)); | |
| 8443 | ||
| 8444 | switch (offset & 0x700c) | |
| 8445 | { | |
| 8446 | case 0x0000: | |
| 8447 | break; | |
| 8448 | case 0x2000: | |
| 8449 | prg16_89ab(space->machine(), data); | |
| 8450 | break; | |
| 8451 | ||
| 8452 | // the part below works like VRC-2. how was the original board wired up? | |
| 8453 | // was there a VRC2? if so, we can use VRC-2 and add proper pin settings to xml! | |
| 8454 | case 0x1000: | |
| 8455 | case 0x1004: | |
| 8456 | case 0x1008: | |
| 8457 | case 0x100c: | |
| 8458 | switch (data & 0x03) | |
| 8459 | { | |
| 8460 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 8461 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 8462 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 8463 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 8464 | } | |
| 8465 | break; | |
| 8466 | ||
| 8467 | case 0x3000: | |
| 8468 | case 0x3004: | |
| 8469 | case 0x3008: | |
| 8470 | case 0x300c: | |
| 8471 | case 0x4000: | |
| 8472 | case 0x4004: | |
| 8473 | case 0x4008: | |
| 8474 | case 0x400c: | |
| 8475 | case 0x5000: | |
| 8476 | case 0x5004: | |
| 8477 | case 0x5008: | |
| 8478 | case 0x500c: | |
| 8479 | case 0x6000: | |
| 8480 | case 0x6004: | |
| 8481 | case 0x6008: | |
| 8482 | case 0x600c: | |
| 8483 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 2); | |
| 8484 | if (offset & 0x0004) | |
| 8485 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | (data << 4); | |
| 8486 | else | |
| 8487 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 8488 | ||
| 8489 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], state->m_mmc_chr_source); | |
| 8490 | break; | |
| 8491 | case 0x7000: | |
| 8492 | state->m_IRQ_count_latch &= ~0x0f; | |
| 8493 | state->m_IRQ_count_latch |= data & 0x0f; | |
| 8494 | break; | |
| 8495 | case 0x7004: | |
| 8496 | state->m_IRQ_count_latch &= ~0xf0; | |
| 8497 | state->m_IRQ_count_latch |= (data << 4) & 0xf0; | |
| 8498 | break; | |
| 8499 | case 0x7008: | |
| 8500 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 8501 | state->m_IRQ_enable = data & 0x02; | |
| 8502 | state->m_IRQ_enable_latch = data & 0x01; | |
| 8503 | if (data & 0x02) | |
| 8504 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 8505 | break; | |
| 8506 | ||
| 8507 | default: | |
| 8508 | logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data); | |
| 8509 | break; | |
| 8510 | } | |
| 8511 | } | |
| 8512 | ||
| 8513 | /************************************************************* | |
| 8514 | ||
| 8515 | Bootleg Board for KOF96 | |
| 8516 | ||
| 8517 | Games: The King of Fighters 96, Sonic 3D Blast 6, Street | |
| 8518 | Fighter Zero 2 | |
| 8519 | ||
| 8520 | MMC3 clone | |
| 8521 | ||
| 8522 | iNES: mapper 187 | |
| 8523 | ||
| 8524 | In MESS: Preliminary Support. | |
| 8525 | ||
| 8526 | *************************************************************/ | |
| 8527 | ||
| 8528 | static void kof96_prg_cb( running_machine &machine, int start, int bank ) | |
| 8529 | { | |
| 8530 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8531 | ||
| 8532 | if (!(state->m_mmc_reg[0] & 0x80)) | |
| 8533 | prg8_x(machine, start, bank); | |
| 8534 | } | |
| 8535 | ||
| 8536 | static void kof96_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8537 | { | |
| 8538 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8539 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 8540 | ||
| 8541 | if ((start & 0x04) == chr_page) | |
| 8542 | bank |= 0x100; | |
| 8543 | ||
| 8544 | chr1_x(machine, start, bank, source); | |
| 8545 | } | |
| 8546 | ||
| 8547 | static WRITE8_HANDLER( kof96_l_w ) | |
| 8548 | { | |
| 8549 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8550 | UINT8 new_bank; | |
| 8551 | LOG_MMC(("kof96_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8552 | offset += 0x100; | |
| 8553 | ||
| 8554 | if (offset == 0x1000) | |
| 8555 | { | |
| 8556 | state->m_mmc_reg[0] = data; | |
| 8557 | ||
| 8558 | if (state->m_mmc_reg[0] & 0x80) | |
| 8559 | { | |
| 8560 | new_bank = (state->m_mmc_reg[0] & 0x1f); | |
| 8561 | ||
| 8562 | if (state->m_mmc_reg[0] & 0x20) | |
| 8563 | prg32(space->machine(), new_bank >> 2); | |
| 8564 | else | |
| 8565 | { | |
| 8566 | prg16_89ab(space->machine(), new_bank); | |
| 8567 | prg16_cdef(space->machine(), new_bank); | |
| 8568 | } | |
| 8569 | } | |
| 8570 | else | |
| 8571 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8572 | } | |
| 8573 | ||
| 8574 | if (offset >= 0x1000) | |
| 8575 | { | |
| 8576 | switch (data & 0x03) | |
| 8577 | { | |
| 8578 | case 0x00: | |
| 8579 | case 0x01: | |
| 8580 | state->m_mmc_reg[1] = 0x83; | |
| 8581 | break; | |
| 8582 | case 0x02: | |
| 8583 | state->m_mmc_reg[1] = 0x42; | |
| 8584 | break; | |
| 8585 | case 0x03: | |
| 8586 | state->m_mmc_reg[1] = 0x00; | |
| 8587 | break; | |
| 8588 | } | |
| 8589 | ||
| 8590 | } | |
| 8591 | ||
| 8592 | if (!state->m_mmc_reg[3] && offset > 0x1000) | |
| 8593 | { | |
| 8594 | state->m_mmc_reg[3] = 1; | |
| 8595 | space->write_byte(0x4017, 0x40); | |
| 8596 | } | |
| 8597 | } | |
| 8598 | ||
| 8599 | static READ8_HANDLER( kof96_l_r ) | |
| 8600 | { | |
| 8601 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8602 | LOG_MMC(("kof96_l_r, offset: %04x\n", offset)); | |
| 8603 | offset += 0x100; | |
| 8604 | ||
| 8605 | if (!(offset < 0x1000)) | |
| 8606 | return state->m_mmc_reg[1]; | |
| 8607 | else | |
| 8608 | return 0; | |
| 8609 | } | |
| 8610 | ||
| 8611 | static WRITE8_HANDLER( kof96_w ) | |
| 8612 | { | |
| 8613 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8614 | LOG_MMC(("kof96_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8615 | ||
| 8616 | switch (offset & 0x6003) | |
| 8617 | { | |
| 8618 | case 0x0000: | |
| 8619 | state->m_mmc_reg[2] = 1; | |
| 8620 | txrom_w(space, 0x0000, data); | |
| 8621 | break; | |
| 8622 | ||
| 8623 | case 0x0001: | |
| 8624 | if (state->m_mmc_reg[2]) | |
| 8625 | txrom_w(space, 0x0001, data); | |
| 8626 | break; | |
| 8627 | ||
| 8628 | case 0x0002: | |
| 8629 | break; | |
| 8630 | ||
| 8631 | case 0x0003: | |
| 8632 | state->m_mmc_reg[2] = 0; | |
| 8633 | ||
| 8634 | if (data == 0x28) | |
| 8635 | prg8_cd(space->machine(), 0x17); | |
| 8636 | else if (data == 0x2a) | |
| 8637 | prg8_ab(space->machine(), 0x0f); | |
| 8638 | break; | |
| 8639 | ||
| 8640 | default: | |
| 8641 | txrom_w(space, offset, data); | |
| 8642 | break; | |
| 8643 | } | |
| 8644 | } | |
| 8645 | ||
| 8646 | /************************************************************* | |
| 8647 | ||
| 8648 | Bootleg Board for MK2 | |
| 8649 | ||
| 8650 | Games: Mortal Kombat II, Street Fighter III, Super Mario | |
| 8651 | Kart Rider | |
| 8652 | ||
| 8653 | This board uses an IRQ system very similar to MMC3. We indeed | |
| 8654 | use mapper4_irq, but there is some small glitch! | |
| 8655 | ||
| 8656 | iNES: mapper 91 | |
| 8657 | ||
| 8658 | In MESS: Supported. | |
| 8659 | ||
| 8660 | *************************************************************/ | |
| 8661 | ||
| 8662 | static WRITE8_HANDLER( mk2_m_w ) | |
| 8663 | { | |
| 8664 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8665 | LOG_MMC(("mk2_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8666 | ||
| 8667 | switch (offset & 0x1000) | |
| 8668 | { | |
| 8669 | case 0x0000: | |
| 8670 | switch (offset & 0x03) | |
| 8671 | { | |
| 8672 | case 0x00: chr2_0(space->machine(), data, CHRROM); break; | |
| 8673 | case 0x01: chr2_2(space->machine(), data, CHRROM); break; | |
| 8674 | case 0x02: chr2_4(space->machine(), data, CHRROM); break; | |
| 8675 | case 0x03: chr2_6(space->machine(), data, CHRROM); break; | |
| 8676 | } | |
| 8677 | break; | |
| 8678 | case 0x1000: | |
| 8679 | switch (offset & 0x03) | |
| 8680 | { | |
| 8681 | case 0x00: prg8_89(space->machine(), data); break; | |
| 8682 | case 0x01: prg8_ab(space->machine(), data); break; | |
| 8683 | case 0x02: state->m_IRQ_enable = 0; state->m_IRQ_count = 0; break; | |
| 8684 | case 0x03: state->m_IRQ_enable = 1; state->m_IRQ_count = 7; break; | |
| 8685 | } | |
| 8686 | break; | |
| 8687 | default: | |
| 8688 | logerror("mk2_m_w uncaught addr: %04x value: %02x\n", offset + 0x6000, data); | |
| 8689 | break; | |
| 8690 | } | |
| 8691 | } | |
| 8692 | ||
| 8693 | /************************************************************* | |
| 8694 | ||
| 8695 | Bootleg Board N625092 | |
| 8696 | ||
| 8697 | Games: 400 in 1, 700 in 1, 1000 in 1 | |
| 8698 | ||
| 8699 | iNES: mapper 221 | |
| 8700 | ||
| 8701 | In MESS: Supported. | |
| 8702 | ||
| 8703 | *************************************************************/ | |
| 8704 | ||
| 8705 | static void n625092_set_prg( running_machine &machine, UINT8 reg1, UINT8 reg2 ) | |
| 8706 | { | |
| 8707 | UINT8 map221_helper1, map221_helper2; | |
| 8708 | ||
| 8709 | map221_helper1 = !(reg1 & 0x01) ? reg2 : | |
| 8710 | (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00; | |
| 8711 | map221_helper2 = !(reg1 & 0x01) ? reg2 : | |
| 8712 | (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01; | |
| 8713 | ||
| 8714 | prg16_89ab(machine, map221_helper1 | ((reg1 & 0x70) >> 1)); | |
| 8715 | prg16_cdef(machine, map221_helper2 | ((reg1 & 0x70) >> 1)); | |
| 8716 | } | |
| 8717 | ||
| 8718 | static WRITE8_HANDLER( n625092_w ) | |
| 8719 | { | |
| 8720 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8721 | LOG_MMC(("n625092_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8722 | ||
| 8723 | if (offset < 0x4000) | |
| 8724 | { | |
| 8725 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8726 | offset = (offset >> 1) & 0xff; | |
| 8727 | ||
| 8728 | if (state->m_mmc_latch1 != offset) | |
| 8729 | { | |
| 8730 | state->m_mmc_latch1 = offset; | |
| 8731 | n625092_set_prg(space->machine(), state->m_mmc_latch1, state->m_mmc_latch2); | |
| 8732 | } | |
| 8733 | } | |
| 8734 | else | |
| 8735 | { | |
| 8736 | offset &= 0x07; | |
| 8737 | ||
| 8738 | if (state->m_mmc_latch2 != offset) | |
| 8739 | { | |
| 8740 | state->m_mmc_latch2 = offset; | |
| 8741 | n625092_set_prg(space->machine(), state->m_mmc_latch1, state->m_mmc_latch2); | |
| 8742 | } | |
| 8743 | } | |
| 8744 | } | |
| 8745 | ||
| 8746 | /************************************************************* | |
| 8747 | ||
| 8748 | SC-127 Board | |
| 8749 | ||
| 8750 | Games: Wario World II (Kirby Hack) | |
| 8751 | ||
| 8752 | iNES: mapper 35 | |
| 8753 | ||
| 8754 | In MESS: Supported | |
| 8755 | ||
| 8756 | *************************************************************/ | |
| 8757 | ||
| 8758 | static void sc127_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 8759 | { | |
| 8760 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 8761 | ||
| 8762 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && state->m_IRQ_enable) | |
| 8763 | { | |
| 8764 | state->m_IRQ_count--; | |
| 8765 | ||
| 8766 | if (!blanked && (state->m_IRQ_count == 0)) | |
| 8767 | { | |
| 8768 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 8769 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 8770 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 8771 | state->m_IRQ_enable = 0; | |
| 8772 | } | |
| 8773 | } | |
| 8774 | } | |
| 8775 | ||
| 8776 | static WRITE8_HANDLER( sc127_w ) | |
| 8777 | { | |
| 8778 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8779 | LOG_MMC(("sc127_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8780 | ||
| 8781 | switch (offset) | |
| 8782 | { | |
| 8783 | case 0x0000: | |
| 8784 | prg8_89(space->machine(), data); | |
| 8785 | break; | |
| 8786 | case 0x0001: | |
| 8787 | prg8_ab(space->machine(), data); | |
| 8788 | break; | |
| 8789 | case 0x0002: | |
| 8790 | // state->m_mmc_prg_bank[offset & 0x02] = data; | |
| 8791 | prg8_cd(space->machine(), data); | |
| 8792 | break; | |
| 8793 | case 0x1000: | |
| 8794 | case 0x1001: | |
| 8795 | case 0x1002: | |
| 8796 | case 0x1003: | |
| 8797 | case 0x1004: | |
| 8798 | case 0x1005: | |
| 8799 | case 0x1006: | |
| 8800 | case 0x1007: | |
| 8801 | // state->m_mmc_vrom_bank[offset & 0x07] = data; | |
| 8802 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 8803 | break; | |
| 8804 | case 0x4002: | |
| 8805 | state->m_IRQ_enable = 0; | |
| 8806 | break; | |
| 8807 | case 0x4003: | |
| 8808 | state->m_IRQ_enable = 1; | |
| 8809 | break; | |
| 8810 | case 0x4005: | |
| 8811 | state->m_IRQ_count = data; | |
| 8812 | break; | |
| 8813 | case 0x5001: | |
| 8814 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8815 | break; | |
| 8816 | } | |
| 8817 | } | |
| 8818 | ||
| 8819 | /************************************************************* | |
| 8820 | ||
| 8821 | Bootleg Board SMB2J | |
| 8822 | ||
| 8823 | Games: Super Mario Bros. 2 Pirate (LF36) | |
| 8824 | ||
| 8825 | iNES: mapper 43 | |
| 8826 | ||
| 8827 | In MESS: Supported? The only image I found is not working | |
| 8828 | (not even in NEStopia). | |
| 8829 | ||
| 8830 | *************************************************************/ | |
| 8831 | ||
| 8832 | static WRITE8_HANDLER( smb2j_w ) | |
| 8833 | { | |
| 8834 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8835 | int bank = (((offset >> 8) & 0x03) * 0x20) + (offset & 0x1f); | |
| 8836 | ||
| 8837 | LOG_MMC(("smb2j_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8838 | ||
| 8839 | set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8840 | ||
| 8841 | if (offset & 0x0800) | |
| 8842 | { | |
| 8843 | if (offset & 0x1000) | |
| 8844 | { | |
| 8845 | if (bank * 2 >= state->m_prg_chunks) | |
| 8846 | { | |
| 8847 | memory_set_bankptr(space->machine(), "bank3", state->m_wram); | |
| 8848 | memory_set_bankptr(space->machine(), "bank4", state->m_wram); | |
| 8849 | } | |
| 8850 | else | |
| 8851 | { | |
| 8852 | LOG_MMC(("smb2j_w, selecting upper 16KB bank of #%02x\n", bank)); | |
| 8853 | prg16_cdef(space->machine(), 2 * bank + 1); | |
| 8854 | } | |
| 8855 | } | |
| 8856 | else | |
| 8857 | { | |
| 8858 | if (bank * 2 >= state->m_prg_chunks) | |
| 8859 | { | |
| 8860 | memory_set_bankptr(space->machine(), "bank1", state->m_wram); | |
| 8861 | memory_set_bankptr(space->machine(), "bank2", state->m_wram); | |
| 8862 | } | |
| 8863 | else | |
| 8864 | { | |
| 8865 | LOG_MMC(("smb2j_w, selecting lower 16KB bank of #%02x\n", bank)); | |
| 8866 | prg16_89ab(space->machine(), 2 * bank); | |
| 8867 | } | |
| 8868 | } | |
| 8869 | } | |
| 8870 | else | |
| 8871 | { | |
| 8872 | if (bank * 2 >= state->m_prg_chunks) | |
| 8873 | { | |
| 8874 | memory_set_bankptr(space->machine(), "bank1", state->m_wram); | |
| 8875 | memory_set_bankptr(space->machine(), "bank2", state->m_wram); | |
| 8876 | memory_set_bankptr(space->machine(), "bank3", state->m_wram); | |
| 8877 | memory_set_bankptr(space->machine(), "bank4", state->m_wram); | |
| 8878 | } | |
| 8879 | else | |
| 8880 | { | |
| 8881 | LOG_MMC(("smb2j_w, selecting 32KB bank #%02x\n", bank)); | |
| 8882 | prg32(space->machine(), bank); | |
| 8883 | } | |
| 8884 | } | |
| 8885 | } | |
| 8886 | ||
| 8887 | /************************************************************* | |
| 8888 | ||
| 8889 | BTL-SMB2B | |
| 8890 | ||
| 8891 | Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) | |
| 8892 | ||
| 8893 | This was marked as Alt. Levels. is it true? | |
| 8894 | ||
| 8895 | iNES: mapper 50 | |
| 8896 | ||
| 8897 | In MESS: Supported. | |
| 8898 | ||
| 8899 | *************************************************************/ | |
| 8900 | ||
| 8901 | static void smb2jb_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 8902 | { | |
| 8903 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 8904 | if (state->m_IRQ_enable) | |
| 8905 | { | |
| 8906 | if (state->m_IRQ_count < 0x1000) | |
| 8907 | { | |
| 8908 | if ((0x1000 - state->m_IRQ_count) <= 114) | |
| 8909 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 8910 | else | |
| 8911 | state->m_IRQ_count += 114; | |
| 8912 | } | |
| 8913 | else | |
| 8914 | state->m_IRQ_count += 114; | |
| 8915 | ||
| 8916 | state->m_IRQ_count &= 0xffff; // according to docs is 16bit counter -> it wraps only after 0xffff | |
| 8917 | } | |
| 8918 | } | |
| 8919 | ||
| 8920 | static WRITE8_HANDLER( smb2jb_l_w ) | |
| 8921 | { | |
| 8922 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8923 | UINT8 prg; | |
| 8924 | LOG_MMC(("smb2jb_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8925 | offset += 0x100; | |
| 8926 | ||
| 8927 | switch (offset & 0x160) | |
| 8928 | { | |
| 8929 | case 0x020: | |
| 8930 | prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); | |
| 8931 | prg8_cd(space->machine(), prg); | |
| 8932 | break; | |
| 8933 | case 0x120: | |
| 8934 | state->m_IRQ_enable = data & 0x01; | |
| 8935 | break; | |
| 8936 | } | |
| 8937 | } | |
| 8938 | ||
| 8939 | /* This goes to 0x4020-0x403f */ | |
| 8940 | WRITE8_HANDLER( smb2jb_extra_w ) | |
| 8941 | { | |
| 8942 | UINT8 prg; | |
| 8943 | LOG_MMC(("smb2jb_extra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8944 | ||
| 8945 | prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); | |
| 8946 | prg8_cd(space->machine(), prg); | |
| 8947 | } | |
| 8948 | ||
| 8949 | /************************************************************* | |
| 8950 | ||
| 8951 | Bootleg Board for Super Fighter III | |
| 8952 | ||
| 8953 | MMC3 clone | |
| 8954 | ||
| 8955 | iNES: mapper 197 | |
| 8956 | ||
| 8957 | In MESS: Supported. | |
| 8958 | ||
| 8959 | *************************************************************/ | |
| 8960 | ||
| 8961 | static void unl_sf3_set_chr( running_machine &machine, UINT8 chr_source, int chr_base, int chr_mask ) | |
| 8962 | { | |
| 8963 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8964 | chr4_0(machine, chr_base | ((state->m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source); | |
| 8965 | chr2_4(machine, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), chr_source); | |
| 8966 | chr2_6(machine, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr_source); | |
| 8967 | } | |
| 8968 | ||
| 8969 | static WRITE8_HANDLER( unl_sf3_w ) | |
| 8970 | { | |
| 8971 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8972 | UINT8 mmc_helper, cmd; | |
| 8973 | LOG_MMC(("unl_sf3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8974 | ||
| 8975 | switch (offset & 0x6001) | |
| 8976 | { | |
| 8977 | case 0x0000: | |
| 8978 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 8979 | state->m_mmc3_latch = data; | |
| 8980 | ||
| 8981 | /* Has PRG Mode changed? */ | |
| 8982 | if (mmc_helper & 0x40) | |
| 8983 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8984 | ||
| 8985 | /* Has CHR Mode changed? */ | |
| 8986 | if (mmc_helper & 0x80) | |
| 8987 | unl_sf3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8988 | break; | |
| 8989 | ||
| 8990 | case 0x0001: | |
| 8991 | cmd = state->m_mmc3_latch & 0x0f; | |
| 8992 | switch (cmd) | |
| 8993 | { | |
| 8994 | case 0: case 2: case 4: | |
| 8995 | state->m_mmc_vrom_bank[cmd >> 1] = data; | |
| 8996 | unl_sf3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8997 | break; | |
| 8998 | case 6: | |
| 8999 | case 7: | |
| 9000 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 9001 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9002 | break; | |
| 9003 | } | |
| 9004 | break; | |
| 9005 | ||
| 9006 | default: | |
| 9007 | txrom_w(space, offset, data); | |
| 9008 | break; | |
| 9009 | } | |
| 9010 | } | |
| 9011 | ||
| 9012 | /************************************************************* | |
| 9013 | ||
| 9014 | Bootleg Board for Xiao Zhuan Yuan | |
| 9015 | ||
| 9016 | Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan | |
| 9017 | ||
| 9018 | Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1), | |
| 9019 | while writes to 0x5ff2 set chr8 | |
| 9020 | ||
| 9021 | iNES: mapper 176 | |
| 9022 | ||
| 9023 | In MESS: Supported. | |
| 9024 | ||
| 9025 | *************************************************************/ | |
| 9026 | ||
| 9027 | static WRITE8_HANDLER( unl_xzy_l_w ) | |
| 9028 | { | |
| 9029 | LOG_MMC(("unl_xzy_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9030 | ||
| 9031 | switch (offset) | |
| 9032 | { | |
| 9033 | case 0x1ef1: /* 0x5ff1 */ | |
| 9034 | prg32(space->machine(), data >> 1); | |
| 9035 | break; | |
| 9036 | case 0x1ef2: /* 0x5ff2 */ | |
| 9037 | chr8(space->machine(), data, CHRROM); | |
| 9038 | break; | |
| 9039 | } | |
| 9040 | } | |
| 9041 | ||
| 9042 | /************************************************************* | |
| 9043 | ||
| 9044 | Board UNL-RACERMATE | |
| 9045 | ||
| 9046 | In MESS: *VERY* preliminary support. Also, it seems that this | |
| 9047 | board saves to battery the CHRRAM!!! | |
| 9048 | ||
| 9049 | *************************************************************/ | |
| 9050 | ||
| 9051 | static void racmate_update_banks( running_machine &machine ) | |
| 9052 | { | |
| 9053 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9054 | chr4_4(machine, state->m_mmc_latch1 & 0x0f, state->m_mmc_chr_source); | |
| 9055 | prg16_89ab(machine, state->m_mmc_latch1 >> 1); | |
| 9056 | } | |
| 9057 | ||
| 9058 | static WRITE8_HANDLER( unl_racmate_w ) | |
| 9059 | { | |
| 9060 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9061 | LOG_MMC(("unl_racmate_w offset: %04x, data: %02x\n", offset, data)); | |
| 9062 | ||
| 9063 | if (offset == 0x3000) | |
| 9064 | { | |
| 9065 | state->m_mmc_latch1 = data; | |
| 9066 | racmate_update_banks(space->machine()); | |
| 9067 | } | |
| 9068 | } | |
| 9069 | ||
| 9070 | /************************************************************* | |
| 9071 | ||
| 9072 | BOOTLEG CART VERSIONS OF FDS GAMES | |
| 9073 | ||
| 9074 | *************************************************************/ | |
| 9075 | ||
| 9076 | /************************************************************* | |
| 9077 | ||
| 9078 | BTL-SUPERBROS11 | |
| 9079 | ||
| 9080 | Games: Super Mario Bros. 11, Super Mario Bros. 17 | |
| 9081 | ||
| 9082 | This acts basically like a MMC3 with different use of write | |
| 9083 | address. | |
| 9084 | ||
| 9085 | iNES: mapper 196 | |
| 9086 | ||
| 9087 | In MESS: Supported. | |
| 9088 | ||
| 9089 | *************************************************************/ | |
| 9090 | ||
| 9091 | static WRITE8_HANDLER( btl_smb11_w ) | |
| 9092 | { | |
| 9093 | LOG_MMC(("btl_smb11_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9094 | ||
| 9095 | txrom_w(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data); | |
| 9096 | } | |
| 9097 | ||
| 9098 | /************************************************************* | |
| 9099 | ||
| 9100 | BTL-MARIOBABY | |
| 9101 | ||
| 9102 | Games: Mario Baby, Ai Senshi Nicol | |
| 9103 | ||
| 9104 | iNES: mapper 42 | |
| 9105 | ||
| 9106 | In MESS: Supported. | |
| 9107 | ||
| 9108 | *************************************************************/ | |
| 9109 | ||
| 9110 | // is the code fine for ai senshi nicol?!? | |
| 9111 | static WRITE8_HANDLER( btl_mariobaby_w ) | |
| 9112 | { | |
| 9113 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9114 | LOG_MMC(("btl_mariobaby_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9115 | ||
| 9116 | if (offset >= 0x7000) | |
| 9117 | { | |
| 9118 | switch (offset & 0x03) | |
| 9119 | { | |
| 9120 | case 0x00: | |
| 9121 | prg8_67(space->machine(), data); | |
| 9122 | break; | |
| 9123 | case 0x01: | |
| 9124 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9125 | break; | |
| 9126 | case 0x02: | |
| 9127 | /* Check if IRQ is being enabled */ | |
| 9128 | if (!state->m_IRQ_enable && (data & 0x02)) | |
| 9129 | { | |
| 9130 | state->m_IRQ_enable = 1; | |
| 9131 | state->m_irq_timer->adjust(downcast<cpu_device *>(state->m_maincpu)->cycles_to_attotime(24576)); | |
| 9132 | } | |
| 9133 | if (!(data & 0x02)) | |
| 9134 | { | |
| 9135 | state->m_IRQ_enable = 0; | |
| 9136 | state->m_irq_timer->adjust(attotime::never); | |
| 9137 | } | |
| 9138 | break; | |
| 9139 | } | |
| 9140 | } | |
| 9141 | } | |
| 9142 | ||
| 9143 | /************************************************************* | |
| 9144 | ||
| 9145 | BTL-SMB2A | |
| 9146 | ||
| 9147 | Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) | |
| 9148 | ||
| 9149 | iNES: mapper 40 | |
| 9150 | ||
| 9151 | In MESS: Supported. | |
| 9152 | ||
| 9153 | *************************************************************/ | |
| 9154 | ||
| 9155 | static void btl_smb2a_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 9156 | { | |
| 9157 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 9158 | ||
| 9159 | if (state->m_IRQ_enable) | |
| 9160 | { | |
| 9161 | if ((0xfff - state->m_IRQ_count) <= 114) | |
| 9162 | { | |
| 9163 | state->m_IRQ_count = (state->m_IRQ_count + 1) & 0xfff; | |
| 9164 | state->m_IRQ_enable = 0; | |
| 9165 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 9166 | } | |
| 9167 | else | |
| 9168 | state->m_IRQ_count += 114; | |
| 9169 | } | |
| 9170 | } | |
| 9171 | ||
| 9172 | static WRITE8_HANDLER( btl_smb2a_w ) | |
| 9173 | { | |
| 9174 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9175 | LOG_MMC(("btl_smb2a_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9176 | ||
| 9177 | switch (offset & 0x6000) | |
| 9178 | { | |
| 9179 | case 0x0000: | |
| 9180 | state->m_IRQ_enable = 0; | |
| 9181 | state->m_IRQ_count = 0; | |
| 9182 | break; | |
| 9183 | case 0x2000: | |
| 9184 | state->m_IRQ_enable = 1; | |
| 9185 | break; | |
| 9186 | case 0x6000: | |
| 9187 | prg8_cd(space->machine(), data); | |
| 9188 | break; | |
| 9189 | } | |
| 9190 | } | |
| 9191 | ||
| 9192 | /************************************************************* | |
| 9193 | ||
| 9194 | WHIRLWIND-2706 | |
| 9195 | ||
| 9196 | Games: Meikyuu Jiin Dababa (FDS conversion) | |
| 9197 | ||
| 9198 | iNES: mapper 108 | |
| 9199 | ||
| 9200 | In MESS: Supported. | |
| 9201 | ||
| 9202 | *************************************************************/ | |
| 9203 | ||
| 9204 | static WRITE8_HANDLER( whirl2706_w ) | |
| 9205 | { | |
| 9206 | LOG_MMC(("whirl2706_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9207 | prg8_67(space->machine(), data); | |
| 9208 | } | |
| 9209 | ||
| 9210 | /************************************************************* | |
| 9211 | ||
| 9212 | Bootleg Board used for FDS conversion | |
| 9213 | ||
| 9214 | Games: Tobidase Daisakusen (FDS conversion) | |
| 9215 | ||
| 9216 | iNES: mapper 120 | |
| 9217 | ||
| 9218 | In MESS: Partially Supported. | |
| 9219 | ||
| 9220 | *************************************************************/ | |
| 9221 | ||
| 9222 | static WRITE8_HANDLER( btl_tobi_l_w ) | |
| 9223 | { | |
| 9224 | LOG_MMC(("btl_tobi_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9225 | offset += 0x100; | |
| 9226 | ||
| 9227 | if ((offset & 0x43c0) == 0x41c0) | |
| 9228 | prg8_67(space->machine(), data & 0x07); | |
| 9229 | } | |
| 9230 | ||
| 9231 | /************************************************************* | |
| 9232 | ||
| 9233 | BTL-SMB3 | |
| 9234 | ||
| 9235 | Games: Super Mario Bros. 3 Pirate | |
| 9236 | ||
| 9237 | iNES: mapper 106 | |
| 9238 | ||
| 9239 | In MESS: Supported. | |
| 9240 | ||
| 9241 | *************************************************************/ | |
| 9242 | ||
| 9243 | static void btl_smb3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 9244 | { | |
| 9245 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 9246 | ||
| 9247 | if (state->m_IRQ_enable) | |
| 9248 | { | |
| 9249 | if ((0xffff - state->m_IRQ_count) < 114) | |
| 9250 | { | |
| 9251 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 9252 | state->m_IRQ_enable = 0; | |
| 9253 | } | |
| 9254 | ||
| 9255 | state->m_IRQ_count = (state->m_IRQ_count + 114) & 0xffff; | |
| 9256 | } | |
| 9257 | } | |
| 9258 | ||
| 9259 | static WRITE8_HANDLER( btl_smb3_w ) | |
| 9260 | { | |
| 9261 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9262 | LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9263 | switch (offset & 0x0f) | |
| 9264 | { | |
| 9265 | case 0x00: | |
| 9266 | case 0x02: | |
| 9267 | chr1_x(space->machine(), offset & 0x07, data & 0xfe, CHRROM); | |
| 9268 | break; | |
| 9269 | case 0x01: | |
| 9270 | case 0x03: | |
| 9271 | chr1_x(space->machine(), offset & 0x07, data | 0x01, CHRROM); | |
| 9272 | break; | |
| 9273 | case 0x04: case 0x05: | |
| 9274 | case 0x06: case 0x07: | |
| 9275 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 9276 | break; | |
| 9277 | case 0x08: | |
| 9278 | prg8_89(space->machine(), data | 0x10); | |
| 9279 | break; | |
| 9280 | case 0x09: | |
| 9281 | prg8_ab(space->machine(), data); | |
| 9282 | break; | |
| 9283 | case 0x0a: | |
| 9284 | prg8_cd(space->machine(), data); | |
| 9285 | break; | |
| 9286 | case 0x0b: | |
| 9287 | prg8_ef(space->machine(), data | 0x10); | |
| 9288 | break; | |
| 9289 | case 0x0c: | |
| 9290 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9291 | break; | |
| 9292 | case 0x0d: | |
| 9293 | state->m_IRQ_count = 0; | |
| 9294 | state->m_IRQ_enable = 0; | |
| 9295 | break; | |
| 9296 | case 0x0e: | |
| 9297 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 9298 | break; | |
| 9299 | case 0x0f: | |
| 9300 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 9301 | state->m_IRQ_enable = 1; | |
| 9302 | break; | |
| 9303 | } | |
| 9304 | } | |
| 9305 | ||
| 9306 | /************************************************************* | |
| 9307 | ||
| 9308 | BTL-DRAGONNINJA | |
| 9309 | ||
| 9310 | Games: Dragon Ninja (Bootleg), Super Mario Bros. 8 | |
| 9311 | ||
| 9312 | iNES: mapper 222 | |
| 9313 | ||
| 9314 | In MESS: Unsupported. | |
| 9315 | ||
| 9316 | *************************************************************/ | |
| 9317 | ||
| 9318 | /* Scanline based IRQ ? */ | |
| 9319 | static void btl_dn_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 9320 | { | |
| 9321 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 9322 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 9323 | { | |
| 9324 | if (!state->m_IRQ_count || ++state->m_IRQ_count < 240) | |
| 9325 | return; | |
| 9326 | ||
| 9327 | state->m_IRQ_count = 0; | |
| 9328 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 9329 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 9330 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 9331 | } | |
| 9332 | } | |
| 9333 | ||
| 9334 | static WRITE8_HANDLER( btl_dn_w ) | |
| 9335 | { | |
| 9336 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9337 | UINT8 bank; | |
| 9338 | LOG_MMC(("btl_dn_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9339 | ||
| 9340 | switch (offset & 0x7003) | |
| 9341 | { | |
| 9342 | case 0x0000: | |
| 9343 | prg8_89(space->machine(), data); | |
| 9344 | break; | |
| 9345 | case 0x1000: | |
| 9346 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9347 | break; | |
| 9348 | case 0x2000: | |
| 9349 | prg8_ab(space->machine(), data); | |
| 9350 | break; | |
| 9351 | case 0x3000: | |
| 9352 | case 0x3002: | |
| 9353 | case 0x4000: | |
| 9354 | case 0x4002: | |
| 9355 | case 0x5000: | |
| 9356 | case 0x5002: | |
| 9357 | case 0x6000: | |
| 9358 | case 0x6002: | |
| 9359 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 3); | |
| 9360 | chr1_x(space->machine(), bank, data, CHRROM); | |
| 9361 | break; | |
| 9362 | case 0x7000: | |
| 9363 | state->m_IRQ_count = data; | |
| 9364 | break; | |
| 9365 | } | |
| 9366 | } | |
| 9367 | ||
| 9368 | /************************************************************* | |
| 9369 | ||
| 9370 | BTL-PIKACHUY2K | |
| 9371 | ||
| 9372 | Games: Pikachu Y2k | |
| 9373 | ||
| 9374 | iNES: mapper 254 | |
| 9375 | ||
| 9376 | In MESS: | |
| 9377 | ||
| 9378 | *************************************************************/ | |
| 9379 | ||
| 9380 | static WRITE8_HANDLER( btl_pika_y2k_w ) | |
| 9381 | { | |
| 9382 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9383 | LOG_MMC(("btl_pika_y2k_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9384 | ||
| 9385 | switch (offset & 0x6001) | |
| 9386 | { | |
| 9387 | case 0x2001: | |
| 9388 | state->m_mmc_latch2 = data; | |
| 9389 | break; | |
| 9390 | ||
| 9391 | case 0x2000: | |
| 9392 | state->m_mmc_reg[0] = 0; | |
| 9393 | default: | |
| 9394 | txrom_w(space, offset, data); | |
| 9395 | break; | |
| 9396 | } | |
| 9397 | } | |
| 9398 | ||
| 9399 | // strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000 | |
| 9400 | static WRITE8_HANDLER( btl_pika_y2k_m_w ) | |
| 9401 | { | |
| 9402 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9403 | LOG_MMC(("btl_pika_y2k_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9404 | ||
| 9405 | state->m_wram[offset] = data; | |
| 9406 | } | |
| 9407 | ||
| 9408 | static READ8_HANDLER( btl_pika_y2k_m_r ) | |
| 9409 | { | |
| 9410 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9411 | LOG_MMC(("btl_pika_y2k_m_r, offset: %04x\n", offset)); | |
| 9412 | ||
| 9413 | return state->m_wram[offset] ^ (state->m_mmc_latch2 & state->m_mmc_reg[0]); | |
| 9414 | } | |
| 9415 | ||
| 9416 | /************************************************************* | |
| 9417 | ||
| 9418 | MULTICART | |
| 9419 | ||
| 9420 | *************************************************************/ | |
| 9421 | ||
| 9422 | /************************************************************* | |
| 9423 | ||
| 9424 | Board BMC-FK23C | |
| 9425 | ||
| 9426 | In MESS: partially supported (still to sort initial banking | |
| 9427 | for many games) | |
| 9428 | ||
| 9429 | *************************************************************/ | |
| 9430 | ||
| 9431 | #if 0 | |
| 9432 | static void fk23c_prg_cb( running_machine &machine, int start, int bank ) | |
| 9433 | { | |
| 9434 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9435 | ||
| 9436 | if (((state->m_mmc_reg[0] & 0x07) - 3) > 1 && (!(state->m_mmc_reg[3] & 0x02) || start < 2)) | |
| 9437 | { | |
| 9438 | if (state->m_mmc_reg[0] & 0x03) | |
| 9439 | bank = (bank & (0x3f >> (state->m_mmc_reg[0] & 0x03))) | (state->m_mmc_reg[1] << 1); | |
| 9440 | ||
| 9441 | prg8_x(machine, start, bank); | |
| 9442 | } | |
| 9443 | } | |
| 9444 | ||
| 9445 | static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 9446 | { | |
| 9447 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9448 | ||
| 9449 | if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3))) | |
| 9450 | chr1_x(machine, start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source); | |
| 9451 | } | |
| 9452 | ||
| 9453 | #endif | |
| 9454 | ||
| 9455 | static void fk23c_prg_cb( running_machine &machine, int start, int bank ) | |
| 9456 | { | |
| 9457 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9458 | UINT8 mask = (0x3f >> (state->m_mmc_reg[0] & 0x03)); | |
| 9459 | ||
| 9460 | if ((state->m_mmc_reg[0] & 0x07) < 3) | |
| 9461 | { | |
| 9462 | if (!(state->m_mmc_reg[0] & 0x03)) | |
| 9463 | bank = (bank & mask) | ((state->m_mmc_reg[1] & (0x7f ^ mask)) << 1); | |
| 9464 | ||
| 9465 | prg8_x(machine, start, bank); | |
| 9466 | } | |
| 9467 | } | |
| 9468 | ||
| 9469 | static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 9470 | { | |
| 9471 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9472 | ||
| 9473 | if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3))) | |
| 9474 | chr1_x(machine, start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source); | |
| 9475 | } | |
| 9476 | ||
| 9477 | static void fk23c_set_prg( running_machine &machine ) | |
| 9478 | { | |
| 9479 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9480 | ||
| 9481 | if ((state->m_mmc_reg[0] & 0x07) == 4) | |
| 9482 | prg32(machine, (state->m_mmc_reg[1] & 0x7f) >> 1); | |
| 9483 | else if ((state->m_mmc_reg[0] & 0x07) == 3) | |
| 9484 | { | |
| 9485 | prg16_89ab(machine, state->m_mmc_reg[1] & 0x7f); | |
| 9486 | prg16_cdef(machine, state->m_mmc_reg[1] & 0x7f); | |
| 9487 | } | |
| 9488 | else | |
| 9489 | { | |
| 9490 | if (state->m_mmc_reg[3] & 0x02) | |
| 9491 | { | |
| 9492 | prg8_cd(machine, state->m_mmc_reg[4]); | |
| 9493 | prg8_ef(machine, state->m_mmc_reg[5]); | |
| 9494 | } | |
| 9495 | ||
| 9496 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9497 | } | |
| 9498 | } | |
| 9499 | ||
| 9500 | static void fk23c_set_chr( running_machine &machine ) | |
| 9501 | { | |
| 9502 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9503 | ||
| 9504 | if (state->m_mmc_reg[0] & 0x40) | |
| 9505 | chr8(machine, state->m_mmc_reg[2] | state->m_mmc_cmd1, state->m_mmc_chr_source); | |
| 9506 | else | |
| 9507 | { | |
| 9508 | if (state->m_mmc_reg[3] & 0x02) | |
| 9509 | { | |
| 9510 | int base = (state->m_mmc_reg[2] & 0x7f) << 3; | |
| 9511 | chr1_x(machine, 1, base | state->m_mmc_reg[6], state->m_mmc_chr_source); | |
| 9512 | chr1_x(machine, 3, base | state->m_mmc_reg[7], state->m_mmc_chr_source); | |
| 9513 | } | |
| 9514 | ||
| 9515 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 9516 | } | |
| 9517 | } | |
| 9518 | ||
| 9519 | static WRITE8_HANDLER( fk23c_l_w ) | |
| 9520 | { | |
| 9521 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9522 | LOG_MMC(("fk23c_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9523 | offset += 0x100; | |
| 9524 | ||
| 9525 | if (offset >= 0x1000) | |
| 9526 | { | |
| 9527 | if (offset & (1 << 4)) // here it should be (4 + state->m_mmc_dipsetting) | |
| 9528 | { | |
| 9529 | state->m_mmc_reg[offset & 0x03] = data; | |
| 9530 | ||
| 9531 | fk23c_set_prg(space->machine()); | |
| 9532 | fk23c_set_chr(space->machine()); | |
| 9533 | } | |
| 9534 | } | |
| 9535 | } | |
| 9536 | ||
| 9537 | static WRITE8_HANDLER( fk23c_w ) | |
| 9538 | { | |
| 9539 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9540 | LOG_MMC(("fk23c_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9541 | ||
| 9542 | if (state->m_mmc_reg[0] & 0x40) | |
| 9543 | { | |
| 9544 | if (state->m_mmc_reg[0] & 0x30) | |
| 9545 | state->m_mmc_cmd1 = 0; | |
| 9546 | else | |
| 9547 | { | |
| 9548 | state->m_mmc_cmd1 = data & 0x03; | |
| 9549 | fk23c_set_chr(space->machine()); | |
| 9550 | } | |
| 9551 | } | |
| 9552 | else | |
| 9553 | { | |
| 9554 | switch (offset & 0x6001) | |
| 9555 | { | |
| 9556 | case 0x0001: | |
| 9557 | if ((state->m_mmc_reg[3] & 0x02) && (state->m_mmc3_latch & 0x08)) | |
| 9558 | { | |
| 9559 | state->m_mmc_reg[4 | (state->m_mmc3_latch & 0x03)] = data; | |
| 9560 | fk23c_set_prg(space->machine()); | |
| 9561 | fk23c_set_chr(space->machine()); | |
| 9562 | } | |
| 9563 | else | |
| 9564 | txrom_w(space, offset, data); | |
| 9565 | break; | |
| 9566 | ||
| 9567 | case 0x2000: | |
| 9568 | set_nt_mirroring(space->machine(), data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9569 | break; | |
| 9570 | ||
| 9571 | default: | |
| 9572 | txrom_w(space, offset, data); | |
| 9573 | break; | |
| 9574 | } | |
| 9575 | } | |
| 9576 | } | |
| 9577 | ||
| 9578 | ||
| 9579 | /************************************************************* | |
| 9580 | ||
| 9581 | Board BMC-64IN1NOREPEAT | |
| 9582 | ||
| 9583 | Games: 64-in-1 Y2K | |
| 9584 | ||
| 9585 | In MESS: Supported | |
| 9586 | ||
| 9587 | *************************************************************/ | |
| 9588 | ||
| 9589 | static void bmc_64in1nr_set_prg( running_machine &machine ) | |
| 9590 | { | |
| 9591 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9592 | UINT8 helper1 = (state->m_mmc_reg[1] & 0x1f); | |
| 9593 | UINT8 helper2 = (helper1 << 1) | ((state->m_mmc_reg[1] & 0x40) >> 6); | |
| 9594 | ||
| 9595 | if (state->m_mmc_reg[0] & 0x80) | |
| 9596 | { | |
| 9597 | if (state->m_mmc_reg[1] & 0x80) | |
| 9598 | prg32(machine, helper1); | |
| 9599 | else | |
| 9600 | { | |
| 9601 | prg16_89ab(machine, helper2); | |
| 9602 | prg16_cdef(machine, helper2); | |
| 9603 | } | |
| 9604 | } | |
| 9605 | else | |
| 9606 | prg16_cdef(machine, helper2); | |
| 9607 | } | |
| 9608 | ||
| 9609 | static WRITE8_HANDLER( bmc_64in1nr_l_w ) | |
| 9610 | { | |
| 9611 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9612 | LOG_MMC(("bmc_64in1nr_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 9613 | offset += 0x100; | |
| 9614 | ||
| 9615 | switch (offset) | |
| 9616 | { | |
| 9617 | case 0x1000: | |
| 9618 | case 0x1001: | |
| 9619 | case 0x1002: | |
| 9620 | case 0x1003: | |
| 9621 | state->m_mmc_reg[offset & 0x03] = data; | |
| 9622 | bmc_64in1nr_set_prg(space->machine()); | |
| 9623 | chr8(space->machine(), ((state->m_mmc_reg[0] >> 1) & 0x03) | (state->m_mmc_reg[2] << 2), CHRROM); | |
| 9624 | break; | |
| 9625 | } | |
| 9626 | if (offset == 0x1000) /* reg[0] also sets mirroring */ | |
| 9627 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9628 | } | |
| 9629 | ||
| 9630 | static WRITE8_HANDLER( bmc_64in1nr_w ) | |
| 9631 | { | |
| 9632 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9633 | LOG_MMC(("bmc_64in1nr_w offset: %04x, data: %02x\n", offset, data)); | |
| 9634 | ||
| 9635 | state->m_mmc_reg[3] = data; // reg[3] is currently unused?!? | |
| 9636 | } | |
| 9637 | ||
| 9638 | /************************************************************* | |
| 9639 | ||
| 9640 | Board BMC-190IN1 | |
| 9641 | ||
| 9642 | Games: 190-in-1 | |
| 9643 | ||
| 9644 | In MESS: Supported | |
| 9645 | ||
| 9646 | *************************************************************/ | |
| 9647 | ||
| 9648 | static WRITE8_HANDLER( bmc_190in1_w ) | |
| 9649 | { | |
| 9650 | LOG_MMC(("bmc_190in1_w offset: %04x, data: %02x\n", offset, data)); | |
| 9651 | ||
| 9652 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9653 | offset >>= 2; | |
| 9654 | prg16_89ab(space->machine(), offset); | |
| 9655 | prg16_cdef(space->machine(), offset); | |
| 9656 | chr8(space->machine(), offset, CHRROM); | |
| 9657 | } | |
| 9658 | ||
| 9659 | /************************************************************* | |
| 9660 | ||
| 9661 | Board BMC-A65AS | |
| 9662 | ||
| 9663 | Games: 3-in-1 (N068) | |
| 9664 | ||
| 9665 | In MESS: Supported | |
| 9666 | ||
| 9667 | *************************************************************/ | |
| 9668 | ||
| 9669 | static WRITE8_HANDLER( bmc_a65as_w ) | |
| 9670 | { | |
| 9671 | UINT8 helper = (data & 0x30) >> 1; | |
| 9672 | LOG_MMC(("bmc_a65as_w offset: %04x, data: %02x\n", offset, data)); | |
| 9673 | ||
| 9674 | if (data & 0x80) | |
| 9675 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 9676 | else | |
| 9677 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9678 | ||
| 9679 | if (data & 0x40) | |
| 9680 | prg32(space->machine(), data >> 1); | |
| 9681 | else | |
| 9682 | { | |
| 9683 | prg16_89ab(space->machine(), helper | (data & 0x07)); | |
| 9684 | prg16_cdef(space->machine(), helper | 0x07); | |
| 9685 | } | |
| 9686 | } | |
| 9687 | ||
| 9688 | /************************************************************* | |
| 9689 | ||
| 9690 | Board BMC-GS2004 | |
| 9691 | ||
| 9692 | Games: Tetris Family 6-in-1 | |
| 9693 | ||
| 9694 | In MESS: Preliminary Support. It also misses WRAM handling | |
| 9695 | (we need reads from 0x6000-0x7fff) | |
| 9696 | ||
| 9697 | *************************************************************/ | |
| 9698 | ||
| 9699 | static WRITE8_HANDLER( bmc_gs2004_w ) | |
| 9700 | { | |
| 9701 | LOG_MMC(("bmc_gs2004_w offset: %04x, data: %02x\n", offset, data)); | |
| 9702 | ||
| 9703 | prg32(space->machine(), data); | |
| 9704 | } | |
| 9705 | ||
| 9706 | /************************************************************* | |
| 9707 | ||
| 9708 | Board BMC-GS2013 | |
| 9709 | ||
| 9710 | Games: Tetris Family 12-in-1 | |
| 9711 | ||
| 9712 | In MESS: Preliminary Support. It also misses WRAM handling | |
| 9713 | (we need reads from 0x6000-0x7fff) | |
| 9714 | ||
| 9715 | *************************************************************/ | |
| 9716 | ||
| 9717 | static WRITE8_HANDLER( bmc_gs2013_w ) | |
| 9718 | { | |
| 9719 | LOG_MMC(("bmc_gs2013_w offset: %04x, data: %02x\n", offset, data)); | |
| 9720 | ||
| 9721 | if (data & 0x08) | |
| 9722 | prg32(space->machine(), data & 0x09); | |
| 9723 | else | |
| 9724 | prg32(space->machine(), data & 0x07); | |
| 9725 | } | |
| 9726 | ||
| 9727 | /************************************************************* | |
| 9728 | ||
| 9729 | Board BMC-SUPER24IN1SC03 | |
| 9730 | ||
| 9731 | Games: Super 24-in-1 | |
| 9732 | ||
| 9733 | In MESS: Partially Supported | |
| 9734 | ||
| 9735 | *************************************************************/ | |
| 9736 | ||
| 9737 | static void bmc_s24in1sc03_prg_cb( running_machine &machine, int start, int bank ) | |
| 9738 | { | |
| 9739 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9740 | static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00}; | |
| 9741 | int prg_base = state->m_mmc_reg[1] << 1; | |
| 9742 | int prg_mask = masks[state->m_mmc_reg[0] & 0x07]; | |
| 9743 | ||
| 9744 | bank = prg_base | (bank & prg_mask); | |
| 9745 | prg8_x(machine, start, bank); | |
| 9746 | } | |
| 9747 | ||
| 9748 | static void bmc_s24in1sc03_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 9749 | { | |
| 9750 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9751 | UINT8 chr = BIT(state->m_mmc_reg[0], 5) ? CHRRAM : CHRROM; | |
| 9752 | int chr_base = (state->m_mmc_reg[2] << 3) & 0xf00; | |
| 9753 | ||
| 9754 | chr1_x(machine, start, chr_base | bank, chr); | |
| 9755 | } | |
| 9756 | ||
| 9757 | static WRITE8_HANDLER( bmc_s24in1sc03_l_w ) | |
| 9758 | { | |
| 9759 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9760 | LOG_MMC(("bmc_s24in1sc03_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 9761 | offset += 0x100; | |
| 9762 | ||
| 9763 | if (offset == 0x1ff0) | |
| 9764 | { | |
| 9765 | state->m_mmc_reg[0] = data; | |
| 9766 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 9767 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9768 | } | |
| 9769 | ||
| 9770 | if (offset == 0x1ff1) | |
| 9771 | { | |
| 9772 | state->m_mmc_reg[1] = data; | |
| 9773 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9774 | } | |
| 9775 | ||
| 9776 | if (offset == 0x1ff2) | |
| 9777 | { | |
| 9778 | state->m_mmc_reg[2] = data; | |
| 9779 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 9780 | } | |
| 9781 | } | |
| 9782 | ||
| 9783 | /************************************************************* | |
| 9784 | ||
| 9785 | Board BMC-T-262 | |
| 9786 | ||
| 9787 | Games: 4-in-1 (D-010), 8-in-1 (A-020) | |
| 9788 | ||
| 9789 | In MESS: Supported | |
| 9790 | ||
| 9791 | *************************************************************/ | |
| 9792 | ||
| 9793 | static WRITE8_HANDLER( bmc_t262_w ) | |
| 9794 | { | |
| 9795 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9796 | UINT8 mmc_helper; | |
| 9797 | LOG_MMC(("bmc_t262_w offset: %04x, data: %02x\n", offset, data)); | |
| 9798 | ||
| 9799 | if (state->m_mmc_latch2 || offset == 0) | |
| 9800 | { | |
| 9801 | state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x38) | (data & 0x07); | |
| 9802 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 9803 | } | |
| 9804 | else | |
| 9805 | { | |
| 9806 | state->m_mmc_latch2 = 1; | |
| 9807 | set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9808 | mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18); | |
| 9809 | state->m_mmc_latch1 = mmc_helper | (state->m_mmc_latch1 & 0x07); | |
| 9810 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 9811 | prg16_cdef(space->machine(), mmc_helper | 0x07); | |
| 9812 | } | |
| 9813 | } | |
| 9814 | ||
| 9815 | /************************************************************* | |
| 9816 | ||
| 9817 | Board BMC-WS | |
| 9818 | ||
| 9819 | Games: Super 40-in-1 | |
| 9820 | ||
| 9821 | In MESS: Partially Supported (some games, like Galaxian, have | |
| 9822 | issues) | |
| 9823 | ||
| 9824 | *************************************************************/ | |
| 9825 | ||
| 9826 | static WRITE8_HANDLER( bmc_ws_m_w ) | |
| 9827 | { | |
| 9828 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9829 | UINT8 mmc_helper; | |
| 9830 | LOG_MMC(("bmc_ws_m_w offset: %04x, data: %02x\n", offset, data)); | |
| 9831 | ||
| 9832 | if (offset < 0x1000) | |
| 9833 | { | |
| 9834 | switch (offset & 0x01) | |
| 9835 | { | |
| 9836 | case 0: | |
| 9837 | if (!state->m_mmc_latch1) | |
| 9838 | { | |
| 9839 | state->m_mmc_latch1 = data & 0x20; | |
| 9840 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9841 | mmc_helper = (~data & 0x08) >> 3; | |
| 9842 | prg16_89ab(space->machine(), data & ~mmc_helper); | |
| 9843 | prg16_cdef(space->machine(), data | mmc_helper); | |
| 9844 | } | |
| 9845 | break; | |
| 9846 | case 1: | |
| 9847 | if (!state->m_mmc_latch1) | |
| 9848 | { | |
| 9849 | chr8(space->machine(), data, CHRROM); | |
| 9850 | } | |
| 9851 | break; | |
| 9852 | } | |
| 9853 | } | |
| 9854 | } | |
| 9855 | ||
| 9856 | /************************************************************* | |
| 9857 | ||
| 9858 | BMC-NOVELDIAMOND and BMC-999999in1 | |
| 9859 | ||
| 9860 | Unknown Bootleg Multigame Board | |
| 9861 | Games: I only found 'Novel Diamond 999999-in-1.unf' using | |
| 9862 | this mapper (hence the code is used for BMC_NOVELDIAMOND | |
| 9863 | board). The code is included here in case a mapper 54 | |
| 9864 | dump arises. | |
| 9865 | ||
| 9866 | iNES: mappers 54 and 213 | |
| 9867 | ||
| 9868 | In MESS: Partial Support. | |
| 9869 | ||
| 9870 | *************************************************************/ | |
| 9871 | ||
| 9872 | // Are this correct or should they work the same? | |
| 9873 | static WRITE8_HANDLER( novel1_w ) | |
| 9874 | { | |
| 9875 | LOG_MMC(("novel1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9876 | ||
| 9877 | prg32(space->machine(), offset & 0x03); | |
| 9878 | chr8(space->machine(), offset & 0x07, CHRROM); | |
| 9879 | } | |
| 9880 | ||
| 9881 | static WRITE8_HANDLER( novel2_w ) | |
| 9882 | { | |
| 9883 | LOG_MMC(("novel2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9884 | ||
| 9885 | prg32(space->machine(), offset >> 1); | |
| 9886 | chr8(space->machine(), offset >> 3, CHRROM); | |
| 9887 | } | |
| 9888 | ||
| 9889 | /************************************************************* | |
| 9890 | ||
| 9891 | Board BMC-GKA | |
| 9892 | ||
| 9893 | Unknown Bootleg Multigame Board | |
| 9894 | Games: 6 in 1, 54 in 1, 106 in 1 | |
| 9895 | ||
| 9896 | iNES: mapper 57 | |
| 9897 | ||
| 9898 | In MESS: Supported. | |
| 9899 | ||
| 9900 | *************************************************************/ | |
| 9901 | ||
| 9902 | static WRITE8_HANDLER( bmc_gka_w ) | |
| 9903 | { | |
| 9904 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9905 | LOG_MMC(("bmc_gka_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9906 | ||
| 9907 | if (offset & 0x0800) | |
| 9908 | state->m_mmc_latch2 = data; | |
| 9909 | else | |
| 9910 | state->m_mmc_latch1 = data; | |
| 9911 | ||
| 9912 | if (state->m_mmc_latch2 & 0x80) | |
| 9913 | prg32(space->machine(), 2 | (state->m_mmc_latch2 >> 6)); | |
| 9914 | else | |
| 9915 | { | |
| 9916 | prg16_89ab(space->machine(), (state->m_mmc_latch2 >> 5) & 0x03); | |
| 9917 | prg16_cdef(space->machine(), (state->m_mmc_latch2 >> 5) & 0x03); | |
| 9918 | } | |
| 9919 | ||
| 9920 | set_nt_mirroring(space->machine(), (state->m_mmc_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9921 | ||
| 9922 | chr8(space->machine(), (state->m_mmc_latch1 & 0x03) | (state->m_mmc_latch2 & 0x07) | ((state->m_mmc_latch2 & 0x10) >> 1), CHRROM); | |
| 9923 | } | |
| 9924 | ||
| 9925 | ||
| 9926 | /************************************************************* | |
| 9927 | ||
| 9928 | Board UNL-STUDYNGAME | |
| 9929 | ||
| 9930 | Games: Study n Game 32 in 1 | |
| 9931 | ||
| 9932 | iNES: mapper 39 | |
| 9933 | ||
| 9934 | In MESS: Partially Supported (problems with PRG bankswitch, | |
| 9935 | only keyboard exercise work). | |
| 9936 | ||
| 9937 | *************************************************************/ | |
| 9938 | ||
| 9939 | static WRITE8_HANDLER( sng32_w ) | |
| 9940 | { | |
| 9941 | LOG_MMC(("sng32_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9942 | prg32(space->machine(), data); | |
| 9943 | } | |
| 9944 | ||
| 9945 | /************************************************************* | |
| 9946 | ||
| 9947 | Board BMC-GKB | |
| 9948 | ||
| 9949 | Unknown Bootleg Multigame Board | |
| 9950 | Games: 68 in 1, 73 in 1, 98 in 1 | |
| 9951 | ||
| 9952 | iNES: mapper 58 | |
| 9953 | ||
| 9954 | In MESS: Supported. | |
| 9955 | ||
| 9956 | *************************************************************/ | |
| 9957 | ||
| 9958 | static WRITE8_HANDLER( bmc_gkb_w ) | |
| 9959 | { | |
| 9960 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9961 | UINT8 bank = (offset & 0x40) ? 0 : 1; | |
| 9962 | LOG_MMC(("bmc_gkb_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9963 | ||
| 9964 | prg16_89ab(space->machine(), offset & ~bank); | |
| 9965 | prg16_cdef(space->machine(), offset | bank); | |
| 9966 | chr8(space->machine(), offset >> 3, state->m_mmc_chr_source); | |
| 9967 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9968 | } | |
| 9969 | ||
| 9970 | /************************************************************* | |
| 9971 | ||
| 9972 | BMC-SUPER-700IN1 | |
| 9973 | ||
| 9974 | Unknown Bootleg Multigame Board | |
| 9975 | Games: Super 700 in 1 | |
| 9976 | ||
| 9977 | iNES: mapper 62 | |
| 9978 | ||
| 9979 | In MESS: Supported. | |
| 9980 | ||
| 9981 | *************************************************************/ | |
| 9982 | ||
| 9983 | static WRITE8_HANDLER( bmc_super700in1_w ) | |
| 9984 | { | |
| 9985 | LOG_MMC(("bmc_super700in1_w, offset :%04x, data: %02x\n", offset, data)); | |
| 9986 | ||
| 9987 | chr8(space->machine(), ((offset & 0x1f) << 2) | (data & 0x03), CHRROM); | |
| 9988 | ||
| 9989 | if (offset & 0x20) | |
| 9990 | { | |
| 9991 | prg16_89ab(space->machine(), (offset & 0x40) | ((offset >> 8) & 0x3f)); | |
| 9992 | prg16_cdef(space->machine(), (offset & 0x40) | ((offset >> 8) & 0x3f)); | |
| 9993 | } | |
| 9994 | else | |
| 9995 | { | |
| 9996 | prg32(space->machine(), ((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1); | |
| 9997 | } | |
| 9998 | ||
| 9999 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10000 | } | |
| 10001 | ||
| 10002 | /************************************************************* | |
| 10003 | ||
| 10004 | BMC-36IN1 | |
| 10005 | ||
| 10006 | Unknown Bootleg Multigame Board | |
| 10007 | Games: 36 in 1, 1200 in 1 | |
| 10008 | ||
| 10009 | iNES: mapper 200 | |
| 10010 | ||
| 10011 | In MESS: Supported. | |
| 10012 | ||
| 10013 | *************************************************************/ | |
| 10014 | ||
| 10015 | static WRITE8_HANDLER( bmc_36in1_w ) | |
| 10016 | { | |
| 10017 | LOG_MMC(("bmc_36in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10018 | ||
| 10019 | prg16_89ab(space->machine(), offset & 0x07); | |
| 10020 | prg16_cdef(space->machine(), offset & 0x07); | |
| 10021 | chr8(space->machine(), offset & 0x07, CHRROM); | |
| 10022 | ||
| 10023 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10024 | } | |
| 10025 | ||
| 10026 | /************************************************************* | |
| 10027 | ||
| 10028 | BMC-21IN1 | |
| 10029 | ||
| 10030 | Unknown Bootleg Multigame Board | |
| 10031 | Games: 8 in 1, 21 in 1 | |
| 10032 | ||
| 10033 | iNES: mapper 201 | |
| 10034 | ||
| 10035 | In MESS: Supported. | |
| 10036 | ||
| 10037 | *************************************************************/ | |
| 10038 | ||
| 10039 | static WRITE8_HANDLER( bmc_21in1_w ) | |
| 10040 | { | |
| 10041 | LOG_MMC(("bmc_21in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10042 | ||
| 10043 | prg32(space->machine(), offset & 0x03); | |
| 10044 | chr8(space->machine(), offset & 0x03, CHRROM); | |
| 10045 | } | |
| 10046 | ||
| 10047 | /************************************************************* | |
| 10048 | ||
| 10049 | BMC-150IN1 | |
| 10050 | ||
| 10051 | Unknown Bootleg Multigame Board | |
| 10052 | Games: 150 in 1 | |
| 10053 | ||
| 10054 | iNES: mapper 202 | |
| 10055 | ||
| 10056 | In MESS: Supported. | |
| 10057 | ||
| 10058 | *************************************************************/ | |
| 10059 | ||
| 10060 | static WRITE8_HANDLER( bmc_150in1_w ) | |
| 10061 | { | |
| 10062 | int bank = (offset >> 1) & 0x07; | |
| 10063 | ||
| 10064 | LOG_MMC(("bmc_150in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10065 | ||
| 10066 | prg16_89ab(space->machine(), bank); | |
| 10067 | prg16_cdef(space->machine(), bank + (((bank & 0x06) == 0x06) ? 1 : 0)); | |
| 10068 | chr8(space->machine(), bank, CHRROM); | |
| 10069 | ||
| 10070 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); | |
| 10071 | } | |
| 10072 | ||
| 10073 | /************************************************************* | |
| 10074 | ||
| 10075 | BMC-35IN1 | |
| 10076 | ||
| 10077 | Unknown Bootleg Multigame Board | |
| 10078 | Games: 35 in 1 | |
| 10079 | ||
| 10080 | iNES: mapper 203 | |
| 10081 | ||
| 10082 | In MESS: Supported. | |
| 10083 | ||
| 10084 | *************************************************************/ | |
| 10085 | ||
| 10086 | static WRITE8_HANDLER( bmc_35in1_w ) | |
| 10087 | { | |
| 10088 | LOG_MMC(("bmc_35in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10089 | ||
| 10090 | prg16_89ab(space->machine(), (data >> 2) & 0x03); | |
| 10091 | prg16_cdef(space->machine(), (data >> 2) & 0x03); | |
| 10092 | chr8(space->machine(), data & 0x03, CHRROM); | |
| 10093 | } | |
| 10094 | ||
| 10095 | /************************************************************* | |
| 10096 | ||
| 10097 | BMC-64IN1 | |
| 10098 | ||
| 10099 | Unknown Bootleg Multigame Board | |
| 10100 | Games: 64 in 1 | |
| 10101 | ||
| 10102 | iNES: mapper 204 | |
| 10103 | ||
| 10104 | In MESS: Supported. | |
| 10105 | ||
| 10106 | *************************************************************/ | |
| 10107 | ||
| 10108 | static WRITE8_HANDLER( bmc_64in1_w ) | |
| 10109 | { | |
| 10110 | int bank = (offset >> 1) & (offset >> 2) & 0x01; | |
| 10111 | ||
| 10112 | LOG_MMC(("bmc_64in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10113 | ||
| 10114 | prg16_89ab(space->machine(), offset & ~bank); | |
| 10115 | prg16_cdef(space->machine(), offset | bank); | |
| 10116 | chr8(space->machine(), offset & ~bank, CHRROM); | |
| 10117 | ||
| 10118 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); | |
| 10119 | } | |
| 10120 | ||
| 10121 | /************************************************************* | |
| 10122 | ||
| 10123 | BMC-15IN1 | |
| 10124 | ||
| 10125 | Unknown Bootleg Multigame Board | |
| 10126 | Games: 3 in 1, 15 in 1 | |
| 10127 | ||
| 10128 | iNES: mapper 205, MMC3 clone | |
| 10129 | ||
| 10130 | In MESS: Supported. | |
| 10131 | ||
| 10132 | *************************************************************/ | |
| 10133 | ||
| 10134 | static WRITE8_HANDLER( bmc_15in1_m_w ) | |
| 10135 | { | |
| 10136 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10137 | LOG_MMC(("bmc_15in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10138 | ||
| 10139 | if (offset & 0x0800) | |
| 10140 | { | |
| 10141 | state->m_mmc_prg_base = (data & 0x03) << 4; | |
| 10142 | state->m_mmc_prg_mask = (data & 0x02) ? 0x0f : 0x1f; | |
| 10143 | state->m_mmc_chr_base = (data & 0x03) << 7; | |
| 10144 | state->m_mmc_chr_mask = (data & 0x02) ? 0x7f : 0xff; | |
| 10145 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10146 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10147 | } | |
| 10148 | } | |
| 10149 | ||
| 10150 | /************************************************************* | |
| 10151 | ||
| 10152 | BMC-SUPERHIK_300IN1 | |
| 10153 | ||
| 10154 | Unknown Bootleg Multigame Board | |
| 10155 | Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1 | |
| 10156 | ||
| 10157 | iNES: mapper 212 | |
| 10158 | ||
| 10159 | In MESS: Supported. | |
| 10160 | ||
| 10161 | *************************************************************/ | |
| 10162 | ||
| 10163 | static WRITE8_HANDLER( bmc_hik300_w ) | |
| 10164 | { | |
| 10165 | LOG_MMC(("bmc_hik300_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10166 | ||
| 10167 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10168 | chr8(space->machine(), offset, CHRROM); | |
| 10169 | ||
| 10170 | if (offset < 0x4000) | |
| 10171 | { | |
| 10172 | prg16_89ab(space->machine(), offset); | |
| 10173 | prg16_cdef(space->machine(), offset); | |
| 10174 | } | |
| 10175 | else | |
| 10176 | prg32(space->machine(), offset >> 1); | |
| 10177 | } | |
| 10178 | ||
| 10179 | /************************************************************* | |
| 10180 | ||
| 10181 | BMC-SUPERGUN-20IN1 | |
| 10182 | ||
| 10183 | Unknown Bootleg Multigame Board | |
| 10184 | Games: Super Gun 20 in 1 | |
| 10185 | ||
| 10186 | iNES: mapper 214 | |
| 10187 | ||
| 10188 | In MESS: Supported. | |
| 10189 | ||
| 10190 | *************************************************************/ | |
| 10191 | ||
| 10192 | static WRITE8_HANDLER( supergun20in1_w ) | |
| 10193 | { | |
| 10194 | LOG_MMC(("supergun20in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10195 | ||
| 10196 | prg16_89ab(space->machine(), offset >> 2); | |
| 10197 | prg16_cdef(space->machine(), offset >> 2); | |
| 10198 | chr8(space->machine(), offset, CHRROM); | |
| 10199 | } | |
| 10200 | ||
| 10201 | /************************************************************* | |
| 10202 | ||
| 10203 | BMC-72IN1 | |
| 10204 | ||
| 10205 | Unknown Bootleg Multigame Board | |
| 10206 | Games: 72 in 1, 115 in 1 and other multigame carts | |
| 10207 | ||
| 10208 | iNES: mapper 225 | |
| 10209 | ||
| 10210 | In MESS: Supported. | |
| 10211 | ||
| 10212 | *************************************************************/ | |
| 10213 | ||
| 10214 | static WRITE8_HANDLER( bmc_72in1_w ) | |
| 10215 | { | |
| 10216 | int hi_bank; | |
| 10217 | int size_16; | |
| 10218 | int bank; | |
| 10219 | ||
| 10220 | LOG_MMC(("bmc_72in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10221 | ||
| 10222 | chr8(space->machine(), offset, CHRROM); | |
| 10223 | set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10224 | ||
| 10225 | hi_bank = offset & 0x40; | |
| 10226 | size_16 = offset & 0x1000; | |
| 10227 | bank = (offset & 0xf80) >> 7; | |
| 10228 | if (size_16) | |
| 10229 | { | |
| 10230 | bank <<= 1; | |
| 10231 | if (hi_bank) | |
| 10232 | bank ++; | |
| 10233 | ||
| 10234 | prg16_89ab(space->machine(), bank); | |
| 10235 | prg16_cdef(space->machine(), bank); | |
| 10236 | } | |
| 10237 | else | |
| 10238 | prg32(space->machine(), bank); | |
| 10239 | } | |
| 10240 | ||
| 10241 | /************************************************************* | |
| 10242 | ||
| 10243 | BMC-76IN1 | |
| 10244 | ||
| 10245 | Unknown Bootleg Multigame Board | |
| 10246 | Games: 76 in 1, Super 42 in 1 | |
| 10247 | ||
| 10248 | iNES: mapper 226 | |
| 10249 | ||
| 10250 | In MESS: Supported. | |
| 10251 | ||
| 10252 | *************************************************************/ | |
| 10253 | ||
| 10254 | // does this work for super42in1 as well?!? | |
| 10255 | static WRITE8_HANDLER( bmc_76in1_w ) | |
| 10256 | { | |
| 10257 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10258 | int hi_bank; | |
| 10259 | int size_16; | |
| 10260 | int bank; | |
| 10261 | ||
| 10262 | LOG_MMC(("bmc_76in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10263 | ||
| 10264 | if (offset & 0x01) | |
| 10265 | state->m_mmc_latch2 = data; | |
| 10266 | else | |
| 10267 | state->m_mmc_latch1 = data; | |
| 10268 | ||
| 10269 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10270 | ||
| 10271 | hi_bank = state->m_mmc_latch1 & 0x01; | |
| 10272 | size_16 = state->m_mmc_latch1 & 0x20; | |
| 10273 | bank = ((state->m_mmc_latch1 & 0x1e) >> 1) | ((state->m_mmc_latch1 & 0x80) >> 3) | ((state->m_mmc_latch2 & 0x01) << 5); | |
| 10274 | ||
| 10275 | if (size_16) | |
| 10276 | { | |
| 10277 | bank <<= 1; | |
| 10278 | if (hi_bank) | |
| 10279 | bank ++; | |
| 10280 | ||
| 10281 | prg16_89ab(space->machine(), bank); | |
| 10282 | prg16_cdef(space->machine(), bank); | |
| 10283 | } | |
| 10284 | else | |
| 10285 | prg32(space->machine(), bank); | |
| 10286 | } | |
| 10287 | ||
| 10288 | /************************************************************* | |
| 10289 | ||
| 10290 | BMC-1200IN1 | |
| 10291 | ||
| 10292 | Unknown Bootleg Multigame Board | |
| 10293 | Games: 1200 in 1, 295 in 1, 76 in 1 | |
| 10294 | ||
| 10295 | iNES: mapper 227 | |
| 10296 | ||
| 10297 | In MESS: Supported. | |
| 10298 | ||
| 10299 | *************************************************************/ | |
| 10300 | ||
| 10301 | static WRITE8_HANDLER( bmc_1200in1_w ) | |
| 10302 | { | |
| 10303 | int hi_bank; | |
| 10304 | int size_32; | |
| 10305 | int bank; | |
| 10306 | ||
| 10307 | LOG_MMC(("bmc_1200in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10308 | ||
| 10309 | hi_bank = offset & 0x04; | |
| 10310 | size_32 = offset & 0x01; | |
| 10311 | bank = ((offset & 0x78) >> 3) | ((offset & 0x0100) >> 4); | |
| 10312 | if (!size_32) | |
| 10313 | { | |
| 10314 | bank <<= 1; | |
| 10315 | if (hi_bank) | |
| 10316 | bank ++; | |
| 10317 | ||
| 10318 | prg16_89ab(space->machine(), bank); | |
| 10319 | prg16_cdef(space->machine(), bank); | |
| 10320 | } | |
| 10321 | else | |
| 10322 | prg32(space->machine(), bank); | |
| 10323 | ||
| 10324 | if (!(offset & 0x80)) | |
| 10325 | { | |
| 10326 | if (offset & 0x200) | |
| 10327 | prg16_cdef(space->machine(), ((bank << 1) & 0x38) + 7); | |
| 10328 | else | |
| 10329 | prg16_cdef(space->machine(), ((bank << 1) & 0x38)); | |
| 10330 | } | |
| 10331 | ||
| 10332 | set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10333 | } | |
| 10334 | ||
| 10335 | /************************************************************* | |
| 10336 | ||
| 10337 | BMC-31IN1 | |
| 10338 | ||
| 10339 | Unknown Bootleg Multigame Board | |
| 10340 | Games: 31 in 1 | |
| 10341 | ||
| 10342 | iNES: mapper 229 | |
| 10343 | ||
| 10344 | In MESS: Supported. | |
| 10345 | ||
| 10346 | *************************************************************/ | |
| 10347 | ||
| 10348 | static WRITE8_HANDLER( bmc_31in1_w ) | |
| 10349 | { | |
| 10350 | LOG_MMC(("bmc_31in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10351 | ||
| 10352 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10353 | chr8(space->machine(), offset, CHRROM); | |
| 10354 | ||
| 10355 | if ((offset & 0x1e) == 0) | |
| 10356 | { | |
| 10357 | prg16_89ab(space->machine(), 0); | |
| 10358 | prg16_89ab(space->machine(), 1); | |
| 10359 | } | |
| 10360 | else | |
| 10361 | { | |
| 10362 | prg16_89ab(space->machine(), offset & 0x1f); | |
| 10363 | prg16_89ab(space->machine(), offset & 0x1f); | |
| 10364 | } | |
| 10365 | } | |
| 10366 | ||
| 10367 | /************************************************************* | |
| 10368 | ||
| 10369 | BMC-22GAMES | |
| 10370 | ||
| 10371 | Unknown Bootleg Multigame Board | |
| 10372 | Games: 22 in 1 | |
| 10373 | ||
| 10374 | iNES: mapper 230 | |
| 10375 | ||
| 10376 | In MESS: Partially Supported. It would need a reset | |
| 10377 | to work (not possible yet) | |
| 10378 | ||
| 10379 | *************************************************************/ | |
| 10380 | ||
| 10381 | static WRITE8_HANDLER( bmc_22g_w ) | |
| 10382 | { | |
| 10383 | LOG_MMC(("bmc_22g_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10384 | ||
| 10385 | if (1) // this should flip at reset | |
| 10386 | { | |
| 10387 | prg16_89ab(space->machine(), data & 0x07); | |
| 10388 | } | |
| 10389 | else | |
| 10390 | { | |
| 10391 | if (data & 0x20) | |
| 10392 | { | |
| 10393 | prg16_89ab(space->machine(), (data & 0x1f) + 8); | |
| 10394 | prg16_cdef(space->machine(), (data & 0x1f) + 8); | |
| 10395 | } | |
| 10396 | else | |
| 10397 | { | |
| 10398 | prg16_89ab(space->machine(), (data & 0x1f) + 8); | |
| 10399 | prg16_cdef(space->machine(), (data & 0x1f) + 9); | |
| 10400 | } | |
| 10401 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 10402 | } | |
| 10403 | } | |
| 10404 | ||
| 10405 | /************************************************************* | |
| 10406 | ||
| 10407 | BMC-20IN1 | |
| 10408 | ||
| 10409 | Unknown Bootleg Multigame Board | |
| 10410 | Games: 20 in 1 | |
| 10411 | ||
| 10412 | iNES: mapper 231 | |
| 10413 | ||
| 10414 | In MESS: Supported. | |
| 10415 | ||
| 10416 | *************************************************************/ | |
| 10417 | ||
| 10418 | static WRITE8_HANDLER( bmc_20in1_w ) | |
| 10419 | { | |
| 10420 | LOG_MMC(("bmc_20in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10421 | ||
| 10422 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10423 | ||
| 10424 | prg16_89ab(space->machine(), (offset & 0x1e)); | |
| 10425 | prg16_cdef(space->machine(), (offset & 0x1e) | ((offset & 0x20) ? 1 : 0)); | |
| 10426 | } | |
| 10427 | ||
| 10428 | /************************************************************* | |
| 10429 | ||
| 10430 | BMC-110IN1 | |
| 10431 | ||
| 10432 | Known Boards: Unknown Bootleg Board | |
| 10433 | Games: 110 in 1 | |
| 10434 | ||
| 10435 | iNES: mapper 255 | |
| 10436 | ||
| 10437 | In MESS: Preliminary support. | |
| 10438 | ||
| 10439 | *************************************************************/ | |
| 10440 | ||
| 10441 | static WRITE8_HANDLER( bmc_110in1_w ) | |
| 10442 | { | |
| 10443 | UINT8 map255_helper1 = (offset >> 12) ? 0 : 1; | |
| 10444 | UINT8 map255_helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f); | |
| 10445 | ||
| 10446 | LOG_MMC(("bmc_110in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10447 | ||
| 10448 | set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10449 | prg16_89ab(space->machine(), map255_helper1 & ~map255_helper2); | |
| 10450 | prg16_cdef(space->machine(), map255_helper1 | map255_helper2); | |
| 10451 | chr8(space->machine(), ((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM); | |
| 10452 | } | |
| 10453 | ||
| 10454 | /************************************************************* | |
| 10455 | ||
| 10456 | BMC-SUPERBIG-7IN1 | |
| 10457 | ||
| 10458 | Known Boards: Unknown Multigame Bootleg Board | |
| 10459 | Games: Kunio 8 in 1, Super Big 7 in 1 | |
| 10460 | ||
| 10461 | iNES: mapper 44 | |
| 10462 | ||
| 10463 | In MESS: Supported. It also uses mmc3_irq. | |
| 10464 | ||
| 10465 | *************************************************************/ | |
| 10466 | ||
| 10467 | static WRITE8_HANDLER( bmc_sbig7_w ) | |
| 10468 | { | |
| 10469 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10470 | UINT8 page; | |
| 10471 | LOG_MMC(("bmc_sbig7_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10472 | ||
| 10473 | switch (offset & 0x6001) | |
| 10474 | { | |
| 10475 | case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */ | |
| 10476 | page = (data & 0x07); | |
| 10477 | if (page > 6) | |
| 10478 | page = 6; | |
| 10479 | ||
| 10480 | state->m_mmc_prg_base = page << 4; | |
| 10481 | state->m_mmc_prg_mask = (page > 5) ? 0x1f : 0x0f; | |
| 10482 | state->m_mmc_chr_base = page << 7; | |
| 10483 | state->m_mmc_chr_mask = (page > 5) ? 0xff : 0x7f; | |
| 10484 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10485 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10486 | break; | |
| 10487 | ||
| 10488 | default: | |
| 10489 | txrom_w(space, offset, data); | |
| 10490 | break; | |
| 10491 | } | |
| 10492 | } | |
| 10493 | ||
| 10494 | /************************************************************* | |
| 10495 | ||
| 10496 | BMC-HIK8IN1 | |
| 10497 | ||
| 10498 | Known Boards: Unknown Multigame Bootleg Board | |
| 10499 | Games: Street Fighter V, various multigame carts | |
| 10500 | ||
| 10501 | iNES: mapper 45 | |
| 10502 | ||
| 10503 | In MESS: Supported. It also uses mmc3_irq. | |
| 10504 | ||
| 10505 | *************************************************************/ | |
| 10506 | ||
| 10507 | static WRITE8_HANDLER( bmc_hik8_m_w ) | |
| 10508 | { | |
| 10509 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10510 | LOG_MMC(("bmc_hik8_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10511 | ||
| 10512 | /* This bit is the "register lock". Once register are locked, writes go to WRAM | |
| 10513 | and there is no way to unlock them (except by resetting the machine) */ | |
| 10514 | if ((state->m_mmc_reg[3] & 0x40) && state->m_wram != NULL) | |
| 10515 | state->m_wram[offset] = data; | |
| 10516 | else | |
| 10517 | { | |
| 10518 | state->m_mmc_reg[state->m_mmc_count] = data; | |
| 10519 | state->m_mmc_count = (state->m_mmc_count + 1) & 0x03; | |
| 10520 | ||
| 10521 | if (!state->m_mmc_count) | |
| 10522 | { | |
| 10523 | LOG_MMC(("bmc_hik8_m_w, command completed %02x %02x %02x %02x\n", state->m_mmc_reg[3], | |
| 10524 | state->m_mmc_reg[2], state->m_mmc_reg[1], state->m_mmc_reg[0])); | |
| 10525 | ||
| 10526 | state->m_mmc_prg_base = state->m_mmc_reg[1]; | |
| 10527 | state->m_mmc_prg_mask = 0x3f ^ (state->m_mmc_reg[3] & 0x3f); | |
| 10528 | state->m_mmc_chr_base = ((state->m_mmc_reg[2] & 0xf0) << 4) | state->m_mmc_reg[0]; | |
| 10529 | if (BIT(state->m_mmc_reg[2], 3)) | |
| 10530 | state->m_mmc_chr_mask = (1 << ((state->m_mmc_reg[2] & 7) + 1)) - 1; | |
| 10531 | else if (state->m_mmc_reg[2]) | |
| 10532 | state->m_mmc_chr_mask = 0; | |
| 10533 | else | |
| 10534 | state->m_mmc_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking | |
| 10535 | ||
| 10536 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10537 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10538 | } | |
| 10539 | } | |
| 10540 | } | |
| 10541 | ||
| 10542 | /************************************************************* | |
| 10543 | ||
| 10544 | BMC-SUPERHIK-4IN1 | |
| 10545 | ||
| 10546 | Known Boards: Unknown Multigame Bootleg Board | |
| 10547 | Games: Super HIK 4 in 1 | |
| 10548 | ||
| 10549 | iNES: mapper 49 | |
| 10550 | ||
| 10551 | In MESS: Supported. It also uses mmc3_irq. | |
| 10552 | ||
| 10553 | *************************************************************/ | |
| 10554 | ||
| 10555 | static WRITE8_HANDLER( bmc_hik4in1_m_w ) | |
| 10556 | { | |
| 10557 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10558 | LOG_MMC(("bmc_hik4in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10559 | ||
| 10560 | /* mid writes only work when WRAM is enabled. not sure if I should | |
| 10561 | change the condition to state->m_mmc_latch2==0x80 (i.e. what is the effect of | |
| 10562 | the read-only bit?) */ | |
| 10563 | if (state->m_mmc3_wram_protect & 0x80) | |
| 10564 | { | |
| 10565 | if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */ | |
| 10566 | { | |
| 10567 | state->m_mmc_prg_base = (data & 0xc0) >> 2; | |
| 10568 | state->m_mmc_prg_mask = 0x0f; | |
| 10569 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10570 | } | |
| 10571 | else | |
| 10572 | prg32(space->machine(), (data & 0x30) >> 4); | |
| 10573 | ||
| 10574 | state->m_mmc_chr_base = (data & 0xc0) << 1; | |
| 10575 | state->m_mmc_chr_mask = 0x7f; | |
| 10576 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10577 | } | |
| 10578 | } | |
| 10579 | ||
| 10580 | /************************************************************* | |
| 10581 | ||
| 10582 | BMC-BALLGAMES-11IN1 | |
| 10583 | ||
| 10584 | Known Boards: Unknown Multigame Bootleg Board | |
| 10585 | Games: 11 in 1 Ball Games | |
| 10586 | ||
| 10587 | iNES: mapper 51 | |
| 10588 | ||
| 10589 | In MESS: Partially Supported. | |
| 10590 | ||
| 10591 | *************************************************************/ | |
| 10592 | ||
| 10593 | static void bmc_ball11_set_banks( running_machine &machine ) | |
| 10594 | { | |
| 10595 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10596 | set_nt_mirroring(machine, (state->m_mmc_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10597 | ||
| 10598 | if (state->m_mmc_reg[0] & 0x01) | |
| 10599 | { | |
| 10600 | prg32(machine, state->m_mmc_reg[1]); | |
| 10601 | } | |
| 10602 | else | |
| 10603 | { | |
| 10604 | prg16_89ab(machine, (state->m_mmc_reg[1] << 1) | (state->m_mmc_reg[0] >> 1)); | |
| 10605 | prg16_cdef(machine, (state->m_mmc_reg[1] << 1) | 0x07); | |
| 10606 | } | |
| 10607 | } | |
| 10608 | ||
| 10609 | static WRITE8_HANDLER( bmc_ball11_m_w ) | |
| 10610 | { | |
| 10611 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10612 | ||
| 10613 | LOG_MMC(("bmc_ball11_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10614 | ||
| 10615 | state->m_mmc_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02); | |
| 10616 | bmc_ball11_set_banks(space->machine()); | |
| 10617 | } | |
| 10618 | ||
| 10619 | static WRITE8_HANDLER( bmc_ball11_w ) | |
| 10620 | { | |
| 10621 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10622 | ||
| 10623 | LOG_MMC(("bmc_ball11_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10624 | ||
| 10625 | switch (offset & 0x6000) | |
| 10626 | { | |
| 10627 | case 0x4000: // here we also update reg[0] upper bit | |
| 10628 | state->m_mmc_reg[0] = (state->m_mmc_reg[0] & 0x01) | ((data >> 3) & 0x02); | |
| 10629 | case 0x0000: | |
| 10630 | case 0x2000: | |
| 10631 | case 0x6000: | |
| 10632 | state->m_mmc_reg[1] = data & 0x0f; | |
| 10633 | bmc_ball11_set_banks(space->machine()); | |
| 10634 | break; | |
| 10635 | } | |
| 10636 | } | |
| 10637 | ||
| 10638 | /************************************************************* | |
| 10639 | ||
| 10640 | BMC-MARIOPARTY-7IN1 | |
| 10641 | ||
| 10642 | Known Boards: Unknown Multigame Bootleg Board | |
| 10643 | Games: Mario 7 in 1 | |
| 10644 | ||
| 10645 | MMC3 clone | |
| 10646 | ||
| 10647 | iNES: mapper 52 | |
| 10648 | ||
| 10649 | In MESS: Supported. | |
| 10650 | ||
| 10651 | *************************************************************/ | |
| 10652 | ||
| 10653 | static WRITE8_HANDLER( bmc_mario7in1_m_w ) | |
| 10654 | { | |
| 10655 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10656 | UINT8 map52_helper1, map52_helper2; | |
| 10657 | LOG_MMC(("bmc_mario7in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10658 | ||
| 10659 | /* mid writes only work when WRAM is enabled. not sure if I should | |
| 10660 | change the condition to state->m_mmc_latch2==0x80 (i.e. what is the effect of | |
| 10661 | the read-only bit?) and it only can happen once! */ | |
| 10662 | if ((state->m_mmc3_wram_protect & 0x80) && !state->m_map52_reg_written) | |
| 10663 | { | |
| 10664 | map52_helper1 = (data & 0x08); | |
| 10665 | map52_helper2 = (data & 0x40); | |
| 10666 | ||
| 10667 | state->m_mmc_prg_base = map52_helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); | |
| 10668 | state->m_mmc_prg_mask = map52_helper1 ? 0x0f : 0x1f; | |
| 10669 | state->m_mmc_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (map52_helper2 ? ((data & 0x10) << 3) : 0); | |
| 10670 | state->m_mmc_chr_mask = map52_helper2 ? 0x7f : 0xff; | |
| 10671 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10672 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10673 | ||
| 10674 | state->m_map52_reg_written = 1; | |
| 10675 | } | |
| 10676 | else | |
| 10677 | state->m_wram[offset] = data; | |
| 10678 | } | |
| 10679 | ||
| 10680 | /************************************************************* | |
| 10681 | ||
| 10682 | BMC-GOLDENCARD-6IN1 | |
| 10683 | ||
| 10684 | Known Boards: Unknown Bootleg Multigame Board | |
| 10685 | Games: Golden Card 6 in 1 | |
| 10686 | ||
| 10687 | MMC3 clone | |
| 10688 | ||
| 10689 | iNES: mapper 217 | |
| 10690 | ||
| 10691 | In MESS: Supported. | |
| 10692 | ||
| 10693 | *************************************************************/ | |
| 10694 | ||
| 10695 | // remove mask & base parameters! | |
| 10696 | static void bmc_gc6in1_set_prg( running_machine &machine, int prg_base, int prg_mask ) | |
| 10697 | { | |
| 10698 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10699 | state->m_mmc_prg_base = (state->m_mmc_reg[1] & 0x08) ? 0 : (state->m_mmc_reg[1] & 0x10); | |
| 10700 | state->m_mmc_prg_mask = (state->m_mmc_reg[1] & 0x08) ? 0x1f : 0x0f; | |
| 10701 | ||
| 10702 | state->m_mmc_prg_base |= ((state->m_mmc_reg[1] & 0x03) << 5); | |
| 10703 | ||
| 10704 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10705 | } | |
| 10706 | ||
| 10707 | static void bmc_gc6in1_set_chr( running_machine &machine, UINT8 chr ) | |
| 10708 | { | |
| 10709 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10710 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 10711 | int chr_base = (state->m_mmc_reg[1] & 0x08) ? 0x00 : ((state->m_mmc_reg[1] & 0x10) << 3); | |
| 10712 | int chr_mask = (state->m_mmc_reg[1] & 0x08) ? 0xff : 0x7f; | |
| 10713 | ||
| 10714 | chr_base |= ((state->m_mmc_reg[1] & 0x03) << 8); | |
| 10715 | ||
| 10716 | chr1_x(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); | |
| 10717 | chr1_x(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); | |
| 10718 | chr1_x(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); | |
| 10719 | chr1_x(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); | |
| 10720 | chr1_x(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr); | |
| 10721 | chr1_x(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr); | |
| 10722 | chr1_x(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr); | |
| 10723 | chr1_x(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr); | |
| 10724 | } | |
| 10725 | ||
| 10726 | static WRITE8_HANDLER( bmc_gc6in1_l_w ) | |
| 10727 | { | |
| 10728 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10729 | UINT8 bank; | |
| 10730 | LOG_MMC(("bmc_gc6in1_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10731 | offset += 0x100; | |
| 10732 | ||
| 10733 | if (offset == 0x1000) | |
| 10734 | { | |
| 10735 | state->m_mmc_reg[0] = data; | |
| 10736 | if (data & 0x80) | |
| 10737 | { | |
| 10738 | bank = (data & 0x0f) | ((state->m_mmc_reg[1] & 0x03) << 4); | |
| 10739 | prg16_89ab(space->machine(), bank); | |
| 10740 | prg16_cdef(space->machine(), bank); | |
| 10741 | } | |
| 10742 | else | |
| 10743 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10744 | } | |
| 10745 | else if (offset == 0x1001) | |
| 10746 | { | |
| 10747 | state->m_mmc_reg[1] = data; | |
| 10748 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10749 | } | |
| 10750 | else if (offset == 0x1007) | |
| 10751 | { | |
| 10752 | state->m_mmc_reg[2] = data; | |
| 10753 | } | |
| 10754 | } | |
| 10755 | ||
| 10756 | static WRITE8_HANDLER( bmc_gc6in1_w ) | |
| 10757 | { | |
| 10758 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10759 | UINT8 mmc_helper, cmd; | |
| 10760 | static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1}; | |
| 10761 | LOG_MMC(("bmc_gc6in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10762 | ||
| 10763 | if (!state->m_mmc_reg[2]) // in this case we act like MMC3, only with alt prg/chr handlers | |
| 10764 | { | |
| 10765 | switch (offset & 0x6001) | |
| 10766 | { | |
| 10767 | case 0x0000: | |
| 10768 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 10769 | state->m_mmc3_latch = data; | |
| 10770 | ||
| 10771 | /* Has PRG Mode changed? */ | |
| 10772 | if (mmc_helper & 0x40) | |
| 10773 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10774 | ||
| 10775 | /* Has CHR Mode changed? */ | |
| 10776 | if (mmc_helper & 0x80) | |
| 10777 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10778 | break; | |
| 10779 | ||
| 10780 | case 0x0001: | |
| 10781 | cmd = state->m_mmc3_latch & 0x07; | |
| 10782 | switch (cmd) | |
| 10783 | { | |
| 10784 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 10785 | case 2: case 3: case 4: case 5: | |
| 10786 | state->m_mmc_vrom_bank[cmd] = data; | |
| 10787 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10788 | break; | |
| 10789 | case 6: | |
| 10790 | case 7: | |
| 10791 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 10792 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10793 | break; | |
| 10794 | } | |
| 10795 | break; | |
| 10796 | ||
| 10797 | default: | |
| 10798 | txrom_w(space, offset, data); | |
| 10799 | break; | |
| 10800 | } | |
| 10801 | } | |
| 10802 | else | |
| 10803 | { | |
| 10804 | switch (offset & 0x6001) | |
| 10805 | { | |
| 10806 | case 0x0000: | |
| 10807 | txrom_w(space, 0x4000, data); | |
| 10808 | break; | |
| 10809 | ||
| 10810 | case 0x0001: | |
| 10811 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 10812 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 10813 | state->m_mmc3_latch = data; | |
| 10814 | ||
| 10815 | /* Has PRG Mode changed? */ | |
| 10816 | if (mmc_helper & 0x40) | |
| 10817 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10818 | ||
| 10819 | /* Has CHR Mode changed? */ | |
| 10820 | if (mmc_helper & 0x80) | |
| 10821 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10822 | ||
| 10823 | state->m_mmc_reg[3] = 1; | |
| 10824 | break; | |
| 10825 | ||
| 10826 | case 0x2000: | |
| 10827 | cmd = state->m_mmc3_latch & 0x07; | |
| 10828 | if (state->m_mmc_reg[3]) | |
| 10829 | { | |
| 10830 | state->m_mmc_reg[3] = 0; | |
| 10831 | switch (cmd) | |
| 10832 | { | |
| 10833 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 10834 | case 2: case 3: case 4: case 5: | |
| 10835 | state->m_mmc_vrom_bank[cmd] = data; | |
| 10836 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10837 | break; | |
| 10838 | case 6: | |
| 10839 | case 7: | |
| 10840 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 10841 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10842 | break; | |
| 10843 | } | |
| 10844 | } | |
| 10845 | break; | |
| 10846 | ||
| 10847 | ||
| 10848 | case 0x2001: | |
| 10849 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10850 | break; | |
| 10851 | ||
| 10852 | default: | |
| 10853 | txrom_w(space, offset, data); | |
| 10854 | break; | |
| 10855 | } | |
| 10856 | } | |
| 10857 | } | |
| 10858 | ||
| 10859 | /************************************************************* | |
| 10860 | ||
| 10861 | BMC-FAMILY-4646B | |
| 10862 | ||
| 10863 | Known Boards: Unknown Multigame Bootleg Board (4646B) | |
| 10864 | Games: 2 in 1 - Family Kid & Aladdin 4 | |
| 10865 | ||
| 10866 | MMC3 clone | |
| 10867 | ||
| 10868 | iNES: mapper 134 | |
| 10869 | ||
| 10870 | In MESS: Supported. | |
| 10871 | ||
| 10872 | *************************************************************/ | |
| 10873 | ||
| 10874 | static WRITE8_HANDLER( bmc_family4646_m_w ) | |
| 10875 | { | |
| 10876 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10877 | LOG_MMC(("bmc_family4646_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10878 | ||
| 10879 | if (offset == 0x01) | |
| 10880 | { | |
| 10881 | state->m_mmc_prg_base = (data & 0x02) << 4; | |
| 10882 | state->m_mmc_prg_mask = 0x1f; | |
| 10883 | state->m_mmc_chr_base = (data & 0x20) << 3; | |
| 10884 | state->m_mmc_chr_mask = 0xff; | |
| 10885 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10886 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10887 | } | |
| 10888 | } | |
| 10889 | ||
| 10890 | /************************************************************* | |
| 10891 | ||
| 10892 | BMC-VT5201 | |
| 10893 | ||
| 10894 | *************************************************************/ | |
| 10895 | ||
| 10896 | static WRITE8_HANDLER( bmc_vt5201_w ) | |
| 10897 | { | |
| 10898 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10899 | LOG_MMC(("bmc_vt5201_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10900 | ||
| 10901 | state->m_mmc_latch1 = BIT(offset, 8); | |
| 10902 | ||
| 10903 | // not sure about this mirroring bit!! | |
| 10904 | // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian! | |
| 10905 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10906 | if (BIT(offset, 7)) | |
| 10907 | { | |
| 10908 | prg16_89ab(space->machine(), (offset >> 4) & 0x07); | |
| 10909 | prg16_cdef(space->machine(), (offset >> 4) & 0x07); | |
| 10910 | } | |
| 10911 | else | |
| 10912 | prg32(space->machine(), (offset >> 5) & 0x03); | |
| 10913 | chr8(space->machine(), offset, CHRROM); | |
| 10914 | } | |
| 10915 | ||
| 10916 | static READ8_HANDLER( bmc_vt5201_r ) | |
| 10917 | { | |
| 10918 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10919 | LOG_MMC(("bmc_vt5201_r, offset: %04x\n", offset)); | |
| 10920 | // state->m_mmc_dipsetting = input_port_read(space->machine(), "CARTDIPS"); | |
| 10921 | ||
| 10922 | if (state->m_mmc_latch1) | |
| 10923 | return state->m_mmc_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs) | |
| 10924 | else | |
| 10925 | return mmc_hi_access_rom(space->machine(), offset); | |
| 10926 | } | |
| 10927 | ||
| 10928 | /************************************************************* | |
| 10929 | ||
| 10930 | BMC-BS-5 | |
| 10931 | ||
| 10932 | Games: a few 4 in 1 multicarts | |
| 10933 | ||
| 10934 | *************************************************************/ | |
| 10935 | ||
| 10936 | static void bmc_bs5_update_banks( running_machine &machine ) | |
| 10937 | { | |
| 10938 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10939 | ||
| 10940 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 10941 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 10942 | prg8_cd(machine, state->m_mmc_prg_bank[2]); | |
| 10943 | prg8_ef(machine, state->m_mmc_prg_bank[3]); | |
| 10944 | chr2_0(machine, state->m_mmc_vrom_bank[0], CHRROM); | |
| 10945 | chr2_2(machine, state->m_mmc_vrom_bank[1], CHRROM); | |
| 10946 | chr2_4(machine, state->m_mmc_vrom_bank[2], CHRROM); | |
| 10947 | chr2_6(machine, state->m_mmc_vrom_bank[3], CHRROM); | |
| 10948 | } | |
| 10949 | ||
| 10950 | static WRITE8_HANDLER( bmc_bs5_w ) | |
| 10951 | { | |
| 10952 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10953 | UINT8 bs5_helper = (offset & 0xc00) >> 10; | |
| 10954 | LOG_MMC(("bmc_bs5_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10955 | // state->m_mmc_dipsetting = input_port_read(space->machine(), "CARTDIPS"); | |
| 10956 | ||
| 10957 | switch (offset & 0x7000) | |
| 10958 | { | |
| 10959 | case 0x0000: | |
| 10960 | state->m_mmc_vrom_bank[bs5_helper] = offset & 0x1f; | |
| 10961 | break; | |
| 10962 | case 0x2000: | |
| 10963 | if (BIT(offset, state->m_mmc_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs | |
| 10964 | state->m_mmc_prg_bank[bs5_helper] = offset & 0x0f; | |
| 10965 | break; | |
| 10966 | } | |
| 10967 | bmc_bs5_update_banks(space->machine()); | |
| 10968 | } | |
| 10969 | ||
| 10970 | /************************************************************* | |
| 10971 | ||
| 10972 | BMC-810544-C-A1 | |
| 10973 | ||
| 10974 | Games: 200-in-1 Elfland | |
| 10975 | ||
| 10976 | *************************************************************/ | |
| 10977 | ||
| 10978 | static WRITE8_HANDLER( bmc_810544_w ) | |
| 10979 | { | |
| 10980 | UINT8 bank = (offset >> 7); | |
| 10981 | LOG_MMC(("bmc_810544_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10982 | ||
| 10983 | if (!BIT(offset, 6)) | |
| 10984 | { | |
| 10985 | prg16_89ab(space->machine(), (bank << 1) | BIT(offset, 5)); | |
| 10986 | prg16_cdef(space->machine(), (bank << 1) | BIT(offset, 5)); | |
| 10987 | } | |
| 10988 | else | |
| 10989 | prg32(space->machine(), bank); | |
| 10990 | ||
| 10991 | set_nt_mirroring(space->machine(), BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10992 | ||
| 10993 | chr8(space->machine(), offset & 0x0f, CHRROM); | |
| 10994 | } | |
| 10995 | ||
| 10996 | /************************************************************* | |
| 10997 | ||
| 10998 | BMC-NTD-03 | |
| 10999 | ||
| 11000 | *************************************************************/ | |
| 11001 | ||
| 11002 | static WRITE8_HANDLER( bmc_ntd03_w ) | |
| 11003 | { | |
| 11004 | UINT8 pbank, cbank; | |
| 11005 | LOG_MMC(("bmc_ntd03_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11006 | ||
| 11007 | pbank = (offset >> 10) & 0x1e; | |
| 11008 | cbank = ((offset & 0x300) >> 5) | (offset & 0x07); | |
| 11009 | ||
| 11010 | if (BIT(offset, 7)) | |
| 11011 | { | |
| 11012 | prg16_89ab(space->machine(), pbank | BIT(offset, 6)); | |
| 11013 | prg16_cdef(space->machine(), pbank | BIT(offset, 6)); | |
| 11014 | } | |
| 11015 | else | |
| 11016 | prg32(space->machine(), pbank >> 1); | |
| 11017 | ||
| 11018 | set_nt_mirroring(space->machine(), BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 11019 | ||
| 11020 | chr8(space->machine(), cbank, CHRROM); | |
| 11021 | } | |
| 11022 | ||
| 11023 | /************************************************************* | |
| 11024 | ||
| 11025 | BMC-GHOSTBUSTERS63IN1 | |
| 11026 | ||
| 11027 | in MESS: only preliminar support | |
| 11028 | ||
| 11029 | *************************************************************/ | |
| 11030 | ||
| 11031 | static void bmc_gb63_update( running_machine &machine ) | |
| 11032 | { | |
| 11033 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11034 | ||
| 11035 | set_nt_mirroring(machine, BIT(state->m_mmc_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 11036 | ||
| 11037 | if (BIT(state->m_mmc_reg[0], 5)) | |
| 11038 | { | |
| 11039 | prg16_89ab(machine, state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1! | |
| 11040 | prg16_cdef(machine, state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1! | |
| 11041 | } | |
| 11042 | else | |
| 11043 | prg32(machine, (state->m_mmc_reg[0] & 0x1f) >> 1); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1! | |
| 11044 | ||
| 11045 | if (BIT(state->m_mmc_reg[1], 2)) | |
| 11046 | chr8(machine, 0, CHRRAM); | |
| 11047 | // else | |
| 11048 | // chr8(machine, 0, CHRROM); | |
| 11049 | } | |
| 11050 | ||
| 11051 | static WRITE8_HANDLER( bmc_gb63_w ) | |
| 11052 | { | |
| 11053 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11054 | LOG_MMC(("bmc_gb63_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11055 | ||
| 11056 | state->m_mmc_reg[offset & 1] = data; | |
| 11057 | state->m_mmc_latch1 = BIT(state->m_mmc_reg[0], 7) | (BIT(state->m_mmc_reg[1], 0) << 1); | |
| 11058 | ||
| 11059 | } | |
| 11060 | ||
| 11061 | static READ8_HANDLER( bmc_gb63_r ) | |
| 11062 | { | |
| 11063 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11064 | LOG_MMC(("bmc_gb63_r, offset: %04x\n", offset)); | |
| 11065 | // state->m_mmc_dipsetting = input_port_read(space->machine(), "CARTDIPS"); | |
| 11066 | ||
| 11067 | if (state->m_mmc_latch1 == 1) | |
| 11068 | return 0xff; // open bus | |
| 11069 | else | |
| 11070 | return mmc_hi_access_rom(space->machine(), offset); | |
| 11071 | } | |
| 11072 | ||
| 11073 | /************************************************************* | |
| 11074 | ||
| 11075 | UNL-EDU2000 | |
| 11076 | ||
| 11077 | *************************************************************/ | |
| 11078 | ||
| 11079 | static WRITE8_HANDLER( edu2k_w ) | |
| 11080 | { | |
| 11081 | LOG_MMC(("edu2k_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11082 | ||
| 11083 | prg32(space->machine(), data & 0x1f); | |
| 11084 | wram_bank(space->machine(), (data & 0xc0) >> 6, NES_WRAM); | |
| 11085 | } | |
| 11086 | ||
| 11087 | /************************************************************* | |
| 11088 | ||
| 11089 | UNL-H2288 | |
| 11090 | ||
| 11091 | *************************************************************/ | |
| 11092 | ||
| 11093 | static void h2288_prg_cb( running_machine &machine, int start, int bank ) | |
| 11094 | { | |
| 11095 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11096 | ||
| 11097 | if (!(state->m_mmc_reg[0] & 0x40)) | |
| 11098 | prg8_x(machine, start, bank); | |
| 11099 | } | |
| 11100 | ||
| 11101 | static WRITE8_HANDLER( h2288_l_w ) | |
| 11102 | { | |
| 11103 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11104 | LOG_MMC(("h2288_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 11105 | offset += 0x100; | |
| 11106 | ||
| 11107 | if (offset >= 0x1800) | |
| 11108 | { | |
| 11109 | state->m_mmc_reg[offset & 1] = data; | |
| 11110 | if (state->m_mmc_reg[0] & 0x40) | |
| 11111 | { | |
| 11112 | UINT8 helper1 = (state->m_mmc_reg[0] & 0x05) | ((state->m_mmc_reg[0] >> 2) & 0x0a); | |
| 11113 | UINT8 helper2 = BIT(state->m_mmc_reg[0], 1); | |
| 11114 | prg16_89ab(space->machine(), helper1 & ~helper2); | |
| 11115 | prg16_cdef(space->machine(), helper1 | helper2); | |
| 11116 | } | |
| 11117 | else | |
| 11118 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11119 | } | |
| 11120 | } | |
| 11121 | ||
| 11122 | static READ8_HANDLER( h2288_l_r ) | |
| 11123 | { | |
| 11124 | LOG_MMC(("h2288_l_r offset: %04x\n", offset)); | |
| 11125 | offset += 0x100; | |
| 11126 | ||
| 11127 | if (offset >= 0x1000) | |
| 11128 | { | |
| 11129 | int helper = offset >> 8; | |
| 11130 | if (offset & 1) | |
| 11131 | return helper | 0x01; | |
| 11132 | else | |
| 11133 | return helper ^ 0x01; | |
| 11134 | } | |
| 11135 | ||
| 11136 | return 0; | |
| 11137 | } | |
| 11138 | ||
| 11139 | static WRITE8_HANDLER( h2288_w ) | |
| 11140 | { | |
| 11141 | static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; | |
| 11142 | LOG_MMC(("h2288_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11143 | ||
| 11144 | switch (offset & 0x6001) | |
| 11145 | { | |
| 11146 | case 0x0000: | |
| 11147 | txrom_w(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07]); | |
| 11148 | break; | |
| 11149 | ||
| 11150 | default: | |
| 11151 | txrom_w(space, offset, data); | |
| 11152 | break; | |
| 11153 | } | |
| 11154 | } | |
| 11155 | ||
| 11156 | /************************************************************* | |
| 11157 | ||
| 11158 | UNL-SHJY3 | |
| 11159 | ||
| 11160 | *************************************************************/ | |
| 11161 | ||
| 11162 | /* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */ | |
| 11163 | static void shjy3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 11164 | { | |
| 11165 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 11166 | if (state->m_IRQ_enable & 0x02) | |
| 11167 | { | |
| 11168 | if (state->m_IRQ_count == 0xff) | |
| 11169 | { | |
| 11170 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 11171 | state->m_IRQ_enable = state->m_IRQ_enable | ((state->m_IRQ_enable & 0x01) << 1); | |
| 11172 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 11173 | } | |
| 11174 | else | |
| 11175 | state->m_IRQ_count++; | |
| 11176 | } | |
| 11177 | } | |
| 11178 | ||
| 11179 | static void shjy3_update( running_machine &machine ) | |
| 11180 | { | |
| 11181 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11182 | int i; | |
| 11183 | ||
| 11184 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 11185 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 11186 | ||
| 11187 | for (i = 0; i < 8; i++) | |
| 11188 | { | |
| 11189 | UINT8 chr_bank = state->m_mmc_vrom_bank[i] | (state->m_mmc_extra_bank[i] << 4); | |
| 11190 | if (state->m_mmc_vrom_bank[i] == 0xc8) | |
| 11191 | { | |
| 11192 | state->m_mmc_latch1 = 0; | |
| 11193 | continue; | |
| 11194 | } | |
| 11195 | else if (state->m_mmc_vrom_bank[i] == 0x88) | |
| 11196 | { | |
| 11197 | state->m_mmc_latch1 = 1; | |
| 11198 | continue; | |
| 11199 | } | |
| 11200 | if ((state->m_mmc_vrom_bank[i] == 4 || state->m_mmc_vrom_bank[i] == 5) && !state->m_mmc_latch1) | |
| 11201 | chr1_x(machine, i, chr_bank & 1, CHRRAM); | |
| 11202 | else | |
| 11203 | chr1_x(machine, i, chr_bank, CHRROM); | |
| 11204 | } | |
| 11205 | } | |
| 11206 | ||
| 11207 | static WRITE8_HANDLER( shjy3_w ) | |
| 11208 | { | |
| 11209 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11210 | UINT8 mmc_helper, shift; | |
| 11211 | LOG_MMC(("shjy3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11212 | ||
| 11213 | if (offset >= 0x3000 && offset <= 0x600c) | |
| 11214 | { | |
| 11215 | mmc_helper = ((offset & 8) | (offset >> 8)) >> 3; | |
| 11216 | mmc_helper += 2; | |
| 11217 | mmc_helper &= 7; | |
| 11218 | shift = offset & 4; | |
| 11219 | ||
| 11220 | state->m_mmc_vrom_bank[mmc_helper] = (state->m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift); | |
| 11221 | if (shift) | |
| 11222 | state->m_mmc_extra_bank[mmc_helper] = data >> 4; | |
| 11223 | } | |
| 11224 | else | |
| 11225 | { | |
| 11226 | switch (offset) | |
| 11227 | { | |
| 11228 | case 0x0010: | |
| 11229 | state->m_mmc_prg_bank[0] = data; | |
| 11230 | break; | |
| 11231 | case 0x2010: | |
| 11232 | state->m_mmc_prg_bank[1] = data; | |
| 11233 | break; | |
| 11234 | case 0x1400: | |
| 11235 | switch (data & 0x03) | |
| 11236 | { | |
| 11237 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 11238 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 11239 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 11240 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 11241 | } | |
| 11242 | break; | |
| 11243 | case 0x7000: | |
| 11244 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f); | |
| 11245 | break; | |
| 11246 | case 0x7004: | |
| 11247 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4); | |
| 11248 | break; | |
| 11249 | case 0x7008: | |
| 11250 | state->m_IRQ_enable = data & 0x03; | |
| 11251 | if (state->m_IRQ_enable & 0x02) | |
| 11252 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 11253 | break; | |
| 11254 | } | |
| 11255 | } | |
| 11256 | shjy3_update(space->machine()); | |
| 11257 | } | |
| 11258 | ||
| 11259 | /************************************************************* | |
| 11260 | ||
| 11261 | UNL-603-5052 | |
| 11262 | ||
| 11263 | MMC3 + protection access in 0x4020 - 0x7fff | |
| 11264 | ||
| 11265 | in MESS: Partial support | |
| 11266 | ||
| 11267 | *************************************************************/ | |
| 11268 | ||
| 11269 | WRITE8_HANDLER( unl_6035052_extra_w ) | |
| 11270 | { | |
| 11271 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11272 | LOG_MMC(("unl_6035052_extra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11273 | state->m_mmc_latch1 = data & 0x03; | |
| 11274 | if (state->m_mmc_latch1 == 1) | |
| 11275 | state->m_mmc_latch1 = 2; | |
| 11276 | } | |
| 11277 | ||
| 11278 | READ8_HANDLER( unl_6035052_extra_r ) | |
| 11279 | { | |
| 11280 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11281 | LOG_MMC(("unl_6035052_extra_r, offset: %04x\n", offset)); | |
| 11282 | return state->m_mmc_latch1; | |
| 11283 | } | |
| 11284 | ||
| 11285 | ||
| 11286 | /************************************************************* | |
| 11287 | ||
| 11288 | BMC-POWERJOY | |
| 11289 | ||
| 11290 | *************************************************************/ | |
| 11291 | ||
| 11292 | static void pjoy84_prg_cb( running_machine &machine, int start, int bank ) | |
| 11293 | { | |
| 11294 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11295 | UINT8 flip = (state->m_mmc3_latch & 0x40) ? 2 : 0; | |
| 11296 | ||
| 11297 | if (!(state->m_mmc_reg[3] & 0x03)) | |
| 11298 | prg8_x(machine, start, bank); | |
| 11299 | else if (start == flip) | |
| 11300 | { | |
| 11301 | if ((state->m_mmc_reg[3] & 0x03) == 0x03) | |
| 11302 | prg32(machine, bank >> 2); | |
| 11303 | else | |
| 11304 | { | |
| 11305 | prg16_89ab(machine, bank >> 1); | |
| 11306 | prg16_cdef(machine, bank >> 1); | |
| 11307 | } | |
| 11308 | } | |
| 11309 | } | |
| 11310 | ||
| 11311 | static void pjoy84_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 11312 | { | |
| 11313 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11314 | ||
| 11315 | if (!(state->m_mmc_reg[3] & 0x10)) | |
| 11316 | chr1_x(machine, start, bank, source); | |
| 11317 | } | |
| 11318 | ||
| 11319 | INLINE void pjoy84_set_base_mask( running_machine &machine ) | |
| 11320 | { | |
| 11321 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11322 | ||
| 11323 | state->m_mmc_prg_base = ((state->m_mmc_reg[0] & (0x06 | BIT(state->m_mmc_reg[0], 6))) << 4) | | |
| 11324 | (BIT(state->m_mmc_reg[0], 4) << 7); | |
| 11325 | ||
| 11326 | state->m_mmc_chr_base = ((~state->m_mmc_reg[0] << 0) & 0x080 & state->m_mmc_reg[2]) | | |
| 11327 | ((state->m_mmc_reg[0] << 4) & 0x080 & state->m_mmc_reg[0]) | | |
| 11328 | ((state->m_mmc_reg[0] << 3) & 0x100) | | |
| 11329 | ((state->m_mmc_reg[0] << 5) & 0x200); | |
| 11330 | ||
| 11331 | state->m_mmc_prg_mask = BIT(state->m_mmc_reg[0], 6) ? 0x0f : 0x1f; | |
| 11332 | state->m_mmc_chr_mask = BIT(state->m_mmc_reg[0], 7) ? 0x7f : 0xff; | |
| 11333 | } | |
| 11334 | ||
| 11335 | static WRITE8_HANDLER( pjoy84_m_w ) | |
| 11336 | { | |
| 11337 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11338 | LOG_MMC(("pjoy84_m_w offset: %04x, data: %02x\n", offset, data)); | |
| 11339 | ||
| 11340 | switch (offset & 0x03) | |
| 11341 | { | |
| 11342 | case 0x00: | |
| 11343 | case 0x03: | |
| 11344 | if (state->m_mmc_reg[3] & 0x80) | |
| 11345 | return; // else we act as if offset & 3 = 1,2 | |
| 11346 | case 0x01: | |
| 11347 | case 0x02: | |
| 11348 | state->m_mmc_reg[offset & 0x03] = data; | |
| 11349 | pjoy84_set_base_mask(space->machine()); | |
| 11350 | if (state->m_mmc_reg[3] & 0x10) | |
| 11351 | chr8(space->machine(), (state->m_mmc_chr_base >> 3) | (state->m_mmc_reg[2] & 0x0f), state->m_mmc_chr_source); | |
| 11352 | else | |
| 11353 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11354 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11355 | break; | |
| 11356 | } | |
| 11357 | } | |
| 11358 | ||
| 11359 | /************************************************************* | |
| 11360 | ||
| 11361 | SOMERI TEAM | |
| 11362 | ||
| 11363 | iNES: mapper 116 | |
| 11364 | ||
| 11365 | Emulation note about regs in MESS: currently, | |
| 11366 | - state->m_mmc_cmd1 represent the board mode | |
| 11367 | - state->m_mmc_reg[n] for n=0,1,2,3 represent the MMC1 regs | |
| 11368 | - state->m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks | |
| 11369 | - state->m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks | |
| 11370 | - state->m_mmc_prg_bank[n] for n=4,5 represent the VRC2 PRG banks | |
| 11371 | - state->m_mmc_vrom_bank[n] for n=6,...,13 represent the VRC2 CHR banks | |
| 11372 | ||
| 11373 | In MESS: Preliminary support | |
| 11374 | ||
| 11375 | *************************************************************/ | |
| 11376 | ||
| 11377 | // MMC1 Mode emulation | |
| 11378 | static void someri_mmc1_set_prg( running_machine &machine ) | |
| 11379 | { | |
| 11380 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11381 | UINT8 prg_mode = state->m_mmc_reg[0] & 0x0c; | |
| 11382 | UINT8 prg_offset = state->m_mmc_reg[1] & 0x10; | |
| 11383 | ||
| 11384 | switch (prg_mode) | |
| 11385 | { | |
| 11386 | case 0x00: | |
| 11387 | case 0x04: | |
| 11388 | prg32(machine, (prg_offset + state->m_mmc_reg[3]) >> 1); | |
| 11389 | break; | |
| 11390 | case 0x08: | |
| 11391 | prg16_89ab(machine, prg_offset + 0); | |
| 11392 | prg16_cdef(machine, prg_offset + state->m_mmc_reg[3]); | |
| 11393 | break; | |
| 11394 | case 0x0c: | |
| 11395 | prg16_89ab(machine, prg_offset + state->m_mmc_reg[3]); | |
| 11396 | prg16_cdef(machine, prg_offset + 0x0f); | |
| 11397 | break; | |
| 11398 | } | |
| 11399 | } | |
| 11400 | ||
| 11401 | static void someri_mmc1_set_chr( running_machine &machine ) | |
| 11402 | { | |
| 11403 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11404 | UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4); | |
| 11405 | ||
| 11406 | if (chr_mode) | |
| 11407 | { | |
| 11408 | chr4_0(machine, state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source); | |
| 11409 | chr4_4(machine, state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source); | |
| 11410 | } | |
| 11411 | else | |
| 11412 | chr8(machine, (state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source); | |
| 11413 | } | |
| 11414 | ||
| 11415 | static WRITE8_HANDLER( someri_mmc1_w ) | |
| 11416 | { | |
| 11417 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11418 | ||
| 11419 | assert(state->m_mmc_cmd1 == 2); | |
| 11420 | ||
| 11421 | if (data & 0x80) | |
| 11422 | { | |
| 11423 | state->m_mmc1_count = 0; | |
| 11424 | state->m_mmc1_latch = 0; | |
| 11425 | ||
| 11426 | state->m_mmc_reg[0] |= 0x0c; | |
| 11427 | someri_mmc1_set_prg(space->machine()); | |
| 11428 | return; | |
| 11429 | } | |
| 11430 | ||
| 11431 | if (state->m_mmc1_count < 5) | |
| 11432 | { | |
| 11433 | if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0; | |
| 11434 | state->m_mmc1_latch >>= 1; | |
| 11435 | state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; | |
| 11436 | state->m_mmc1_count++; | |
| 11437 | } | |
| 11438 | ||
| 11439 | if (state->m_mmc1_count == 5) | |
| 11440 | { | |
| 11441 | switch (offset & 0x6000) | |
| 11442 | { | |
| 11443 | case 0x0000: | |
| 11444 | state->m_mmc_reg[0] = state->m_mmc1_latch; | |
| 11445 | switch (state->m_mmc_reg[0] & 0x03) | |
| 11446 | { | |
| 11447 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 11448 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 11449 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 11450 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 11451 | } | |
| 11452 | someri_mmc1_set_chr(space->machine()); | |
| 11453 | someri_mmc1_set_prg(space->machine()); | |
| 11454 | break; | |
| 11455 | case 0x2000: | |
| 11456 | state->m_mmc_reg[1] = state->m_mmc1_latch; | |
| 11457 | someri_mmc1_set_chr(space->machine()); | |
| 11458 | someri_mmc1_set_prg(space->machine()); | |
| 11459 | break; | |
| 11460 | case 0x4000: | |
| 11461 | state->m_mmc_reg[2] = state->m_mmc1_latch; | |
| 11462 | someri_mmc1_set_chr(space->machine()); | |
| 11463 | break; | |
| 11464 | case 0x6000: | |
| 11465 | state->m_mmc_reg[3] = state->m_mmc1_latch; | |
| 11466 | someri_mmc1_set_prg(space->machine()); | |
| 11467 | break; | |
| 11468 | } | |
| 11469 | ||
| 11470 | state->m_mmc1_count = 0; | |
| 11471 | } | |
| 11472 | } | |
| 11473 | ||
| 11474 | // MMC3 Mode emulation | |
| 11475 | static WRITE8_HANDLER( someri_mmc3_w ) | |
| 11476 | { | |
| 11477 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11478 | UINT8 mmc_helper, cmd; | |
| 11479 | ||
| 11480 | assert(state->m_mmc_cmd1 == 1); | |
| 11481 | switch (offset & 0x6001) | |
| 11482 | { | |
| 11483 | case 0x0000: | |
| 11484 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 11485 | state->m_mmc3_latch = data; | |
| 11486 | ||
| 11487 | if (mmc_helper & 0x40) | |
| 11488 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11489 | ||
| 11490 | if (mmc_helper & 0x80) | |
| 11491 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11492 | break; | |
| 11493 | ||
| 11494 | case 0x0001: | |
| 11495 | cmd = state->m_mmc3_latch & 0x07; | |
| 11496 | switch (cmd) | |
| 11497 | { | |
| 11498 | case 0: case 1: | |
| 11499 | case 2: case 3: case 4: case 5: | |
| 11500 | state->m_mmc_vrom_bank[cmd] = data; | |
| 11501 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11502 | break; | |
| 11503 | case 6: | |
| 11504 | case 7: | |
| 11505 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 11506 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11507 | break; | |
| 11508 | } | |
| 11509 | break; | |
| 11510 | ||
| 11511 | case 0x2000: | |
| 11512 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 11513 | break; | |
| 11514 | case 0x2001: break; | |
| 11515 | case 0x4000: state->m_IRQ_count_latch = data; break; | |
| 11516 | case 0x4001: state->m_IRQ_count = 0; break; | |
| 11517 | case 0x6000: state->m_IRQ_enable = 0; break; | |
| 11518 | case 0x6001: state->m_IRQ_enable = 1; break; | |
| 11519 | } | |
| 11520 | } | |
| 11521 | ||
| 11522 | // VRC2 Mode emulation | |
| 11523 | static WRITE8_HANDLER( someri_vrc2_w ) | |
| 11524 | { | |
| 11525 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11526 | UINT8 bank, shift; | |
| 11527 | ||
| 11528 | assert(state->m_mmc_cmd1 == 0); | |
| 11529 | ||
| 11530 | if (offset < 0x1000) | |
| 11531 | { | |
| 11532 | state->m_mmc_prg_bank[4] = data; | |
| 11533 | prg8_89(space->machine(), state->m_mmc_prg_bank[4]); | |
| 11534 | } | |
| 11535 | else if (offset < 0x2000) | |
| 11536 | { | |
| 11537 | switch (data & 0x03) | |
| 11538 | { | |
| 11539 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 11540 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 11541 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 11542 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 11543 | } | |
| 11544 | } | |
| 11545 | else if (offset < 0x3000) | |
| 11546 | { | |
| 11547 | state->m_mmc_prg_bank[5] = data; | |
| 11548 | prg8_ab(space->machine(), state->m_mmc_prg_bank[5]); | |
| 11549 | } | |
| 11550 | else if (offset < 0x7000) | |
| 11551 | { | |
| 11552 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); | |
| 11553 | shift = BIT(offset, 2) * 4; | |
| 11554 | data = (data & 0x0f) << shift; | |
| 11555 | state->m_mmc_vrom_bank[6 + bank] = data | state->m_mmc_chr_base; | |
| 11556 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[6 + bank], CHRROM); | |
| 11557 | } | |
| 11558 | } | |
| 11559 | ||
| 11560 | static WRITE8_HANDLER( someri_w ) | |
| 11561 | { | |
| 11562 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11563 | LOG_MMC(("someri_w mode %d, offset: %04x, data: %02x\n", state->m_mmc_cmd1, offset, data)); | |
| 11564 | ||
| 11565 | switch (state->m_mmc_cmd1) | |
| 11566 | { | |
| 11567 | case 0x00: someri_vrc2_w(space, offset, data); break; | |
| 11568 | case 0x01: someri_mmc3_w(space, offset, data); break; | |
| 11569 | case 0x02: someri_mmc1_w(space, offset, data); break; | |
| 11570 | } | |
| 11571 | } | |
| 11572 | ||
| 11573 | static void someri_mode_update( running_machine &machine ) | |
| 11574 | { | |
| 11575 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11576 | int i; | |
| 11577 | ||
| 11578 | switch (state->m_mmc_cmd1) | |
| 11579 | { | |
| 11580 | case 0x00: | |
| 11581 | prg8_89(machine, state->m_mmc_prg_bank[4]); | |
| 11582 | prg8_ab(machine, state->m_mmc_prg_bank[5]); | |
| 11583 | for (i = 0; i < 8; i++) | |
| 11584 | chr1_x(machine, i, state->m_mmc_vrom_bank[6 + i], CHRROM); | |
| 11585 | break; | |
| 11586 | case 0x01: | |
| 11587 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11588 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11589 | break; | |
| 11590 | case 0x02: | |
| 11591 | someri_mmc1_set_prg(machine); | |
| 11592 | someri_mmc1_set_chr(machine); | |
| 11593 | break; | |
| 11594 | } | |
| 11595 | } | |
| 11596 | ||
| 11597 | static WRITE8_HANDLER( someri_l_w ) | |
| 11598 | { | |
| 11599 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11600 | LOG_MMC(("someri_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11601 | offset += 0x100; | |
| 11602 | ||
| 11603 | if (offset & 0x100) | |
| 11604 | { | |
| 11605 | state->m_mmc_cmd1 = data & 0x03; | |
| 11606 | state->m_mmc_chr_base = ((state->m_mmc_cmd1 & 0x04) << 6); | |
| 11607 | if (state->m_mmc_cmd1 != 1) | |
| 11608 | state->m_IRQ_enable = 0; | |
| 11609 | someri_mode_update(space->machine()); | |
| 11610 | } | |
| 11611 | } | |
| 11612 | ||
| 11613 | #ifdef UNUSED_FUNCTION | |
| 11614 | /************************************************************* | |
| 11615 | ||
| 11616 | FUJIYA Board - mapper 170 according to NEStopia | |
| 11617 | ||
| 11618 | Which games are supposed to use this? | |
| 11619 | ||
| 11620 | *************************************************************/ | |
| 11621 | ||
| 11622 | static WRITE8_HANDLER( fujiya_m_w ) | |
| 11623 | { | |
| 11624 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11625 | LOG_MMC(("fujiya_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11626 | offset += 0x6000; | |
| 11627 | ||
| 11628 | if (offset == 0x6502 || offset == 0x7000) | |
| 11629 | state->m_mmc_latch1 = (data & 0x40) << 1; | |
| 11630 | } | |
| 11631 | ||
| 11632 | static READ8_HANDLER( fujiya_m_r ) | |
| 11633 | { | |
| 11634 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11635 | LOG_MMC(("fujiya_m_r, offset: %04x\n", offset)); | |
| 11636 | offset += 0x6000; | |
| 11637 | ||
| 11638 | if (offset == 0x7001 || offset == 0x7777) | |
| 11639 | return state->m_mmc_latch1 | ((offset >> 8) & 0x7f); | |
| 11640 | ||
| 11641 | return 0; | |
| 11642 | } | |
| 11643 | #endif | |
| 11644 | ||
| 11645 | ||
| 11646 | ||
| 11647 | ||
| 11648 | typedef void (*nes_ppu_latch)(device_t *device, offs_t offset); | |
| 11649 | ||
| 11650 | struct nes_memory_accessor | |
| 11651 | { | |
| 11652 | write8_space_func write; | |
| 11653 | const char *write_name; | |
| 11654 | read8_space_func read; | |
| 11655 | const char *read_name; | |
| 11656 | }; | |
| 11657 | ||
| 11658 | typedef struct _nes_pcb_intf nes_pcb_intf; | |
| 11659 | struct _nes_pcb_intf | |
| 11660 | { | |
| 11661 | int mmc_pcb; | |
| 11662 | nes_memory_accessor mmc_l; /* $4100-$5fff read/write routines */ | |
| 11663 | nes_memory_accessor mmc_m; /* $6000-$7fff read/write routines */ | |
| 11664 | nes_memory_accessor mmc_h; /* $8000-$ffff read/write routines */ | |
| 11665 | nes_ppu_latch mmc_ppu_latch; | |
| 11666 | ppu2c0x_scanline_cb mmc_scanline; | |
| 11667 | ppu2c0x_hblank_cb mmc_hblank; | |
| 11668 | }; | |
| 11669 | ||
| 11670 | #define NES_NOACCESS \ | |
| 11671 | {FUNC_NULL, FUNC_NULL} | |
| 11672 | ||
| 11673 | #define NES_READONLY(a) \ | |
| 11674 | {FUNC_NULL, FUNC(a)} | |
| 11675 | ||
| 11676 | #define NES_WRITEONLY(a) \ | |
| 11677 | {FUNC(a), FUNC_NULL} | |
| 11678 | ||
| 11679 | static WRITE8_HANDLER( dummy_l_w ) | |
| 11680 | { | |
| 11681 | logerror("write access, offset: %04x, data: %02x\n", offset + 0x4100, data); | |
| 11682 | } | |
| 11683 | ||
| 11684 | static WRITE8_HANDLER( dummy_m_w ) | |
| 11685 | { | |
| 11686 | logerror("write access, offset: %04x, data: %02x\n", offset + 0x6000, data); | |
| 11687 | } | |
| 11688 | ||
| 11689 | static WRITE8_HANDLER( dummy_w ) | |
| 11690 | { | |
| 11691 | logerror("write access, offset: %04x, data: %02x\n", offset + 0x8000, data); | |
| 11692 | } | |
| 11693 | ||
| 11694 | static READ8_HANDLER( dummy_l_r ) | |
| 11695 | { | |
| 11696 | logerror("read access, offset: %04x\n", offset + 0x4100); | |
| 11697 | return 0x00; | |
| 11698 | } | |
| 11699 | ||
| 11700 | static READ8_HANDLER( dummy_m_r ) | |
| 11701 | { | |
| 11702 | logerror("read access, offset: %04x\n", offset + 0x6000); | |
| 11703 | return 0x00; | |
| 11704 | } | |
| 11705 | ||
| 11706 | static READ8_HANDLER( dummy_r ) | |
| 11707 | { | |
| 11708 | logerror("read access, offset: %04x\n", offset + 0x8000); | |
| 11709 | return 0x00; | |
| 11710 | } | |
| 11711 | ||
| 11712 | static const nes_pcb_intf nes_intf_list[] = | |
| 11713 | { | |
| 11714 | { STD_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11715 | { HVC_FAMBASIC, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11716 | { GG_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11717 | { STD_UXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(uxrom_w), NULL, NULL, NULL }, | |
| 11718 | { STD_UN1ROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(un1rom_w), NULL, NULL, NULL }, | |
| 11719 | { STD_CPROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cprom_w), NULL, NULL, NULL }, | |
| 11720 | { STD_CNROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cnrom_w), NULL, NULL, NULL }, | |
| 11721 | { BANDAI_PT554, NES_NOACCESS, NES_WRITEONLY(bandai_pt554_m_w), NES_WRITEONLY(cnrom_w), NULL, NULL, NULL }, | |
| 11722 | { STD_AXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(axrom_w), NULL, NULL, NULL }, | |
| 11723 | { STD_PXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(pxrom_w), mmc2_latch, NULL, NULL }, | |
| 11724 | { STD_FXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(fxrom_w), mmc2_latch, NULL, NULL }, | |
| 11725 | { STD_BXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bxrom_w), NULL, NULL, NULL }, | |
| 11726 | { STD_GXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gxrom_w), NULL, NULL, NULL }, | |
| 11727 | { STD_MXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gxrom_w), NULL, NULL, NULL }, | |
| 11728 | { STD_NXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntbrom_w), NULL, NULL, NULL }, | |
| 11729 | { SUNSOFT_DCS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntbrom_w), NULL, NULL, NULL }, | |
| 11730 | { STD_JXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jxrom_w), NULL, NULL, jxrom_irq }, | |
| 11731 | { STD_SXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11732 | { STD_SOROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11733 | { STD_SXROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11734 | { STD_SOROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11735 | { STD_TXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11736 | { STD_TVROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11737 | { STD_TKROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11738 | { STD_HKROM, NES_NOACCESS, {FUNC(hkrom_m_w), FUNC(hkrom_m_r)}, NES_WRITEONLY(hkrom_w), NULL, NULL, mmc3_irq }, | |
| 11739 | { STD_TQROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tqrom_w), NULL, NULL, mmc3_irq }, | |
| 11740 | { STD_TXSROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txsrom_w), NULL, NULL, mmc3_irq }, | |
| 11741 | { STD_DXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL }, | |
| 11742 | { STD_DRROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL }, | |
| 11743 | { NAMCOT_34X3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL }, | |
| 11744 | { NAMCOT_3425, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3425_w), NULL, NULL, NULL }, | |
| 11745 | { NAMCOT_3446, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3446_w), NULL, NULL, NULL }, | |
| 11746 | { NAMCOT_3453, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3453_w), NULL, NULL, NULL }, | |
| 11747 | { STD_EXROM, {FUNC(exrom_l_w), FUNC(exrom_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, mmc5_irq }, | |
| 11748 | { NES_QJ, NES_NOACCESS, NES_WRITEONLY(qj_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11749 | { PAL_ZZ, NES_NOACCESS, NES_WRITEONLY(zz_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11750 | { UXROM_CC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(uxrom_cc_w), NULL, NULL, NULL }, | |
| 11751 | // | |
| 11752 | { DIS_74X139X74, NES_NOACCESS, NES_WRITEONLY(dis_74x139x74_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11753 | { DIS_74X377, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dis_74x377_w), NULL, NULL, NULL }, | |
| 11754 | { DIS_74X161X161X32, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dis_74x161x161x32_w), NULL, NULL, NULL }, | |
| 11755 | { DIS_74X161X138, NES_NOACCESS, NES_WRITEONLY(dis_74x161x138_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11756 | { BANDAI_LZ93, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11757 | { BANDAI_LZ93EX, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11758 | { BANDAI_FCG, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11759 | { BANDAI_DATACH, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11760 | { BANDAI_JUMP2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(fjump2_w), NULL, NULL, bandai_lz_irq }, | |
| 11761 | { BANDAI_KARAOKE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bandai_ks_w), NULL, NULL, NULL }, | |
| 11762 | { BANDAI_OEKAKIDS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bandai_ok_w), NULL, NULL, NULL }, | |
| 11763 | { IREM_G101, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(g101_w), NULL, NULL, NULL }, | |
| 11764 | { IREM_LROG017, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(lrog017_w), NULL, NULL, NULL }, | |
| 11765 | { IREM_H3001, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(h3001_w), NULL, NULL, h3001_irq }, | |
| 11766 | { IREM_TAM_S1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tam_s1_w), NULL, NULL, NULL }, | |
| 11767 | { IREM_HOLYDIV, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(irem_hd_w), NULL, NULL, NULL }, | |
| 11768 | { JALECO_SS88006, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ss88006_w), NULL, NULL, ss88006_irq }, | |
| 11769 | { JALECO_JF11, NES_NOACCESS, NES_WRITEONLY(jf11_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11770 | { JALECO_JF13, NES_NOACCESS, NES_WRITEONLY(jf13_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11771 | { JALECO_JF16, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf16_w), NULL, NULL, NULL }, | |
| 11772 | { JALECO_JF17, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf17_w), NULL, NULL, NULL }, | |
| 11773 | { JALECO_JF19, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf19_w), NULL, NULL, NULL }, | |
| 11774 | { KONAMI_VRC1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc1_w), NULL, NULL, NULL }, | |
| 11775 | { KONAMI_VRC2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc2_w), NULL, NULL, NULL }, | |
| 11776 | { KONAMI_VRC3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc3_w), NULL, NULL, konami_irq }, | |
| 11777 | { KONAMI_VRC4, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc4_w), NULL, NULL, konami_irq }, | |
| 11778 | { KONAMI_VRC6, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc6_w), NULL, NULL, konami_irq }, | |
| 11779 | { KONAMI_VRC7, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc7_w), NULL, NULL, konami_irq }, | |
| 11780 | { NAMCOT_163, {FUNC(namcot163_l_w), FUNC(namcot163_l_r) }, NES_NOACCESS, NES_WRITEONLY(namcot163_w), NULL, NULL, namcot_irq }, | |
| 11781 | { SUNSOFT_1, NES_NOACCESS, NES_WRITEONLY(sunsoft1_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11782 | { SUNSOFT_2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sunsoft2_w), NULL, NULL, NULL }, | |
| 11783 | { SUNSOFT_3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sunsoft3_w), NULL, NULL, sunsoft3_irq }, | |
| 11784 | { TAITO_TC0190FMC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tc0190fmc_w), NULL, NULL, NULL }, | |
| 11785 | { TAITO_TC0190FMCP, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tc0190fmc_p16_w), NULL, NULL, mmc3_irq }, | |
| 11786 | { TAITO_X1_005, NES_NOACCESS, {FUNC(x1005_m_w), FUNC(x1005_m_r)}, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11787 | { TAITO_X1_005_A, NES_NOACCESS, {FUNC(x1005a_m_w), FUNC(x1005_m_r)}, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11788 | { TAITO_X1_017, NES_NOACCESS, {FUNC(x1017_m_w), FUNC(x1017_m_r)}, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11789 | // | |
| 11790 | { AGCI_50282, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(agci_50282_w), NULL, NULL, NULL }, | |
| 11791 | { ACTENT_ACT52, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ae_act52_w), NULL, NULL, NULL }, | |
| 11792 | { AVE_NINA01, NES_NOACCESS, NES_WRITEONLY(nina01_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11793 | { AVE_NINA06, NES_WRITEONLY(nina06_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11794 | { CNE_DECATHLON, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cne_decathl_w), NULL, NULL, NULL }, | |
| 11795 | { CNE_FSB, NES_NOACCESS, NES_WRITEONLY(cne_fsb_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11796 | { CNE_SHLZ, NES_WRITEONLY(cne_shlz_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11797 | { CALTRON_6IN1, NES_NOACCESS, NES_WRITEONLY(caltron6in1_m_w), NES_WRITEONLY(caltron6in1_w), NULL, NULL, NULL }, | |
| 11798 | { CAMERICA_BF9093, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bf9093_w), NULL, NULL, NULL }, | |
| 11799 | { CAMERICA_BF9097, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bf9093_w), NULL, NULL, NULL }, | |
| 11800 | { CAMERICA_BF9096, NES_NOACCESS, NES_WRITEONLY(bf9096_w), NES_WRITEONLY(bf9096_w), NULL, NULL, NULL }, | |
| 11801 | { CAMERICA_GOLDENFIVE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(golden5_w), NULL, NULL, NULL }, | |
| 11802 | { CONY_BOARD, {FUNC(cony_l_w), FUNC(cony_l_r)}, NES_NOACCESS, NES_WRITEONLY(cony_w), NULL, NULL, sunsoft3_irq }, | |
| 11803 | { DREAMTECH_BOARD, NES_WRITEONLY(dreamtech_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11804 | { FUTUREMEDIA_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(futuremedia_w), NULL, NULL, futuremedia_irq }, | |
| 11805 | { FUKUTAKE_BOARD, {FUNC(fukutake_l_w), FUNC(fukutake_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11806 | { GOUDER_37017, {FUNC(gouder_sf4_l_w), FUNC(gouder_sf4_l_r)}, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11807 | { HENGEDIANZI_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(henggedianzi_w), NULL, NULL, NULL }, | |
| 11808 | { HENGEDIANZI_XJZB, NES_WRITEONLY(heng_xjzb_l_w), NES_NOACCESS, NES_WRITEONLY(heng_xjzb_w), NULL, NULL, NULL }, | |
| 11809 | { HES6IN1_BOARD, NES_WRITEONLY(hes6in1_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11810 | { HES_BOARD, NES_WRITEONLY(hes_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11811 | { HOSENKAN_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(hosenkan_w), NULL, NULL, mmc3_irq }, | |
| 11812 | { KAISER_KS7058, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7058_w), NULL, NULL, NULL }, | |
| 11813 | { KAISER_KS7022, NES_NOACCESS, NES_NOACCESS, {FUNC(ks7022_w), FUNC(ks7022_r)}, NULL, NULL, NULL }, | |
| 11814 | { KAISER_KS7032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7032_w), NULL, NULL, ks7032_irq }, | |
| 11815 | { KAISER_KS202, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks202_w), NULL, NULL, ks7032_irq }, | |
| 11816 | { KAISER_KS7017, NES_WRITEONLY(ks7017_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, mmc_fds_irq }, | |
| 11817 | { KAY_PANDAPRINCE, {FUNC(kay_pp_l_w), FUNC(kay_pp_l_r)}, NES_NOACCESS, NES_WRITEONLY(kay_pp_w), NULL, NULL, mmc3_irq }, | |
| 11818 | { KASING_BOARD, NES_NOACCESS, NES_WRITEONLY(kasing_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11819 | { SACHEN_74LS374, {FUNC(sachen_74x374_l_w), FUNC(sachen_74x374_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11820 | { SACHEN_74LS374_A, NES_WRITEONLY(sachen_74x374a_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11821 | { SACHEN_8259A, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11822 | { SACHEN_8259B, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11823 | { SACHEN_8259C, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11824 | { SACHEN_8259D, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11825 | { SACHEN_SA009, NES_WRITEONLY(sa009_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11826 | { SACHEN_SA0036, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sa0036_w), NULL, NULL, NULL }, | |
| 11827 | { SACHEN_SA0037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sa0037_w), NULL, NULL, NULL }, | |
| 11828 | { SACHEN_SA72007, NES_WRITEONLY(sa72007_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11829 | { SACHEN_SA72008, NES_WRITEONLY(sa72008_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11830 | { SACHEN_TCA01, NES_READONLY(tca01_l_r), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11831 | { SACHEN_TCU01, NES_WRITEONLY(tcu01_l_w), NES_WRITEONLY(tcu01_m_w), NES_WRITEONLY(tcu01_w), NULL, NULL, NULL }, | |
| 11832 | { SACHEN_TCU02, {FUNC(tcu02_l_w), FUNC(tcu02_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11833 | { SUBOR_TYPE0, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(subor0_w), NULL, NULL, NULL }, | |
| 11834 | { SUBOR_TYPE1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(subor1_w), NULL, NULL, NULL }, | |
| 11835 | { MAGICSERIES_MD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(magics_md_w), NULL, NULL, NULL }, | |
| 11836 | { NANJING_BOARD, {FUNC(nanjing_l_w), FUNC(nanjing_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, nanjing_irq }, | |
| 11837 | { NITRA_TDA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nitra_w), NULL, NULL, mmc3_irq }, | |
| 11838 | { NTDEC_ASDER, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntdec_asder_w), NULL, NULL, NULL }, | |
| 11839 | { NTDEC_FIGHTINGHERO, NES_NOACCESS, NES_WRITEONLY(ntdec_fh_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11840 | { OPENCORP_DAOU306, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(daou306_w), NULL, NULL, NULL }, | |
| 11841 | { RCM_GS2015, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gs2015_w), NULL, NULL, NULL }, | |
| 11842 | { RCM_TETRISFAMILY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(rcm_tf_w), NULL, NULL, NULL }, | |
| 11843 | { REXSOFT_DBZ5, {FUNC(rex_dbz_l_w), FUNC(rex_dbz_l_r)}, NES_READONLY(rex_dbz_l_r), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11844 | { REXSOFT_SL1632, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(rex_sl1632_w), NULL, NULL, mmc3_irq }, | |
| 11845 | { RUMBLESTATION_BOARD, NES_NOACCESS, NES_WRITEONLY(rumblestation_m_w), NES_WRITEONLY(rumblestation_w), NULL, NULL, NULL }, | |
| 11846 | { SOMERI_SL12, NES_WRITEONLY(someri_l_w), NES_NOACCESS, NES_WRITEONLY(someri_w), NULL, NULL, mmc3_irq }, | |
| 11847 | { SUPERGAME_BOOGERMAN, NES_WRITEONLY(sgame_boog_l_w), NES_WRITEONLY(sgame_boog_m_w), NES_WRITEONLY(sgame_boog_w), NULL, NULL, mmc3_irq }, | |
| 11848 | { SUPERGAME_LIONKING, NES_NOACCESS, NES_WRITEONLY(sgame_lion_m_w), NES_WRITEONLY(sgame_lion_w), NULL, NULL, mmc3_irq }, | |
| 11849 | { TENGEN_800008, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800008_w), NULL, NULL, NULL }, | |
| 11850 | { TENGEN_800032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800032_w), NULL, NULL, tengen_800032_irq }, | |
| 11851 | { TENGEN_800037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800037_w), NULL, NULL, tengen_800032_irq }, | |
| 11852 | { TXC_22211A, {FUNC(txc_22211_l_w), FUNC(txc_22211_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211_w), NULL, NULL, NULL }, | |
| 11853 | { TXC_22211B, {FUNC(txc_22211_l_w), FUNC(txc_22211_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211b_w), NULL, NULL, NULL }, | |
| 11854 | { TXC_22211C, {FUNC(txc_22211_l_w), FUNC(txc_22211c_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211_w), NULL, NULL, NULL }, | |
| 11855 | { TXC_TW, NES_WRITEONLY(txc_tw_l_w), NES_WRITEONLY(txc_tw_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11856 | { TXC_STRIKEWOLF, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txc_strikewolf_w), NULL, NULL, NULL }, | |
| 11857 | { TXC_MXMDHTWO, NES_READONLY(txc_mxmdhtwo_l_r), NES_NOACCESS, NES_WRITEONLY(txc_mxmdhtwo_w), NULL, NULL, NULL }, | |
| 11858 | { WAIXING_TYPE_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11859 | { WAIXING_TYPE_A_1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11860 | { WAIXING_TYPE_B, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11861 | { WAIXING_TYPE_C, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11862 | { WAIXING_TYPE_D, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11863 | { WAIXING_TYPE_E, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11864 | { WAIXING_TYPE_F, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_f_w), NULL, NULL, mmc3_irq }, | |
| 11865 | { WAIXING_TYPE_G, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_g_w), NULL, NULL, mmc3_irq }, | |
| 11866 | { WAIXING_TYPE_H, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_h_w), NULL, NULL, mmc3_irq }, | |
| 11867 | { WAIXING_TYPE_I, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff | |
| 11868 | { WAIXING_TYPE_J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff | |
| 11869 | { WAIXING_SGZ, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_sgz_w), NULL, NULL, konami_irq }, | |
| 11870 | { WAIXING_SGZLZ, NES_WRITEONLY(waixing_sgzlz_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11871 | { WAIXING_FFV, NES_WRITEONLY(waixing_ffv_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11872 | { WAIXING_ZS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_zs_w), NULL, NULL, NULL }, | |
| 11873 | { WAIXING_DQ8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_dq8_w), NULL, NULL, NULL }, | |
| 11874 | { WAIXING_SECURITY, NES_WRITEONLY(waixing_sec_l_w), NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11875 | { WAIXING_SH2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff | |
| 11876 | { WAIXING_PS2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_ps2_w), NULL, NULL, NULL }, | |
| 11877 | { UNL_8237, NES_WRITEONLY(unl_8237_l_w), NES_NOACCESS, NES_WRITEONLY(unl_8237_w), NULL, NULL, mmc3_irq }, | |
| 11878 | { UNL_AX5705, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_ax5705_w), NULL, NULL, NULL }, | |
| 11879 | { UNL_CC21, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_cc21_w), NULL, NULL, NULL }, | |
| 11880 | { UNL_KOF97, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_kof97_w), NULL, NULL, mmc3_irq }, | |
| 11881 | { UNL_T230, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_t230_w), NULL, NULL, konami_irq }, | |
| 11882 | { UNL_KOF96, {FUNC(kof96_l_w), FUNC(kof96_l_r)}, NES_NOACCESS, NES_WRITEONLY(kof96_w), NULL, NULL, mmc3_irq }, | |
| 11883 | { UNL_MK2, NES_NOACCESS, NES_WRITEONLY(mk2_m_w), NES_NOACCESS, NULL, NULL, mmc3_irq }, | |
| 11884 | { UNL_N625092, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(n625092_w), NULL, NULL, NULL }, | |
| 11885 | { UNL_SC127, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sc127_w), NULL, NULL, sc127_irq }, | |
| 11886 | { UNL_SMB2J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(smb2j_w), NULL, NULL, NULL }, | |
| 11887 | { UNL_SUPERFIGHTER3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_sf3_w), NULL, NULL, mmc3_irq }, | |
| 11888 | { UNL_XZY, NES_WRITEONLY(unl_xzy_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11889 | { UNL_RACERMATE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_racmate_w), NULL, NULL, NULL }, | |
| 11890 | { UNL_STUDYNGAME, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sng32_w), NULL, NULL, NULL }, | |
| 11891 | { UNL_603_5052, {FUNC(unl_6035052_extra_w), FUNC(unl_6035052_extra_r)}, {FUNC(unl_6035052_extra_w), FUNC(unl_6035052_extra_r)}, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11892 | { UNL_EDU2K, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(edu2k_w), NULL, NULL, NULL }, | |
| 11893 | { UNL_SHJY3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(shjy3_w), NULL, NULL, shjy3_irq }, | |
| 11894 | { UNL_H2288, {FUNC(h2288_l_w), FUNC(h2288_l_r)}, NES_NOACCESS, NES_WRITEONLY(h2288_w), NULL, NULL, mmc3_irq }, | |
| 11895 | // | |
| 11896 | { BTL_AISENSHINICOL, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_mariobaby_w), NULL, NULL, NULL }, | |
| 11897 | { BTL_DRAGONNINJA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_dn_w), NULL, NULL, btl_dn_irq }, | |
| 11898 | { BTL_MARIOBABY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_mariobaby_w), NULL, NULL, NULL }, | |
| 11899 | { BTL_SMB2A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb2a_w), NULL, NULL, btl_smb2a_irq }, | |
| 11900 | { BTL_SMB2B, NES_WRITEONLY(smb2jb_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, smb2jb_irq }, | |
| 11901 | { BTL_SMB3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb3_w), NULL, NULL, btl_smb3_irq }, | |
| 11902 | { BTL_SUPERBROS11, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb11_w), NULL, NULL, mmc3_irq }, | |
| 11903 | { BTL_TOBIDASE, NES_WRITEONLY(btl_tobi_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11904 | { BTL_PIKACHUY2K, NES_NOACCESS, {FUNC(btl_pika_y2k_m_w), FUNC(btl_pika_y2k_m_r)}, NES_WRITEONLY(btl_pika_y2k_w), NULL, NULL, mmc3_irq }, | |
| 11905 | { WHIRLWIND_2706, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(whirl2706_w), NULL, NULL, NULL }, | |
| 11906 | // | |
| 11907 | { BMC_190IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_190in1_w), NULL, NULL, NULL }, | |
| 11908 | { BMC_A65AS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_a65as_w), NULL, NULL, NULL }, | |
| 11909 | { BMC_GS2004, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gs2004_w), NULL, NULL, NULL }, | |
| 11910 | { BMC_GS2013, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gs2013_w), NULL, NULL, NULL }, | |
| 11911 | { BMC_NOVELDIAMOND, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(novel1_w), NULL, NULL, NULL }, | |
| 11912 | { BMC_9999999IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(novel2_w), NULL, NULL, NULL }, | |
| 11913 | { BMC_T262, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_t262_w), NULL, NULL, NULL }, | |
| 11914 | { BMC_WS, NES_NOACCESS, NES_WRITEONLY(bmc_ws_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11915 | { BMC_GKA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gka_w), NULL, NULL, NULL }, | |
| 11916 | { BMC_GKB, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gkb_w), NULL, NULL, NULL }, | |
| 11917 | { BMC_SUPER_700IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_super700in1_w), NULL, NULL, NULL }, | |
| 11918 | { BMC_36IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_36in1_w), NULL, NULL, NULL }, | |
| 11919 | { BMC_21IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_21in1_w), NULL, NULL, NULL }, | |
| 11920 | { BMC_150IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_150in1_w), NULL, NULL, NULL }, | |
| 11921 | { BMC_35IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_35in1_w), NULL, NULL, NULL }, | |
| 11922 | { BMC_64IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_64in1_w), NULL, NULL, NULL }, | |
| 11923 | { BMC_SUPERHIK_300IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_hik300_w), NULL, NULL, NULL }, | |
| 11924 | { BMC_SUPERGUN_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(supergun20in1_w), NULL, NULL, NULL }, | |
| 11925 | { BMC_72IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_72in1_w), NULL, NULL, NULL }, | |
| 11926 | { BMC_76IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_76in1_w), NULL, NULL, NULL }, | |
| 11927 | { BMC_SUPER_42IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_76in1_w), NULL, NULL, NULL }, | |
| 11928 | { BMC_1200IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_1200in1_w), NULL, NULL, NULL }, | |
| 11929 | { BMC_31IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_31in1_w), NULL, NULL, NULL }, | |
| 11930 | { BMC_22GAMES, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_22g_w), NULL, NULL, NULL }, | |
| 11931 | { BMC_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_20in1_w), NULL, NULL, NULL }, | |
| 11932 | { BMC_110IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_110in1_w), NULL, NULL, NULL }, | |
| 11933 | { BMC_64IN1NR, NES_WRITEONLY(bmc_64in1nr_l_w), NES_NOACCESS, NES_WRITEONLY(bmc_64in1nr_w), NULL, NULL, NULL }, | |
| 11934 | { BMC_S24IN1SC03, NES_WRITEONLY(bmc_s24in1sc03_l_w), NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11935 | { BMC_HIK8IN1, NES_NOACCESS, NES_WRITEONLY(bmc_hik8_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11936 | { BMC_SUPERHIK_4IN1, NES_NOACCESS, NES_WRITEONLY(bmc_hik4in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11937 | { BMC_SUPERBIG_7IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_sbig7_w), NULL, NULL, mmc3_irq }, | |
| 11938 | { BMC_MARIOPARTY_7IN1, NES_NOACCESS, NES_WRITEONLY(bmc_mario7in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11939 | { BMC_FAMILY_4646B, NES_NOACCESS, NES_WRITEONLY(bmc_family4646_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11940 | { BMC_15IN1, NES_NOACCESS, NES_WRITEONLY(bmc_15in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11941 | { BMC_BALLGAMES_11IN1, NES_NOACCESS, NES_WRITEONLY(bmc_ball11_m_w), NES_WRITEONLY(bmc_ball11_w), NULL, NULL, NULL }, | |
| 11942 | { BMC_GOLDENCARD_6IN1, NES_WRITEONLY(bmc_gc6in1_l_w), NES_NOACCESS, NES_WRITEONLY(bmc_gc6in1_w), NULL, NULL, mmc3_irq }, | |
| 11943 | { BMC_VT5201, NES_NOACCESS, NES_NOACCESS, {FUNC(bmc_vt5201_w), FUNC(bmc_vt5201_r)}, NULL, NULL, NULL }, | |
| 11944 | { BMC_BENSHENG_BS5, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_bs5_w), NULL, NULL, NULL }, | |
| 11945 | { BMC_810544, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_810544_w), NULL, NULL, NULL }, | |
| 11946 | { BMC_NTD_03, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_ntd03_w), NULL, NULL, NULL }, | |
| 11947 | { BMC_G63IN1, NES_NOACCESS, NES_NOACCESS, {FUNC(bmc_gb63_w), FUNC(bmc_gb63_r)}, NULL, NULL, NULL }, | |
| 11948 | { BMC_FK23C, NES_WRITEONLY(fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(fk23c_w), NULL, NULL, mmc3_irq }, | |
| 11949 | { BMC_FK23CA, NES_WRITEONLY(fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(fk23c_w), NULL, NULL, mmc3_irq }, | |
| 11950 | { BMC_PJOY84, NES_NOACCESS, NES_WRITEONLY(pjoy84_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11951 | // | |
| 11952 | { FFE_MAPPER6, NES_WRITEONLY(mapper6_l_w), NES_NOACCESS, NES_WRITEONLY(mapper6_w), NULL, NULL, ffe_irq }, | |
| 11953 | { FFE_MAPPER8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(mapper8_w), NULL, NULL, NULL }, | |
| 11954 | { FFE_MAPPER17, NES_WRITEONLY(mapper17_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, ffe_irq }, | |
| 11955 | // for debug and development | |
| 11956 | { UNKNOWN_BOARD, {FUNC(dummy_l_w), FUNC(dummy_l_r)}, {FUNC(dummy_m_w), FUNC(dummy_m_r)}, {FUNC(dummy_w), FUNC(dummy_r)}, NULL, NULL, NULL }, | |
| 11957 | // | |
| 11958 | { UNSUPPORTED_BOARD, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11959 | // | |
| 11960 | }; | |
| 11961 | ||
| 11962 | const nes_pcb_intf *nes_pcb_intf_lookup( int pcb_id ) | |
| 11963 | { | |
| 11964 | int i; | |
| 11965 | for (i = 0; i < ARRAY_LENGTH(nes_intf_list); i++) | |
| 11966 | { | |
| 11967 | if (nes_intf_list[i].mmc_pcb == pcb_id) | |
| 11968 | return &nes_intf_list[i]; | |
| 11969 | } | |
| 11970 | return NULL; | |
| 11971 | } | |
| 11972 | ||
| 11973 | void pcb_handlers_setup( running_machine &machine ) | |
| 11974 | { | |
| 11975 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11976 | const nes_pcb_intf *intf = nes_pcb_intf_lookup(state->m_pcb_id); | |
| 11977 | device_t *ppu = machine.device("ppu"); | |
| 11978 | ||
| 11979 | if (intf == NULL) | |
| 11980 | fatalerror("Missing PCB interface\n"); | |
| 11981 | ||
| 11982 | if (intf) | |
| 11983 | { | |
| 11984 | state->m_mmc_write_low = intf->mmc_l.write; | |
| 11985 | state->m_mmc_write_low_name = intf->mmc_l.write_name; | |
| 11986 | state->m_mmc_write_mid = intf->mmc_m.write; | |
| 11987 | state->m_mmc_write_mid_name = intf->mmc_m.write_name; | |
| 11988 | state->m_mmc_write = intf->mmc_h.write; | |
| 11989 | state->m_mmc_write_name = intf->mmc_h.write_name; | |
| 11990 | state->m_mmc_read_low = intf->mmc_l.read; | |
| 11991 | state->m_mmc_read_low_name = intf->mmc_l.read_name; | |
| 11992 | state->m_mmc_read_mid = intf->mmc_m.read; // in progress | |
| 11993 | state->m_mmc_read_mid_name = intf->mmc_m.read_name; | |
| 11994 | state->m_mmc_read = intf->mmc_h.read; // in progress | |
| 11995 | state->m_mmc_read_name = intf->mmc_h.read_name; | |
| 11996 | ppu2c0x_set_latch(ppu, intf->mmc_ppu_latch); | |
| 11997 | } | |
| 11998 | else | |
| 11999 | { | |
| 12000 | logerror("PCB %d is not yet supported, defaulting to no mapper.\n", state->m_pcb_id); | |
| 12001 | state->m_mmc_write_low = NULL; | |
| 12002 | state->m_mmc_write_mid = NULL; | |
| 12003 | state->m_mmc_write = NULL; | |
| 12004 | state->m_mmc_read_low = NULL; | |
| 12005 | state->m_mmc_read_mid = NULL; // in progress | |
| 12006 | state->m_mmc_read = NULL; // in progress | |
| 12007 | ppu2c0x_set_latch(ppu, NULL); | |
| 12008 | } | |
| 12009 | ||
| 12010 | state->m_mmc3_prg_cb = prg8_x; | |
| 12011 | state->m_mmc3_chr_cb = chr1_x; | |
| 12012 | ||
| 12013 | switch (state->m_pcb_id) | |
| 12014 | { | |
| 12015 | case STD_TXSROM: | |
| 12016 | state->m_mmc3_chr_cb = txsrom_chr_cb; | |
| 12017 | break; | |
| 12018 | case GOUDER_37017: | |
| 12019 | state->m_mmc3_prg_cb = gouder_sf4_prg_cb; | |
| 12020 | break; | |
| 12021 | case KASING_BOARD: | |
| 12022 | state->m_mmc3_prg_cb = kasing_prg_cb; | |
| 12023 | break; | |
| 12024 | case REXSOFT_DBZ5: | |
| 12025 | state->m_mmc3_chr_cb = rex_dbz_chr_cb; | |
| 12026 | break; | |
| 12027 | case TXC_TW: | |
| 12028 | state->m_mmc3_prg_cb = txc_tw_prg_cb; | |
| 12029 | break; | |
| 12030 | case WAIXING_TYPE_A: | |
| 12031 | state->m_mmc3_chr_cb = waixing_a_chr_cb; | |
| 12032 | break; | |
| 12033 | case WAIXING_TYPE_A_1: | |
| 12034 | state->m_mmc3_chr_cb = waixing_a1_chr_cb; | |
| 12035 | break; | |
| 12036 | case WAIXING_TYPE_B: | |
| 12037 | state->m_mmc3_chr_cb = waixing_b_chr_cb; | |
| 12038 | break; | |
| 12039 | case WAIXING_TYPE_C: | |
| 12040 | state->m_mmc3_chr_cb = waixing_c_chr_cb; | |
| 12041 | break; | |
| 12042 | case WAIXING_TYPE_D: | |
| 12043 | state->m_mmc3_chr_cb = waixing_d_chr_cb; | |
| 12044 | break; | |
| 12045 | case WAIXING_TYPE_E: | |
| 12046 | state->m_mmc3_chr_cb = waixing_e_chr_cb; | |
| 12047 | break; | |
| 12048 | case WAIXING_TYPE_G: | |
| 12049 | state->m_mmc3_chr_cb = waixing_g_chr_cb; | |
| 12050 | break; | |
| 12051 | case WAIXING_TYPE_H: | |
| 12052 | state->m_mmc3_chr_cb = waixing_h_chr_cb; | |
| 12053 | break; | |
| 12054 | case WAIXING_SECURITY: | |
| 12055 | state->m_mmc3_prg_cb = waixing_sec_prg_cb; | |
| 12056 | state->m_mmc3_chr_cb = waixing_sec_chr_cb; | |
| 12057 | break; | |
| 12058 | case WAIXING_SH2: | |
| 12059 | state->m_mmc3_chr_cb = waixing_sh2_chr_cb; | |
| 12060 | break; | |
| 12061 | case UNL_8237: | |
| 12062 | state->m_mmc3_prg_cb = unl_8237_prg_cb; | |
| 12063 | state->m_mmc3_chr_cb = unl_8237_chr_cb; | |
| 12064 | break; | |
| 12065 | case UNL_H2288: | |
| 12066 | state->m_mmc3_prg_cb = h2288_prg_cb; | |
| 12067 | break; | |
| 12068 | case SUPERGAME_BOOGERMAN: | |
| 12069 | state->m_mmc3_prg_cb = sgame_boog_prg_cb; | |
| 12070 | state->m_mmc3_chr_cb = sgame_boog_chr_cb; | |
| 12071 | break; | |
| 12072 | case UNL_KOF96: | |
| 12073 | state->m_mmc3_prg_cb = kof96_prg_cb; | |
| 12074 | state->m_mmc3_chr_cb = kof96_chr_cb; | |
| 12075 | break; | |
| 12076 | case KAY_PANDAPRINCE: | |
| 12077 | state->m_mmc3_prg_cb = kay_pp_prg_cb; | |
| 12078 | state->m_mmc3_chr_cb = kay_pp_chr_cb; | |
| 12079 | break; | |
| 12080 | case BMC_FK23C: | |
| 12081 | state->m_mmc3_prg_cb = fk23c_prg_cb; | |
| 12082 | state->m_mmc3_chr_cb = fk23c_chr_cb; | |
| 12083 | break; | |
| 12084 | case BMC_S24IN1SC03: | |
| 12085 | state->m_mmc3_prg_cb = bmc_s24in1sc03_prg_cb; | |
| 12086 | state->m_mmc3_chr_cb = bmc_s24in1sc03_chr_cb; | |
| 12087 | break; | |
| 12088 | case BMC_PJOY84: | |
| 12089 | state->m_mmc3_prg_cb = pjoy84_prg_cb; | |
| 12090 | state->m_mmc3_chr_cb = pjoy84_chr_cb; | |
| 12091 | break; | |
| 12092 | } | |
| 12093 | } | |
| 12094 | ||
| 12095 | /************************************************************* | |
| 12096 | ||
| 12097 | pcb_initialize | |
| 12098 | ||
| 12099 | Initialize all the necessary registers and quantities for | |
| 12100 | emulation of each board | |
| 12101 | ||
| 12102 | *************************************************************/ | |
| 12103 | ||
| 12104 | /* this is used by many boards (MMC3, MMC6 + most MMC3 pirate clone boards) */ | |
| 12105 | static void mmc3_common_initialize( running_machine &machine, int prg_mask, int chr_mask, int IRQ_type ) | |
| 12106 | { | |
| 12107 | nes_state *state = machine.driver_data<nes_state>(); | |
| 12108 | ||
| 12109 | state->m_mmc3_alt_irq = IRQ_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev... | |
| 12110 | state->m_mmc_prg_bank[0] = state->m_mmc_prg_bank[2] = 0xfe; // prg_bank[2] & prg_bank[3] remain always the same in most MMC3 variants | |
| 12111 | state->m_mmc_prg_bank[1] = state->m_mmc_prg_bank[3] = 0xff; // but some pirate clone mappers change them after writing certain registers | |
| 12112 | state->m_mmc3_latch = 0; | |
| 12113 | state->m_mmc3_wram_protect = 0x80; | |
| 12114 | state->m_mmc_prg_base = state->m_mmc_chr_base = 0; | |
| 12115 | state->m_mmc_prg_mask = prg_mask; | |
| 12116 | state->m_mmc_chr_mask = chr_mask; | |
| 12117 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12118 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12119 | } | |
| 12120 | ||
| 12121 | // WIP code | |
| 12122 | static int pcb_initialize( running_machine &machine, int idx ) | |
| 12123 | { | |
| 12124 | nes_state *state = machine.driver_data<nes_state>(); | |
| 12125 | int err = 0, i; | |
| 12126 | ||
| 12127 | /* basic PRG config */ | |
| 12128 | prg32(machine, 0); | |
| 12129 | ||
| 12130 | /* some boards will not use this, but directly CHRROM (resp. CHRRAM) if the board only has VROM (resp. VRAM) */ | |
| 12131 | state->m_mmc_chr_source = state->m_chr_chunks ? CHRROM : CHRRAM; | |
| 12132 | chr8(machine, 0, state->m_mmc_chr_source); | |
| 12133 | ||
| 12134 | /* Here, we init a few helpers: 4 prg banks and 16 chr banks - some mappers use them */ | |
| 12135 | for (i = 0; i < 4; i++) | |
| 12136 | state->m_mmc_prg_bank[i] = 0; | |
| 12137 | for (i = 0; i < 16; i++) | |
| 12138 | state->m_mmc_vrom_bank[i] = 0; | |
| 12139 | for (i = 0; i < 16; i++) | |
| 12140 | state->m_mmc_extra_bank[i] = 0; | |
| 12141 | ||
| 12142 | state->m_mmc_latch1 = 0; | |
| 12143 | state->m_mmc_latch2 = 0; | |
| 12144 | ||
| 12145 | /* Finally, we init IRQ-related quantities. */ | |
| 12146 | state->m_IRQ_enable = state->m_IRQ_enable_latch = 0; | |
| 12147 | state->m_IRQ_count = state->m_IRQ_count_latch = 0; | |
| 12148 | state->m_IRQ_toggle = 0; | |
| 12149 | ||
| 12150 | switch (idx) | |
| 12151 | { | |
| 12152 | /* many boards only needs PRG to point at first 32k and CHR at first 8k */ | |
| 12153 | case STD_NROM: // mapper 0 | |
| 12154 | case HVC_FAMBASIC: | |
| 12155 | case GG_NROM: | |
| 12156 | case UXROM_CC: // mapper 180 | |
| 12157 | case STD_CNROM: // mapper 3, 185 | |
| 12158 | case BANDAI_PT554: | |
| 12159 | case TENGEN_800008: | |
| 12160 | case STD_BXROM: // mapper 34 | |
| 12161 | case STD_GXROM: // mapper 66 | |
| 12162 | case STD_MXROM: | |
| 12163 | case BANDAI_OEKAKIDS: // mapper 96 | |
| 12164 | case JALECO_JF11: // mapper 140 | |
| 12165 | case JALECO_JF13: // mapper 86 | |
| 12166 | case JALECO_JF19: // mapper 92 | |
| 12167 | case DIS_74X377: // mapper 11 | |
| 12168 | case DIS_74X161X138: // mapper 38 | |
| 12169 | case CALTRON_6IN1: // mapper 41 | |
| 12170 | case TXC_STRIKEWOLF: // mapper 36 | |
| 12171 | case UNL_STUDYNGAME: // mapper 39 | |
| 12172 | case RUMBLESTATION_BOARD: // mapper 46 | |
| 12173 | case BMC_GKB: // mapper 58 | |
| 12174 | case RCM_TETRISFAMILY: // mapper 61 | |
| 12175 | case BMC_SUPER_700IN1: // mapper 62 | |
| 12176 | case MAGICSERIES_MD: // mapper 107 | |
| 12177 | case HES_BOARD: // mapper 113 | |
| 12178 | case HES6IN1_BOARD: // mapper 113 | |
| 12179 | case SACHEN_SA72008: // mapper 133 | |
| 12180 | case SACHEN_TCU02: // mapper 136 | |
| 12181 | case SACHEN_SA72007: // mapper 145 | |
| 12182 | case SACHEN_TCU01: // mapper 147 | |
| 12183 | case SACHEN_SA009: // mapper 160 | |
| 12184 | case SACHEN_SA0037: // mapper 148 | |
| 12185 | case SACHEN_SA0036: // mapper 149 | |
| 12186 | case AGCI_50282: // mapper 144 | |
| 12187 | case KAISER_KS7058: // mapper 171 | |
| 12188 | case HENGEDIANZI_BOARD: // mapper 177 | |
| 12189 | case WAIXING_SGZLZ: // mapper 178 | |
| 12190 | case HENGEDIANZI_XJZB: // mapper 179 | |
| 12191 | case BMC_21IN1: // mapper 201 | |
| 12192 | case BMC_9999999IN1: // mapper 213 | |
| 12193 | case RCM_GS2015: // mapper 216 | |
| 12194 | case BMC_72IN1: // mapper 225 | |
| 12195 | case BMC_76IN1: // mapper 226 | |
| 12196 | case BMC_SUPER_42IN1: // mapper 226 | |
| 12197 | case ACTENT_ACT52: // mapper 228 | |
| 12198 | case CNE_SHLZ: // mapper 240 | |
| 12199 | case TXC_MXMDHTWO: // mapper 241 | |
| 12200 | case WAIXING_ZS: // mapper 242 | |
| 12201 | case WAIXING_DQ8: // mapper 242 | |
| 12202 | case CNE_DECATHLON: // mapper 244 | |
| 12203 | case UNL_CC21: | |
| 12204 | case BMC_VT5201: | |
| 12205 | case BMC_WS: | |
| 12206 | case UNL_EDU2K: | |
| 12207 | break; | |
| 12208 | ||
| 12209 | /* other boards need additional initialization */ | |
| 12210 | case STD_UXROM: // mapper 2 | |
| 12211 | case STD_UN1ROM: // mapper 94 | |
| 12212 | case STD_JXROM: // mapper 69 | |
| 12213 | case SUNSOFT_5B: | |
| 12214 | case SUNSOFT_FME7: | |
| 12215 | case NAMCOT_3425: // mapper 95 | |
| 12216 | case DIS_74X139X74: // mapper 87 | |
| 12217 | case DIS_74X161X161X32: // mapper 152 & 70 | |
| 12218 | case BANDAI_LZ93: // mapper 16, 157 | |
| 12219 | case BANDAI_LZ93EX: // same + EEPROM | |
| 12220 | case BANDAI_DATACH: | |
| 12221 | case BANDAI_FCG: | |
| 12222 | case IREM_HOLYDIV: // mapper 78 | |
| 12223 | case IREM_G101: // mapper 32 | |
| 12224 | case IREM_H3001: // mapper 65 | |
| 12225 | case JALECO_SS88006: // mapper 18 | |
| 12226 | case JALECO_JF16: // mapper 78 | |
| 12227 | case JALECO_JF17: // mapper 72 | |
| 12228 | case KONAMI_VRC1: // mapper 75 | |
| 12229 | case KONAMI_VRC2: | |
| 12230 | case KONAMI_VRC3: // mapper 73 | |
| 12231 | case KONAMI_VRC4: | |
| 12232 | case KONAMI_VRC6: | |
| 12233 | case SUNSOFT_3: // mapper 67 | |
| 12234 | case TAITO_TC0190FMC: // mapper 33 | |
| 12235 | case TAITO_TC0190FMCP: // mapper 48 | |
| 12236 | case TAITO_X1_005: // mapper 80 | |
| 12237 | case TAITO_X1_005_A: // mapper 207 | |
| 12238 | case TAITO_X1_017: // mapper 82 | |
| 12239 | case NTDEC_ASDER: // mapper 112 | |
| 12240 | case FUTUREMEDIA_BOARD: // mapper 117 | |
| 12241 | case BTL_DRAGONNINJA: // mapper 222 | |
| 12242 | case WAIXING_SGZ: // mapper 252 | |
| 12243 | case UNL_T230: | |
| 12244 | case BMC_NTD_03: | |
| 12245 | case KAISER_KS7022: | |
| 12246 | case UNL_SHJY3: | |
| 12247 | case KAISER_KS7017: | |
| 12248 | case KAISER_KS7032: | |
| 12249 | case KAISER_KS202: | |
| 12250 | prg16_89ab(machine, 0); | |
| 12251 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12252 | break; | |
| 12253 | ||
| 12254 | case STD_CPROM: // mapper 13 | |
| 12255 | chr4_0(machine, 0, CHRRAM); | |
| 12256 | chr4_4(machine, 0, CHRRAM); | |
| 12257 | break; | |
| 12258 | case STD_AXROM: // mapper 7 | |
| 12259 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 12260 | break; | |
| 12261 | case STD_SXROM: // mapper 1, 155 | |
| 12262 | case STD_SOROM: | |
| 12263 | case STD_SXROM_A: | |
| 12264 | case STD_SOROM_A: | |
| 12265 | state->m_mmc1_latch = 0; | |
| 12266 | state->m_mmc1_count = 0; | |
| 12267 | state->m_mmc_reg[0] = 0x0f; | |
| 12268 | state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12269 | state->m_mmc1_reg_write_enable = 1; | |
| 12270 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 12271 | mmc1_set_chr(machine); | |
| 12272 | mmc1_set_prg(machine); | |
| 12273 | if (state->m_battery || state->m_wram) | |
| 12274 | wram_bank(machine, 0, (idx == STD_SOROM) ? NES_WRAM : NES_BATTERY); | |
| 12275 | break; | |
| 12276 | case STD_PXROM: // mapper 9 | |
| 12277 | state->m_mmc_reg[0] = state->m_mmc_reg[2] = 0; | |
| 12278 | state->m_mmc_reg[1] = state->m_mmc_reg[3] = 0; | |
| 12279 | state->m_mmc_latch1 = state->m_mmc_latch2 = 0xfe; | |
| 12280 | prg8_89(machine, 0); | |
| 12281 | prg8_ab(machine, (state->m_prg_chunks << 1) - 3); | |
| 12282 | prg8_cd(machine, (state->m_prg_chunks << 1) - 2); | |
| 12283 | prg8_ef(machine, (state->m_prg_chunks << 1) - 1); | |
| 12284 | break; | |
| 12285 | case STD_FXROM: // mapper 10 | |
| 12286 | state->m_mmc_reg[0] = state->m_mmc_reg[2] = 0; | |
| 12287 | state->m_mmc_reg[1] = state->m_mmc_reg[3] = 0; | |
| 12288 | state->m_mmc_latch1 = state->m_mmc_latch2 = 0xfe; | |
| 12289 | prg16_89ab(machine, 0); | |
| 12290 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12291 | break; | |
| 12292 | case STD_TXROM: // mapper 4 | |
| 12293 | case STD_TVROM: | |
| 12294 | case STD_TKROM: | |
| 12295 | case REXSOFT_DBZ5: // mapper 12 | |
| 12296 | case WAIXING_TYPE_A: // mapper 74 | |
| 12297 | case WAIXING_TYPE_A_1: | |
| 12298 | case STD_TXSROM: // mapper 118 | |
| 12299 | case STD_TQROM: // mapper 119 | |
| 12300 | case WAIXING_SH2: // mapper 165 | |
| 12301 | case WAIXING_TYPE_B: // mapper 191 | |
| 12302 | case WAIXING_TYPE_C: // mapper 192 | |
| 12303 | case WAIXING_TYPE_D: // mapper 194 | |
| 12304 | case WAIXING_TYPE_E: // mapper 195 | |
| 12305 | case WAIXING_TYPE_H: // mapper 245 | |
| 12306 | case BTL_SUPERBROS11: // mapper 196 | |
| 12307 | case UNL_H2288: // mapper 123 | |
| 12308 | case UNL_KOF97: | |
| 12309 | case UNL_603_5052: | |
| 12310 | case NITRA_TDA: // mapper 250 | |
| 12311 | if (state->m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring | |
| 12312 | { | |
| 12313 | set_nt_page(machine, 0, CART_NTRAM, 0, 1); | |
| 12314 | set_nt_page(machine, 1, CART_NTRAM, 1, 1); | |
| 12315 | set_nt_page(machine, 2, CART_NTRAM, 2, 1); | |
| 12316 | set_nt_page(machine, 3, CART_NTRAM, 3, 1); | |
| 12317 | } | |
| 12318 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12319 | break; | |
| 12320 | case STD_HKROM: // MMC6 (basically the same as TxROM, but alt IRQ behaviour) | |
| 12321 | mmc3_common_initialize(machine, 0xff, 0xff, 1); | |
| 12322 | state->m_mmc6_reg = 0xf0; | |
| 12323 | state->m_mmc_latch2 = 0; // this is used differently here compared to MMC3 | |
| 12324 | break; | |
| 12325 | case PAL_ZZ: // mapper 37 | |
| 12326 | mmc3_common_initialize(machine, 0x07, 0x7f, 0); | |
| 12327 | break; | |
| 12328 | case NES_QJ: // mapper 47 | |
| 12329 | mmc3_common_initialize(machine, 0x0f, 0x7f, 0); | |
| 12330 | break; | |
| 12331 | case STD_EXROM: // mapper 5 | |
| 12332 | state->m_MMC5_rom_bank_mode = 3; | |
| 12333 | state->m_MMC5_vrom_bank_mode = 0; | |
| 12334 | state->m_MMC5_vram_protect = 0; | |
| 12335 | state->m_mmc5_high_chr = 0; | |
| 12336 | state->m_mmc5_vram_control = 0; | |
| 12337 | state->m_mmc5_split_scr = 0; | |
| 12338 | memset(state->m_MMC5_vrom_bank, 0, ARRAY_LENGTH(state->m_MMC5_vrom_bank)); | |
| 12339 | state->m_mmc5_prg_mode = 3; | |
| 12340 | state->m_mmc5_last_chr_a = 1; | |
| 12341 | state->m_mmc5_prg_regs[0] = 0xfc; | |
| 12342 | state->m_mmc5_prg_regs[1] = 0xfd; | |
| 12343 | state->m_mmc5_prg_regs[2] = 0xfe; | |
| 12344 | state->m_mmc5_prg_regs[3] = 0xff; | |
| 12345 | memset(state->m_mmc5_vrom_regA, ~0, ARRAY_LENGTH(state->m_mmc5_vrom_regA)); | |
| 12346 | memset(state->m_mmc5_vrom_regB, ~0, ARRAY_LENGTH(state->m_mmc5_vrom_regB)); | |
| 12347 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12348 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12349 | break; | |
| 12350 | case STD_NXROM: // mapper 68 | |
| 12351 | case SUNSOFT_DCS: // mapper 68 | |
| 12352 | state->m_mmc_reg[0] = 0; | |
| 12353 | prg16_89ab(machine, 0); | |
| 12354 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12355 | break; | |
| 12356 | case NAMCOT_34X3: // mapper 88 | |
| 12357 | case STD_DXROM: // mapper 206 | |
| 12358 | case STD_DRROM: | |
| 12359 | if (state->m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring | |
| 12360 | { | |
| 12361 | set_nt_page(machine, 0, CART_NTRAM, 0, 1); | |
| 12362 | set_nt_page(machine, 1, CART_NTRAM, 1, 1); | |
| 12363 | set_nt_page(machine, 2, CART_NTRAM, 2, 1); | |
| 12364 | set_nt_page(machine, 3, CART_NTRAM, 3, 1); | |
| 12365 | } | |
| 12366 | case NAMCOT_3453: // mapper 154 | |
| 12367 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12368 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12369 | break; | |
| 12370 | case NAMCOT_3446: // mapper 76 | |
| 12371 | prg8_89(machine, 0); | |
| 12372 | prg8_ab(machine, 1); | |
| 12373 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12374 | chr2_0(machine, 0, CHRROM); | |
| 12375 | chr2_2(machine, 1, CHRROM); | |
| 12376 | chr2_4(machine, 2, CHRROM); | |
| 12377 | chr2_6(machine, 3, CHRROM); | |
| 12378 | break; | |
| 12379 | case BANDAI_JUMP2: // mapper 153 | |
| 12380 | for (i = 0; i < 8; i++) | |
| 12381 | state->m_mmc_reg[i] = 0; | |
| 12382 | prg16_89ab(machine, 0); | |
| 12383 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12384 | fjump2_set_prg(machine); | |
| 12385 | break; | |
| 12386 | case BANDAI_KARAOKE: // mapper 188 | |
| 12387 | prg16_89ab(machine, 0); | |
| 12388 | prg16_cdef(machine, (state->m_prg_chunks - 1) ^ 0x08); | |
| 12389 | break; | |
| 12390 | case IREM_LROG017: // mapper 77 | |
| 12391 | chr2_2(machine, 0, CHRROM); | |
| 12392 | chr2_4(machine, 1, CHRROM); | |
| 12393 | chr2_6(machine, 2, CHRROM); | |
| 12394 | break; | |
| 12395 | case IREM_TAM_S1: // mapper 97 | |
| 12396 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12397 | prg16_cdef(machine, 0); | |
| 12398 | break; | |
| 12399 | case KONAMI_VRC7: // mapper 85 | |
| 12400 | prg8_89(machine, 0); | |
| 12401 | prg8_ab(machine, 0); | |
| 12402 | prg8_cd(machine, 0); | |
| 12403 | prg8_ef(machine, 0xff); | |
| 12404 | break; | |
| 12405 | case NAMCOT_163: // mapper 19 | |
| 12406 | prg16_89ab(machine, 0); | |
| 12407 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12408 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12409 | break; | |
| 12410 | case SUNSOFT_1: // mapper 184 | |
| 12411 | case SUNSOFT_2: // mapper 89 & 93 | |
| 12412 | prg16_89ab(machine, 0); | |
| 12413 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12414 | if (!state->m_hard_mirroring) | |
| 12415 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 12416 | break; | |
| 12417 | ||
| 12418 | // mapper 14 | |
| 12419 | case REXSOFT_SL1632: | |
| 12420 | state->m_mmc_extra_bank[2] = 0xfe; | |
| 12421 | state->m_mmc_extra_bank[3] = 0xff; | |
| 12422 | state->m_mmc_extra_bank[0] = state->m_mmc_extra_bank[1] = state->m_mmc_extra_bank[4] = state->m_mmc_extra_bank[5] = state->m_mmc_extra_bank[6] = 0; | |
| 12423 | state->m_mmc_extra_bank[7] = state->m_mmc_extra_bank[8] = state->m_mmc_extra_bank[9] = state->m_mmc_extra_bank[0xa] = state->m_mmc_extra_bank[0xb] = 0; | |
| 12424 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = 0; | |
| 12425 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12426 | break; | |
| 12427 | // mapper 15 | |
| 12428 | case WAIXING_PS2: | |
| 12429 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12430 | break; | |
| 12431 | ||
| 12432 | // mapper 35 | |
| 12433 | case UNL_SC127: | |
| 12434 | // mapper 42 | |
| 12435 | case BTL_MARIOBABY: | |
| 12436 | case BTL_AISENSHINICOL: | |
| 12437 | prg32(machine, 0xff); | |
| 12438 | break; | |
| 12439 | ||
| 12440 | // mapper 40 | |
| 12441 | case BTL_SMB2A: | |
| 12442 | prg8_67(machine, 0xfe); | |
| 12443 | prg8_89(machine, 0xfc); | |
| 12444 | prg8_ab(machine, 0xfd); | |
| 12445 | prg8_cd(machine, 0xfe); | |
| 12446 | prg8_ef(machine, 0xff); | |
| 12447 | break; | |
| 12448 | ||
| 12449 | // mapper 43 | |
| 12450 | case UNL_SMB2J: | |
| 12451 | if (state->m_battery) | |
| 12452 | memset(state->m_battery_ram, 0x2000, 0xff); | |
| 12453 | else if (state->m_prg_ram) | |
| 12454 | memset(state->m_wram, 0x2000, 0xff); | |
| 12455 | break; | |
| 12456 | // mapper 44 | |
| 12457 | case BMC_SUPERBIG_7IN1: | |
| 12458 | // mapper 49 | |
| 12459 | case BMC_SUPERHIK_4IN1: | |
| 12460 | mmc3_common_initialize(machine, 0x0f, 0x7f, 0); | |
| 12461 | break; | |
| 12462 | // mapper 45 | |
| 12463 | case BMC_HIK8IN1: | |
| 12464 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12465 | mmc3_common_initialize(machine, 0x3f, 0xff, 0); | |
| 12466 | break; | |
| 12467 | ||
| 12468 | // mapper 50 | |
| 12469 | case BTL_SMB2B: | |
| 12470 | prg8_67(machine, 0x0f); | |
| 12471 | prg8_89(machine, 0x08); | |
| 12472 | prg8_ab(machine, 0x09); | |
| 12473 | prg8_cd(machine, 0); | |
| 12474 | prg8_ef(machine, 0x0b); | |
| 12475 | break; | |
| 12476 | // mapper 51 | |
| 12477 | case BMC_BALLGAMES_11IN1: | |
| 12478 | state->m_mmc_reg[0] = 0x01; | |
| 12479 | state->m_mmc_reg[1] = 0x00; | |
| 12480 | bmc_ball11_set_banks(machine); | |
| 12481 | break; | |
| 12482 | // mapper 52 | |
| 12483 | case BMC_MARIOPARTY_7IN1: | |
| 12484 | state->m_map52_reg_written = 0; | |
| 12485 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12486 | break; | |
| 12487 | // mapper 54 | |
| 12488 | case BMC_NOVELDIAMOND: | |
| 12489 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12490 | break; | |
| 12491 | // mapper 57 | |
| 12492 | case BMC_GKA: | |
| 12493 | prg16_89ab(machine, 0); | |
| 12494 | prg16_cdef(machine, 0); | |
| 12495 | break; | |
| 12496 | ||
| 12497 | // mapper 64 | |
| 12498 | case TENGEN_800032: | |
| 12499 | // mapper 158 | |
| 12500 | case TENGEN_800037: | |
| 12501 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12502 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12503 | break; | |
| 12504 | // mapper 71 | |
| 12505 | case CAMERICA_BF9097: | |
| 12506 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 12507 | case CAMERICA_BF9093: | |
| 12508 | prg32(machine, 0xff); | |
| 12509 | break; | |
| 12510 | ||
| 12511 | // mapper 79 (& 146) | |
| 12512 | case AVE_NINA06: | |
| 12513 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 12514 | break; | |
| 12515 | ||
| 12516 | // mapper 83 | |
| 12517 | case CONY_BOARD: | |
| 12518 | state->m_mapper83_reg[9] = 0x0f; | |
| 12519 | prg8_cd(machine, 0x1e); | |
| 12520 | prg8_ef(machine, 0x1f); | |
| 12521 | break; | |
| 12522 | ||
| 12523 | // mapper 91 | |
| 12524 | case UNL_MK2: | |
| 12525 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12526 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12527 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12528 | break; | |
| 12529 | ||
| 12530 | // mapper 104 | |
| 12531 | case CAMERICA_GOLDENFIVE: | |
| 12532 | prg16_89ab(machine, 0x00); | |
| 12533 | prg16_cdef(machine, 0x0f); | |
| 12534 | break; | |
| 12535 | // mapper 106 | |
| 12536 | case BTL_SMB3: | |
| 12537 | prg8_89(machine, (state->m_prg_chunks << 1) - 1); | |
| 12538 | prg8_ab(machine, 0); | |
| 12539 | prg8_cd(machine, 0); | |
| 12540 | prg8_ef(machine, (state->m_prg_chunks << 1) - 1); | |
| 12541 | break; | |
| 12542 | ||
| 12543 | // mapper 108 | |
| 12544 | case WHIRLWIND_2706: | |
| 12545 | prg32(machine, 0xff); | |
| 12546 | break; | |
| 12547 | ||
| 12548 | // mapper 114 | |
| 12549 | case SUPERGAME_LIONKING: | |
| 12550 | state->m_map114_reg = state->m_map114_reg_enabled = 0; | |
| 12551 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12552 | break; | |
| 12553 | // mapper 115 | |
| 12554 | case KASING_BOARD: | |
| 12555 | state->m_mmc_reg[0] = 0; | |
| 12556 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12557 | break; | |
| 12558 | // mapper 116 | |
| 12559 | case SOMERI_SL12: | |
| 12560 | state->m_mmc_prg_base = state->m_mmc_chr_base = 0; | |
| 12561 | state->m_mmc_prg_mask = 0xff; | |
| 12562 | state->m_mmc_chr_mask = 0xff; | |
| 12563 | state->m_mmc_cmd1 = 2; // mode | |
| 12564 | state->m_mmc3_latch = 0; | |
| 12565 | state->m_mmc3_wram_protect = 0; | |
| 12566 | // MMC1 regs | |
| 12567 | state->m_mmc1_count = 0; | |
| 12568 | state->m_mmc_reg[0] = 0x0c; | |
| 12569 | state->m_mmc_reg[1] = 0x00; | |
| 12570 | state->m_mmc_reg[2] = 0x00; | |
| 12571 | state->m_mmc_reg[3] = 0x00; | |
| 12572 | // MMC3 regs | |
| 12573 | state->m_mmc_prg_bank[0] = 0x3c; | |
| 12574 | state->m_mmc_prg_bank[1] = 0x3d; | |
| 12575 | state->m_mmc_prg_bank[2] = 0xfe; | |
| 12576 | state->m_mmc_prg_bank[3] = 0xff; | |
| 12577 | state->m_mmc_vrom_bank[0] = 0x00; | |
| 12578 | state->m_mmc_vrom_bank[1] = 0x01; | |
| 12579 | state->m_mmc_vrom_bank[2] = 0x04; | |
| 12580 | state->m_mmc_vrom_bank[3] = 0x05; | |
| 12581 | state->m_mmc_vrom_bank[4] = 0x06; | |
| 12582 | state->m_mmc_vrom_bank[5] = 0x07; | |
| 12583 | // VRC2 regs | |
| 12584 | state->m_mmc_prg_bank[4] = 0x00; | |
| 12585 | state->m_mmc_prg_bank[5] = 0x01; | |
| 12586 | for (i = 0; i < 8; ++i) | |
| 12587 | state->m_mmc_vrom_bank[6 + i] = i; | |
| 12588 | someri_mode_update(machine); | |
| 12589 | break; | |
| 12590 | ||
| 12591 | // mapper 120 | |
| 12592 | case BTL_TOBIDASE: | |
| 12593 | prg32(machine, 2); | |
| 12594 | break; | |
| 12595 | ||
| 12596 | // mapper 121 | |
| 12597 | case KAY_PANDAPRINCE: | |
| 12598 | state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0; | |
| 12599 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12600 | break; | |
| 12601 | ||
| 12602 | // mapper 126 | |
| 12603 | case BMC_PJOY84: | |
| 12604 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12605 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12606 | pjoy84_set_base_mask(machine); | |
| 12607 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12608 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12609 | break; | |
| 12610 | ||
| 12611 | // mapper 132 | |
| 12612 | case TXC_22211A: | |
| 12613 | // mapper 172 | |
| 12614 | case TXC_22211B: | |
| 12615 | // mapper 173 | |
| 12616 | case TXC_22211C: | |
| 12617 | state->m_txc_reg[0] = state->m_txc_reg[1] = state->m_txc_reg[2] = state->m_txc_reg[3] = 0; | |
| 12618 | break; | |
| 12619 | ||
| 12620 | // mapper 134 | |
| 12621 | case BMC_FAMILY_4646B: | |
| 12622 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12623 | break; | |
| 12624 | ||
| 12625 | // mapper 137 | |
| 12626 | case SACHEN_8259D: | |
| 12627 | chr8(machine, state->m_chr_chunks - 1, CHRROM); | |
| 12628 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12629 | break; | |
| 12630 | // mapper 138 | |
| 12631 | case SACHEN_8259B: | |
| 12632 | // mapper 139 | |
| 12633 | case SACHEN_8259C: | |
| 12634 | // mapper 141 | |
| 12635 | case SACHEN_8259A: | |
| 12636 | // mapper 150 | |
| 12637 | case SACHEN_74LS374: | |
| 12638 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12639 | break; | |
| 12640 | // mapper 143 | |
| 12641 | case SACHEN_TCA01: | |
| 12642 | prg16_89ab(machine, 0); | |
| 12643 | prg16_cdef(machine, 1); | |
| 12644 | break; | |
| 12645 | ||
| 12646 | // mapper 156 | |
| 12647 | case OPENCORP_DAOU306: | |
| 12648 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12649 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12650 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 12651 | break; | |
| 12652 | // mapper 163 | |
| 12653 | case NANJING_BOARD: | |
| 12654 | state->m_mmc_count = 0xff; | |
| 12655 | state->m_mmc_reg[0] = 0xff; | |
| 12656 | state->m_mmc_reg[1] = 0; | |
| 12657 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12658 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12659 | break; | |
| 12660 | // mapper 164 | |
| 12661 | case WAIXING_FFV: | |
| 12662 | prg16_89ab(machine, 0); | |
| 12663 | prg16_cdef(machine, 0x1f); | |
| 12664 | break; | |
| 12665 | // mapper 166 | |
| 12666 | case SUBOR_TYPE1: | |
| 12667 | state->m_subor_reg[0] = state->m_subor_reg[1] = state->m_subor_reg[2] = state->m_subor_reg[3] = 0; | |
| 12668 | prg16_89ab(machine, 0); | |
| 12669 | prg16_cdef(machine, 0x07); | |
| 12670 | break; | |
| 12671 | // mapper 167 | |
| 12672 | case SUBOR_TYPE0: | |
| 12673 | state->m_subor_reg[0] = state->m_subor_reg[1] = state->m_subor_reg[2] = state->m_subor_reg[3] = 0; | |
| 12674 | prg16_89ab(machine, 0); | |
| 12675 | prg16_cdef(machine, 0x20); | |
| 12676 | break; | |
| 12677 | ||
| 12678 | // mapper 176 | |
| 12679 | case UNL_XZY: | |
| 12680 | // mapper 182 | |
| 12681 | case HOSENKAN_BOARD: | |
| 12682 | prg32(machine, (state->m_prg_chunks - 1) >> 1); | |
| 12683 | break; | |
| 12684 | ||
| 12685 | case FUKUTAKE_BOARD: // mapper 186 | |
| 12686 | prg16_89ab(machine, 0); | |
| 12687 | prg16_cdef(machine, 0); | |
| 12688 | break; | |
| 12689 | ||
| 12690 | // mapper 187 | |
| 12691 | case UNL_KOF96: | |
| 12692 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12693 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12694 | break; | |
| 12695 | // mapper 189 | |
| 12696 | case TXC_TW: | |
| 12697 | state->m_mmc_latch1 = 0; | |
| 12698 | state->m_mmc_latch2 = 0x80; | |
| 12699 | state->m_mmc_chr_base = 0; | |
| 12700 | state->m_mmc_chr_mask = 0xff; | |
| 12701 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12702 | break; | |
| 12703 | // mapper 193 | |
| 12704 | case NTDEC_FIGHTINGHERO: | |
| 12705 | prg32(machine, (state->m_prg_chunks - 1) >> 1); | |
| 12706 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12707 | break; | |
| 12708 | // mapper 197 | |
| 12709 | case UNL_SUPERFIGHTER3: | |
| 12710 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12711 | unl_sf3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12712 | break; | |
| 12713 | // mapper 198 | |
| 12714 | case WAIXING_TYPE_F: | |
| 12715 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12716 | state->m_mmc_prg_bank[0] = 0x00; | |
| 12717 | state->m_mmc_prg_bank[1] = 0x01; | |
| 12718 | state->m_mmc_prg_bank[2] = 0x4e; | |
| 12719 | state->m_mmc_prg_bank[3] = 0x4f; | |
| 12720 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12721 | break; | |
| 12722 | // mapper 199 | |
| 12723 | case WAIXING_TYPE_G: | |
| 12724 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12725 | state->m_mmc_prg_bank[0] = 0x00; | |
| 12726 | state->m_mmc_prg_bank[1] = 0x01; | |
| 12727 | state->m_mmc_prg_bank[2] = 0x3e; | |
| 12728 | state->m_mmc_prg_bank[3] = 0x3f; | |
| 12729 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12730 | state->m_mmc_vrom_bank[0] = 0x00; | |
| 12731 | state->m_mmc_vrom_bank[1] = 0x02; | |
| 12732 | state->m_mmc_vrom_bank[2] = 0x04; | |
| 12733 | state->m_mmc_vrom_bank[3] = 0x05; | |
| 12734 | state->m_mmc_vrom_bank[4] = 0x06; | |
| 12735 | state->m_mmc_vrom_bank[5] = 0x07; | |
| 12736 | state->m_mmc_vrom_bank[6] = 0x01; | |
| 12737 | state->m_mmc_vrom_bank[7] = 0x03; | |
| 12738 | waixing_g_set_chr(machine, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12739 | break; | |
| 12740 | ||
| 12741 | // mapper 200 | |
| 12742 | case BMC_36IN1: | |
| 12743 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12744 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12745 | break; | |
| 12746 | ||
| 12747 | // mapper 202 | |
| 12748 | case BMC_150IN1: | |
| 12749 | // mapper 203 | |
| 12750 | case BMC_35IN1: | |
| 12751 | // mapper 204 | |
| 12752 | case BMC_64IN1: | |
| 12753 | // mapper 214 | |
| 12754 | case BMC_SUPERGUN_20IN1: | |
| 12755 | prg16_89ab(machine, 0); | |
| 12756 | prg16_cdef(machine, 0); | |
| 12757 | break; | |
| 12758 | // mapper 205 | |
| 12759 | case BMC_15IN1: | |
| 12760 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12761 | state->m_mmc_prg_base = 0x10; // this board has a diff prg_base | |
| 12762 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12763 | break; | |
| 12764 | ||
| 12765 | // mapper 208 | |
| 12766 | case GOUDER_37017: | |
| 12767 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = state->m_mmc_reg[4] = 0; | |
| 12768 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12769 | break; | |
| 12770 | // mapper 212 | |
| 12771 | case BMC_SUPERHIK_300IN1: | |
| 12772 | chr8(machine, 0xff, CHRROM); | |
| 12773 | prg32(machine, 0xff); | |
| 12774 | break; | |
| 12775 | ||
| 12776 | // mapper 215 | |
| 12777 | case SUPERGAME_BOOGERMAN: | |
| 12778 | state->m_mmc_reg[0] = 0x00; | |
| 12779 | state->m_mmc_reg[1] = 0xff; | |
| 12780 | state->m_mmc_reg[2] = 0x04; | |
| 12781 | state->m_mmc_reg[3] = 0; | |
| 12782 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12783 | sgame_boog_set_prg(machine); | |
| 12784 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12785 | break; | |
| 12786 | ||
| 12787 | // mapper 217 | |
| 12788 | case BMC_GOLDENCARD_6IN1: | |
| 12789 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12790 | state->m_mmc_reg[0] = 0x00; | |
| 12791 | state->m_mmc_reg[1] = 0xff; | |
| 12792 | state->m_mmc_reg[2] = 0x03; | |
| 12793 | state->m_mmc_reg[3] = 0; | |
| 12794 | bmc_gc6in1_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12795 | bmc_gc6in1_set_chr(machine, state->m_mmc_chr_source); | |
| 12796 | break; | |
| 12797 | // mapper 221 | |
| 12798 | case UNL_N625092: | |
| 12799 | prg16_89ab(machine, 0); | |
| 12800 | prg16_cdef(machine, 0); | |
| 12801 | break; | |
| 12802 | ||
| 12803 | // mapper 223? | |
| 12804 | case WAIXING_TYPE_I: | |
| 12805 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12806 | state->m_mmc3_wram_protect = 0; | |
| 12807 | break; | |
| 12808 | ||
| 12809 | // mapper 224? | |
| 12810 | case WAIXING_TYPE_J: | |
| 12811 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12812 | state->m_mmc_prg_bank[0] = 0x01; | |
| 12813 | state->m_mmc_prg_bank[1] = 0x02; | |
| 12814 | state->m_mmc_prg_bank[2] = 0x7e; | |
| 12815 | state->m_mmc_prg_bank[3] = 0x7f; | |
| 12816 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12817 | break; | |
| 12818 | ||
| 12819 | // mapper 227 | |
| 12820 | case BMC_1200IN1: | |
| 12821 | prg16_89ab(machine, 0); | |
| 12822 | prg16_cdef(machine, 0); | |
| 12823 | break; | |
| 12824 | ||
| 12825 | // mapper 229 | |
| 12826 | case BMC_31IN1: | |
| 12827 | prg16_89ab(machine, 0); | |
| 12828 | prg16_cdef(machine, 1); | |
| 12829 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12830 | break; | |
| 12831 | // mapper 230 | |
| 12832 | case BMC_22GAMES: | |
| 12833 | prg16_89ab(machine, 0); | |
| 12834 | prg16_cdef(machine, 7); | |
| 12835 | break; | |
| 12836 | // mapper 231 | |
| 12837 | case BMC_20IN1: | |
| 12838 | prg16_89ab(machine, 0); | |
| 12839 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12840 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12841 | break; | |
| 12842 | // mapper 232 | |
| 12843 | case CAMERICA_BF9096: | |
| 12844 | state->m_mmc_latch1 = 0x18; | |
| 12845 | state->m_mmc_latch2 = 0x00; | |
| 12846 | bf9096_set_prg(machine); | |
| 12847 | break; | |
| 12848 | ||
| 12849 | // mapper 243 | |
| 12850 | case SACHEN_74LS374_A: | |
| 12851 | state->m_mmc_vrom_bank[0] = 3; | |
| 12852 | chr8(machine, 3, CHRROM); | |
| 12853 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12854 | break; | |
| 12855 | ||
| 12856 | // mapper 246 | |
| 12857 | case CNE_FSB: | |
| 12858 | prg32(machine, 0xff); | |
| 12859 | break; | |
| 12860 | // mapper 249 | |
| 12861 | case WAIXING_SECURITY: | |
| 12862 | state->m_mmc_reg[0] = 0; | |
| 12863 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12864 | break; | |
| 12865 | ||
| 12866 | // mapper 254 | |
| 12867 | case BTL_PIKACHUY2K: | |
| 12868 | state->m_mmc_reg[0] = 0xff; | |
| 12869 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12870 | break; | |
| 12871 | ||
| 12872 | // mapper 255 | |
| 12873 | case BMC_110IN1: | |
| 12874 | prg16_89ab(machine, 0); | |
| 12875 | prg16_cdef(machine, 1); | |
| 12876 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12877 | break; | |
| 12878 | ||
| 12879 | // UNIF only | |
| 12880 | case BMC_64IN1NR: | |
| 12881 | state->m_mmc_reg[0] = 0x80; | |
| 12882 | state->m_mmc_reg[1] = 0x43; | |
| 12883 | state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12884 | bmc_64in1nr_set_prg(machine); | |
| 12885 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12886 | break; | |
| 12887 | case BMC_190IN1: | |
| 12888 | prg16_89ab(machine, 0); | |
| 12889 | prg16_cdef(machine, 0); | |
| 12890 | break; | |
| 12891 | case BMC_A65AS: | |
| 12892 | prg16_89ab(machine, 0); | |
| 12893 | prg16_cdef(machine, 7); | |
| 12894 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12895 | break; | |
| 12896 | case BMC_GS2004: | |
| 12897 | case BMC_GS2013: | |
| 12898 | prg32(machine, 0xff); | |
| 12899 | break; | |
| 12900 | case BMC_S24IN1SC03: | |
| 12901 | state->m_mmc_reg[0] = 0x24; | |
| 12902 | state->m_mmc_reg[1] = 0x9f; | |
| 12903 | state->m_mmc_reg[2] = 0; | |
| 12904 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12905 | break; | |
| 12906 | case BMC_T262: | |
| 12907 | state->m_mmc_latch1 = 0; | |
| 12908 | state->m_mmc_latch2 = 0; | |
| 12909 | prg16_89ab(machine, 0); | |
| 12910 | prg16_cdef(machine, 7); | |
| 12911 | break; | |
| 12912 | case DREAMTECH_BOARD: | |
| 12913 | prg16_89ab(machine, 0); | |
| 12914 | prg16_cdef(machine, 8); | |
| 12915 | break; | |
| 12916 | case UNL_8237: | |
| 12917 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = 0; | |
| 12918 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12919 | break; | |
| 12920 | case UNL_AX5705: | |
| 12921 | state->m_mmc_prg_bank[0] = 0; | |
| 12922 | state->m_mmc_prg_bank[1] = 1; | |
| 12923 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 12924 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 12925 | prg8_cd(machine, 0xfe); | |
| 12926 | prg8_ef(machine, 0xff); | |
| 12927 | break; | |
| 12928 | case UNL_RACERMATE: | |
| 12929 | chr4_0(machine, 0, state->m_mmc_chr_source); | |
| 12930 | chr4_4(machine, 0, state->m_mmc_chr_source); | |
| 12931 | prg16_89ab(machine, 0); | |
| 12932 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12933 | break; | |
| 12934 | ||
| 12935 | case BMC_BENSHENG_BS5: | |
| 12936 | state->m_mmc_prg_bank[0] = 0xff; | |
| 12937 | state->m_mmc_prg_bank[1] = 0xff; | |
| 12938 | state->m_mmc_prg_bank[2] = 0xff; | |
| 12939 | state->m_mmc_prg_bank[3] = 0xff; | |
| 12940 | bmc_bs5_update_banks(machine); | |
| 12941 | break; | |
| 12942 | ||
| 12943 | case BMC_810544: | |
| 12944 | prg16_89ab(machine, 0); | |
| 12945 | prg16_cdef(machine, 0); | |
| 12946 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12947 | break; | |
| 12948 | ||
| 12949 | case BMC_G63IN1: | |
| 12950 | bmc_gb63_update(machine); | |
| 12951 | break; | |
| 12952 | ||
| 12953 | case BMC_FK23C: | |
| 12954 | state->m_mmc_reg[0] = 4; | |
| 12955 | state->m_mmc_reg[1] = 0xff; | |
| 12956 | state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12957 | state->m_mmc_reg[4] = state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0xff; | |
| 12958 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12959 | fk23c_set_prg(machine); | |
| 12960 | fk23c_set_chr(machine); | |
| 12961 | break; | |
| 12962 | ||
| 12963 | case BMC_FK23CA: | |
| 12964 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12965 | state->m_mmc_reg[4] = state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0xff; | |
| 12966 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12967 | fk23c_set_prg(machine); | |
| 12968 | fk23c_set_chr(machine); | |
| 12969 | break; | |
| 12970 | ||
| 12971 | ||
| 12972 | case FFE_MAPPER6: | |
| 12973 | prg16_89ab(machine, 0); | |
| 12974 | prg16_cdef(machine, 7); | |
| 12975 | break; | |
| 12976 | case FFE_MAPPER8: | |
| 12977 | prg32(machine, 0); | |
| 12978 | break; | |
| 12979 | case FFE_MAPPER17: | |
| 12980 | prg16_89ab(machine, 0); | |
| 12981 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12982 | break; | |
| 12983 | ||
| 12984 | case UNSUPPORTED_BOARD: | |
| 12985 | default: | |
| 12986 | /* Mapper not supported */ | |
| 12987 | err = 2; | |
| 12988 | break; | |
| 12989 | } | |
| 12990 | ||
| 12991 | return err; | |
| 12992 | } | |
| 12993 | ||
| 12994 | /************************************************************* | |
| 12995 | ||
| 12996 | nes_pcb_reset | |
| 12997 | ||
| 12998 | Resets the mmc bankswitch areas to their defaults. | |
| 12999 | It returns a value "err" that indicates if it was | |
| 13000 | successful. Possible values for err are: | |
| 13001 | ||
| 13002 | 0 = success | |
| 13003 | 1 = no pcb found | |
| 13004 | 2 = pcb not supported | |
| 13005 | ||
| 13006 | *************************************************************/ | |
| 13007 | ||
| 13008 | int nes_pcb_reset( running_machine &machine ) | |
| 13009 | { | |
| 13010 | nes_state *state = machine.driver_data<nes_state>(); | |
| 13011 | int err = 0; | |
| 13012 | const nes_pcb_intf *intf = nes_pcb_intf_lookup(state->m_pcb_id); | |
| 13013 | ||
| 13014 | if (intf == NULL) | |
| 13015 | fatalerror("Missing PCB interface\n"); | |
| 13016 | ||
| 13017 | /* Set the mapper irq callback */ | |
| 13018 | ppu2c0x_set_scanline_callback(state->m_ppu, intf ? intf->mmc_scanline : NULL); | |
| 13019 | ppu2c0x_set_hblank_callback(state->m_ppu, intf ? intf->mmc_hblank : NULL); | |
| 13020 | ||
| 13021 | err = pcb_initialize(machine, state->m_pcb_id); | |
| 13022 | ||
| 13023 | return err; | |
| 13024 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | aescart.c | |
| 4 | ||
| 5 | Neo-Geo AES cartridge management | |
| 6 | R. Belmont, 2009 | |
| 7 | ||
| 8 | Based on ti99cart.c by Michael Zapf | |
| 9 | ||
| 10 | We leave the support in place for multiple slots in case MAME | |
| 11 | uses this at some future point for MVS multi-cart. | |
| 12 | ||
| 13 | *********************************************************************/ | |
| 14 | #include "emu.h" | |
| 15 | #include "aescart.h" | |
| 16 | #include "imagedev/cartslot.h" | |
| 17 | #include "imagedev/multcart.h" | |
| 18 | #include "includes/neogeo.h" | |
| 19 | ||
| 20 | typedef int assmfct(running_machine &machine, device_t *); | |
| 21 | ||
| 22 | enum | |
| 23 | { | |
| 24 | AESCART_FCT_ASSM = DEVINFO_FCT_DEVICE_SPECIFIC, | |
| 25 | AESCART_FCT_DISASSM | |
| 26 | }; | |
| 27 | ||
| 28 | struct _aes_multicart_t | |
| 29 | { | |
| 30 | /* Reserves space for all cartridges. This is also used in the legacy | |
| 31 | cartridge system, but only for slot 0. */ | |
| 32 | aescartridge_t cartridge[AES_NUMBER_OF_CARTRIDGE_SLOTS]; | |
| 33 | ||
| 34 | /* Determines which slot is currently active. This value is changed when there | |
| 35 | are accesses to other GROM base addresses. */ | |
| 36 | int active_slot; | |
| 37 | ||
| 38 | /* Used in order to enforce a special slot. This value is retrieved | |
| 39 | from the dipswitch setting. A value of -1 means automatic, that is, | |
| 40 | the grom base switch is used. Values 0 .. max refer to the | |
| 41 | respective slot. */ | |
| 42 | int fixed_slot; | |
| 43 | ||
| 44 | /* Holds the highest index of a cartridge being plugged in plus one. | |
| 45 | If we only have one cartridge inserted, we don't want to get a | |
| 46 | selection option, so we just mirror the memory contents. */ | |
| 47 | int next_free_slot; | |
| 48 | ||
| 49 | /* Counts the number of slots which currently contain legacy format | |
| 50 | cartridge images. */ | |
| 51 | int legacy_slots; | |
| 52 | ||
| 53 | /* Counts the number of slots which currently contain new format | |
| 54 | cartridge images. */ | |
| 55 | int multi_slots; | |
| 56 | }; | |
| 57 | typedef struct _aes_multicart_t aes_multicart_t; | |
| 58 | ||
| 59 | #define AUTO -1 | |
| 60 | ||
| 61 | /* Access to the pcb. Contained in the token of the pcb instance. */ | |
| 62 | struct _aes_pcb_t | |
| 63 | { | |
| 64 | /* Link up to the cartridge structure which contains this pcb. */ | |
| 65 | aescartridge_t *cartridge; | |
| 66 | ||
| 67 | /* Function to assemble this cartridge. */ | |
| 68 | assmfct *assemble; | |
| 69 | ||
| 70 | /* Function to disassemble this cartridge. */ | |
| 71 | assmfct *disassemble; | |
| 72 | }; | |
| 73 | typedef struct _aes_pcb_t aes_pcb_t; | |
| 74 | ||
| 75 | INLINE aes_multicart_t *get_safe_token(device_t *device) | |
| 76 | { | |
| 77 | assert(device != NULL); | |
| 78 | assert(device->type() == AES_MULTICART); | |
| 79 | ||
| 80 | return (aes_multicart_t *)downcast<legacy_device_base *>(device)->token(); | |
| 81 | } | |
| 82 | ||
| 83 | INLINE aes_pcb_t *get_safe_pcb_token(device_t *device) | |
| 84 | { | |
| 85 | assert(device != NULL); | |
| 86 | assert(device->type() == AES_CARTRIDGE_PCB_NONE || device->type() == AES_CARTRIDGE_PCB_STD); | |
| 87 | ||
| 88 | return (aes_pcb_t *)downcast<legacy_device_base *>(device)->token(); | |
| 89 | } | |
| 90 | ||
| 91 | INLINE cartslot_t *get_safe_cartslot_token(device_t *device) | |
| 92 | { | |
| 93 | assert(device != NULL); | |
| 94 | assert(device->type() == CARTSLOT); | |
| 95 | ||
| 96 | return (cartslot_t *)downcast<legacy_device_base *>(device)->token(); | |
| 97 | } | |
| 98 | ||
| 99 | /* | |
| 100 | Find the index of the cartridge name. We assume the format | |
| 101 | <name><number>, i.e. the number is the longest string from the right | |
| 102 | which can be interpreted as a number. | |
| 103 | */ | |
| 104 | static int get_index_from_tagname(device_t *image) | |
| 105 | { | |
| 106 | const char *tag = image->tag(); | |
| 107 | int maxlen = strlen(tag); | |
| 108 | int i; | |
| 109 | for (i=maxlen-1; i >=0; i--) | |
| 110 | if (tag[i] < 48 || tag[i] > 57) break; | |
| 111 | ||
| 112 | return atoi(tag+i+1); | |
| 113 | } | |
| 114 | ||
| 115 | /* | |
| 116 | Common routine to assemble cartridges from resources. | |
| 117 | */ | |
| 118 | static aescartridge_t *assemble_common(running_machine &machine, device_t *cartslot) | |
| 119 | { | |
| 120 | /* Pointer to the cartridge structure. */ | |
| 121 | aescartridge_t *cartridge; | |
| 122 | device_t *cartsys = cartslot->owner(); | |
| 123 | aes_multicart_t *cartslots = get_safe_token(cartsys); | |
| 124 | UINT8 *socketcont, *romrgn; | |
| 125 | int reslength, i, blockofs; | |
| 126 | char sprname1[16], sprname2[16]; | |
| 127 | ||
| 128 | int slotnumber = get_index_from_tagname(cartslot)-1; | |
| 129 | assert(slotnumber>=0 && slotnumber<AES_NUMBER_OF_CARTRIDGE_SLOTS); | |
| 130 | ||
| 131 | /* There is a cartridge in this slot, check the maximum slot number. */ | |
| 132 | if (cartslots->next_free_slot <= slotnumber) | |
| 133 | { | |
| 134 | cartslots->next_free_slot = slotnumber+1; | |
| 135 | } | |
| 136 | cartridge = &cartslots->cartridge[slotnumber]; | |
| 137 | ||
| 138 | // check for up to 4 program ROMs | |
| 139 | romrgn = (UINT8 *)machine.region("maincpu")->base(); | |
| 140 | blockofs = 0; | |
| 141 | for (i = 0; i < 4; i++) | |
| 142 | { | |
| 143 | sprintf(sprname1, "p%d", i+1); | |
| 144 | ||
| 145 | socketcont = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 146 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 147 | ||
| 148 | if (socketcont != NULL) | |
| 149 | { | |
| 150 | memcpy(romrgn+blockofs, socketcont, reslength); | |
| 151 | blockofs += reslength; | |
| 152 | } | |
| 153 | } | |
| 154 | ||
| 155 | // 1 m1 ROM | |
| 156 | socketcont = (UINT8*)cartslot_get_socket(cartslot, "m1"); | |
| 157 | reslength = cartslot_get_resource_length(cartslot, "m1"); | |
| 158 | if (socketcont != NULL) | |
| 159 | { | |
| 160 | romrgn = (UINT8 *)machine.region("audiocpu")->base(); | |
| 161 | ||
| 162 | memcpy(romrgn, socketcont, reslength); | |
| 163 | // mirror (how does this really work?) | |
| 164 | memcpy(romrgn+0x10000, socketcont, reslength); | |
| 165 | } | |
| 166 | ||
| 167 | // up to 8 YM sample ROMs | |
| 168 | romrgn = (UINT8 *)machine.region("ymsnd")->base(); | |
| 169 | blockofs = 0; | |
| 170 | for (i = 0; i < 8; i++) | |
| 171 | { | |
| 172 | sprintf(sprname1, "v1%d", i+1); | |
| 173 | ||
| 174 | socketcont = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 175 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 176 | ||
| 177 | if (socketcont != NULL) | |
| 178 | { | |
| 179 | memcpy(romrgn+blockofs, socketcont, reslength); | |
| 180 | blockofs += reslength; | |
| 181 | } | |
| 182 | } | |
| 183 | ||
| 184 | // up to 8 YM delta-T sample ROMs | |
| 185 | romrgn = (UINT8 *)machine.region("ymsnd.deltat")->base(); | |
| 186 | blockofs = 0; | |
| 187 | for (i = 0; i < 8; i++) | |
| 188 | { | |
| 189 | sprintf(sprname1, "v2%d", i+1); | |
| 190 | ||
| 191 | socketcont = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 192 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 193 | ||
| 194 | if (socketcont != NULL) | |
| 195 | { | |
| 196 | memcpy(romrgn+blockofs, socketcont, reslength); | |
| 197 | blockofs += reslength; | |
| 198 | } | |
| 199 | } | |
| 200 | ||
| 201 | // 1 s1 ROM | |
| 202 | socketcont = (UINT8*)cartslot_get_socket(cartslot, "s1"); | |
| 203 | reslength = cartslot_get_resource_length(cartslot, "s1"); | |
| 204 | if (socketcont != NULL) | |
| 205 | { | |
| 206 | romrgn = (UINT8 *)machine.region("fixed")->base(); | |
| 207 | ||
| 208 | memcpy(romrgn, socketcont, reslength); | |
| 209 | } | |
| 210 | ||
| 211 | // up to 8 sprite ROMs in byte-interleaved pairs | |
| 212 | romrgn = (UINT8 *)machine.region("sprites")->base(); | |
| 213 | blockofs = 0; | |
| 214 | for (i = 0; i < 8; i+=2) | |
| 215 | { | |
| 216 | UINT8 *spr1, *spr2; | |
| 217 | int j; | |
| 218 | ||
| 219 | sprintf(sprname1, "c%d", i+1); | |
| 220 | sprintf(sprname2, "c%d", i+2); | |
| 221 | ||
| 222 | spr1 = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 223 | spr2 = (UINT8*)cartslot_get_socket(cartslot, sprname2); | |
| 224 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 225 | ||
| 226 | if ((spr1) && (spr2)) | |
| 227 | { | |
| 228 | for (j = 0; j < reslength; j++) | |
| 229 | { | |
| 230 | romrgn[blockofs + (j*2)] = spr1[j]; | |
| 231 | romrgn[blockofs + (j*2) + 1] = spr2[j]; | |
| 232 | } | |
| 233 | ||
| 234 | blockofs += reslength*2; | |
| 235 | } | |
| 236 | } | |
| 237 | ||
| 238 | return cartridge; | |
| 239 | } | |
| 240 | ||
| 241 | static void set_pointers(device_t *pcb, int index) | |
| 242 | { | |
| 243 | device_t *cartsys = pcb->owner()->owner(); | |
| 244 | aes_multicart_t *cartslots = get_safe_token(cartsys); | |
| 245 | aes_pcb_t *pcb_def = get_safe_pcb_token(pcb); | |
| 246 | ||
| 247 | pcb_def->assemble = (assmfct *)downcast<const legacy_cart_slot_device_base *>(pcb)->get_legacy_fct(AESCART_FCT_ASSM); | |
| 248 | pcb_def->disassemble = (assmfct *)downcast<const legacy_cart_slot_device_base *>(pcb)->get_legacy_fct(AESCART_FCT_DISASSM); | |
| 249 | ||
| 250 | pcb_def->cartridge = &cartslots->cartridge[index]; | |
| 251 | pcb_def->cartridge->pcb = pcb; | |
| 252 | } | |
| 253 | ||
| 254 | /***************************************************************************** | |
| 255 | Cartridge type: None | |
| 256 | This PCB device is just a pseudo device; the legacy mode is handled | |
| 257 | by dedicated functions. | |
| 258 | ******************************************************************************/ | |
| 259 | static DEVICE_START(aes_pcb_none) | |
| 260 | { | |
| 261 | /* device is aes_cartslot:cartridge:pcb */ | |
| 262 | // printf("DEVICE_START(aes_pcb_none), tag of device=%s\n", device->tag()); | |
| 263 | set_pointers(device, get_index_from_tagname(device->owner())-1); | |
| 264 | } | |
| 265 | ||
| 266 | /***************************************************************************** | |
| 267 | Cartridge type: Standard | |
| 268 | Most cartridges are built in this type. This includes word-swapped program, | |
| 269 | z80 program, YM samples, delta-T samples, sprites, and sfix. | |
| 270 | ******************************************************************************/ | |
| 271 | ||
| 272 | static DEVICE_START(aes_pcb_std) | |
| 273 | { | |
| 274 | /* device is aes_cartslot:cartridge:pcb */ | |
| 275 | // printf("DEVICE_START(aes_pcb_std), tag of device=%s\n", device->tag()); | |
| 276 | set_pointers(device, get_index_from_tagname(device->owner())-1); | |
| 277 | } | |
| 278 | ||
| 279 | /* | |
| 280 | The standard cartridge assemble routine. We just call the common | |
| 281 | function here. | |
| 282 | */ | |
| 283 | static int assemble_std(running_machine &machine, device_t *image) | |
| 284 | { | |
| 285 | // aescartridge_t *cart; | |
| 286 | // printf("assemble_std, %s\n", image->tag); | |
| 287 | /*cart = */assemble_common(machine, image); | |
| 288 | ||
| 289 | return IMAGE_INIT_PASS; | |
| 290 | } | |
| 291 | ||
| 292 | /* | |
| 293 | Removes pointers and restores the state before plugging in the | |
| 294 | cartridge. | |
| 295 | The pointer to the location after the last cartridge is adjusted. | |
| 296 | As it seems, we can use the same function for the disassembling of all | |
| 297 | cartridge types. | |
| 298 | */ | |
| 299 | static int disassemble_std(device_t *image) | |
| 300 | { | |
| 301 | // int slotnumber; | |
| 302 | // int i; | |
| 303 | // aescartridge_t *cart; | |
| 304 | // device_t *cartsys = image->owner(); | |
| 305 | // aes_multicart_t *cartslots = (aes_multicart_t *)cartsys->token; | |
| 306 | ||
| 307 | // slotnumber = get_index_from_tagname(image)-1; | |
| 308 | // printf("Disassemble cartridge %d\n", slotnumber); | |
| 309 | #if 0 | |
| 310 | /* Search the highest remaining cartridge. */ | |
| 311 | cartslots->next_free_slot = 0; | |
| 312 | for (i=AES_NUMBER_OF_CARTRIDGE_SLOTS-1; i >= 0; i--) | |
| 313 | { | |
| 314 | if (i != slotnumber) | |
| 315 | { | |
| 316 | if (0) //!slot_is_empty(cartsys, i)) (for future use?) | |
| 317 | { | |
| 318 | cartslots->next_free_slot = i+1; | |
| 319 | // printf("Setting new next_free_slot to %d\n", cartslots->next_free_slot); | |
| 320 | break; | |
| 321 | } | |
| 322 | } | |
| 323 | } | |
| 324 | #endif | |
| 325 | /* Do we have RAM? If so, swap the bytes (undo the BIG_ENDIANIZE) */ | |
| 326 | // cart = &cartslots->cartridge[slotnumber]; | |
| 327 | ||
| 328 | // clear_slot(cartsys, slotnumber); | |
| 329 | ||
| 330 | return IMAGE_INIT_PASS; | |
| 331 | } | |
| 332 | ||
| 333 | /***************************************************************************** | |
| 334 | Device metadata | |
| 335 | ******************************************************************************/ | |
| 336 | ||
| 337 | static DEVICE_GET_INFO(aes_cart_common) | |
| 338 | { | |
| 339 | switch(state) | |
| 340 | { | |
| 341 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 342 | case DEVINFO_INT_TOKEN_BYTES: | |
| 343 | info->i = sizeof(aes_pcb_t); | |
| 344 | break; | |
| 345 | case DEVINFO_INT_INLINE_CONFIG_BYTES: | |
| 346 | info->i = 0; | |
| 347 | break; | |
| 348 | ||
| 349 | /* --- the following bits of info are returned as pointers to functions --- */ | |
| 350 | case DEVINFO_FCT_START: | |
| 351 | info->start = DEVICE_START_NAME(aes_pcb_std); | |
| 352 | break; | |
| 353 | case DEVINFO_FCT_STOP: | |
| 354 | /* Nothing */ | |
| 355 | break; | |
| 356 | case DEVINFO_FCT_RESET: | |
| 357 | /* Nothing */ | |
| 358 | break; | |
| 359 | ||
| 360 | case AESCART_FCT_ASSM: | |
| 361 | info->f = (genf *) assemble_std; | |
| 362 | break; | |
| 363 | ||
| 364 | case AESCART_FCT_DISASSM: | |
| 365 | info->f = (genf *) disassemble_std; | |
| 366 | break; | |
| 367 | ||
| 368 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 369 | case DEVINFO_STR_NAME: | |
| 370 | strcpy(info->s, "AES standard cartridge pcb"); | |
| 371 | break; | |
| 372 | case DEVINFO_STR_FAMILY: | |
| 373 | strcpy(info->s, "AES cartridge pcb"); | |
| 374 | break; | |
| 375 | case DEVINFO_STR_VERSION: | |
| 376 | strcpy(info->s, "1.0"); | |
| 377 | break; | |
| 378 | case DEVINFO_STR_SOURCE_FILE: | |
| 379 | strcpy(info->s, __FILE__); | |
| 380 | break; | |
| 381 | case DEVINFO_STR_CREDITS: | |
| 382 | /* Nothing */ | |
| 383 | break; | |
| 384 | } | |
| 385 | } | |
| 386 | ||
| 387 | DEVICE_GET_INFO(aes_cartridge_pcb_none) | |
| 388 | { | |
| 389 | switch(state) | |
| 390 | { | |
| 391 | case DEVINFO_FCT_START: | |
| 392 | info->start = DEVICE_START_NAME(aes_pcb_none); | |
| 393 | break; | |
| 394 | ||
| 395 | case DEVINFO_STR_NAME: | |
| 396 | strcpy(info->s, "AES empty cartridge"); | |
| 397 | break; | |
| 398 | ||
| 399 | default: | |
| 400 | DEVICE_GET_INFO_CALL(aes_cart_common); | |
| 401 | break; | |
| 402 | } | |
| 403 | } | |
| 404 | ||
| 405 | DEVICE_GET_INFO(aes_cartridge_pcb_std) | |
| 406 | { | |
| 407 | DEVICE_GET_INFO_CALL(aes_cart_common); | |
| 408 | } | |
| 409 | ||
| 410 | /***************************************************************************** | |
| 411 | The cartridge handling of the multi-cartridge system. | |
| 412 | Every cartridge contains a PCB device. The memory handlers delegate the calls | |
| 413 | to the respective handlers of the cartridges. | |
| 414 | ******************************************************************************/ | |
| 415 | /* | |
| 416 | Initialize a cartridge. Each cartridge contains a PCB device. | |
| 417 | */ | |
| 418 | static DEVICE_START( aes_cartridge ) | |
| 419 | { | |
| 420 | cartslot_t *cart = get_safe_cartslot_token(device); | |
| 421 | ||
| 422 | /* find the PCB device */ | |
| 423 | cart->pcb_device = device->subdevice(TAG_PCB); | |
| 424 | } | |
| 425 | ||
| 426 | // handle protected carts | |
| 427 | static void install_protection(device_image_interface& image) | |
| 428 | { | |
| 429 | neogeo_state *state = image.device().machine().driver_data<neogeo_state>(); | |
| 430 | const char *crypt_feature = image.get_feature( "crypt" ); | |
| 431 | ||
| 432 | if(crypt_feature == NULL) | |
| 433 | return; | |
| 434 | ||
| 435 | if(strcmp(crypt_feature,"fatfury2_prot") == 0) | |
| 436 | { | |
| 437 | fatfury2_install_protection(image.device().machine()); | |
| 438 | logerror("Installed Fatal Fury 2 protection\n"); | |
| 439 | } | |
| 440 | if(strcmp(crypt_feature,"kof99_crypt") == 0) | |
| 441 | { | |
| 442 | kof99_decrypt_68k(image.device().machine()); | |
| 443 | state->m_fixed_layer_bank_type = 1; | |
| 444 | kof99_neogeo_gfx_decrypt(image.device().machine(), 0x00); | |
| 445 | kof99_install_protection(image.device().machine()); | |
| 446 | logerror("Decrypted KOF99 code and graphics.\n"); | |
| 447 | } | |
| 448 | if(strcmp(crypt_feature,"mslug3_crypt") == 0) | |
| 449 | { | |
| 450 | state->m_fixed_layer_bank_type = 1; | |
| 451 | kof99_neogeo_gfx_decrypt(image.device().machine(), 0xad); | |
| 452 | logerror("Decrypted Metal Slug 3 graphics\n"); | |
| 453 | } | |
| 454 | if(strcmp(crypt_feature,"matrim_crypt") == 0) | |
| 455 | { | |
| 456 | matrim_decrypt_68k(image.device().machine()); | |
| 457 | neo_pcm2_swap(image.device().machine(), 1); | |
| 458 | state->m_fixed_layer_bank_type = 2; | |
| 459 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 460 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x6a); | |
| 461 | logerror("Decrypted Matrimelee code, sound and graphics\n"); | |
| 462 | } | |
| 463 | if(strcmp(crypt_feature,"svc_crypt") == 0) | |
| 464 | { | |
| 465 | svc_px_decrypt(image.device().machine()); | |
| 466 | neo_pcm2_swap(image.device().machine(), 3); | |
| 467 | state->m_fixed_layer_bank_type = 2; | |
| 468 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 469 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x57); | |
| 470 | install_pvc_protection(image.device().machine()); | |
| 471 | logerror("Decrypted SvC code, sound and graphics.\n"); | |
| 472 | } | |
| 473 | if(strcmp(crypt_feature,"samsho5_crypt") == 0) | |
| 474 | { | |
| 475 | samsho5_decrypt_68k(image.device().machine()); | |
| 476 | neo_pcm2_swap(image.device().machine(), 4); | |
| 477 | state->m_fixed_layer_bank_type = 1; | |
| 478 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 479 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x0f); | |
| 480 | logerror("Decrypted Samurai Shodown V code, sound and graphics.\n"); | |
| 481 | } | |
| 482 | if(strcmp(crypt_feature,"kof2000_crypt") == 0) | |
| 483 | { | |
| 484 | kof2000_decrypt_68k(image.device().machine()); | |
| 485 | state->m_fixed_layer_bank_type = 2; | |
| 486 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 487 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x00); | |
| 488 | kof2000_install_protection(image.device().machine()); | |
| 489 | logerror("Decrypted KOF2000 code, sound and graphics.\n"); | |
| 490 | } | |
| 491 | if(strcmp(crypt_feature,"kof2001_crypt") == 0) | |
| 492 | { | |
| 493 | state->m_fixed_layer_bank_type = 1; | |
| 494 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x1e); | |
| 495 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 496 | logerror("Decrypted KOF2001 code and graphics.\n"); | |
| 497 | } | |
| 498 | if(strcmp(crypt_feature,"kof2002_crypt") == 0) | |
| 499 | { | |
| 500 | kof2002_decrypt_68k(image.device().machine()); | |
| 501 | neo_pcm2_swap(image.device().machine(), 0); | |
| 502 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 503 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0xec); | |
| 504 | logerror("Decrypted KOF2002 code, sound and graphics.\n"); | |
| 505 | } | |
| 506 | if(strcmp(crypt_feature,"mslug4_crypt") == 0) | |
| 507 | { | |
| 508 | state->m_fixed_layer_bank_type = 1; /* USA violent content screen is wrong -- not a bug, confirmed on real hardware! */ | |
| 509 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 510 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x31); | |
| 511 | neo_pcm2_snk_1999(image.device().machine(), 8); | |
| 512 | logerror("Decrypted Metal Slug 4 code, sound and graphics.\n"); | |
| 513 | } | |
| 514 | if(strcmp(crypt_feature,"mslug5_crypt") == 0) | |
| 515 | { | |
| 516 | mslug5_decrypt_68k(image.device().machine()); | |
| 517 | neo_pcm2_swap(image.device().machine(), 2); | |
| 518 | state->m_fixed_layer_bank_type = 1; | |
| 519 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 520 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x19); | |
| 521 | install_pvc_protection(image.device().machine()); | |
| 522 | logerror("Decrypted Metal Slug 5 code and graphics, and installed protection routines.\n"); | |
| 523 | } | |
| 524 | if(strcmp(crypt_feature,"kof2003_crypt") == 0) | |
| 525 | { | |
| 526 | kof2003h_decrypt_68k(image.device().machine()); | |
| 527 | neo_pcm2_swap(image.device().machine(), 5); | |
| 528 | state->m_fixed_layer_bank_type = 2; | |
| 529 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 530 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x9d); | |
| 531 | install_pvc_protection(image.device().machine()); | |
| 532 | logerror("Decrypted KOF2003 code and graphicss, and installed protection routines.\n"); | |
| 533 | } | |
| 534 | if(strcmp(crypt_feature,"samsho5s_crypt") == 0) | |
| 535 | { | |
| 536 | samsh5sp_decrypt_68k(image.device().machine()); | |
| 537 | neo_pcm2_swap(image.device().machine(), 6); | |
| 538 | state->m_fixed_layer_bank_type = 1; | |
| 539 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 540 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x0d); | |
| 541 | } | |
| 542 | } | |
| 543 | ||
| 544 | /* | |
| 545 | Load the cartridge image files. Apart from reading, we set pointers | |
| 546 | to the image files so that during runtime we do not need search | |
| 547 | operations. | |
| 548 | */ | |
| 549 | static DEVICE_IMAGE_LOAD( aes_cartridge ) | |
| 550 | { | |
| 551 | device_t *pcbdev = cartslot_get_pcb(image); | |
| 552 | aes_pcb_t *pcb; | |
| 553 | cartslot_t *cart; | |
| 554 | multicart_open_error me; | |
| 555 | UINT32 size; | |
| 556 | device_t* ym = image.device().machine().device("ymsnd"); | |
| 557 | ||
| 558 | // first check software list | |
| 559 | if(image.software_entry() != NULL) | |
| 560 | { | |
| 561 | // create memory regions | |
| 562 | size = image.get_software_region_length("maincpu"); | |
| 563 | image.device().machine().region_free("maincpu"); | |
| 564 | image.device().machine().region_alloc("maincpu",size,1, ENDIANNESS_LITTLE); | |
| 565 | memcpy(image.device().machine().region("maincpu")->base(),image.get_software_region("maincpu"),size); | |
| 566 | size = image.get_software_region_length("fixed"); | |
| 567 | image.device().machine().region_free("fixed"); | |
| 568 | image.device().machine().region_alloc("fixed",size,1, ENDIANNESS_LITTLE); | |
| 569 | memcpy(image.device().machine().region("fixed")->base(),image.get_software_region("fixed"),size); | |
| 570 | size = image.get_software_region_length("audiocpu"); | |
| 571 | image.device().machine().region_free("audiocpu"); | |
| 572 | image.device().machine().region_alloc("audiocpu",size,1, ENDIANNESS_LITTLE); | |
| 573 | memcpy(image.device().machine().region("audiocpu")->base(),image.get_software_region("audiocpu"),size); | |
| 574 | size = image.get_software_region_length("ymsnd"); | |
| 575 | image.device().machine().region_free("ymsnd"); | |
| 576 | image.device().machine().region_alloc("ymsnd",size,1, ENDIANNESS_LITTLE); | |
| 577 | memcpy(image.device().machine().region("ymsnd")->base(),image.get_software_region("ymsnd"),size); | |
| 578 | if(image.get_software_region("ymsnd.deltat") != NULL) | |
| 579 | { | |
| 580 | size = image.get_software_region_length("ymsnd.deltat"); | |
| 581 | image.device().machine().region_free("ymsnd.deltat"); | |
| 582 | image.device().machine().region_alloc("ymsnd.deltat",size,1, ENDIANNESS_LITTLE); | |
| 583 | memcpy(image.device().machine().region("ymsnd.deltat")->base(),image.get_software_region("ymsnd.deltat"),size); | |
| 584 | } | |
| 585 | else | |
| 586 | image.device().machine().region_free("ymsnd.deltat"); // removing the region will fix sound glitches in non-Delta-T games | |
| 587 | ym->reset(); | |
| 588 | size = image.get_software_region_length("sprites"); | |
| 589 | image.device().machine().region_free("sprites"); | |
| 590 | image.device().machine().region_alloc("sprites",size,1, ENDIANNESS_LITTLE); | |
| 591 | memcpy(image.device().machine().region("sprites")->base(),image.get_software_region("sprites"),size); | |
| 592 | if(image.get_software_region("audiocrypt") != NULL) // encrypted Z80 code | |
| 593 | { | |
| 594 | size = image.get_software_region_length("audiocrypt"); | |
| 595 | image.device().machine().region_alloc("audiocrypt",size,1, ENDIANNESS_LITTLE); | |
| 596 | memcpy(image.device().machine().region("audiocrypt")->base(),image.get_software_region("audiocrypt"),size); | |
| 597 | } | |
| 598 | ||
| 599 | // setup cartridge ROM area | |
| 600 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x000080,0x0fffff,"cart_rom"); | |
| 601 | memory_set_bankptr(image.device().machine(),"cart_rom",&image.device().machine().region("maincpu")->base()[0x80]); | |
| 602 | ||
| 603 | // handle possible protection | |
| 604 | install_protection(image); | |
| 605 | ||
| 606 | return IMAGE_INIT_PASS; | |
| 607 | } | |
| 608 | ||
| 609 | if (pcbdev == NULL) | |
| 610 | fatalerror("Error loading multicart: no pcb found."); | |
| 611 | ||
| 612 | /* If we are here, we have a multicart. */ | |
| 613 | pcb = get_safe_pcb_token(pcbdev); | |
| 614 | cart = get_safe_cartslot_token(&image.device()); | |
| 615 | ||
| 616 | /* try opening this as a multicart */ | |
| 617 | /* This line requires that cartslot_t be included in cartslot.h, | |
| 618 | otherwise one cannot make use of multicart handling within such a | |
| 619 | custom LOAD function. */ | |
| 620 | me = multicart_open(image.device().machine().options(), image.filename(), image.device().machine().system().name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc); | |
| 621 | ||
| 622 | /* Now that we have loaded the image files, let the PCB put them all | |
| 623 | together. This means we put the images in a structure which allows | |
| 624 | for a quick access by the memory handlers. Every PCB defines an | |
| 625 | own assembly method. */ | |
| 626 | if (me != MCERR_NONE) | |
| 627 | fatalerror("Error loading multicart: %s", multicart_error_text(me)); | |
| 628 | ||
| 629 | return pcb->assemble(pcbdev->machine(), image); | |
| 630 | } | |
| 631 | ||
| 632 | /* | |
| 633 | This is called when the cartridge is unplugged (or the emulator is | |
| 634 | stopped). | |
| 635 | */ | |
| 636 | static DEVICE_IMAGE_UNLOAD( aes_cartridge ) | |
| 637 | { | |
| 638 | device_t *pcbdev; | |
| 639 | ||
| 640 | if (downcast<legacy_device_base *>(&image.device())->token() == NULL) | |
| 641 | { | |
| 642 | /* This means something went wrong during the pcb | |
| 643 | identification (e.g. one of the cartridge files was not | |
| 644 | found). We do not need to (and cannot) unload | |
| 645 | the cartridge. */ | |
| 646 | return; | |
| 647 | } | |
| 648 | pcbdev = cartslot_get_pcb(image); | |
| 649 | ||
| 650 | if (pcbdev != NULL) | |
| 651 | { | |
| 652 | aes_pcb_t *pcb = get_safe_pcb_token(pcbdev); | |
| 653 | cartslot_t *cart = get_safe_cartslot_token(&image.device()); | |
| 654 | ||
| 655 | // printf("unload\n"); | |
| 656 | if (cart->mc != NULL) | |
| 657 | { | |
| 658 | /* Remove pointers and de-big-endianize RAM contents. */ | |
| 659 | pcb->disassemble(pcbdev->machine(), image); | |
| 660 | ||
| 661 | /* Close the multicart; all RAM resources will be | |
| 662 | written to disk */ | |
| 663 | multicart_close(pcbdev->machine().options(), cart->mc); | |
| 664 | cart->mc = NULL; | |
| 665 | } | |
| 666 | // else | |
| 667 | // fatalerror("Lost pointer to multicart in cartridge. Report bug."); | |
| 668 | } | |
| 669 | } | |
| 670 | ||
| 671 | /***************************************************************************** | |
| 672 | The overall multi-cartridge slot system. It contains instances of | |
| 673 | cartridges which contain PCB devices. The memory handlers delegate the calls | |
| 674 | to the respective handlers of the cartridges. | |
| 675 | ||
| 676 | Note that the term "multi-cartridge system" and "multicart" are not the same: | |
| 677 | A "multicart" may contain multiple resources, organized on a PCB. The multi- | |
| 678 | cart system may thus host multiple multicarts. | |
| 679 | ||
| 680 | Actually, the name of the device should be changed (however, the device name | |
| 681 | length is limited) | |
| 682 | ******************************************************************************/ | |
| 683 | /* | |
| 684 | Instantiation of a multicart system for the Neo Geo AES. | |
| 685 | */ | |
| 686 | static DEVICE_START(aes_multicart) | |
| 687 | { | |
| 688 | int i; | |
| 689 | // printf("DEVICE_START(aes_multicart)\n"); | |
| 690 | aes_multicart_t *cartslots = get_safe_token(device); | |
| 691 | ||
| 692 | /* Save this in the shortcut; we don't want to look for it each time | |
| 693 | that we have a memory access. And currently we do not plan for | |
| 694 | multiple multicart instances. */ | |
| 695 | cartslots->active_slot = 0; | |
| 696 | cartslots->next_free_slot = 0; | |
| 697 | ||
| 698 | for (i=0; i < AES_NUMBER_OF_CARTRIDGE_SLOTS; i++) | |
| 699 | { | |
| 700 | cartslots->cartridge[i].pcb = NULL; | |
| 701 | } | |
| 702 | ||
| 703 | cartslots->multi_slots = 0; | |
| 704 | ||
| 705 | /* The cartslot system is initialized now. The cartridges themselves | |
| 706 | need to check whether their parts are available. */ | |
| 707 | } | |
| 708 | ||
| 709 | static DEVICE_STOP(aes_multicart) | |
| 710 | { | |
| 711 | // printf("DEVICE_STOP(aes_multicart)\n"); | |
| 712 | } | |
| 713 | ||
| 714 | static MACHINE_CONFIG_FRAGMENT(aes_multicart) | |
| 715 | MCFG_CARTSLOT_ADD("cartridge1") | |
| 716 | MCFG_CARTSLOT_EXTENSION_LIST("rpk,bin") | |
| 717 | MCFG_CARTSLOT_PCBTYPE(0, "none", AES_CARTRIDGE_PCB_NONE) | |
| 718 | MCFG_CARTSLOT_PCBTYPE(1, "standard", AES_CARTRIDGE_PCB_STD) | |
| 719 | ||
| 720 | MCFG_CARTSLOT_START(aes_cartridge) | |
| 721 | MCFG_CARTSLOT_LOAD(aes_cartridge) | |
| 722 | MCFG_CARTSLOT_UNLOAD(aes_cartridge) | |
| 723 | MCFG_CARTSLOT_INTERFACE("aes_cart") | |
| 724 | MCFG_CARTSLOT_MANDATORY | |
| 725 | MACHINE_CONFIG_END | |
| 726 | ||
| 727 | ||
| 728 | DEVICE_GET_INFO(aes_multicart) | |
| 729 | { | |
| 730 | switch (state) | |
| 731 | { | |
| 732 | /* --- the following bits of info are returned as pointers to data --- */ | |
| 733 | case DEVINFO_PTR_MACHINE_CONFIG: | |
| 734 | info->machine_config = MACHINE_CONFIG_NAME(aes_multicart); break; | |
| 735 | ||
| 736 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 737 | case DEVINFO_STR_NAME: | |
| 738 | strcpy(info->s, "AES Cartridge handler"); | |
| 739 | break; | |
| 740 | ||
| 741 | case DEVINFO_INT_TOKEN_BYTES: /* private storage, automatically allocated */ | |
| 742 | info->i = sizeof(aes_multicart_t); | |
| 743 | break; | |
| 744 | ||
| 745 | case DEVINFO_STR_FAMILY: | |
| 746 | strcpy(info->s, "Cartridge slot"); | |
| 747 | break; | |
| 748 | case DEVINFO_STR_VERSION: | |
| 749 | strcpy(info->s, "1.0"); | |
| 750 | break; | |
| 751 | case DEVINFO_STR_SOURCE_FILE: | |
| 752 | strcpy(info->s, __FILE__); | |
| 753 | break; | |
| 754 | /* --- the following bits of info are returned as pointers to functions --- */ | |
| 755 | case DEVINFO_FCT_START: | |
| 756 | info->start = DEVICE_START_NAME(aes_multicart); | |
| 757 | break; | |
| 758 | case DEVINFO_FCT_STOP: | |
| 759 | info->stop = DEVICE_STOP_NAME(aes_multicart); | |
| 760 | break; | |
| 761 | case DEVINFO_FCT_RESET: | |
| 762 | /* Nothing */ | |
| 763 | break; | |
| 764 | } | |
| 765 | } | |
| 766 | ||
| 767 | DEFINE_LEGACY_CART_SLOT_DEVICE(AES_MULTICART, aes_multicart); | |
| 768 | DEFINE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_NONE, aes_cartridge_pcb_none); | |
| 769 | DEFINE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_STD, aes_cartridge_pcb_std); |
| r11531 | r11532 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | aescart.h | |
| 4 | ||
| 5 | AES cartridge management | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #ifndef __AESCART_H__ | |
| 10 | #define __AESCART_H__ | |
| 11 | ||
| 12 | #include "image.h" | |
| 13 | #include "imagedev/cartslot.h" | |
| 14 | ||
| 15 | DECLARE_LEGACY_CART_SLOT_DEVICE(AES_MULTICART, aes_multicart); | |
| 16 | DECLARE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_NONE, aes_cartridge_pcb_none); | |
| 17 | DECLARE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_STD, aes_cartridge_pcb_std); | |
| 18 | ||
| 19 | /* There's only 1 slot in an AES */ | |
| 20 | #define AES_NUMBER_OF_CARTRIDGE_SLOTS 1 | |
| 21 | ||
| 22 | /* Generic AES cartridge structure. */ | |
| 23 | struct _aescartridge_t | |
| 24 | { | |
| 25 | /* PCB device associated to this cartridge. If NULL, the slot is empty. */ | |
| 26 | device_t *pcb; | |
| 27 | }; | |
| 28 | typedef struct _aescartridge_t aescartridge_t; | |
| 29 | ||
| 30 | #define MCFG_AES_CARTRIDGE_ADD(_tag) \ | |
| 31 | MCFG_DEVICE_ADD(_tag, AES_MULTICART, 0) | |
| 32 | ||
| 33 | #endif /* __AESCART_H__ */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Amiga CD-ROM controller emulation | |
| 4 | ||
| 5 | Notes: | |
| 6 | Many thanks to Toni Wilen for all the help and information about the | |
| 7 | DMAC controller. | |
| 8 | ||
| 9 | ***************************************************************************/ | |
| 10 | ||
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | #include "includes/amiga.h" | |
| 14 | #include "amigacd.h" | |
| 15 | #include "machine/6525tpi.h" | |
| 16 | #include "machine/6526cia.h" | |
| 17 | #include "machine/wd33c93.h" | |
| 18 | #include "imagedev/chd_cd.h" | |
| 19 | #include "machine/matsucd.h" | |
| 20 | ||
| 21 | ||
| 22 | #define VERBOSE_DMAC 0 | |
| 23 | ||
| 24 | #define LOG(x) do { if (VERBOSE_DMAC) logerror x; } while (0) | |
| 25 | ||
| 26 | /* constants */ | |
| 27 | #define CD_SECTOR_TIME (1000/((300*1024)/2048)) /* 2X CDROM sector time in msec (300KBps) */ | |
| 28 | ||
| 29 | /*************************************************************************** | |
| 30 | ||
| 31 | DMAC | |
| 32 | ||
| 33 | ***************************************************************************/ | |
| 34 | ||
| 35 | /* | |
| 36 | * value to go into DAWR | |
| 37 | */ | |
| 38 | #define DAWR_ATZSC 3 /* according to A3000T service-manual */ | |
| 39 | ||
| 40 | /* | |
| 41 | * bits defined for CNTR | |
| 42 | */ | |
| 43 | #define CNTR_TCEN (1<<7) /* Terminal Count Enable */ | |
| 44 | #define CNTR_PREST (1<<6) /* Perp Reset (not implemented :-((( ) */ | |
| 45 | #define CNTR_PDMD (1<<5) /* Perp Device Mode Select (1=SCSI,0=XT/AT) */ | |
| 46 | #define CNTR_INTEN (1<<4) /* Interrupt Enable */ | |
| 47 | #define CNTR_DDIR (1<<3) /* Device Direction. 1==rd host, wr to perp */ | |
| 48 | ||
| 49 | /* | |
| 50 | * bits defined for ISTR | |
| 51 | */ | |
| 52 | #define ISTR_INTX (1<<8) /* XT/AT Interrupt pending */ | |
| 53 | #define ISTR_INT_F (1<<7) /* Interrupt Follow */ | |
| 54 | #define ISTR_INTS (1<<6) /* SCSI Peripheral Interrupt */ | |
| 55 | #define ISTR_E_INT (1<<5) /* End-Of-Process Interrupt */ | |
| 56 | #define ISTR_INT_P (1<<4) /* Interrupt Pending */ | |
| 57 | #define ISTR_UE_INT (1<<3) /* Under-Run FIFO Error Interrupt */ | |
| 58 | #define ISTR_OE_INT (1<<2) /* Over-Run FIFO Error Interrupt */ | |
| 59 | #define ISTR_FF_FLG (1<<1) /* FIFO-Full Flag */ | |
| 60 | #define ISTR_FE_FLG (1<<0) /* FIFO-Empty Flag */ | |
| 61 | ||
| 62 | typedef struct | |
| 63 | { | |
| 64 | UINT16 istr; /* Interrupt Status Register (R) */ | |
| 65 | UINT16 cntr; /* Control Register (RW) */ | |
| 66 | UINT32 wtc; /* Word Transfer Count Register (RW) */ | |
| 67 | UINT32 acr; /* Address Count Register (RW) */ | |
| 68 | UINT16 dawr; /* DACK Width Register (W) */ | |
| 69 | emu_timer *dma_timer; | |
| 70 | } _dmac_data; | |
| 71 | ||
| 72 | static _dmac_data dmac_data; | |
| 73 | ||
| 74 | static void check_interrupts( running_machine &machine ) | |
| 75 | { | |
| 76 | /* if interrupts are disabled, bail */ | |
| 77 | if ( (dmac_data.cntr & CNTR_INTEN) == 0 ) | |
| 78 | return; | |
| 79 | ||
| 80 | /* if no interrupts are pending, bail */ | |
| 81 | if ( (dmac_data.istr & ISTR_INT_P) == 0 ) | |
| 82 | return; | |
| 83 | ||
| 84 | /* otherwise, generate the IRQ */ | |
| 85 | amiga_custom_w(machine.device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff); | |
| 86 | } | |
| 87 | ||
| 88 | static TIMER_CALLBACK(dmac_dma_proc) | |
| 89 | { | |
| 90 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 91 | while( dmac_data.wtc > 0 ) | |
| 92 | { | |
| 93 | UINT16 dat16; | |
| 94 | UINT8 dat8; | |
| 95 | ||
| 96 | if ( matsucd_get_next_byte( &dat8 ) < 0 ) | |
| 97 | break; | |
| 98 | ||
| 99 | dat16 = dat8; | |
| 100 | ||
| 101 | if ( matsucd_get_next_byte( &dat8 ) < 0 ) | |
| 102 | break; | |
| 103 | ||
| 104 | dat16 <<= 8; | |
| 105 | dat16 |= dat8; | |
| 106 | ||
| 107 | (*state->m_chip_ram_w)(state, dmac_data.acr, dat16); | |
| 108 | ||
| 109 | dmac_data.acr += 2; | |
| 110 | dmac_data.wtc--; | |
| 111 | } | |
| 112 | ||
| 113 | if ( dmac_data.wtc > 0 ) | |
| 114 | { | |
| 115 | matsucd_read_next_block(); | |
| 116 | dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME )); | |
| 117 | } | |
| 118 | else | |
| 119 | { | |
| 120 | dmac_data.istr |= ISTR_INT_P | ISTR_E_INT; | |
| 121 | check_interrupts( machine ); | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | static READ16_HANDLER( amiga_dmac_r ) | |
| 126 | { | |
| 127 | offset &= 0xff; | |
| 128 | ||
| 129 | switch( offset ) | |
| 130 | { | |
| 131 | case 0x20: | |
| 132 | { | |
| 133 | UINT8 v = dmac_data.istr; | |
| 134 | LOG(( "DMAC: PC=%08x - ISTR Read(%04x)\n", cpu_get_pc(&space->device()), dmac_data.istr )); | |
| 135 | ||
| 136 | dmac_data.istr &= ~0x0f; | |
| 137 | return v; | |
| 138 | } | |
| 139 | break; | |
| 140 | ||
| 141 | case 0x21: | |
| 142 | { | |
| 143 | LOG(( "DMAC: PC=%08x - CNTR Read(%04x)\n", cpu_get_pc(&space->device()), dmac_data.cntr )); | |
| 144 | return dmac_data.cntr; | |
| 145 | } | |
| 146 | break; | |
| 147 | ||
| 148 | case 0x40: /* wtc hi */ | |
| 149 | { | |
| 150 | LOG(( "DMAC: PC=%08x - WTC HI Read\n", cpu_get_pc(&space->device()) )); | |
| 151 | return (dmac_data.wtc >> 16); | |
| 152 | } | |
| 153 | break; | |
| 154 | ||
| 155 | case 0x41: /* wtc lo */ | |
| 156 | { | |
| 157 | LOG(( "DMAC: PC=%08x - WTC LO Read\n", cpu_get_pc(&space->device()) )); | |
| 158 | return dmac_data.wtc; | |
| 159 | } | |
| 160 | break; | |
| 161 | ||
| 162 | case 0x42: /* acr hi */ | |
| 163 | { | |
| 164 | LOG(( "DMAC: PC=%08x - ACR HI Read\n", cpu_get_pc(&space->device()) )); | |
| 165 | return (dmac_data.acr >> 16); | |
| 166 | } | |
| 167 | break; | |
| 168 | ||
| 169 | case 0x43: /* acr lo */ | |
| 170 | { | |
| 171 | LOG(( "DMAC: PC=%08x - ACR LO Read\n", cpu_get_pc(&space->device()) )); | |
| 172 | return dmac_data.acr; | |
| 173 | } | |
| 174 | break; | |
| 175 | ||
| 176 | case 0x48: /* wd33c93 SCSI expansion */ | |
| 177 | case 0x49: | |
| 178 | { | |
| 179 | LOG(( "DMAC: PC=%08x - WD33C93 Read(%d)\n", cpu_get_pc(&space->device()), offset & 1 )); | |
| 180 | return 0x00; /* Not available without SCSI expansion */ | |
| 181 | } | |
| 182 | break; | |
| 183 | ||
| 184 | case 0x50: | |
| 185 | { | |
| 186 | LOG(( "DMAC: PC=%08x - CDROM RESP Read\n", cpu_get_pc(&space->device()) )); | |
| 187 | return matsucd_response_r(space->machine()); | |
| 188 | } | |
| 189 | break; | |
| 190 | ||
| 191 | case 0x51: /* XT IO */ | |
| 192 | case 0x52: | |
| 193 | case 0x53: | |
| 194 | { | |
| 195 | LOG(( "DMAC: PC=%08x - XT IO Read(%d)\n", cpu_get_pc(&space->device()), (offset & 3)-1 )); | |
| 196 | return 0xff; | |
| 197 | } | |
| 198 | break; | |
| 199 | ||
| 200 | case 0x58: /* TPI6525 */ | |
| 201 | case 0x59: | |
| 202 | case 0x5A: | |
| 203 | case 0x5B: | |
| 204 | case 0x5C: | |
| 205 | case 0x5D: | |
| 206 | case 0x5E: | |
| 207 | case 0x5F: | |
| 208 | case 0x60: | |
| 209 | case 0x61: | |
| 210 | case 0x62: | |
| 211 | case 0x63: | |
| 212 | case 0x64: | |
| 213 | case 0x65: | |
| 214 | case 0x66: | |
| 215 | case 0x67: | |
| 216 | { | |
| 217 | device_t *tpi = space->machine().device("tpi6525"); | |
| 218 | LOG(( "DMAC: PC=%08x - TPI6525 Read(%d)\n", cpu_get_pc(&space->device()), (offset - 0x58) )); | |
| 219 | return tpi6525_r(tpi, offset - 0x58); | |
| 220 | } | |
| 221 | break; | |
| 222 | ||
| 223 | case 0x70: /* DMA start strobe */ | |
| 224 | { | |
| 225 | LOG(( "DMAC: PC=%08x - DMA Start Strobe\n", cpu_get_pc(&space->device()) )); | |
| 226 | dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME )); | |
| 227 | } | |
| 228 | break; | |
| 229 | ||
| 230 | case 0x71: /* DMA stop strobe */ | |
| 231 | { | |
| 232 | LOG(( "DMAC: PC=%08x - DMA Stop Strobe\n", cpu_get_pc(&space->device()) )); | |
| 233 | dmac_data.dma_timer->reset( ); | |
| 234 | } | |
| 235 | break; | |
| 236 | ||
| 237 | case 0x72: /* Clear IRQ strobe */ | |
| 238 | { | |
| 239 | LOG(( "DMAC: PC=%08x - IRQ Clear Strobe\n", cpu_get_pc(&space->device()) )); | |
| 240 | dmac_data.istr &= ~ISTR_INT_P; | |
| 241 | } | |
| 242 | break; | |
| 243 | ||
| 244 | case 0x74: /* Flush strobe */ | |
| 245 | { | |
| 246 | LOG(( "DMAC: PC=%08x - Flush Strobe\n", cpu_get_pc(&space->device()) )); | |
| 247 | dmac_data.istr |= ISTR_FE_FLG; | |
| 248 | } | |
| 249 | break; | |
| 250 | ||
| 251 | default: | |
| 252 | logerror( "DMAC-READ: PC=%08x, offset = %02x\n", cpu_get_pc(&space->device()), offset ); | |
| 253 | break; | |
| 254 | } | |
| 255 | ||
| 256 | return 0; | |
| 257 | } | |
| 258 | ||
| 259 | static WRITE16_HANDLER( amiga_dmac_w ) | |
| 260 | { | |
| 261 | offset &= 0xff; | |
| 262 | ||
| 263 | switch( offset ) | |
| 264 | { | |
| 265 | case 0x21: /* control write */ | |
| 266 | { | |
| 267 | LOG(( "DMAC: PC=%08x - CNTR Write(%04x)\n", cpu_get_pc(&space->device()), data )); | |
| 268 | dmac_data.cntr = data; | |
| 269 | check_interrupts(space->machine()); | |
| 270 | } | |
| 271 | break; | |
| 272 | ||
| 273 | case 0x40: /* wtc hi */ | |
| 274 | { | |
| 275 | LOG(( "DMAC: PC=%08x - WTC HI Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 276 | dmac_data.wtc &= 0x0000ffff; | |
| 277 | dmac_data.wtc |= ((UINT32)data) << 16; | |
| 278 | } | |
| 279 | break; | |
| 280 | ||
| 281 | case 0x41: /* wtc lo */ | |
| 282 | { | |
| 283 | LOG(( "DMAC: PC=%08x - WTC LO Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 284 | dmac_data.wtc &= 0xffff0000; | |
| 285 | dmac_data.wtc |= data; | |
| 286 | } | |
| 287 | break; | |
| 288 | ||
| 289 | case 0x42: /* acr hi */ | |
| 290 | { | |
| 291 | LOG(( "DMAC: PC=%08x - ACR HI Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 292 | dmac_data.acr &= 0x0000ffff; | |
| 293 | dmac_data.acr |= ((UINT32)data) << 16; | |
| 294 | } | |
| 295 | break; | |
| 296 | ||
| 297 | case 0x43: /* acr lo */ | |
| 298 | { | |
| 299 | LOG(( "DMAC: PC=%08x - ACR LO Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 300 | dmac_data.acr &= 0xffff0000; | |
| 301 | dmac_data.acr |= data; | |
| 302 | } | |
| 303 | break; | |
| 304 | ||
| 305 | case 0x47: /* dawr */ | |
| 306 | { | |
| 307 | LOG(( "DMAC: PC=%08x - DAWR Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 308 | dmac_data.dawr = data; | |
| 309 | } | |
| 310 | break; | |
| 311 | ||
| 312 | case 0x48: /* wd33c93 SCSI expansion */ | |
| 313 | case 0x49: | |
| 314 | { | |
| 315 | LOG(( "DMAC: PC=%08x - WD33C93 Write(%d) - data = %04x\n", cpu_get_pc(&space->device()), offset & 1, data )); | |
| 316 | /* Not available without SCSI expansion */ | |
| 317 | } | |
| 318 | break; | |
| 319 | ||
| 320 | case 0x50: | |
| 321 | { | |
| 322 | LOG(( "DMAC: PC=%08x - CDROM CMD Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 323 | matsucd_command_w(space->machine(), data ); | |
| 324 | } | |
| 325 | break; | |
| 326 | ||
| 327 | case 0x58: /* TPI6525 */ | |
| 328 | case 0x59: | |
| 329 | case 0x5A: | |
| 330 | case 0x5B: | |
| 331 | case 0x5C: | |
| 332 | case 0x5D: | |
| 333 | case 0x5E: | |
| 334 | case 0x5F: | |
| 335 | case 0x60: | |
| 336 | case 0x61: | |
| 337 | case 0x62: | |
| 338 | case 0x63: | |
| 339 | case 0x64: | |
| 340 | case 0x65: | |
| 341 | case 0x66: | |
| 342 | case 0x67: | |
| 343 | { | |
| 344 | device_t *tpi = space->machine().device("tpi6525"); | |
| 345 | LOG(( "DMAC: PC=%08x - TPI6525 Write(%d) - data = %04x\n", cpu_get_pc(&space->device()), (offset - 0x58), data )); | |
| 346 | tpi6525_w(tpi, offset - 0x58, data); | |
| 347 | } | |
| 348 | break; | |
| 349 | ||
| 350 | case 0x70: /* DMA start strobe */ | |
| 351 | { | |
| 352 | LOG(( "DMAC: PC=%08x - DMA Start Strobe\n", cpu_get_pc(&space->device()) )); | |
| 353 | dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME )); | |
| 354 | } | |
| 355 | break; | |
| 356 | ||
| 357 | case 0x71: /* DMA stop strobe */ | |
| 358 | { | |
| 359 | LOG(( "DMAC: PC=%08x - DMA Stop Strobe\n", cpu_get_pc(&space->device()) )); | |
| 360 | dmac_data.dma_timer->reset( ); | |
| 361 | } | |
| 362 | break; | |
| 363 | ||
| 364 | case 0x72: /* Clear IRQ strobe */ | |
| 365 | { | |
| 366 | LOG(( "DMAC: PC=%08x - IRQ Clear Strobe\n", cpu_get_pc(&space->device()) )); | |
| 367 | dmac_data.istr &= ~ISTR_INT_P; | |
| 368 | } | |
| 369 | break; | |
| 370 | ||
| 371 | case 0x74: /* Flush Strobe */ | |
| 372 | { | |
| 373 | LOG(( "DMAC: PC=%08x - Flush Strobe\n", cpu_get_pc(&space->device()) )); | |
| 374 | dmac_data.istr |= ISTR_FE_FLG; | |
| 375 | } | |
| 376 | break; | |
| 377 | ||
| 378 | default: | |
| 379 | logerror( "DMAC-WRITE: PC=%08x, offset = %02x, data = %04x\n", cpu_get_pc(&space->device()), offset, data ); | |
| 380 | break; | |
| 381 | } | |
| 382 | } | |
| 383 | ||
| 384 | /*************************************************************************** | |
| 385 | ||
| 386 | Autoconfig | |
| 387 | ||
| 388 | ***************************************************************************/ | |
| 389 | ||
| 390 | static void dmac_install(running_machine &machine, offs_t base) | |
| 391 | { | |
| 392 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 393 | space->install_legacy_read_handler(base, base + 0xFFFF, FUNC(amiga_dmac_r)); | |
| 394 | space->install_legacy_write_handler(base, base + 0xFFFF, FUNC(amiga_dmac_w)); | |
| 395 | } | |
| 396 | ||
| 397 | static void dmac_uninstall(running_machine &machine, offs_t base) | |
| 398 | { | |
| 399 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 400 | space->unmap_readwrite(base, base + 0xFFFF); | |
| 401 | } | |
| 402 | ||
| 403 | static const amiga_autoconfig_device dmac_device = | |
| 404 | { | |
| 405 | 0, /* link into free memory list */ | |
| 406 | 0, /* ROM vector offset valid */ | |
| 407 | 0, /* multiple devices on card */ | |
| 408 | 1, /* number of 64k pages */ | |
| 409 | 3, /* product number (DMAC) */ | |
| 410 | 0, /* prefer 8MB address space */ | |
| 411 | 0, /* can be shut up */ | |
| 412 | 0x0202, /* manufacturers number (Commodore) */ | |
| 413 | 0, /* serial number */ | |
| 414 | 0, /* ROM vector offset */ | |
| 415 | NULL, /* interrupt control read */ | |
| 416 | NULL, /* interrupt control write */ | |
| 417 | dmac_install, /* memory installation */ | |
| 418 | dmac_uninstall /* memory uninstallation */ | |
| 419 | }; | |
| 420 | ||
| 421 | /*************************************************************************** | |
| 422 | ||
| 423 | TPI6525 | |
| 424 | ||
| 425 | ***************************************************************************/ | |
| 426 | ||
| 427 | READ8_DEVICE_HANDLER( amigacd_tpi6525_portc_r ) | |
| 428 | { | |
| 429 | int ret = 0; | |
| 430 | ||
| 431 | if ( (tpi6525_get_ddr_c(device) & 0x04) == 0 ) /* if pin 2 is set to input */ | |
| 432 | { | |
| 433 | ret |= matsucd_stch_r() ? 0x00 : 0x04; /* read status change signal */ | |
| 434 | } | |
| 435 | ||
| 436 | if ( (tpi6525_get_ddr_c(device) & 0x08) == 0 ) /* if pin 3 is set to input */ | |
| 437 | ret |= matsucd_sten_r() ? 0x08 : 0x00; /* read enable signal */ | |
| 438 | ||
| 439 | return ret; | |
| 440 | } | |
| 441 | ||
| 442 | WRITE8_DEVICE_HANDLER( amigacd_tpi6525_portb_w ) | |
| 443 | { | |
| 444 | if ( tpi6525_get_ddr_b(device) & 0x01 ) /* if pin 0 is set to output */ | |
| 445 | matsucd_cmd_w( data & 1 ); /* write to the /CMD signal */ | |
| 446 | ||
| 447 | if ( tpi6525_get_ddr_b(device) & 0x02 ) /* if pin 1 is set to output */ | |
| 448 | matsucd_enable_w( data & 2 ); /* write to the /ENABLE signal */ | |
| 449 | } | |
| 450 | ||
| 451 | static emu_timer *tp6525_delayed_timer; | |
| 452 | ||
| 453 | static TIMER_CALLBACK(tp6525_delayed_irq) | |
| 454 | { | |
| 455 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 456 | (void)param; | |
| 457 | ||
| 458 | if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 ) | |
| 459 | { | |
| 460 | amiga_custom_w(machine.device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff); | |
| 461 | } | |
| 462 | else | |
| 463 | { | |
| 464 | tp6525_delayed_timer->adjust(attotime::from_msec(1)); | |
| 465 | } | |
| 466 | } | |
| 467 | ||
| 468 | static void amigacd_tpi6525_irq_trampoline(device_t *device, int level) | |
| 469 | { | |
| 470 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 471 | LOG(( "TPI6525 Interrupt: level = %d\n", level )); | |
| 472 | ||
| 473 | if ( level ) | |
| 474 | { | |
| 475 | if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 ) | |
| 476 | { | |
| 477 | amiga_custom_w(device->machine().device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff); | |
| 478 | } | |
| 479 | else | |
| 480 | { | |
| 481 | /* we *have to* deliver the irq, so if we can't, delay it and try again later */ | |
| 482 | tp6525_delayed_timer->adjust(attotime::from_msec(1)); | |
| 483 | } | |
| 484 | } | |
| 485 | } | |
| 486 | ||
| 487 | WRITE_LINE_DEVICE_HANDLER( amigacd_tpi6525_irq ) | |
| 488 | { | |
| 489 | amigacd_tpi6525_irq_trampoline(device, state); | |
| 490 | } | |
| 491 | ||
| 492 | static void cdrom_status_enabled( running_machine &machine, int level ) | |
| 493 | { | |
| 494 | device_t *tpi = machine.device("tpi6525"); | |
| 495 | ||
| 496 | /* PC3 on the 6525 */ | |
| 497 | tpi6525_i3_w(tpi, level); | |
| 498 | } | |
| 499 | ||
| 500 | static void cdrom_status_change( running_machine &machine, int level ) | |
| 501 | { | |
| 502 | device_t *tpi = machine.device("tpi6525"); | |
| 503 | ||
| 504 | /* invert */ | |
| 505 | level = level ? 0 : 1; | |
| 506 | ||
| 507 | /* PC2 on the 6525 */ | |
| 508 | tpi6525_i2_w(tpi, level); | |
| 509 | } | |
| 510 | ||
| 511 | static void cdrom_subcode_ready( running_machine &machine, int level ) | |
| 512 | { | |
| 513 | device_t *tpi = machine.device("tpi6525"); | |
| 514 | ||
| 515 | /* PC1 on the 6525 */ | |
| 516 | tpi6525_i1_w(tpi, level); | |
| 517 | } | |
| 518 | ||
| 519 | MACHINE_START( amigacd ) | |
| 520 | { | |
| 521 | /* initialize the dmac */ | |
| 522 | memset( &dmac_data, 0, sizeof( dmac_data ) ); | |
| 523 | ||
| 524 | dmac_data.dma_timer = machine.scheduler().timer_alloc(FUNC(dmac_dma_proc)); | |
| 525 | tp6525_delayed_timer = machine.scheduler().timer_alloc(FUNC(tp6525_delayed_irq)); | |
| 526 | ||
| 527 | /* set up DMAC with autoconfig */ | |
| 528 | amiga_add_autoconfig( machine, &dmac_device ); | |
| 529 | ||
| 530 | matsucd_init( machine.device("cdrom"), "cdda" ); | |
| 531 | } | |
| 532 | ||
| 533 | MACHINE_RESET( amigacd ) | |
| 534 | { | |
| 535 | /* initialize the cdrom */ | |
| 536 | matsucd_set_status_enabled_callback( cdrom_status_enabled ); | |
| 537 | matsucd_set_status_changed_callback( cdrom_status_change ); | |
| 538 | matsucd_set_subcode_ready_callback( cdrom_subcode_ready ); | |
| 539 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | #include "emu.h" | |
| 2 | #include "crsshair.h" | |
| 3 | #include "hash.h" | |
| 4 | #include "cpu/m6502/m6502.h" | |
| 5 | #include "video/ppu2c0x.h" | |
| 6 | #include "includes/nes.h" | |
| 7 | #include "machine/nes_mmc.h" | |
| 8 | #include "imagedev/cartslot.h" | |
| 9 | #include "imagedev/flopdrv.h" | |
| 10 | #include "hashfile.h" | |
| 11 | ||
| 12 | /*************************************************************************** | |
| 13 | CONSTANTS | |
| 14 | ***************************************************************************/ | |
| 15 | ||
| 16 | /* Set to dump info about the inputs to the errorlog */ | |
| 17 | #define LOG_JOY 0 | |
| 18 | ||
| 19 | /* Set to generate prg & chr files when the cart is loaded */ | |
| 20 | #define SPLIT_PRG 0 | |
| 21 | #define SPLIT_CHR 0 | |
| 22 | ||
| 23 | /*************************************************************************** | |
| 24 | FUNCTION PROTOTYPES | |
| 25 | ***************************************************************************/ | |
| 26 | ||
| 27 | static void init_nes_core(running_machine &machine); | |
| 28 | static void nes_machine_stop(running_machine &machine); | |
| 29 | static READ8_HANDLER(nes_fds_r); | |
| 30 | static WRITE8_HANDLER(nes_fds_w); | |
| 31 | static void fds_irq(device_t *device, int scanline, int vblank, int blanked); | |
| 32 | ||
| 33 | /*************************************************************************** | |
| 34 | FUNCTIONS | |
| 35 | ***************************************************************************/ | |
| 36 | ||
| 37 | static void init_nes_core( running_machine &machine ) | |
| 38 | { | |
| 39 | nes_state *state = machine.driver_data<nes_state>(); | |
| 40 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 41 | static const char *const bank_names[] = { "bank1", "bank2", "bank3", "bank4" }; | |
| 42 | int prg_banks = (state->m_prg_chunks == 1) ? (2 * 2) : (state->m_prg_chunks * 2); | |
| 43 | int i; | |
| 44 | ||
| 45 | /* We set these here in case they weren't set in the cart loader */ | |
| 46 | state->m_rom = machine.region("maincpu")->base(); | |
| 47 | state->m_vrom = machine.region("gfx1")->base(); | |
| 48 | state->m_vram = machine.region("gfx2")->base(); | |
| 49 | state->m_ciram = machine.region("gfx3")->base(); | |
| 50 | ||
| 51 | /* Brutal hack put in as a consequence of the new memory system; we really need to fix the NES code */ | |
| 52 | space->install_readwrite_bank(0x0000, 0x07ff, 0, 0x1800, "bank10"); | |
| 53 | ||
| 54 | machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0, 0x1fff, FUNC(nes_chr_r), FUNC(nes_chr_w)); | |
| 55 | machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x2000, 0x3eff, FUNC(nes_nt_r), FUNC(nes_nt_w)); | |
| 56 | ||
| 57 | memory_set_bankptr(machine, "bank10", state->m_rom); | |
| 58 | ||
| 59 | /* If there is Disk Expansion and no cart has been loaded, setup memory accordingly */ | |
| 60 | if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD) | |
| 61 | { | |
| 62 | /* If we are loading a disk we have already filled state->m_fds_data and we don't want to overwrite it, | |
| 63 | if we are loading a cart image identified as mapper 20 (probably wrong mapper...) we need to alloc | |
| 64 | memory for use in nes_fds_r/nes_fds_w. Same goes for allocation of fds_ram (used for bank2) */ | |
| 65 | if (state->m_fds_data == NULL) | |
| 66 | { | |
| 67 | UINT32 size = machine.region("maincpu")->bytes() - 0x10000; | |
| 68 | state->m_fds_data = auto_alloc_array_clear(machine, UINT8, size); | |
| 69 | memcpy(state->m_fds_data, state->m_rom, size); // copy in fds_data the cart PRG | |
| 70 | } | |
| 71 | if (state->m_fds_ram == NULL) | |
| 72 | state->m_fds_ram = auto_alloc_array(machine, UINT8, 0x8000); | |
| 73 | ||
| 74 | space->install_legacy_read_handler(0x4030, 0x403f, FUNC(nes_fds_r)); | |
| 75 | space->install_read_bank(0x6000, 0xdfff, "bank2"); | |
| 76 | space->install_read_bank(0xe000, 0xffff, "bank1"); | |
| 77 | ||
| 78 | space->install_legacy_write_handler(0x4020, 0x402f, FUNC(nes_fds_w)); | |
| 79 | space->install_write_bank(0x6000, 0xdfff, "bank2"); | |
| 80 | ||
| 81 | memory_set_bankptr(machine, "bank1", &state->m_rom[0xe000]); | |
| 82 | memory_set_bankptr(machine, "bank2", state->m_fds_ram); | |
| 83 | return; | |
| 84 | } | |
| 85 | ||
| 86 | /* Set up the mapper callbacks */ | |
| 87 | pcb_handlers_setup(machine); | |
| 88 | ||
| 89 | /* Set up the memory handlers for the mapper */ | |
| 90 | space->install_read_bank(0x8000, 0x9fff, "bank1"); | |
| 91 | space->install_read_bank(0xa000, 0xbfff, "bank2"); | |
| 92 | space->install_read_bank(0xc000, 0xdfff, "bank3"); | |
| 93 | space->install_read_bank(0xe000, 0xffff, "bank4"); | |
| 94 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 95 | ||
| 96 | /* configure banks 1-4 */ | |
| 97 | for (i = 0; i < 4; i++) | |
| 98 | { | |
| 99 | memory_configure_bank(machine, bank_names[i], 0, prg_banks, machine.region("maincpu")->base() + 0x10000, 0x2000); | |
| 100 | // some mappers (e.g. MMC5) can map PRG RAM in 0x8000-0xffff as well | |
| 101 | if (state->m_prg_ram) | |
| 102 | memory_configure_bank(machine, bank_names[i], prg_banks, state->m_wram_size / 0x2000, state->m_wram, 0x2000); | |
| 103 | // however, at start we point to PRG ROM | |
| 104 | memory_set_bank(machine, bank_names[i], i); | |
| 105 | state->m_prg_bank[i] = i; | |
| 106 | } | |
| 107 | ||
| 108 | /* bank 5 configuration is more delicate, since it can have PRG RAM, PRG ROM or SRAM mapped to it */ | |
| 109 | /* we first map PRG ROM banks, then the battery bank (if a battery is present), and finally PRG RAM (state->m_wram) */ | |
| 110 | memory_configure_bank(machine, "bank5", 0, prg_banks, machine.region("maincpu")->base() + 0x10000, 0x2000); | |
| 111 | state->m_battery_bank5_start = prg_banks; | |
| 112 | state->m_prgram_bank5_start = prg_banks; | |
| 113 | state->m_empty_bank5_start = prg_banks; | |
| 114 | ||
| 115 | /* add battery ram, but only if there's no trainer since they share overlapping memory. */ | |
| 116 | if (state->m_battery && !state->m_trainer) | |
| 117 | { | |
| 118 | UINT32 bank_size = (state->m_battery_size > 0x2000) ? 0x2000 : state->m_battery_size; | |
| 119 | int bank_num = (state->m_battery_size > 0x2000) ? state->m_battery_size / 0x2000 : 1; | |
| 120 | memory_configure_bank(machine, "bank5", prg_banks, bank_num, state->m_battery_ram, bank_size); | |
| 121 | state->m_prgram_bank5_start += bank_num; | |
| 122 | state->m_empty_bank5_start += bank_num; | |
| 123 | } | |
| 124 | /* add prg ram. */ | |
| 125 | if (state->m_prg_ram) | |
| 126 | { | |
| 127 | memory_configure_bank(machine, "bank5", state->m_prgram_bank5_start, state->m_wram_size / 0x2000, state->m_wram, 0x2000); | |
| 128 | state->m_empty_bank5_start += state->m_wram_size / 0x2000; | |
| 129 | } | |
| 130 | ||
| 131 | memory_configure_bank(machine, "bank5", state->m_empty_bank5_start, 1, state->m_rom + 0x6000, 0x2000); | |
| 132 | ||
| 133 | /* if we have any additional PRG RAM, point bank5 to its first bank */ | |
| 134 | if (state->m_battery || state->m_prg_ram) | |
| 135 | state->m_prg_bank[4] = state->m_battery_bank5_start; | |
| 136 | else | |
| 137 | state->m_prg_bank[4] = state->m_empty_bank5_start; // or shall we point to "maincpu" region at 0x6000? point is that we should never access this region if no sram or wram is present! | |
| 138 | ||
| 139 | memory_set_bank(machine, "bank5", state->m_prg_bank[4]); | |
| 140 | ||
| 141 | if (state->m_four_screen_vram) | |
| 142 | { | |
| 143 | state->m_extended_ntram = auto_alloc_array(machine, UINT8, 0x2000); | |
| 144 | state->save_pointer(NAME(state->m_extended_ntram), 0x2000); | |
| 145 | } | |
| 146 | ||
| 147 | // there are still some quirk about writes to bank5... I hope to fix them soon. (mappers 34,45,52,246 have both mid_w and WRAM-->check) | |
| 148 | if (state->m_mmc_write_mid) | |
| 149 | space->install_legacy_write_handler(0x6000, 0x7fff, state->m_mmc_write_mid,state->m_mmc_write_mid_name); | |
| 150 | if (state->m_mmc_write) | |
| 151 | space->install_legacy_write_handler(0x8000, 0xffff, state->m_mmc_write, state->m_mmc_write_name); | |
| 152 | ||
| 153 | // In fact, we also allow single pcbs to overwrite the bank read handlers defined above, | |
| 154 | // because some pcbs (mainly pirate ones) require protection values to be read instead of | |
| 155 | // the expected ROM banks: these handlers, though, must take care of the ROM access as well | |
| 156 | if (state->m_mmc_read_mid) | |
| 157 | space->install_legacy_read_handler(0x6000, 0x7fff, state->m_mmc_read_mid,state->m_mmc_read_mid_name); | |
| 158 | if (state->m_mmc_read) | |
| 159 | space->install_legacy_read_handler(0x8000, 0xffff, state->m_mmc_read,state->m_mmc_read_name); | |
| 160 | ||
| 161 | // install additional handlers | |
| 162 | if (state->m_pcb_id == BTL_SMB2B || state->m_mapper == 50) | |
| 163 | { | |
| 164 | space->install_legacy_write_handler(0x4020, 0x403f, FUNC(smb2jb_extra_w)); | |
| 165 | space->install_legacy_write_handler(0x40a0, 0x40bf, FUNC(smb2jb_extra_w)); | |
| 166 | } | |
| 167 | ||
| 168 | if (state->m_pcb_id == KAISER_KS7017) | |
| 169 | { | |
| 170 | space->install_legacy_read_handler(0x4030, 0x4030, FUNC(ks7017_extra_r)); | |
| 171 | space->install_legacy_write_handler(0x4020, 0x40ff, FUNC(ks7017_extra_w)); | |
| 172 | } | |
| 173 | ||
| 174 | if (state->m_pcb_id == UNL_603_5052) | |
| 175 | { | |
| 176 | space->install_legacy_read_handler(0x4020, 0x40ff, FUNC(unl_6035052_extra_r)); | |
| 177 | space->install_legacy_write_handler(0x4020, 0x40ff, FUNC(unl_6035052_extra_w)); | |
| 178 | } | |
| 179 | ||
| 180 | if (state->m_pcb_id == WAIXING_SH2) | |
| 181 | machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0, 0x1fff, FUNC(waixing_sh2_chr_r)); | |
| 182 | } | |
| 183 | ||
| 184 | // to be probably removed (it does nothing since a long time) | |
| 185 | int nes_ppu_vidaccess( device_t *device, int address, int data ) | |
| 186 | { | |
| 187 | return data; | |
| 188 | } | |
| 189 | ||
| 190 | MACHINE_RESET( nes ) | |
| 191 | { | |
| 192 | nes_state *state = machine.driver_data<nes_state>(); | |
| 193 | ||
| 194 | /* Reset the mapper variables. Will also mark the char-gen ram as dirty */ | |
| 195 | if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD) | |
| 196 | ppu2c0x_set_hblank_callback(state->m_ppu, fds_irq); | |
| 197 | else | |
| 198 | nes_pcb_reset(machine); | |
| 199 | ||
| 200 | /* Reset the serial input ports */ | |
| 201 | state->m_in_0.shift = 0; | |
| 202 | state->m_in_1.shift = 0; | |
| 203 | ||
| 204 | machine.device("maincpu")->reset(); | |
| 205 | } | |
| 206 | ||
| 207 | static TIMER_CALLBACK( nes_irq_callback ) | |
| 208 | { | |
| 209 | nes_state *state = machine.driver_data<nes_state>(); | |
| 210 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 211 | state->m_irq_timer->adjust(attotime::never); | |
| 212 | } | |
| 213 | ||
| 214 | static void nes_banks_restore(nes_state *state) | |
| 215 | { | |
| 216 | memory_set_bank(state->machine(), "bank1", state->m_prg_bank[0]); | |
| 217 | memory_set_bank(state->machine(), "bank2", state->m_prg_bank[1]); | |
| 218 | memory_set_bank(state->machine(), "bank3", state->m_prg_bank[2]); | |
| 219 | memory_set_bank(state->machine(), "bank4", state->m_prg_bank[3]); | |
| 220 | memory_set_bank(state->machine(), "bank5", state->m_prg_bank[4]); | |
| 221 | } | |
| 222 | ||
| 223 | static void nes_state_register( running_machine &machine ) | |
| 224 | { | |
| 225 | nes_state *state = machine.driver_data<nes_state>(); | |
| 226 | ||
| 227 | state->save_item(NAME(state->m_prg_bank)); | |
| 228 | ||
| 229 | state->save_item(NAME(state->m_MMC5_floodtile)); | |
| 230 | state->save_item(NAME(state->m_MMC5_floodattr)); | |
| 231 | state->save_item(NAME(state->m_mmc5_vram_control)); | |
| 232 | ||
| 233 | state->save_item(NAME(state->m_nes_vram_sprite)); | |
| 234 | state->save_item(NAME(state->m_last_frame_flip)); | |
| 235 | ||
| 236 | // shared mapper variables | |
| 237 | state->save_item(NAME(state->m_IRQ_enable)); | |
| 238 | state->save_item(NAME(state->m_IRQ_enable_latch)); | |
| 239 | state->save_item(NAME(state->m_IRQ_count)); | |
| 240 | state->save_item(NAME(state->m_IRQ_count_latch)); | |
| 241 | state->save_item(NAME(state->m_IRQ_toggle)); | |
| 242 | state->save_item(NAME(state->m_IRQ_reset)); | |
| 243 | state->save_item(NAME(state->m_IRQ_status)); | |
| 244 | state->save_item(NAME(state->m_IRQ_mode)); | |
| 245 | state->save_item(NAME(state->m_mult1)); | |
| 246 | state->save_item(NAME(state->m_mult2)); | |
| 247 | state->save_item(NAME(state->m_mmc_chr_source)); | |
| 248 | state->save_item(NAME(state->m_mmc_cmd1)); | |
| 249 | state->save_item(NAME(state->m_mmc_cmd2)); | |
| 250 | state->save_item(NAME(state->m_mmc_count)); | |
| 251 | state->save_item(NAME(state->m_mmc_prg_base)); | |
| 252 | state->save_item(NAME(state->m_mmc_prg_mask)); | |
| 253 | state->save_item(NAME(state->m_mmc_chr_base)); | |
| 254 | state->save_item(NAME(state->m_mmc_chr_mask)); | |
| 255 | state->save_item(NAME(state->m_mmc_prg_bank)); | |
| 256 | state->save_item(NAME(state->m_mmc_vrom_bank)); | |
| 257 | state->save_item(NAME(state->m_mmc_extra_bank)); | |
| 258 | ||
| 259 | state->save_item(NAME(state->m_fds_motor_on)); | |
| 260 | state->save_item(NAME(state->m_fds_door_closed)); | |
| 261 | state->save_item(NAME(state->m_fds_current_side)); | |
| 262 | state->save_item(NAME(state->m_fds_head_position)); | |
| 263 | state->save_item(NAME(state->m_fds_status0)); | |
| 264 | state->save_item(NAME(state->m_fds_read_mode)); | |
| 265 | state->save_item(NAME(state->m_fds_write_reg)); | |
| 266 | state->save_item(NAME(state->m_fds_last_side)); | |
| 267 | state->save_item(NAME(state->m_fds_count)); | |
| 268 | ||
| 269 | state->save_pointer(NAME(state->m_wram), state->m_wram_size); | |
| 270 | if (state->m_battery) | |
| 271 | state->save_pointer(NAME(state->m_battery_ram), state->m_battery_size); | |
| 272 | ||
| 273 | machine.save().register_postload(save_prepost_delegate(FUNC(nes_banks_restore), state)); | |
| 274 | } | |
| 275 | ||
| 276 | MACHINE_START( nes ) | |
| 277 | { | |
| 278 | nes_state *state = machine.driver_data<nes_state>(); | |
| 279 | ||
| 280 | init_nes_core(machine); | |
| 281 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(nes_machine_stop),&machine)); | |
| 282 | ||
| 283 | state->m_maincpu = machine.device("maincpu"); | |
| 284 | state->m_ppu = machine.device("ppu"); | |
| 285 | state->m_sound = machine.device("nessound"); | |
| 286 | state->m_cart = machine.device("cart"); | |
| 287 | ||
| 288 | state->m_irq_timer = machine.scheduler().timer_alloc(FUNC(nes_irq_callback)); | |
| 289 | nes_state_register(machine); | |
| 290 | } | |
| 291 | ||
| 292 | static void nes_machine_stop( running_machine &machine ) | |
| 293 | { | |
| 294 | nes_state *state = machine.driver_data<nes_state>(); | |
| 295 | device_image_interface *image = dynamic_cast<device_image_interface *>(state->m_cart); | |
| 296 | /* Write out the battery file if necessary */ | |
| 297 | if (state->m_battery) | |
| 298 | image->battery_save(state->m_battery_ram, state->m_battery_size); | |
| 299 | ||
| 300 | if (state->m_mapper_bram_size) | |
| 301 | image->battery_save(state->m_mapper_bram, state->m_mapper_bram_size); | |
| 302 | } | |
| 303 | ||
| 304 | ||
| 305 | ||
| 306 | READ8_HANDLER( nes_IN0_r ) | |
| 307 | { | |
| 308 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 309 | int cfg = input_port_read(space->machine(), "CTRLSEL"); | |
| 310 | int ret; | |
| 311 | ||
| 312 | if ((cfg & 0x000f) >= 0x07) // for now we treat the FC keyboard separately from other inputs! | |
| 313 | { | |
| 314 | // here we should have the tape input | |
| 315 | ret = 0; | |
| 316 | } | |
| 317 | else | |
| 318 | { | |
| 319 | /* Some games expect bit 6 to be set because the last entry on the data bus shows up */ | |
| 320 | /* in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there. */ | |
| 321 | ret = 0x40; | |
| 322 | ||
| 323 | ret |= ((state->m_in_0.i0 >> state->m_in_0.shift) & 0x01); | |
| 324 | ||
| 325 | /* zapper */ | |
| 326 | if ((cfg & 0x000f) == 0x0002) | |
| 327 | { | |
| 328 | int x = state->m_in_0.i1; /* read Zapper x-position */ | |
| 329 | int y = state->m_in_0.i2; /* read Zapper y-position */ | |
| 330 | UINT32 pix, color_base; | |
| 331 | ||
| 332 | /* get the pixel at the gun position */ | |
| 333 | pix = ppu2c0x_get_pixel(state->m_ppu, x, y); | |
| 334 | ||
| 335 | /* get the color base from the ppu */ | |
| 336 | color_base = ppu2c0x_get_colorbase(state->m_ppu); | |
| 337 | ||
| 338 | /* look at the screen and see if the cursor is over a bright pixel */ | |
| 339 | if ((pix == color_base + 0x20) || (pix == color_base + 0x30) || | |
| 340 | (pix == color_base + 0x33) || (pix == color_base + 0x34)) | |
| 341 | { | |
| 342 | ret &= ~0x08; /* sprite hit */ | |
| 343 | } | |
| 344 | else | |
| 345 | ret |= 0x08; /* no sprite hit */ | |
| 346 | ||
| 347 | /* If button 1 is pressed, indicate the light gun trigger is pressed */ | |
| 348 | ret |= ((state->m_in_0.i0 & 0x01) << 4); | |
| 349 | } | |
| 350 | ||
| 351 | if (LOG_JOY) | |
| 352 | logerror("joy 0 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, cpu_get_pc(&space->device()), state->m_in_0.shift, state->m_in_0.i0); | |
| 353 | ||
| 354 | state->m_in_0.shift++; | |
| 355 | } | |
| 356 | ||
| 357 | return ret; | |
| 358 | } | |
| 359 | ||
| 360 | // row of the keyboard matrix are read 4-bits at time, and gets returned as bit1->bit4 | |
| 361 | static UINT8 nes_read_fc_keyboard_line( running_machine &machine, UINT8 scan, UINT8 mode ) | |
| 362 | { | |
| 363 | static const char *const fc_keyport_names[] = { "FCKEY0", "FCKEY1", "FCKEY2", "FCKEY3", "FCKEY4", "FCKEY5", "FCKEY6", "FCKEY7", "FCKEY8" }; | |
| 364 | return ((input_port_read(machine, fc_keyport_names[scan]) >> (mode * 4)) & 0x0f) << 1; | |
| 365 | } | |
| 366 | ||
| 367 | static UINT8 nes_read_subor_keyboard_line( running_machine &machine, UINT8 scan, UINT8 mode ) | |
| 368 | { | |
| 369 | static const char *const sub_keyport_names[] = { "SUBKEY0", "SUBKEY1", "SUBKEY2", "SUBKEY3", "SUBKEY4", | |
| 370 | "SUBKEY5", "SUBKEY6", "SUBKEY7", "SUBKEY8", "SUBKEY9", "SUBKEY10", "SUBKEY11", "SUBKEY12" }; | |
| 371 | return ((input_port_read(machine, sub_keyport_names[scan]) >> (mode * 4)) & 0x0f) << 1; | |
| 372 | } | |
| 373 | ||
| 374 | READ8_HANDLER( nes_IN1_r ) | |
| 375 | { | |
| 376 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 377 | int cfg = input_port_read(space->machine(), "CTRLSEL"); | |
| 378 | int ret; | |
| 379 | ||
| 380 | if ((cfg & 0x000f) == 0x07) // for now we treat the FC keyboard separately from other inputs! | |
| 381 | { | |
| 382 | if (state->m_fck_scan < 9) | |
| 383 | ret = ~nes_read_fc_keyboard_line(space->machine(), state->m_fck_scan, state->m_fck_mode) & 0x1e; | |
| 384 | else | |
| 385 | ret = 0x1e; | |
| 386 | } | |
| 387 | else if ((cfg & 0x000f) == 0x08) // for now we treat the Subor keyboard separately from other inputs! | |
| 388 | { | |
| 389 | if (state->m_fck_scan < 12) | |
| 390 | ret = ~nes_read_subor_keyboard_line(space->machine(), state->m_fck_scan, state->m_fck_mode) & 0x1e; | |
| 391 | else | |
| 392 | ret = 0x1e; | |
| 393 | } | |
| 394 | else | |
| 395 | { | |
| 396 | /* Some games expect bit 6 to be set because the last entry on the data bus shows up */ | |
| 397 | /* in the unused upper 3 bits, so typically a read from $4017 leaves 0x40 there. */ | |
| 398 | ret = 0x40; | |
| 399 | ||
| 400 | /* Handle data line 0's serial output */ | |
| 401 | ret |= ((state->m_in_1.i0 >> state->m_in_1.shift) & 0x01); | |
| 402 | ||
| 403 | /* zapper */ | |
| 404 | if ((cfg & 0x00f0) == 0x0030) | |
| 405 | { | |
| 406 | int x = state->m_in_1.i1; /* read Zapper x-position */ | |
| 407 | int y = state->m_in_1.i2; /* read Zapper y-position */ | |
| 408 | UINT32 pix, color_base; | |
| 409 | ||
| 410 | /* get the pixel at the gun position */ | |
| 411 | pix = ppu2c0x_get_pixel(state->m_ppu, x, y); | |
| 412 | ||
| 413 | /* get the color base from the ppu */ | |
| 414 | color_base = ppu2c0x_get_colorbase(state->m_ppu); | |
| 415 | ||
| 416 | /* look at the screen and see if the cursor is over a bright pixel */ | |
| 417 | if ((pix == color_base + 0x20) || (pix == color_base + 0x30) || | |
| 418 | (pix == color_base + 0x33) || (pix == color_base + 0x34)) | |
| 419 | { | |
| 420 | ret &= ~0x08; /* sprite hit */ | |
| 421 | } | |
| 422 | else | |
| 423 | ret |= 0x08; /* no sprite hit */ | |
| 424 | ||
| 425 | /* If button 1 is pressed, indicate the light gun trigger is pressed */ | |
| 426 | ret |= ((state->m_in_1.i0 & 0x01) << 4); | |
| 427 | } | |
| 428 | ||
| 429 | /* arkanoid dial */ | |
| 430 | else if ((cfg & 0x00f0) == 0x0040) | |
| 431 | { | |
| 432 | /* Handle data line 2's serial output */ | |
| 433 | ret |= ((state->m_in_1.i2 >> state->m_in_1.shift) & 0x01) << 3; | |
| 434 | ||
| 435 | /* Handle data line 3's serial output - bits are reversed */ | |
| 436 | /* NPW 27-Nov-2007 - there is no third subscript! commenting out */ | |
| 437 | /* ret |= ((state->m_in_1[3] >> state->m_in_1.shift) & 0x01) << 4; */ | |
| 438 | /* ret |= ((state->m_in_1[3] << state->m_in_1.shift) & 0x80) >> 3; */ | |
| 439 | } | |
| 440 | ||
| 441 | if (LOG_JOY) | |
| 442 | logerror("joy 1 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, cpu_get_pc(&space->device()), state->m_in_1.shift, state->m_in_1.i0); | |
| 443 | ||
| 444 | state->m_in_1.shift++; | |
| 445 | } | |
| 446 | ||
| 447 | return ret; | |
| 448 | } | |
| 449 | ||
| 450 | ||
| 451 | // FIXME: this is getting messier and messier (no pun intended). inputs reading should be simplified and port_categories cleaned up | |
| 452 | // to also emulate the fact that nothing should be in Port 2 if there is a Crazy Climber pad, etc. | |
| 453 | static void nes_read_input_device( running_machine &machine, int cfg, nes_input *vals, int pad_port, int supports_zapper ) | |
| 454 | { | |
| 455 | nes_state *state = machine.driver_data<nes_state>(); | |
| 456 | static const char *const padnames[] = { "PAD1", "PAD2", "PAD3", "PAD4", "CC_LEFT", "CC_RIGHT" }; | |
| 457 | ||
| 458 | vals->i0 = 0; | |
| 459 | vals->i1 = 0; | |
| 460 | vals->i2 = 0; | |
| 461 | ||
| 462 | switch (cfg & 0x0f) | |
| 463 | { | |
| 464 | case 0x01: /* gamepad */ | |
| 465 | if (pad_port >= 0) | |
| 466 | vals->i0 = input_port_read(machine, padnames[pad_port]); | |
| 467 | break; | |
| 468 | ||
| 469 | case 0x02: /* zapper 1 */ | |
| 470 | if (supports_zapper) | |
| 471 | { | |
| 472 | vals->i0 = input_port_read(machine, "ZAPPER1_T"); | |
| 473 | vals->i1 = input_port_read(machine, "ZAPPER1_X"); | |
| 474 | vals->i2 = input_port_read(machine, "ZAPPER1_Y"); | |
| 475 | } | |
| 476 | break; | |
| 477 | ||
| 478 | case 0x03: /* zapper 2 */ | |
| 479 | if (supports_zapper) | |
| 480 | { | |
| 481 | vals->i0 = input_port_read(machine, "ZAPPER2_T"); | |
| 482 | vals->i1 = input_port_read(machine, "ZAPPER2_X"); | |
| 483 | vals->i2 = input_port_read(machine, "ZAPPER2_Y"); | |
| 484 | } | |
| 485 | break; | |
| 486 | ||
| 487 | case 0x04: /* arkanoid paddle */ | |
| 488 | if (pad_port == 1) | |
| 489 | vals->i0 = (UINT8) ((UINT8) input_port_read(machine, "PADDLE") + (UINT8)0x52) ^ 0xff; | |
| 490 | break; | |
| 491 | ||
| 492 | case 0x05: /* crazy climber controller */ | |
| 493 | if (pad_port == 0) | |
| 494 | { | |
| 495 | state->m_in_0.i0 = input_port_read(machine, padnames[4]); | |
| 496 | state->m_in_1.i0 = input_port_read(machine, padnames[5]); | |
| 497 | } | |
| 498 | break; | |
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | ||
| 503 | static TIMER_CALLBACK( lightgun_tick ) | |
| 504 | { | |
| 505 | if ((input_port_read(machine, "CTRLSEL") & 0x000f) == 0x0002) | |
| 506 | { | |
| 507 | /* enable lightpen crosshair */ | |
| 508 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL); | |
| 509 | } | |
| 510 | else | |
| 511 | { | |
| 512 | /* disable lightpen crosshair */ | |
| 513 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE); | |
| 514 | } | |
| 515 | ||
| 516 | if ((input_port_read(machine, "CTRLSEL") & 0x00f0) == 0x0030) | |
| 517 | { | |
| 518 | /* enable lightpen crosshair */ | |
| 519 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL); | |
| 520 | } | |
| 521 | else | |
| 522 | { | |
| 523 | /* disable lightpen crosshair */ | |
| 524 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE); | |
| 525 | } | |
| 526 | } | |
| 527 | ||
| 528 | WRITE8_HANDLER( nes_IN0_w ) | |
| 529 | { | |
| 530 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 531 | int cfg = input_port_read(space->machine(), "CTRLSEL"); | |
| 532 | ||
| 533 | /* Check if lightgun has been chosen as input: if so, enable crosshair */ | |
| 534 | space->machine().scheduler().timer_set(attotime::zero, FUNC(lightgun_tick)); | |
| 535 | ||
| 536 | if ((cfg & 0x000f) >= 0x07) // for now we treat the FC keyboard separately from other inputs! | |
| 537 | { | |
| 538 | // here we should also have the tape output | |
| 539 | ||
| 540 | if (BIT(data, 2)) // keyboard active | |
| 541 | { | |
| 542 | int lines = ((cfg & 0x000f) == 0x04) ? 9 : 12; | |
| 543 | UINT8 out = BIT(data, 1); // scan | |
| 544 | ||
| 545 | if (state->m_fck_mode && !out && ++state->m_fck_scan > lines) | |
| 546 | state->m_fck_scan = 0; | |
| 547 | ||
| 548 | state->m_fck_mode = out; // access lower or upper 4 bits | |
| 549 | ||
| 550 | if (BIT(data, 0)) // reset | |
| 551 | state->m_fck_scan = 0; | |
| 552 | } | |
| 553 | } | |
| 554 | else | |
| 555 | { | |
| 556 | if (data & 0x01) | |
| 557 | return; | |
| 558 | ||
| 559 | if (LOG_JOY) | |
| 560 | logerror("joy 0 bits read: %d\n", state->m_in_0.shift); | |
| 561 | ||
| 562 | /* Toggling bit 0 high then low resets both controllers */ | |
| 563 | state->m_in_0.shift = 0; | |
| 564 | state->m_in_1.shift = 0; | |
| 565 | ||
| 566 | /* Read the input devices */ | |
| 567 | if ((cfg & 0x000f) != 0x06) | |
| 568 | { | |
| 569 | nes_read_input_device(space->machine(), cfg >> 0, &state->m_in_0, 0, TRUE); | |
| 570 | nes_read_input_device(space->machine(), cfg >> 4, &state->m_in_1, 1, TRUE); | |
| 571 | nes_read_input_device(space->machine(), cfg >> 8, &state->m_in_2, 2, FALSE); | |
| 572 | nes_read_input_device(space->machine(), cfg >> 12, &state->m_in_3, 3, FALSE); | |
| 573 | } | |
| 574 | else // crazy climber pad | |
| 575 | { | |
| 576 | nes_read_input_device(space->machine(), 0, &state->m_in_1, 1, TRUE); | |
| 577 | nes_read_input_device(space->machine(), 0, &state->m_in_2, 2, FALSE); | |
| 578 | nes_read_input_device(space->machine(), 0, &state->m_in_3, 3, FALSE); | |
| 579 | nes_read_input_device(space->machine(), cfg >> 0, &state->m_in_0, 0, TRUE); | |
| 580 | } | |
| 581 | ||
| 582 | if (cfg & 0x0f00) | |
| 583 | state->m_in_0.i0 |= (state->m_in_2.i0 << 8) | (0x08 << 16); | |
| 584 | ||
| 585 | if (cfg & 0xf000) | |
| 586 | state->m_in_1.i0 |= (state->m_in_3.i0 << 8) | (0x04 << 16); | |
| 587 | } | |
| 588 | } | |
| 589 | ||
| 590 | ||
| 591 | WRITE8_HANDLER( nes_IN1_w ) | |
| 592 | { | |
| 593 | } | |
| 594 | ||
| 595 | struct nes_cart_lines | |
| 596 | { | |
| 597 | const char *tag; | |
| 598 | int line; | |
| 599 | }; | |
| 600 | ||
| 601 | static const struct nes_cart_lines nes_cart_lines_table[] = | |
| 602 | { | |
| 603 | { "PRG A0", 0 }, | |
| 604 | { "PRG A1", 1 }, | |
| 605 | { "PRG A2", 2 }, | |
| 606 | { "PRG A3", 3 }, | |
| 607 | { "PRG A4", 4 }, | |
| 608 | { "PRG A5", 5 }, | |
| 609 | { "PRG A6", 6 }, | |
| 610 | { "PRG A7", 7 }, | |
| 611 | { "CHR A10", 10 }, | |
| 612 | { "CHR A11", 11 }, | |
| 613 | { "CHR A12", 12 }, | |
| 614 | { "CHR A13", 13 }, | |
| 615 | { "CHR A14", 14 }, | |
| 616 | { "CHR A15", 15 }, | |
| 617 | { "CHR A16", 16 }, | |
| 618 | { "CHR A17", 17 }, | |
| 619 | { "NC", 127 }, | |
| 620 | { 0 } | |
| 621 | }; | |
| 622 | ||
| 623 | static int nes_cart_get_line( const char *feature ) | |
| 624 | { | |
| 625 | const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0]; | |
| 626 | ||
| 627 | if (feature == NULL) | |
| 628 | return 128; | |
| 629 | ||
| 630 | while (nes_line->tag) | |
| 631 | { | |
| 632 | if (strcmp(nes_line->tag, feature) == 0) | |
| 633 | break; | |
| 634 | ||
| 635 | nes_line++; | |
| 636 | } | |
| 637 | ||
| 638 | return nes_line->line; | |
| 639 | } | |
| 640 | ||
| 641 | DEVICE_IMAGE_LOAD( nes_cart ) | |
| 642 | { | |
| 643 | nes_state *state = image.device().machine().driver_data<nes_state>(); | |
| 644 | state->m_pcb_id = NO_BOARD; // initialization | |
| 645 | ||
| 646 | if (image.software_entry() == NULL) | |
| 647 | { | |
| 648 | const char *mapinfo = NULL; | |
| 649 | int mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0, goodcrcinfo = 0; | |
| 650 | char magic[4], extend[5]; | |
| 651 | int local_options = 0; | |
| 652 | char m; | |
| 653 | ||
| 654 | /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ | |
| 655 | /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ | |
| 656 | memset(magic, '\0', sizeof(magic)); | |
| 657 | image.fread(magic, 4); | |
| 658 | ||
| 659 | if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ | |
| 660 | { | |
| 661 | UINT32 prg_size; | |
| 662 | state->m_ines20 = 0; | |
| 663 | state->m_battery_size = NES_BATTERY_SIZE; // with iNES we can only support 8K WRAM battery (iNES 2.0 might fix this) | |
| 664 | state->m_prg_ram = 1; // always map state->m_wram in bank5 (eventually, this should be enabled only for some mappers) | |
| 665 | ||
| 666 | // check if the image is recognized by nes.hsi | |
| 667 | mapinfo = hashfile_extrainfo(image); | |
| 668 | ||
| 669 | // image_extrainfo() resets the file position back to start. | |
| 670 | // Let's skip past the magic header once again. | |
| 671 | image.fseek(4, SEEK_SET); | |
| 672 | ||
| 673 | image.fread(&state->m_prg_chunks, 1); | |
| 674 | image.fread(&state->m_chr_chunks, 1); | |
| 675 | /* Read the first ROM option byte (offset 6) */ | |
| 676 | image.fread(&m, 1); | |
| 677 | ||
| 678 | /* Interpret the iNES header flags */ | |
| 679 | state->m_mapper = (m & 0xf0) >> 4; | |
| 680 | local_options = m & 0x0f; | |
| 681 | ||
| 682 | /* Read the second ROM option byte (offset 7) */ | |
| 683 | image.fread(&m, 1); | |
| 684 | ||
| 685 | switch (m & 0xc) | |
| 686 | { | |
| 687 | case 0x4: | |
| 688 | case 0xc: | |
| 689 | // probably the header got corrupted: don't trust upper bits for mapper | |
| 690 | break; | |
| 691 | ||
| 692 | case 0x8: // it's iNES 2.0 format | |
| 693 | state->m_ines20 = 1; | |
| 694 | case 0x0: | |
| 695 | default: | |
| 696 | state->m_mapper = state->m_mapper | (m & 0xf0); | |
| 697 | break; | |
| 698 | } | |
| 699 | ||
| 700 | if (mapinfo /* && !state->m_ines20 */) | |
| 701 | { | |
| 702 | if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4)) | |
| 703 | { | |
| 704 | /* image is present in nes.hsi: overwrite the header settings with these */ | |
| 705 | state->m_mapper = mapint1; | |
| 706 | local_options = mapint2 & 0x0f; | |
| 707 | state->m_crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below) | |
| 708 | state->m_prg_chunks = mapint3; | |
| 709 | state->m_chr_chunks = mapint4; | |
| 710 | logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); | |
| 711 | // mame_printf_error("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); | |
| 712 | goodcrcinfo = 1; | |
| 713 | state->m_ines20 = 0; | |
| 714 | } | |
| 715 | else | |
| 716 | { | |
| 717 | logerror("NES: [%s], Invalid mapinfo found\n", mapinfo); | |
| 718 | } | |
| 719 | } | |
| 720 | else | |
| 721 | { | |
| 722 | logerror("NES: No extrainfo found\n"); | |
| 723 | } | |
| 724 | ||
| 725 | state->m_hard_mirroring = (local_options & 0x01) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ; | |
| 726 | // mame_printf_error("%s\n", state->m_hard_mirroring & 0x01 ? "Vertical" : "Horizontal"); | |
| 727 | state->m_battery = local_options & 0x02; | |
| 728 | state->m_trainer = local_options & 0x04; | |
| 729 | state->m_four_screen_vram = local_options & 0x08; | |
| 730 | ||
| 731 | if (state->m_battery) | |
| 732 | logerror("-- Battery found\n"); | |
| 733 | ||
| 734 | if (state->m_trainer) | |
| 735 | logerror("-- Trainer found\n"); | |
| 736 | ||
| 737 | if (state->m_four_screen_vram) | |
| 738 | logerror("-- 4-screen VRAM\n"); | |
| 739 | ||
| 740 | if (state->m_ines20) | |
| 741 | { | |
| 742 | logerror("Extended iNES format:\n"); | |
| 743 | image.fread(&extend, 5); | |
| 744 | state->m_mapper |= (extend[0] & 0x0f) << 8; | |
| 745 | logerror("-- mapper: %d\n", state->m_mapper); | |
| 746 | logerror("-- submapper: %d\n", (extend[0] & 0xf0) >> 4); | |
| 747 | state->m_prg_chunks |= ((extend[1] & 0x0f) << 8); | |
| 748 | state->m_chr_chunks |= ((extend[1] & 0xf0) << 4); | |
| 749 | logerror("-- PRG chunks: %d\n", state->m_prg_chunks); | |
| 750 | logerror("-- CHR chunks: %d\n", state->m_chr_chunks); | |
| 751 | logerror("-- PRG NVWRAM: %d\n", extend[2] & 0x0f); | |
| 752 | logerror("-- PRG WRAM: %d\n", (extend[2] & 0xf0) >> 4); | |
| 753 | logerror("-- CHR NVWRAM: %d\n", extend[3] & 0x0f); | |
| 754 | logerror("-- CHR WRAM: %d\n", (extend[3] & 0xf0) >> 4); | |
| 755 | logerror("-- TV System: %d\n", extend[4] & 3); | |
| 756 | } | |
| 757 | ||
| 758 | /* Free the regions that were allocated by the ROM loader */ | |
| 759 | image.device().machine().region_free("maincpu"); | |
| 760 | image.device().machine().region_free("gfx1"); | |
| 761 | ||
| 762 | /* Allocate them again with the proper size */ | |
| 763 | prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000; | |
| 764 | image.device().machine().region_alloc("maincpu", 0x10000 + prg_size, 1, ENDIANNESS_LITTLE); | |
| 765 | if (state->m_chr_chunks) | |
| 766 | image.device().machine().region_alloc("gfx1", state->m_chr_chunks * 0x2000, 1, ENDIANNESS_LITTLE); | |
| 767 | ||
| 768 | state->m_rom = image.device().machine().region("maincpu")->base(); | |
| 769 | state->m_vrom = image.device().machine().region("gfx1")->base(); | |
| 770 | ||
| 771 | state->m_vram_chunks = image.device().machine().region("gfx2")->bytes() / 0x2000; | |
| 772 | state->m_vram = image.device().machine().region("gfx2")->base(); | |
| 773 | // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)! | |
| 774 | // or if there is a trainer, I think | |
| 775 | state->m_wram_size = 0x10000; | |
| 776 | state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); | |
| 777 | ||
| 778 | /* Setup PCB type (needed to add proper handlers later) */ | |
| 779 | state->m_pcb_id = nes_get_mmc_id(image.device().machine(), state->m_mapper); | |
| 780 | ||
| 781 | // a few mappers correspond to multiple PCBs, so we need a few additional checks | |
| 782 | switch (state->m_pcb_id) | |
| 783 | { | |
| 784 | case STD_CNROM: | |
| 785 | if (state->m_mapper == 185) | |
| 786 | { | |
| 787 | switch (state->m_crc_hack) | |
| 788 | { | |
| 789 | case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week) | |
| 790 | state->m_ce_mask = 0x03; | |
| 791 | state->m_ce_state = 0x03; | |
| 792 | break; | |
| 793 | case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy) | |
| 794 | state->m_ce_mask = 0x03; | |
| 795 | state->m_ce_state = 0x01; | |
| 796 | break; | |
| 797 | case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen) | |
| 798 | state->m_ce_mask = 0x03; | |
| 799 | state->m_ce_state = 0x02; | |
| 800 | break; | |
| 801 | case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0) | |
| 802 | state->m_ce_mask = 0x03; | |
| 803 | state->m_ce_state = 0x00; | |
| 804 | break; | |
| 805 | } | |
| 806 | } | |
| 807 | break; | |
| 808 | case KONAMI_VRC2: | |
| 809 | if (state->m_mapper == 22) | |
| 810 | { | |
| 811 | state->m_vrc_ls_prg_a = 0; | |
| 812 | state->m_vrc_ls_prg_b = 1; | |
| 813 | state->m_vrc_ls_chr = 1; | |
| 814 | } | |
| 815 | if (state->m_mapper == 23 && !state->m_crc_hack) | |
| 816 | { | |
| 817 | state->m_vrc_ls_prg_a = 1; | |
| 818 | state->m_vrc_ls_prg_b = 0; | |
| 819 | state->m_vrc_ls_chr = 0; | |
| 820 | } | |
| 821 | if (state->m_mapper == 23 && state->m_crc_hack) | |
| 822 | { | |
| 823 | // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4 | |
| 824 | state->m_vrc_ls_prg_a = 3; | |
| 825 | state->m_vrc_ls_prg_b = 2; | |
| 826 | state->m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset | |
| 827 | } | |
| 828 | break; | |
| 829 | case KONAMI_VRC4: | |
| 830 | if (state->m_mapper == 21) | |
| 831 | { | |
| 832 | // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack) | |
| 833 | state->m_vrc_ls_prg_a = state->m_crc_hack ? 7 : 2; | |
| 834 | state->m_vrc_ls_prg_b = state->m_crc_hack ? 6 : 1; | |
| 835 | } | |
| 836 | if (state->m_mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2 | |
| 837 | { | |
| 838 | state->m_vrc_ls_prg_a = state->m_crc_hack ? 2 : 0; | |
| 839 | state->m_vrc_ls_prg_b = state->m_crc_hack ? 3 : 1; | |
| 840 | } | |
| 841 | break; | |
| 842 | case KONAMI_VRC6: | |
| 843 | if (state->m_mapper == 24) | |
| 844 | { | |
| 845 | state->m_vrc_ls_prg_a = 1; | |
| 846 | state->m_vrc_ls_prg_b = 0; | |
| 847 | } | |
| 848 | if (state->m_mapper == 26) | |
| 849 | { | |
| 850 | state->m_vrc_ls_prg_a = 0; | |
| 851 | state->m_vrc_ls_prg_b = 1; | |
| 852 | } | |
| 853 | break; | |
| 854 | case IREM_G101: | |
| 855 | if (state->m_crc_hack) | |
| 856 | state->m_hard_mirroring = PPU_MIRROR_HIGH; // Major League has hardwired mirroring | |
| 857 | break; | |
| 858 | case DIS_74X161X161X32: | |
| 859 | if (state->m_mapper == 70) | |
| 860 | state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 70 & 152 | |
| 861 | break; | |
| 862 | case SUNSOFT_2: | |
| 863 | if (state->m_mapper == 93) | |
| 864 | state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 89 & 93 | |
| 865 | break; | |
| 866 | case STD_BXROM: | |
| 867 | if (state->m_crc_hack) | |
| 868 | state->m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards | |
| 869 | break; | |
| 870 | case BANDAI_LZ93: | |
| 871 | if (state->m_crc_hack) | |
| 872 | state->m_pcb_id = BANDAI_JUMP2; // Mapper 153 is used for 2 diff boards | |
| 873 | break; | |
| 874 | case IREM_HOLYDIV: | |
| 875 | if (state->m_crc_hack) | |
| 876 | state->m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards | |
| 877 | break; | |
| 878 | case CAMERICA_BF9093: | |
| 879 | if (state->m_crc_hack) | |
| 880 | state->m_pcb_id = CAMERICA_BF9097; // Mapper 71 is used for 2 diff boards | |
| 881 | break; | |
| 882 | case HES_BOARD: | |
| 883 | if (state->m_crc_hack) | |
| 884 | state->m_pcb_id = HES6IN1_BOARD; // Mapper 113 is used for 2 diff boards | |
| 885 | break; | |
| 886 | case WAIXING_ZS: | |
| 887 | if (state->m_crc_hack) | |
| 888 | state->m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards | |
| 889 | break; | |
| 890 | //FIXME: we also have to fix Action 52 PRG loading somewhere... | |
| 891 | } | |
| 892 | ||
| 893 | /* Allocate internal Mapper RAM for boards which require it */ | |
| 894 | if (state->m_pcb_id == STD_EXROM) | |
| 895 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x400); | |
| 896 | ||
| 897 | if (state->m_pcb_id == TAITO_X1_005 || state->m_pcb_id == TAITO_X1_005_A) | |
| 898 | state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x80); | |
| 899 | ||
| 900 | if (state->m_pcb_id == TAITO_X1_017) | |
| 901 | state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x1400); | |
| 902 | ||
| 903 | if (state->m_pcb_id == NAMCOT_163) | |
| 904 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x2000); | |
| 905 | ||
| 906 | if (state->m_pcb_id == FUKUTAKE_BOARD) | |
| 907 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 2816); | |
| 908 | ||
| 909 | /* Position past the header */ | |
| 910 | image.fseek(16, SEEK_SET); | |
| 911 | ||
| 912 | /* Load the 0x200 byte trainer at 0x7000 if it exists */ | |
| 913 | if (state->m_trainer) | |
| 914 | image.fread(&state->m_wram[0x1000], 0x200); | |
| 915 | ||
| 916 | /* Read in the program chunks */ | |
| 917 | image.fread(&state->m_rom[0x10000], 0x4000 * state->m_prg_chunks); | |
| 918 | if (state->m_prg_chunks == 1) | |
| 919 | memcpy(&state->m_rom[0x14000], &state->m_rom[0x10000], 0x4000); | |
| 920 | ||
| 921 | #if SPLIT_PRG | |
| 922 | { | |
| 923 | FILE *prgout; | |
| 924 | char outname[255]; | |
| 925 | ||
| 926 | sprintf(outname, "%s.prg", image.filename()); | |
| 927 | prgout = fopen(outname, "wb"); | |
| 928 | if (prgout) | |
| 929 | { | |
| 930 | fwrite(&state->m_rom[0x10000], 1, 0x4000 * state->m_prg_chunks, prgout); | |
| 931 | mame_printf_error("Created PRG chunk\n"); | |
| 932 | } | |
| 933 | ||
| 934 | fclose(prgout); | |
| 935 | } | |
| 936 | #endif | |
| 937 | ||
| 938 | logerror("**\n"); | |
| 939 | logerror("Mapper: %d\n", state->m_mapper); | |
| 940 | logerror("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks); | |
| 941 | // mame_printf_error("Mapper: %d\n", state->m_mapper); | |
| 942 | // mame_printf_error("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks); | |
| 943 | ||
| 944 | /* Read in any chr chunks */ | |
| 945 | if (state->m_chr_chunks > 0) | |
| 946 | { | |
| 947 | image.fread(state->m_vrom, state->m_chr_chunks * 0x2000); | |
| 948 | if (state->m_mapper == 2) | |
| 949 | logerror("Warning: VROM has been found in VRAM-based mapper. Either the mapper is set wrong or the ROM image is incorrect.\n"); | |
| 950 | } | |
| 951 | ||
| 952 | #if SPLIT_CHR | |
| 953 | if (state->m_chr_chunks > 0) | |
| 954 | { | |
| 955 | FILE *chrout; | |
| 956 | char outname[255]; | |
| 957 | ||
| 958 | sprintf(outname, "%s.chr", image.filename()); | |
| 959 | chrout= fopen(outname, "wb"); | |
| 960 | if (chrout) | |
| 961 | { | |
| 962 | fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout); | |
| 963 | mame_printf_error("Created CHR chunk\n"); | |
| 964 | } | |
| 965 | fclose(chrout); | |
| 966 | } | |
| 967 | #endif | |
| 968 | ||
| 969 | logerror("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks); | |
| 970 | logerror("**\n"); | |
| 971 | // mame_printf_error("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks); | |
| 972 | // mame_printf_error("**\n"); | |
| 973 | } | |
| 974 | else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ | |
| 975 | { | |
| 976 | UINT32 unif_ver = 0; | |
| 977 | char magic2[4]; | |
| 978 | UINT8 buffer[4]; | |
| 979 | UINT32 chunk_length = 0, read_length = 0x20; | |
| 980 | UINT32 prg_start = 0, chr_start = 0, prg_size; | |
| 981 | char unif_mapr[32]; // here we should store MAPR chunks | |
| 982 | UINT32 size = image.length(); | |
| 983 | int mapr_chunk_found = 0; | |
| 984 | // allocate space to temporarily store PRG & CHR banks | |
| 985 | UINT8 *temp_prg = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x4000); | |
| 986 | UINT8 *temp_chr = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x2000); | |
| 987 | UINT8 temp_byte = 0; | |
| 988 | ||
| 989 | /* init prg/chr chunks to 0: the exact number of chunks will be determined while reading the file */ | |
| 990 | state->m_prg_chunks = 0; | |
| 991 | state->m_chr_chunks = 0; | |
| 992 | ||
| 993 | image.fread(&buffer, 4); | |
| 994 | unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 995 | logerror("UNIF file found, version %d\n", unif_ver); | |
| 996 | ||
| 997 | if (size <= 0x20) | |
| 998 | { | |
| 999 | logerror("%s only contains the UNIF header and no data.\n", image.filename()); | |
| 1000 | return IMAGE_INIT_FAIL; | |
| 1001 | } | |
| 1002 | ||
| 1003 | do | |
| 1004 | { | |
| 1005 | image.fseek(read_length, SEEK_SET); | |
| 1006 | ||
| 1007 | memset(magic2, '\0', sizeof(magic2)); | |
| 1008 | image.fread(&magic2, 4); | |
| 1009 | ||
| 1010 | /* We first run through the whole image to find a [MAPR] chunk. This is needed | |
| 1011 | because, unfortunately, the MAPR chunk is not always the first chunk (see | |
| 1012 | Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and | |
| 1013 | we go back to load other chunks! */ | |
| 1014 | if (!mapr_chunk_found) | |
| 1015 | { | |
| 1016 | if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) | |
| 1017 | { | |
| 1018 | mapr_chunk_found = 1; | |
| 1019 | logerror("[MAPR] chunk found: "); | |
| 1020 | image.fread(&buffer, 4); | |
| 1021 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1022 | ||
| 1023 | if (chunk_length <= 0x20) | |
| 1024 | image.fread(&unif_mapr, chunk_length); | |
| 1025 | ||
| 1026 | // find out prg/chr size, battery, wram, etc. | |
| 1027 | unif_mapr_setup(image.device().machine(), unif_mapr); | |
| 1028 | ||
| 1029 | /* now that we found the MAPR chunk, we can go back to load other chunks */ | |
| 1030 | image.fseek(0x20, SEEK_SET); | |
| 1031 | read_length = 0x20; | |
| 1032 | } | |
| 1033 | else | |
| 1034 | { | |
| 1035 | logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n"); | |
| 1036 | image.fread(&buffer, 4); | |
| 1037 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1038 | ||
| 1039 | read_length += (chunk_length + 8); | |
| 1040 | } | |
| 1041 | } | |
| 1042 | else | |
| 1043 | { | |
| 1044 | /* What kind of chunk do we have here? */ | |
| 1045 | if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) | |
| 1046 | { | |
| 1047 | /* The [MAPR] chunk has already been read, so we skip it */ | |
| 1048 | /* TO DO: it would be nice to check if more than one MAPR chunk is present */ | |
| 1049 | logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n"); | |
| 1050 | image.fread(&buffer, 4); | |
| 1051 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1052 | ||
| 1053 | read_length += (chunk_length + 8); | |
| 1054 | } | |
| 1055 | else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D')) | |
| 1056 | { | |
| 1057 | logerror("[READ] chunk found. No support yet.\n"); | |
| 1058 | image.fread(&buffer, 4); | |
| 1059 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1060 | ||
| 1061 | read_length += (chunk_length + 8); | |
| 1062 | } | |
| 1063 | else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E')) | |
| 1064 | { | |
| 1065 | logerror("[NAME] chunk found. No support yet.\n"); | |
| 1066 | image.fread(&buffer, 4); | |
| 1067 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1068 | ||
| 1069 | read_length += (chunk_length + 8); | |
| 1070 | } | |
| 1071 | else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R')) | |
| 1072 | { | |
| 1073 | logerror("[WRTR] chunk found. No support yet.\n"); | |
| 1074 | image.fread(&buffer, 4); | |
| 1075 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1076 | ||
| 1077 | read_length += (chunk_length + 8); | |
| 1078 | } | |
| 1079 | else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I')) | |
| 1080 | { | |
| 1081 | logerror("[TVCI] chunk found.\n"); | |
| 1082 | image.fread(&buffer, 4); | |
| 1083 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1084 | ||
| 1085 | image.fread(&temp_byte, 1); | |
| 1086 | logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter"); | |
| 1087 | ||
| 1088 | read_length += (chunk_length + 8); | |
| 1089 | } | |
| 1090 | else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI?? | |
| 1091 | { | |
| 1092 | logerror("[TVSC] chunk found. No support yet.\n"); | |
| 1093 | image.fread(&buffer, 4); | |
| 1094 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1095 | ||
| 1096 | read_length += (chunk_length + 8); | |
| 1097 | } | |
| 1098 | else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F')) | |
| 1099 | { | |
| 1100 | logerror("[DINF] chunk found. No support yet.\n"); | |
| 1101 | image.fread(&buffer, 4); | |
| 1102 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1103 | ||
| 1104 | read_length += (chunk_length + 8); | |
| 1105 | } | |
| 1106 | else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L')) | |
| 1107 | { | |
| 1108 | logerror("[CTRL] chunk found. No support yet.\n"); | |
| 1109 | image.fread(&buffer, 4); | |
| 1110 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1111 | ||
| 1112 | read_length += (chunk_length + 8); | |
| 1113 | } | |
| 1114 | else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R')) | |
| 1115 | { | |
| 1116 | logerror("[BATR] chunk found. No support yet.\n"); | |
| 1117 | image.fread(&buffer, 4); | |
| 1118 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1119 | ||
| 1120 | read_length += (chunk_length + 8); | |
| 1121 | } | |
| 1122 | else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R')) | |
| 1123 | { | |
| 1124 | logerror("[VROR] chunk found. No support yet.\n"); | |
| 1125 | image.fread(&buffer, 4); | |
| 1126 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1127 | ||
| 1128 | read_length += (chunk_length + 8); | |
| 1129 | } | |
| 1130 | else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R')) | |
| 1131 | { | |
| 1132 | logerror("[MIRR] chunk found.\n"); | |
| 1133 | image.fread(&buffer, 4); | |
| 1134 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1135 | ||
| 1136 | image.fread(&temp_byte, 1); | |
| 1137 | switch (temp_byte) | |
| 1138 | { | |
| 1139 | case 0: // Horizontal Mirroring (Hard Wired) | |
| 1140 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1141 | break; | |
| 1142 | case 1: // Vertical Mirroring (Hard Wired) | |
| 1143 | state->m_hard_mirroring = PPU_MIRROR_VERT; | |
| 1144 | break; | |
| 1145 | case 2: // Mirror All Pages From $2000 (Hard Wired) | |
| 1146 | state->m_hard_mirroring = PPU_MIRROR_LOW; | |
| 1147 | break; | |
| 1148 | case 3: // Mirror All Pages From $2400 (Hard Wired) | |
| 1149 | state->m_hard_mirroring = PPU_MIRROR_HIGH; | |
| 1150 | break; | |
| 1151 | case 4: // Four Screens of VRAM (Hard Wired) | |
| 1152 | state->m_four_screen_vram = 1; | |
| 1153 | break; | |
| 1154 | case 5: // Mirroring Controlled By Mapper Hardware | |
| 1155 | logerror("Mirroring handled by the board hardware.\n"); | |
| 1156 | // default to horizontal at start | |
| 1157 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1158 | break; | |
| 1159 | default: | |
| 1160 | logerror("Undocumented mirroring value.\n"); | |
| 1161 | // default to horizontal | |
| 1162 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1163 | break; | |
| 1164 | } | |
| 1165 | ||
| 1166 | read_length += (chunk_length + 8); | |
| 1167 | } | |
| 1168 | else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K')) | |
| 1169 | { | |
| 1170 | logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]); | |
| 1171 | image.fread(&buffer, 4); | |
| 1172 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1173 | ||
| 1174 | read_length += (chunk_length + 8); | |
| 1175 | } | |
| 1176 | else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K')) | |
| 1177 | { | |
| 1178 | logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]); | |
| 1179 | image.fread(&buffer, 4); | |
| 1180 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1181 | ||
| 1182 | read_length += (chunk_length + 8); | |
| 1183 | } | |
| 1184 | else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G')) | |
| 1185 | { | |
| 1186 | logerror("[PRG%c] chunk found. ", magic2[3]); | |
| 1187 | image.fread(&buffer, 4); | |
| 1188 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1189 | ||
| 1190 | // FIXME: we currently don't support PRG chunks smaller than 16K! | |
| 1191 | state->m_prg_chunks += (chunk_length / 0x4000); | |
| 1192 | ||
| 1193 | if (chunk_length / 0x4000) | |
| 1194 | logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000); | |
| 1195 | else | |
| 1196 | logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n"); | |
| 1197 | ||
| 1198 | /* Read in the program chunks */ | |
| 1199 | image.fread(&temp_prg[prg_start], chunk_length); | |
| 1200 | ||
| 1201 | prg_start += chunk_length; | |
| 1202 | read_length += (chunk_length + 8); | |
| 1203 | } | |
| 1204 | else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R')) | |
| 1205 | { | |
| 1206 | logerror("[CHR%c] chunk found. ", magic2[3]); | |
| 1207 | image.fread(&buffer, 4); | |
| 1208 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1209 | ||
| 1210 | state->m_chr_chunks += (chunk_length / 0x2000); | |
| 1211 | ||
| 1212 | logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000); | |
| 1213 | ||
| 1214 | /* Read in the vrom chunks */ | |
| 1215 | image.fread(&temp_chr[chr_start], chunk_length); | |
| 1216 | ||
| 1217 | chr_start += chunk_length; | |
| 1218 | read_length += (chunk_length + 8); | |
| 1219 | } | |
| 1220 | else | |
| 1221 | { | |
| 1222 | logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); | |
| 1223 | read_length = size; | |
| 1224 | } | |
| 1225 | } | |
| 1226 | } while (size > read_length); | |
| 1227 | ||
| 1228 | if (!mapr_chunk_found) | |
| 1229 | { | |
| 1230 | auto_free(image.device().machine(), temp_prg); | |
| 1231 | auto_free(image.device().machine(), temp_chr); | |
| 1232 | fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted"); | |
| 1233 | } | |
| 1234 | ||
| 1235 | if (!prg_start) | |
| 1236 | { | |
| 1237 | auto_free(image.device().machine(), temp_prg); | |
| 1238 | auto_free(image.device().machine(), temp_chr); | |
| 1239 | fatalerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); | |
| 1240 | } | |
| 1241 | ||
| 1242 | /* Free the regions that were allocated by the ROM loader */ | |
| 1243 | image.device().machine().region_free("maincpu"); | |
| 1244 | image.device().machine().region_free("gfx1"); | |
| 1245 | image.device().machine().region_free("gfx2"); | |
| 1246 | ||
| 1247 | /* Allocate them again, and copy PRG/CHR from temp buffers */ | |
| 1248 | /* Take care of PRG */ | |
| 1249 | prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000; | |
| 1250 | image.device().machine().region_alloc("maincpu", 0x10000 + prg_size, 1, ENDIANNESS_LITTLE); | |
| 1251 | state->m_rom = image.device().machine().region("maincpu")->base(); | |
| 1252 | memcpy(&state->m_rom[0x10000], &temp_prg[0x00000], state->m_prg_chunks * 0x4000); | |
| 1253 | /* If only a single 16K PRG chunk is present, mirror it! */ | |
| 1254 | if (state->m_prg_chunks == 1) | |
| 1255 | memcpy(&state->m_rom[0x14000], &state->m_rom[0x10000], 0x4000); | |
| 1256 | ||
| 1257 | /* Take care of CHR ROM */ | |
| 1258 | if (state->m_chr_chunks) | |
| 1259 | { | |
| 1260 | image.device().machine().region_alloc("gfx1", state->m_chr_chunks * 0x2000, 1, ENDIANNESS_LITTLE); | |
| 1261 | state->m_vrom = image.device().machine().region("gfx1")->base(); | |
| 1262 | memcpy(&state->m_vrom[0x00000], &temp_chr[0x00000], state->m_chr_chunks * 0x2000); | |
| 1263 | } | |
| 1264 | ||
| 1265 | /* Take care of CHR RAM */ | |
| 1266 | if (state->m_vram_chunks) | |
| 1267 | { | |
| 1268 | image.device().machine().region_alloc("gfx2", state->m_vram_chunks * 0x2000, 1, ENDIANNESS_LITTLE); | |
| 1269 | state->m_vram = image.device().machine().region("gfx2")->base(); | |
| 1270 | } | |
| 1271 | ||
| 1272 | // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)! | |
| 1273 | state->m_wram_size = 0x10000; | |
| 1274 | state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); | |
| 1275 | ||
| 1276 | #if SPLIT_PRG | |
| 1277 | { | |
| 1278 | FILE *prgout; | |
| 1279 | char outname[255]; | |
| 1280 | ||
| 1281 | sprintf(outname, "%s.prg", image.filename()); | |
| 1282 | prgout = fopen(outname, "wb"); | |
| 1283 | if (prgout) | |
| 1284 | { | |
| 1285 | fwrite(&state->m_rom[0x10000], 1, 0x4000 * state->m_prg_chunks, prgout); | |
| 1286 | mame_printf_error("Created PRG chunk\n"); | |
| 1287 | } | |
| 1288 | ||
| 1289 | fclose(prgout); | |
| 1290 | } | |
| 1291 | #endif | |
| 1292 | ||
| 1293 | #if SPLIT_CHR | |
| 1294 | if (state->m_chr_chunks > 0) | |
| 1295 | { | |
| 1296 | FILE *chrout; | |
| 1297 | char outname[255]; | |
| 1298 | ||
| 1299 | sprintf(outname, "%s.chr", image.filename()); | |
| 1300 | chrout= fopen(outname, "wb"); | |
| 1301 | if (chrout) | |
| 1302 | { | |
| 1303 | fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout); | |
| 1304 | mame_printf_error("Created CHR chunk\n"); | |
| 1305 | } | |
| 1306 | fclose(chrout); | |
| 1307 | } | |
| 1308 | #endif | |
| 1309 | // free the temporary copy of PRG/CHR | |
| 1310 | auto_free(image.device().machine(), temp_prg); | |
| 1311 | auto_free(image.device().machine(), temp_chr); | |
| 1312 | logerror("UNIF support is only very preliminary.\n"); | |
| 1313 | } | |
| 1314 | else | |
| 1315 | { | |
| 1316 | logerror("%s is NOT a file in either iNES or UNIF format.\n", image.filename()); | |
| 1317 | return IMAGE_INIT_FAIL; | |
| 1318 | } | |
| 1319 | } | |
| 1320 | else | |
| 1321 | { | |
| 1322 | UINT32 prg_size = image.get_software_region_length("prg"); | |
| 1323 | UINT32 chr_size = image.get_software_region_length("chr"); | |
| 1324 | UINT32 vram_size = image.get_software_region_length("vram"); | |
| 1325 | vram_size += image.get_software_region_length("vram2"); | |
| 1326 | ||
| 1327 | /* Free the regions that were allocated by the ROM loader */ | |
| 1328 | image.device().machine().region_free("maincpu"); | |
| 1329 | image.device().machine().region_free("gfx1"); | |
| 1330 | image.device().machine().region_free("gfx2"); | |
| 1331 | ||
| 1332 | /* Allocate them again with the proper size */ | |
| 1333 | image.device().machine().region_alloc("maincpu", 0x10000 + prg_size, 1, ENDIANNESS_LITTLE); | |
| 1334 | ||
| 1335 | // validate the xml fields | |
| 1336 | if (!prg_size) | |
| 1337 | fatalerror("No PRG entry for this software! Please check if the xml list got corrupted"); | |
| 1338 | if (prg_size < 0x8000) | |
| 1339 | fatalerror("PRG entry is too small! Please check if the xml list got corrupted"); | |
| 1340 | ||
| 1341 | if (chr_size) | |
| 1342 | image.device().machine().region_alloc("gfx1", chr_size, 1, ENDIANNESS_LITTLE); | |
| 1343 | ||
| 1344 | if (vram_size) | |
| 1345 | image.device().machine().region_alloc("gfx2", vram_size, 1, ENDIANNESS_LITTLE); | |
| 1346 | ||
| 1347 | state->m_rom = image.device().machine().region("maincpu")->base(); | |
| 1348 | state->m_vrom = image.device().machine().region("gfx1")->base(); | |
| 1349 | state->m_vram = image.device().machine().region("gfx2")->base(); | |
| 1350 | ||
| 1351 | memcpy(state->m_rom + 0x10000, image.get_software_region("prg"), prg_size); | |
| 1352 | ||
| 1353 | if (chr_size) | |
| 1354 | memcpy(state->m_vrom, image.get_software_region("chr"), chr_size); | |
| 1355 | ||
| 1356 | state->m_prg_chunks = prg_size / 0x4000; | |
| 1357 | state->m_chr_chunks = chr_size / 0x2000; | |
| 1358 | state->m_vram_chunks = vram_size / 0x2000; | |
| 1359 | ||
| 1360 | state->m_pcb_id = nes_get_pcb_id(image.device().machine(), image.get_feature("pcb")); | |
| 1361 | ||
| 1362 | if (state->m_pcb_id == STD_TVROM || state->m_pcb_id == STD_DRROM || state->m_pcb_id == IREM_LROG017) | |
| 1363 | state->m_four_screen_vram = 1; | |
| 1364 | else | |
| 1365 | state->m_four_screen_vram = 0; | |
| 1366 | ||
| 1367 | state->m_battery = (image.get_software_region("bwram") != NULL) ? 1 : 0; | |
| 1368 | state->m_battery_size = image.get_software_region_length("bwram"); | |
| 1369 | ||
| 1370 | if (state->m_pcb_id == BANDAI_LZ93EX) | |
| 1371 | { | |
| 1372 | // allocate the 24C01 or 24C02 EEPROM | |
| 1373 | state->m_battery = 1; | |
| 1374 | state->m_battery_size += 0x2000; | |
| 1375 | } | |
| 1376 | ||
| 1377 | if (state->m_pcb_id == BANDAI_DATACH) | |
| 1378 | { | |
| 1379 | // allocate the 24C01 and 24C02 EEPROM | |
| 1380 | state->m_battery = 1; | |
| 1381 | state->m_battery_size += 0x4000; | |
| 1382 | } | |
| 1383 | ||
| 1384 | state->m_prg_ram = (image.get_software_region("wram") != NULL) ? 1 : 0; | |
| 1385 | state->m_wram_size = image.get_software_region_length("wram"); | |
| 1386 | state->m_mapper_ram_size = image.get_software_region_length("mapper_ram"); | |
| 1387 | state->m_mapper_bram_size = image.get_software_region_length("mapper_bram"); | |
| 1388 | ||
| 1389 | if (state->m_prg_ram) | |
| 1390 | state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); | |
| 1391 | if (state->m_mapper_ram_size) | |
| 1392 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_ram_size); | |
| 1393 | if (state->m_mapper_bram_size) | |
| 1394 | state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_bram_size); | |
| 1395 | ||
| 1396 | /* Check for mirroring */ | |
| 1397 | if (image.get_feature("mirroring") != NULL) | |
| 1398 | { | |
| 1399 | const char *mirroring = image.get_feature("mirroring"); | |
| 1400 | if (!strcmp(mirroring, "horizontal")) | |
| 1401 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1402 | if (!strcmp(mirroring, "vertical")) | |
| 1403 | state->m_hard_mirroring = PPU_MIRROR_VERT; | |
| 1404 | if (!strcmp(mirroring, "high")) | |
| 1405 | state->m_hard_mirroring = PPU_MIRROR_HIGH; | |
| 1406 | if (!strcmp(mirroring, "low")) | |
| 1407 | state->m_hard_mirroring = PPU_MIRROR_LOW; | |
| 1408 | } | |
| 1409 | ||
| 1410 | state->m_chr_open_bus = 0; | |
| 1411 | state->m_ce_mask = 0; | |
| 1412 | state->m_ce_state = 0; | |
| 1413 | state->m_vrc_ls_prg_a = 0; | |
| 1414 | state->m_vrc_ls_prg_b = 0; | |
| 1415 | state->m_vrc_ls_chr = 0; | |
| 1416 | ||
| 1417 | /* Check for pins in specific boards which require them */ | |
| 1418 | if (state->m_pcb_id == STD_CNROM) | |
| 1419 | { | |
| 1420 | if (image.get_feature("chr-pin26") != NULL) | |
| 1421 | { | |
| 1422 | state->m_ce_mask |= 0x01; | |
| 1423 | state->m_ce_state |= !strcmp(image.get_feature("chr-pin26"), "CE") ? 0x01 : 0; | |
| 1424 | } | |
| 1425 | if (image.get_feature("chr-pin27") != NULL) | |
| 1426 | { | |
| 1427 | state->m_ce_mask |= 0x02; | |
| 1428 | state->m_ce_state |= !strcmp(image.get_feature("chr-pin27"), "CE") ? 0x02 : 0; | |
| 1429 | } | |
| 1430 | } | |
| 1431 | ||
| 1432 | if (state->m_pcb_id == TAITO_X1_005 && image.get_feature("x1-pin17") != NULL && image.get_feature("x1-pin31") != NULL) | |
| 1433 | { | |
| 1434 | if (!strcmp(image.get_feature("x1-pin17"), "CIRAM A10") && !strcmp(image.get_feature("x1-pin31"), "NC")) | |
| 1435 | state->m_pcb_id = TAITO_X1_005_A; | |
| 1436 | } | |
| 1437 | ||
| 1438 | if (state->m_pcb_id == KONAMI_VRC2) | |
| 1439 | { | |
| 1440 | state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc2-pin3")); | |
| 1441 | state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc2-pin4")); | |
| 1442 | state->m_vrc_ls_chr = (nes_cart_get_line(image.get_feature("vrc2-pin21")) != 10) ? 1 : 0; | |
| 1443 | // mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %s\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b, state->m_vrc_ls_chr ? "NC" : "A10"); | |
| 1444 | } | |
| 1445 | ||
| 1446 | if (state->m_pcb_id == KONAMI_VRC4) | |
| 1447 | { | |
| 1448 | state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc4-pin3")); | |
| 1449 | state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc4-pin4")); | |
| 1450 | // mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); | |
| 1451 | } | |
| 1452 | ||
| 1453 | if (state->m_pcb_id == KONAMI_VRC6) | |
| 1454 | { | |
| 1455 | state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc6-pin9")); | |
| 1456 | state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc6-pin10")); | |
| 1457 | // mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); | |
| 1458 | } | |
| 1459 | ||
| 1460 | /* Check for other misc board variants */ | |
| 1461 | if (state->m_pcb_id == STD_SOROM) | |
| 1462 | { | |
| 1463 | if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A")) | |
| 1464 | state->m_pcb_id = STD_SOROM_A; // in MMC1-A PRG RAM is always enabled | |
| 1465 | } | |
| 1466 | ||
| 1467 | if (state->m_pcb_id == STD_SXROM) | |
| 1468 | { | |
| 1469 | if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A")) | |
| 1470 | state->m_pcb_id = STD_SXROM_A; // in MMC1-A PRG RAM is always enabled | |
| 1471 | } | |
| 1472 | ||
| 1473 | if (state->m_pcb_id == STD_NXROM || state->m_pcb_id == SUNSOFT_DCS) | |
| 1474 | { | |
| 1475 | if (image.get_software_region("minicart") != NULL) // check for dual minicart | |
| 1476 | { | |
| 1477 | state->m_pcb_id = SUNSOFT_DCS; | |
| 1478 | // we shall load somewhere the minicart, but we still do not support this | |
| 1479 | } | |
| 1480 | } | |
| 1481 | ||
| 1482 | #if 0 | |
| 1483 | if (state->m_pcb_id == UNSUPPORTED_BOARD) | |
| 1484 | mame_printf_error("This board (%s) is currently not supported by MESS\n", image.get_feature("pcb")); | |
| 1485 | mame_printf_error("PCB Feature: %s\n", image.get_feature("pcb")); | |
| 1486 | mame_printf_error("PRG chunks: %d\n", state->m_prg_chunks); | |
| 1487 | mame_printf_error("CHR chunks: %d\n", state->m_chr_chunks); | |
| 1488 | mame_printf_error("VRAM: Present %s, size: %d\n", state->m_vram_chunks ? "Yes" : "No", vram_size); | |
| 1489 | mame_printf_error("NVWRAM: Present %s, size: %d\n", state->m_battery ? "Yes" : "No", state->m_battery_size); | |
| 1490 | mame_printf_error("WRAM: Present %s, size: %d\n", state->m_prg_ram ? "Yes" : "No", state->m_wram_size); | |
| 1491 | #endif | |
| 1492 | } | |
| 1493 | ||
| 1494 | // Attempt to load a battery file for this ROM | |
| 1495 | // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) | |
| 1496 | if (state->m_battery || state->m_mapper_bram_size) | |
| 1497 | { | |
| 1498 | UINT8 *temp_nvram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size + state->m_mapper_bram_size); | |
| 1499 | image.battery_load(temp_nvram, state->m_battery_size + state->m_mapper_bram_size, 0x00); | |
| 1500 | if (state->m_battery) | |
| 1501 | { | |
| 1502 | state->m_battery_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size); | |
| 1503 | memcpy(state->m_battery_ram, temp_nvram, state->m_battery_size); | |
| 1504 | } | |
| 1505 | if (state->m_mapper_bram_size) | |
| 1506 | memcpy(state->m_mapper_bram, temp_nvram + state->m_battery_size, state->m_mapper_bram_size); | |
| 1507 | ||
| 1508 | auto_free(image.device().machine(), temp_nvram); | |
| 1509 | } | |
| 1510 | ||
| 1511 | return IMAGE_INIT_PASS; | |
| 1512 | } | |
| 1513 | ||
| 1514 | ||
| 1515 | ||
| 1516 | void nes_partialhash(hash_collection &dest, const unsigned char *data, | |
| 1517 | unsigned long length, const char *functions) | |
| 1518 | { | |
| 1519 | if (length <= 16) | |
| 1520 | return; | |
| 1521 | dest.compute(&data[16], length - 16, functions); | |
| 1522 | } | |
| 1523 | ||
| 1524 | /************************** | |
| 1525 | ||
| 1526 | Disk System emulation | |
| 1527 | ||
| 1528 | **************************/ | |
| 1529 | ||
| 1530 | static void fds_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 1531 | { | |
| 1532 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1533 | ||
| 1534 | if (state->m_IRQ_enable_latch) | |
| 1535 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1536 | ||
| 1537 | if (state->m_IRQ_enable) | |
| 1538 | { | |
| 1539 | if (state->m_IRQ_count <= 114) | |
| 1540 | { | |
| 1541 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1542 | state->m_IRQ_enable = 0; | |
| 1543 | state->m_fds_status0 |= 0x01; | |
| 1544 | } | |
| 1545 | else | |
| 1546 | state->m_IRQ_count -= 114; | |
| 1547 | } | |
| 1548 | } | |
| 1549 | ||
| 1550 | static READ8_HANDLER( nes_fds_r ) | |
| 1551 | { | |
| 1552 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1553 | UINT8 ret = 0x00; | |
| 1554 | ||
| 1555 | switch (offset) | |
| 1556 | { | |
| 1557 | case 0x00: /* $4030 - disk status 0 */ | |
| 1558 | ret = state->m_fds_status0; | |
| 1559 | /* clear the disk IRQ detect flag */ | |
| 1560 | state->m_fds_status0 &= ~0x01; | |
| 1561 | break; | |
| 1562 | case 0x01: /* $4031 - data latch */ | |
| 1563 | /* don't read data if disk is unloaded */ | |
| 1564 | if (state->m_fds_data == NULL) | |
| 1565 | ret = 0; | |
| 1566 | else if (state->m_fds_current_side) | |
| 1567 | ret = state->m_fds_data[(state->m_fds_current_side - 1) * 65500 + state->m_fds_head_position++]; | |
| 1568 | else | |
| 1569 | ret = 0; | |
| 1570 | break; | |
| 1571 | case 0x02: /* $4032 - disk status 1 */ | |
| 1572 | /* return "no disk" status if disk is unloaded */ | |
| 1573 | if (state->m_fds_data == NULL) | |
| 1574 | ret = 1; | |
| 1575 | else if (state->m_fds_last_side != state->m_fds_current_side) | |
| 1576 | { | |
| 1577 | /* If we've switched disks, report "no disk" for a few reads */ | |
| 1578 | ret = 1; | |
| 1579 | state->m_fds_count++; | |
| 1580 | if (state->m_fds_count == 50) | |
| 1581 | { | |
| 1582 | state->m_fds_last_side = state->m_fds_current_side; | |
| 1583 | state->m_fds_count = 0; | |
| 1584 | } | |
| 1585 | } | |
| 1586 | else | |
| 1587 | ret = (state->m_fds_current_side == 0); /* 0 if a disk is inserted */ | |
| 1588 | break; | |
| 1589 | case 0x03: /* $4033 */ | |
| 1590 | ret = 0x80; | |
| 1591 | break; | |
| 1592 | default: | |
| 1593 | ret = 0x00; | |
| 1594 | break; | |
| 1595 | } | |
| 1596 | ||
| 1597 | return ret; | |
| 1598 | } | |
| 1599 | ||
| 1600 | static WRITE8_HANDLER( nes_fds_w ) | |
| 1601 | { | |
| 1602 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1603 | ||
| 1604 | switch (offset) | |
| 1605 | { | |
| 1606 | case 0x00: | |
| 1607 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff00) | data; | |
| 1608 | break; | |
| 1609 | case 0x01: | |
| 1610 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x00ff) | (data << 8); | |
| 1611 | break; | |
| 1612 | case 0x02: | |
| 1613 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 1614 | state->m_IRQ_enable = data; | |
| 1615 | break; | |
| 1616 | case 0x03: | |
| 1617 | // d0 = sound io (1 = enable) | |
| 1618 | // d1 = disk io (1 = enable) | |
| 1619 | break; | |
| 1620 | case 0x04: | |
| 1621 | /* write data out to disk */ | |
| 1622 | break; | |
| 1623 | case 0x05: | |
| 1624 | state->m_fds_motor_on = BIT(data, 0); | |
| 1625 | ||
| 1626 | if (BIT(data, 1)) | |
| 1627 | state->m_fds_head_position = 0; | |
| 1628 | ||
| 1629 | state->m_fds_read_mode = BIT(data, 2); | |
| 1630 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 1631 | ||
| 1632 | if ((!(data & 0x40)) && (state->m_fds_write_reg & 0x40)) | |
| 1633 | state->m_fds_head_position -= 2; // ??? | |
| 1634 | ||
| 1635 | state->m_IRQ_enable_latch = BIT(data, 7); | |
| 1636 | state->m_fds_write_reg = data; | |
| 1637 | break; | |
| 1638 | } | |
| 1639 | } | |
| 1640 | ||
| 1641 | static void nes_load_proc( device_image_interface &image ) | |
| 1642 | { | |
| 1643 | nes_state *state = image.device().machine().driver_data<nes_state>(); | |
| 1644 | int header = 0; | |
| 1645 | state->m_fds_sides = 0; | |
| 1646 | ||
| 1647 | if (image.length() % 65500) | |
| 1648 | header = 0x10; | |
| 1649 | ||
| 1650 | state->m_fds_sides = (image.length() - header) / 65500; | |
| 1651 | ||
| 1652 | if (state->m_fds_data == NULL) | |
| 1653 | state->m_fds_data = (UINT8*)image.image_malloc(state->m_fds_sides * 65500); // I don't think we can arrive here ever, probably it can be removed... | |
| 1654 | ||
| 1655 | /* if there is an header, skip it */ | |
| 1656 | image.fseek(header, SEEK_SET); | |
| 1657 | ||
| 1658 | image.fread(state->m_fds_data, 65500 * state->m_fds_sides); | |
| 1659 | return; | |
| 1660 | } | |
| 1661 | ||
| 1662 | static void nes_unload_proc( device_image_interface &image ) | |
| 1663 | { | |
| 1664 | nes_state *state = image.device().machine().driver_data<nes_state>(); | |
| 1665 | ||
| 1666 | /* TODO: should write out changes here as well */ | |
| 1667 | state->m_fds_sides = 0; | |
| 1668 | } | |
| 1669 | ||
| 1670 | DRIVER_INIT( famicom ) | |
| 1671 | { | |
| 1672 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1673 | int i; | |
| 1674 | ||
| 1675 | /* clear some of the variables we don't use */ | |
| 1676 | state->m_trainer = 0; | |
| 1677 | state->m_battery = 0; | |
| 1678 | state->m_prg_ram = 0; | |
| 1679 | state->m_four_screen_vram = 0; | |
| 1680 | state->m_hard_mirroring = 0; | |
| 1681 | state->m_prg_chunks = state->m_chr_chunks = 0; | |
| 1682 | ||
| 1683 | /* initialize the disk system */ | |
| 1684 | state->m_disk_expansion = 1; | |
| 1685 | state->m_pcb_id = NO_BOARD; | |
| 1686 | ||
| 1687 | state->m_fds_sides = 0; | |
| 1688 | state->m_fds_last_side = 0; | |
| 1689 | state->m_fds_count = 0; | |
| 1690 | state->m_fds_motor_on = 0; | |
| 1691 | state->m_fds_door_closed = 0; | |
| 1692 | state->m_fds_current_side = 1; | |
| 1693 | state->m_fds_head_position = 0; | |
| 1694 | state->m_fds_status0 = 0; | |
| 1695 | state->m_fds_read_mode = state->m_fds_write_reg = 0; | |
| 1696 | ||
| 1697 | state->m_fds_data = auto_alloc_array_clear(machine, UINT8, 65500 * 2); | |
| 1698 | state->m_fds_ram = auto_alloc_array_clear(machine, UINT8, 0x8000); | |
| 1699 | state->save_pointer(NAME(state->m_fds_ram), 0x8000); | |
| 1700 | ||
| 1701 | // setup CHR accesses to 8k VRAM | |
| 1702 | state->m_vram = machine.region("gfx2")->base(); | |
| 1703 | for (i = 0; i < 8; i++) | |
| 1704 | { | |
| 1705 | state->m_chr_map[i].source = CHRRAM; | |
| 1706 | state->m_chr_map[i].origin = i * 0x400; // for save state uses! | |
| 1707 | state->m_chr_map[i].access = &state->m_vram[state->m_chr_map[i].origin]; | |
| 1708 | } | |
| 1709 | ||
| 1710 | floppy_install_load_proc(floppy_get_device(machine, 0), nes_load_proc); | |
| 1711 | floppy_install_unload_proc(floppy_get_device(machine, 0), nes_unload_proc); | |
| 1712 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | #ifndef __AMIGACD_H__ | |
| 2 | #define __AMIGACD_H__ | |
| 3 | ||
| 4 | ||
| 5 | MACHINE_START( amigacd ); | |
| 6 | MACHINE_RESET( amigacd ); | |
| 7 | ||
| 8 | /* 6525tpi */ | |
| 9 | READ8_DEVICE_HANDLER( amigacd_tpi6525_portc_r ); | |
| 10 | WRITE8_DEVICE_HANDLER( amigacd_tpi6525_portb_w ); | |
| 11 | WRITE_LINE_DEVICE_HANDLER( amigacd_tpi6525_irq ); | |
| 12 | ||
| 13 | ||
| 14 | #endif /* __AMIGACD_H__ */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES MMC Emulation - UNIF boards | |
| 4 | ||
| 5 | Very preliminary support for UNIF boards | |
| 6 | ||
| 7 | TODO: | |
| 8 | - properly support WRAM, etc. | |
| 9 | ||
| 10 | ****************************************************************************************/ | |
| 11 | ||
| 12 | typedef struct __unif | |
| 13 | { | |
| 14 | const char *board; /* UNIF board */ | |
| 15 | ||
| 16 | int nvwram; | |
| 17 | int wram; | |
| 18 | int chrram; | |
| 19 | int board_idx; | |
| 20 | } unif; | |
| 21 | ||
| 22 | ||
| 23 | /************************************************************* | |
| 24 | ||
| 25 | Constants | |
| 26 | ||
| 27 | *************************************************************/ | |
| 28 | ||
| 29 | /* CHRRAM sizes */ | |
| 30 | enum | |
| 31 | { | |
| 32 | CHRRAM_0 = 0, | |
| 33 | CHRRAM_1, | |
| 34 | CHRRAM_2, | |
| 35 | CHRRAM_4, | |
| 36 | CHRRAM_6, | |
| 37 | CHRRAM_8, | |
| 38 | CHRRAM_16, | |
| 39 | CHRRAM_32 | |
| 40 | }; | |
| 41 | ||
| 42 | /************************************************************* | |
| 43 | ||
| 44 | unif_list | |
| 45 | ||
| 46 | Supported UNIF boards and corresponding handlers | |
| 47 | ||
| 48 | *************************************************************/ | |
| 49 | ||
| 50 | static const unif unif_list[] = | |
| 51 | { | |
| 52 | /* UNIF NVW WRAM CRAM IDX*/ | |
| 53 | { "DREAMTECH01", 0, 0, CHRRAM_8, DREAMTECH_BOARD}, //UNIF only! | |
| 54 | { "NES-ANROM", 0, 0, CHRRAM_8, STD_AXROM}, | |
| 55 | { "NES-AOROM", 0, 0, CHRRAM_8, STD_AXROM}, | |
| 56 | { "NES-CNROM", 0, 0, CHRRAM_0, STD_CNROM}, | |
| 57 | { "NES-NROM", 0, 0, CHRRAM_0, STD_NROM}, | |
| 58 | { "NES-NROM-128", 0, 0, CHRRAM_0, STD_NROM}, | |
| 59 | { "NES-NROM-256", 0, 0, CHRRAM_0, STD_NROM}, | |
| 60 | { "NES-NTBROM", 8, 0, CHRRAM_0, STD_NXROM}, | |
| 61 | { "NES-SLROM", 0, 0, CHRRAM_0, STD_SXROM}, | |
| 62 | { "NES-TBROM", 0, 0, CHRRAM_0, STD_TXROM}, | |
| 63 | { "NES-TFROM", 0, 0, CHRRAM_0, STD_TXROM}, | |
| 64 | { "NES-TKROM", 8, 0, CHRRAM_0, STD_TXROM}, | |
| 65 | { "NES-TLROM", 0, 0, CHRRAM_0, STD_TXROM}, | |
| 66 | { "NES-UOROM", 0, 0, CHRRAM_8, STD_UXROM}, | |
| 67 | { "UNL-22211", 0, 0, CHRRAM_0, TXC_22211A}, | |
| 68 | // mapper 172 & 173 are variant of this one... no UNIF? | |
| 69 | { "UNL-KOF97", 0, 0, CHRRAM_0, UNL_KOF97}, | |
| 70 | { "UNL-SA-NROM", 0, 0, CHRRAM_0, SACHEN_TCA01}, | |
| 71 | { "UNL-VRC7", 0, 0, CHRRAM_0, KONAMI_VRC7}, | |
| 72 | { "UNL-T-230", 0, 0, CHRRAM_8, UNL_T230}, | |
| 73 | { "UNL-CC-21", 0, 0, CHRRAM_0, UNL_CC21}, | |
| 74 | { "UNL-AX5705", 0, 0, CHRRAM_0, UNL_AX5705}, | |
| 75 | { "UNL-SMB2J", 8, 8, CHRRAM_0, UNL_SMB2J}, | |
| 76 | { "UNL-8237", 0, 0, CHRRAM_0, UNL_8237}, | |
| 77 | { "UNL-SL1632", 0, 0, CHRRAM_0, REXSOFT_SL1632}, | |
| 78 | { "UNL-SACHEN-74LS374N", 0, 0, CHRRAM_0, SACHEN_74LS374}, | |
| 79 | // mapper 243 variant exists! how to distinguish?!? mapper243_l_w, NULL, NULL, NULL, NULL, NULL, NULL (also uses NT_VERT!) | |
| 80 | { "UNL-TC-U01-1.5M", 0, 0, CHRRAM_0, SACHEN_TCU01}, | |
| 81 | { "UNL-SACHEN-8259C", 0, 0, CHRRAM_0, SACHEN_8259C}, | |
| 82 | { "UNL-SA-016-1M", 0, 0, CHRRAM_0, AVE_NINA06}, // actually this is Mapper 146, but works like 79! | |
| 83 | { "UNL-SACHEN-8259D", 0, 0, CHRRAM_0, SACHEN_8259D}, | |
| 84 | { "UNL-SA-72007", 0, 0, CHRRAM_0, SACHEN_SA72007}, | |
| 85 | { "UNL-SA-72008", 0, 0, CHRRAM_0, SACHEN_SA72008}, | |
| 86 | { "UNL-SA-0037", 0, 0, CHRRAM_0, SACHEN_SA0037}, | |
| 87 | { "UNL-SA-0036", 0, 0, CHRRAM_0, SACHEN_SA0036}, | |
| 88 | { "UNL-SACHEN-8259A", 0, 0, CHRRAM_0, SACHEN_8259A}, | |
| 89 | { "UNL-SACHEN-8259B", 0, 0, CHRRAM_0, SACHEN_8259B}, | |
| 90 | { "BMC-190IN1", 0, 0, CHRRAM_0, BMC_190IN1}, | |
| 91 | { "BMC-64IN1NOREPEAT", 0, 0, CHRRAM_0, BMC_64IN1NR}, //UNIF only! | |
| 92 | { "BMC-A65AS", 0, 0, CHRRAM_8, BMC_A65AS}, //UNIF only! | |
| 93 | { "BMC-GS-2004", 0, 0, CHRRAM_8, BMC_GS2004}, //UNIF only! | |
| 94 | { "BMC-GS-2013", 0, 0, CHRRAM_8, BMC_GS2013}, //UNIF only! | |
| 95 | { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVELDIAMOND}, | |
| 96 | { "BMC-SUPER24IN1SC03", 8, 0, CHRRAM_8, BMC_S24IN1SC03}, | |
| 97 | { "BMC-SUPERHIK8IN1", 8, 0, CHRRAM_0, BMC_HIK8IN1}, | |
| 98 | { "BMC-T-262", 0, 0, CHRRAM_8, BMC_T262}, //UNIF only! | |
| 99 | { "BMC-WS", 0, 0, CHRRAM_0, BMC_WS}, //UNIF only! | |
| 100 | { "BMC-N625092", 0, 0, CHRRAM_0, UNL_N625092}, | |
| 101 | // below are boards which are not yet supported, but are used by some UNIF files. they are here as a reminder to what is missing to be added | |
| 102 | { "UNL-TEK90", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // related to JY Company? (i.e. mappers 90, 209, 211?) | |
| 103 | { "UNL-KS7017", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 104 | { "UNL-KS7032", 0, 0, CHRRAM_0, KAISER_KS7032}, // mapper 142 | |
| 105 | { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 106 | { "UNL-603-5052", 0, 0, CHRRAM_0, UNL_603_5052}, // mapper 238? | |
| 107 | { "UNL-EDU2000", 32, 0, CHRRAM_8, UNL_EDU2K}, | |
| 108 | { "UNL-H2288", 0, 0, CHRRAM_0, UNL_H2288}, // mapper 123 | |
| 109 | { "UNL-SHERO", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*SACHEN_SHERO*/}, | |
| 110 | { "UNL-TF1201", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD /*UNL_TF1201*/}, | |
| 111 | { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info]} | |
| 112 | { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 113 | { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 55? | |
| 114 | { "BMC-FK23C", 0, 0, CHRRAM_0, BMC_FK23C}, | |
| 115 | { "BMC-FK23CA", 0, 0, CHRRAM_0, BMC_FK23CA}, | |
| 116 | { "BMC-GHOSTBUSTERS63IN1", 0, 0, CHRRAM_8, BMC_G63IN1 }, | |
| 117 | { "BMC-BS-5", 0, 0, CHRRAM_0, BMC_BENSHENG_BS5}, | |
| 118 | { "BMC-810544-C-A1", 0, 0, CHRRAM_0, BMC_810544}, | |
| 119 | { "BMC-411120-C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 120 | { "BMC-8157", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*BMC_8157*/}, | |
| 121 | { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60? | |
| 122 | { "BMC-830118C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 123 | { "BMC-D1038", 0, 0, CHRRAM_0, BMC_VT5201}, // mapper 60? | |
| 124 | { "BMC-12-IN-1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 125 | { "BMC-70IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? | |
| 126 | { "BMC-70IN1B", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? | |
| 127 | { "BMC-SUPERVISION16IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 53 | |
| 128 | { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03} | |
| 129 | }; | |
| 130 | ||
| 131 | const unif *nes_unif_lookup( const char *board ) | |
| 132 | { | |
| 133 | int i; | |
| 134 | for (i = 0; i < ARRAY_LENGTH(unif_list); i++) | |
| 135 | { | |
| 136 | if (!mame_stricmp(unif_list[i].board, board)) | |
| 137 | return &unif_list[i]; | |
| 138 | } | |
| 139 | return NULL; | |
| 140 | } | |
| 141 | ||
| 142 | /************************************************************* | |
| 143 | ||
| 144 | unif_mapr_setup | |
| 145 | ||
| 146 | setup the board specific variables (wram, nvwram, pcb_id etc.) | |
| 147 | for a given board (after reading the MAPR chunk of the UNIF file) | |
| 148 | ||
| 149 | *************************************************************/ | |
| 150 | ||
| 151 | void unif_mapr_setup( running_machine &machine, const char *board ) | |
| 152 | { | |
| 153 | nes_state *state = machine.driver_data<nes_state>(); | |
| 154 | const unif *unif_board = nes_unif_lookup(board); | |
| 155 | ||
| 156 | logerror("%s\n", board); | |
| 157 | ||
| 158 | if (unif_board == NULL) | |
| 159 | fatalerror("Unknown UNIF board %s.", board); | |
| 160 | ||
| 161 | state->m_pcb_id = unif_board->board_idx; | |
| 162 | state->m_battery = unif_board->nvwram; // we should implement battery banks based on the size of this... | |
| 163 | state->m_battery_size = NES_BATTERY_SIZE; // FIXME: we should allow for smaller battery! | |
| 164 | state->m_prg_ram = unif_board->wram; // we should implement WRAM banks based on the size of this... | |
| 165 | ||
| 166 | if (unif_board->chrram <= CHRRAM_8) | |
| 167 | state->m_vram_chunks = 1; | |
| 168 | else if (unif_board->chrram == CHRRAM_16) | |
| 169 | state->m_vram_chunks = 2; | |
| 170 | else if (unif_board->chrram == CHRRAM_32) | |
| 171 | state->m_vram_chunks = 4; | |
| 172 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES MMC Emulation | |
| 4 | ||
| 5 | ||
| 6 | MESS source file to handle various Multi-Memory Controllers (aka Mappers) used by NES carts. | |
| 7 | ||
| 8 | Many information about the mappers below come from the wonderful doc written by Disch. | |
| 9 | Current info (when used) are based on v0.6.1 of his docs. | |
| 10 | You can find the latest version of the doc at http://www.romhacking.net/docs/362/ | |
| 11 | ||
| 12 | ||
| 13 | Missing components: | |
| 14 | * Currently, we are not emulating 4-screen mirroring (only 3 games use it) | |
| 15 | * We need a better way to implement CPU cycle based IRQ. Currently we update their counter once every scanline | |
| 16 | but, with this approach, every time 114 clocks have passed and for certain games it is too much! | |
| 17 | * We need to emulate additional sound hardware in mappers 019, 024, 026, 069, 085 (and possibly other ones) | |
| 18 | * We need to emulate EEPROM in mapper 016 and 159 | |
| 19 | * Barcode World (mapper 069) and Datach games (mapper 157) need Barcode Reader emulation | |
| 20 | Notice that for mapper 157, the barcode reader enters in the irq, so glitches may be related to this! | |
| 21 | * Karaoke Studio (mapper 188) misses input devices | |
| 22 | ||
| 23 | Known issues on specific mappers: | |
| 24 | ||
| 25 | * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches. | |
| 26 | * 001 Yoshi flashes in-game. Back to the Future have heavily corrupted graphics (since forever). | |
| 27 | * 001 SOROM boards do not properly handle the two WRAM/Battery banks | |
| 28 | * 002, 003, 094, 097, 152 Bus conflict? | |
| 29 | * 003 Firehouse Rescue has flashing graphics | |
| 30 | * 004 Mendel Palace has never worked properly | |
| 31 | * 004 Ninja Gaiden 2 has flashing bg graphics in the second level | |
| 32 | * 005 has issues (see e.g. Just Breed or Metal Slader Glory), RAM banking needs hardware flags to determine size | |
| 33 | * 007 Marble Madness has small graphics corruptions | |
| 34 | * 014 in-game graphics is glitched | |
| 35 | * 015 Shanghai Tycoon has corrupted graphics | |
| 36 | * 033 has still some graphics problem (e.g. missing text in Akira) | |
| 37 | * 034 Impossible Mission II does not show graphics | |
| 38 | * 038 seems to miss inputs. separate reads? | |
| 39 | * 042 Ai Senshi Nicol has broken graphics (our Mapper 42 implementation does not handle CHR banks) | |
| 40 | * 048 Don Doko Don 2 freezes when you reach the first boss | |
| 41 | * 051 only half of the games work | |
| 42 | * 064 has many IRQ problems (due to the way we implement CPU based IRQ) - see Skull & Crossbones. | |
| 43 | Klax has problems as well (even if it uses scanline based IRQ, according to Disch's docs). | |
| 44 | * 067 some 1-line glitches that cannot be solved without a better implementation for cycle-based IRQs | |
| 45 | * 071 Fire Hawk is flashing all the times. | |
| 46 | * 072, 086, 092 lack samples support (maybe others as well) | |
| 47 | * 073 16 bit IRQ mode is not implemented | |
| 48 | * 077 Requires 4-screen mirroring. Currently, it is very glitchy | |
| 49 | * 083 has serious glitches | |
| 50 | * 088 Quinty has never worked properly | |
| 51 | * 096 is preliminary (no correct chr switch in connection to PPU) | |
| 52 | * 104 Not all the games work | |
| 53 | * 107 Are the scrolling glitches (check status bar) correct? NEStopia behaves similarly | |
| 54 | * 112 Master Shooter is not working and misses some graphics | |
| 55 | * 117 In-game glitches | |
| 56 | * 119 Pin Bot has glitches when the ball is in the upper half of the screen | |
| 57 | * 133 Qi Wang starts with corrupted graphics (ingame seems better) | |
| 58 | * 143 are Dancing Block borders (in the intro) correct? | |
| 59 | * 158 In addition to IRQ problems (same as 64), mirroring was just a guess (wrong?). info needed! | |
| 60 | * 164 preliminary - no sprites? | |
| 61 | * 176 has some graphics problem | |
| 62 | * 178 Fan Kong Jin Ying is not working (but not even in NEStopia) | |
| 63 | * 180 Crazy Climber controller? | |
| 64 | * 187, 198, 208, 215 have some PRG banking issues - preliminary! | |
| 65 | * 188 needs mic input (reads from 0x6000-0x7fff) | |
| 66 | * 197 Super Fighter 3 has some glitch in-game (maybe mirroring?) | |
| 67 | * 222 is only preliminar (wrong IRQ, mirroring or CHR banking?) | |
| 68 | * 225 115-in-1 has glitches in the menu (games seem fine) | |
| 69 | * 229 is preliminary | |
| 70 | * 230 not working yet (needs a value to flip at reset) | |
| 71 | * 232 has graphics glitches | |
| 72 | * 241 Commandos is not working (but not even in NEStopia) | |
| 73 | * 242 In Dragon Quest VIII graphics of the main character is not drawn (it seems similar to Shanghai Tycoon [map15] | |
| 74 | because in place of the missing graphics we get glitches in the left border) | |
| 75 | * 249 only half of the games work (and Du Bao Ying Hao seems to suffer the same problem as DQ8 and Shanghai Tycoon) | |
| 76 | * 255 does not really select game (same in NEStopia apparently) | |
| 77 | ||
| 78 | A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than | |
| 79 | a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly | |
| 80 | emulation. Games which requires this hack are the following: | |
| 81 | * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise) | |
| 82 | * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still | |
| 83 | unplayable though (see above) | |
| 84 | * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics | |
| 85 | * 078 - Cosmo Carrier needs a different mirroring than Holy Diver | |
| 86 | * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer) | |
| 87 | * 153 - Famicom Jump II uses a different board (or the same in a very different way) | |
| 88 | * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though) | |
| 89 | ||
| 90 | crc_hacks have been added also to handle a few wiring settings which would require submappers: | |
| 91 | * CHR protection pins for mapper 185 | |
| 92 | * VRC-2, VRC-4 and VRC-6 line wiring | |
| 93 | ||
| 94 | Known issues on specific UNIF boards: | |
| 95 | * BMC-GS2004 is not working | |
| 96 | * BMC-GS2013 is not working | |
| 97 | * BMC-WS some games have corrupted graphics (e.g. Galaxian) | |
| 98 | * UNL-8237 is not working | |
| 99 | * UNL-KOF97 is not working | |
| 100 | ||
| 101 | Details to investigate: | |
| 102 | * 034 writes to 0x8000-0xffff should not be used for NINA-001 and BNROM, only unlicensed BxROM... | |
| 103 | * 144 we ignore writes to 0x8000 while NEStopia does not. is it a problem? | |
| 104 | * 240 we do not map writes to 0x4020-0x40ff. is this a problem? | |
| 105 | * some other emus uses mapper 210 for mapper 019 games without additional sound hardware and mirroring capabilities | |
| 106 | (in 210 mirroring is hardwired). However, simply initializing mirroring to Vertical in 019 seems to fix all glitches | |
| 107 | in 210 games, so there seems to be no reason to have this duplicate mapper | |
| 108 | ||
| 109 | Some mappers copy PRG rom in SRAM region. Below is a list of those which does it (in MESS) to further | |
| 110 | investigate if we are supporting them in the right way (e.g. do any of the following have conflicts with SRAM?): | |
| 111 | * 065 (Gimmick! breaks badly without it) | |
| 112 | * 040, 042, 050 | |
| 113 | ||
| 114 | Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is | |
| 115 | in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right? | |
| 116 | ||
| 117 | TODO: | |
| 118 | - add more info | |
| 119 | - add missing mappers | |
| 120 | ||
| 121 | ****************************************************************************************/ | |
| 122 | ||
| 123 | #include "emu.h" | |
| 124 | #include "cpu/m6502/m6502.h" | |
| 125 | #include "video/ppu2c0x.h" | |
| 126 | #include "includes/nes.h" | |
| 127 | #include "nes_mmc.h" | |
| 128 | #include "sound/nes_apu.h" | |
| 129 | ||
| 130 | #ifdef MAME_DEBUG | |
| 131 | #define VERBOSE 1 | |
| 132 | #else | |
| 133 | #define VERBOSE 0 | |
| 134 | #endif | |
| 135 | ||
| 136 | #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) | |
| 137 | #define LOG_FDS(x) do { if (VERBOSE) logerror x; } while (0) | |
| 138 | ||
| 139 | static void ffe_irq( device_t *device, int scanline, int vblank, int blanked ); | |
| 140 | static WRITE8_HANDLER( mapper6_l_w ); | |
| 141 | static WRITE8_HANDLER( mapper6_w ); | |
| 142 | static WRITE8_HANDLER( mapper8_w ); | |
| 143 | static WRITE8_HANDLER( mapper17_l_w ); | |
| 144 | ||
| 145 | /************************************************************* | |
| 146 | ||
| 147 | Base emulation (see drivers/nes.c): | |
| 148 | memory 0x0000-0x1fff RAM | |
| 149 | 0x2000-0x3fff PPU | |
| 150 | 0x4000-0x4017 APU | |
| 151 | 0x4018-0x5fff Expansion Area | |
| 152 | 0x6000-0x7fff PRG RAM | |
| 153 | 0x8000-0xffff PRG ROM | |
| 154 | ||
| 155 | nes_chr_r/w take care of RAM, nes_nt_r/w take care of PPU. | |
| 156 | for mapper specific emulation, we generically setup the | |
| 157 | following handlers: | |
| 158 | - nes_low_mapper_r/w take care of accesses to 0x4100-0x5fff | |
| 159 | (calling state->m_mmc_write_low/state->m_mmc_read_low) | |
| 160 | - state->m_mmc_write/read_mid take care of 0x6000-0x7fff | |
| 161 | - state->m_mmc_write/read take care of access to 0x8000-0xffff | |
| 162 | (most mappers only writes in this area) | |
| 163 | some mappers may access 0x4018-0x4100: this must be taken | |
| 164 | care separately in init_nes_core | |
| 165 | ||
| 166 | *************************************************************/ | |
| 167 | ||
| 168 | WRITE8_HANDLER( nes_chr_w ) | |
| 169 | { | |
| 170 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 171 | int bank = offset >> 10; | |
| 172 | ||
| 173 | if (state->m_chr_map[bank].source == CHRRAM) | |
| 174 | { | |
| 175 | state->m_chr_map[bank].access[offset & 0x3ff] = data; | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 179 | READ8_HANDLER( nes_chr_r ) | |
| 180 | { | |
| 181 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 182 | int bank = offset >> 10; | |
| 183 | ||
| 184 | // a few CNROM boards contained copy protection schemes through | |
| 185 | // suitably configured diodes, so that subsequent CHR reads can | |
| 186 | // give actual VROM content or open bus values. | |
| 187 | // For most boards, chr_open_bus remains always zero. | |
| 188 | if (state->m_chr_open_bus) | |
| 189 | return 0xff; | |
| 190 | ||
| 191 | return state->m_chr_map[bank].access[offset & 0x3ff]; | |
| 192 | } | |
| 193 | ||
| 194 | WRITE8_HANDLER( nes_nt_w ) | |
| 195 | { | |
| 196 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 197 | int page = ((offset & 0xc00) >> 10); | |
| 198 | ||
| 199 | if (state->m_nt_page[page].writable == 0) | |
| 200 | return; | |
| 201 | ||
| 202 | state->m_nt_page[page].access[offset & 0x3ff] = data; | |
| 203 | } | |
| 204 | ||
| 205 | READ8_HANDLER( nes_nt_r ) | |
| 206 | { | |
| 207 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 208 | int page = ((offset & 0xc00) >> 10); | |
| 209 | ||
| 210 | if (state->m_nt_page[page].source == MMC5FILL) | |
| 211 | { | |
| 212 | if ((offset & 0x3ff) >= 0x3c0) | |
| 213 | return state->m_MMC5_floodattr; | |
| 214 | ||
| 215 | return state->m_MMC5_floodtile; | |
| 216 | } | |
| 217 | return state->m_nt_page[page].access[offset & 0x3ff]; | |
| 218 | } | |
| 219 | ||
| 220 | WRITE8_HANDLER( nes_low_mapper_w ) | |
| 221 | { | |
| 222 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 223 | ||
| 224 | if (state->m_mmc_write_low) | |
| 225 | (*state->m_mmc_write_low)(space, offset, data); | |
| 226 | else | |
| 227 | logerror("Unimplemented LOW mapper write, offset: %04x, data: %02x\n", offset + 0x4100, data); | |
| 228 | } | |
| 229 | ||
| 230 | READ8_HANDLER( nes_low_mapper_r ) | |
| 231 | { | |
| 232 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 233 | ||
| 234 | if (state->m_mmc_read_low) | |
| 235 | return (*state->m_mmc_read_low)(space, offset); | |
| 236 | else | |
| 237 | logerror("Unimplemented LOW mapper read, offset: %04x\n", offset + 0x4100); | |
| 238 | ||
| 239 | return 0; | |
| 240 | } | |
| 241 | ||
| 242 | /************************************************************* | |
| 243 | ||
| 244 | Helpers to handle MMC | |
| 245 | ||
| 246 | *************************************************************/ | |
| 247 | ||
| 248 | static void wram_bank( running_machine &machine, int bank, int source ) | |
| 249 | { | |
| 250 | nes_state *state = machine.driver_data<nes_state>(); | |
| 251 | ||
| 252 | assert(state->m_battery || state->m_prg_ram); | |
| 253 | if (source == NES_BATTERY) | |
| 254 | { | |
| 255 | bank &= (state->m_battery_size / 0x2000) - 1; | |
| 256 | state->m_prg_bank[4] = state->m_battery_bank5_start + bank; | |
| 257 | } | |
| 258 | else | |
| 259 | { | |
| 260 | bank &= (state->m_wram_size / 0x2000) - 1; | |
| 261 | state->m_prg_bank[4] = state->m_prgram_bank5_start + bank; | |
| 262 | } | |
| 263 | memory_set_bank(machine, "bank5", state->m_prg_bank[4]); | |
| 264 | } | |
| 265 | ||
| 266 | INLINE void prg_bank_refresh( running_machine &machine ) | |
| 267 | { | |
| 268 | nes_state *state = machine.driver_data<nes_state>(); | |
| 269 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 270 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 271 | memory_set_bank(machine, "bank3", state->m_prg_bank[2]); | |
| 272 | memory_set_bank(machine, "bank4", state->m_prg_bank[3]); | |
| 273 | } | |
| 274 | ||
| 275 | /* PRG ROM in 8K, 16K or 32K blocks */ | |
| 276 | ||
| 277 | static void prg32( running_machine &machine, int bank ) | |
| 278 | { | |
| 279 | nes_state *state = machine.driver_data<nes_state>(); | |
| 280 | ||
| 281 | /* if there is only 16k PRG, return */ | |
| 282 | if (!(state->m_prg_chunks >> 1)) | |
| 283 | return; | |
| 284 | ||
| 285 | /* assumes that bank references a 32k chunk */ | |
| 286 | bank &= ((state->m_prg_chunks >> 1) - 1); | |
| 287 | ||
| 288 | state->m_prg_bank[0] = bank * 4 + 0; | |
| 289 | state->m_prg_bank[1] = bank * 4 + 1; | |
| 290 | state->m_prg_bank[2] = bank * 4 + 2; | |
| 291 | state->m_prg_bank[3] = bank * 4 + 3; | |
| 292 | prg_bank_refresh(machine); | |
| 293 | } | |
| 294 | ||
| 295 | static void prg16_89ab( running_machine &machine, int bank ) | |
| 296 | { | |
| 297 | nes_state *state = machine.driver_data<nes_state>(); | |
| 298 | ||
| 299 | /* assumes that bank references a 16k chunk */ | |
| 300 | bank &= (state->m_prg_chunks - 1); | |
| 301 | ||
| 302 | state->m_prg_bank[0] = bank * 2 + 0; | |
| 303 | state->m_prg_bank[1] = bank * 2 + 1; | |
| 304 | prg_bank_refresh(machine); | |
| 305 | } | |
| 306 | ||
| 307 | static void prg16_cdef( running_machine &machine, int bank ) | |
| 308 | { | |
| 309 | nes_state *state = machine.driver_data<nes_state>(); | |
| 310 | ||
| 311 | /* assumes that bank references a 16k chunk */ | |
| 312 | bank &= (state->m_prg_chunks - 1); | |
| 313 | ||
| 314 | state->m_prg_bank[2] = bank * 2 + 0; | |
| 315 | state->m_prg_bank[3] = bank * 2 + 1; | |
| 316 | prg_bank_refresh(machine); | |
| 317 | } | |
| 318 | ||
| 319 | static void prg8_89( running_machine &machine, int bank ) | |
| 320 | { | |
| 321 | nes_state *state = machine.driver_data<nes_state>(); | |
| 322 | ||
| 323 | /* assumes that bank references an 8k chunk */ | |
| 324 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 325 | ||
| 326 | state->m_prg_bank[0] = bank; | |
| 327 | prg_bank_refresh(machine); | |
| 328 | } | |
| 329 | ||
| 330 | static void prg8_ab( running_machine &machine, int bank ) | |
| 331 | { | |
| 332 | nes_state *state = machine.driver_data<nes_state>(); | |
| 333 | ||
| 334 | /* assumes that bank references an 8k chunk */ | |
| 335 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 336 | ||
| 337 | state->m_prg_bank[1] = bank; | |
| 338 | prg_bank_refresh(machine); | |
| 339 | } | |
| 340 | ||
| 341 | static void prg8_cd( running_machine &machine, int bank ) | |
| 342 | { | |
| 343 | nes_state *state = machine.driver_data<nes_state>(); | |
| 344 | ||
| 345 | /* assumes that bank references an 8k chunk */ | |
| 346 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 347 | ||
| 348 | state->m_prg_bank[2] = bank; | |
| 349 | prg_bank_refresh(machine); | |
| 350 | } | |
| 351 | ||
| 352 | static void prg8_ef( running_machine &machine, int bank ) | |
| 353 | { | |
| 354 | nes_state *state = machine.driver_data<nes_state>(); | |
| 355 | ||
| 356 | /* assumes that bank references an 8k chunk */ | |
| 357 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 358 | ||
| 359 | state->m_prg_bank[3] = bank; | |
| 360 | prg_bank_refresh(machine); | |
| 361 | } | |
| 362 | ||
| 363 | /* We define an additional helper to map PRG-ROM to 0x6000-0x7000 */ | |
| 364 | // TODO: are we implementing this correctly in the mappers which uses it? check! | |
| 365 | ||
| 366 | static void prg8_67( running_machine &machine, int bank ) | |
| 367 | { | |
| 368 | nes_state *state = machine.driver_data<nes_state>(); | |
| 369 | ||
| 370 | /* assumes that bank references an 8k chunk */ | |
| 371 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 372 | ||
| 373 | state->m_prg_bank[4] = bank; | |
| 374 | memory_set_bank(machine, "bank5", state->m_prg_bank[4]); | |
| 375 | } | |
| 376 | ||
| 377 | /* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */ | |
| 378 | static void prg8_x( running_machine &machine, int start, int bank ) | |
| 379 | { | |
| 380 | nes_state *state = machine.driver_data<nes_state>(); | |
| 381 | ||
| 382 | assert(start < 4); | |
| 383 | ||
| 384 | /* assumes that bank references an 8k chunk */ | |
| 385 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 386 | ||
| 387 | state->m_prg_bank[start] = bank; | |
| 388 | prg_bank_refresh(machine); | |
| 389 | } | |
| 390 | ||
| 391 | /* CHR ROM in 1K, 2K, 4K or 8K blocks */ | |
| 392 | ||
| 393 | // this can be probably removed later, but it is useful while testing xml and unf handling with VRAM & VROM | |
| 394 | INLINE void chr_sanity_check( running_machine &machine, int source ) | |
| 395 | { | |
| 396 | nes_state *state = machine.driver_data<nes_state>(); | |
| 397 | ||
| 398 | if (source == CHRRAM && state->m_vram == NULL) | |
| 399 | fatalerror("CHRRAM bankswitch with no VRAM"); | |
| 400 | ||
| 401 | if (source == CHRROM && state->m_vrom == NULL) | |
| 402 | fatalerror("CHRROM bankswitch with no VROM"); | |
| 403 | } | |
| 404 | ||
| 405 | static void chr8( running_machine &machine, int bank, int source ) | |
| 406 | { | |
| 407 | nes_state *state = machine.driver_data<nes_state>(); | |
| 408 | int i; | |
| 409 | ||
| 410 | chr_sanity_check(machine, source); | |
| 411 | ||
| 412 | if (source == CHRRAM) | |
| 413 | { | |
| 414 | bank &= (state->m_vram_chunks - 1); | |
| 415 | for (i = 0; i < 8; i++) | |
| 416 | { | |
| 417 | state->m_chr_map[i].source = source; | |
| 418 | state->m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses! | |
| 419 | state->m_chr_map[i].access = &state->m_vram[state->m_chr_map[i].origin]; | |
| 420 | } | |
| 421 | } | |
| 422 | else | |
| 423 | { | |
| 424 | bank &= (state->m_chr_chunks - 1); | |
| 425 | for (i = 0; i < 8; i++) | |
| 426 | { | |
| 427 | state->m_chr_map[i].source = source; | |
| 428 | state->m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses! | |
| 429 | state->m_chr_map[i].access = &state->m_vrom[state->m_chr_map[i].origin]; | |
| 430 | } | |
| 431 | } | |
| 432 | } | |
| 433 | ||
| 434 | static void chr4_x( running_machine &machine, int start, int bank, int source ) | |
| 435 | { | |
| 436 | nes_state *state = machine.driver_data<nes_state>(); | |
| 437 | int i; | |
| 438 | ||
| 439 | chr_sanity_check(machine, source); | |
| 440 | ||
| 441 | if (source == CHRRAM) | |
| 442 | { | |
| 443 | bank &= ((state->m_vram_chunks << 1) - 1); | |
| 444 | for (i = 0; i < 4; i++) | |
| 445 | { | |
| 446 | state->m_chr_map[i + start].source = source; | |
| 447 | state->m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses! | |
| 448 | state->m_chr_map[i + start].access = &state->m_vram[state->m_chr_map[i + start].origin]; | |
| 449 | } | |
| 450 | } | |
| 451 | else | |
| 452 | { | |
| 453 | bank &= ((state->m_chr_chunks << 1) - 1); | |
| 454 | for (i = 0; i < 4; i++) | |
| 455 | { | |
| 456 | state->m_chr_map[i + start].source = source; | |
| 457 | state->m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses! | |
| 458 | state->m_chr_map[i + start].access = &state->m_vrom[state->m_chr_map[i + start].origin]; | |
| 459 | } | |
| 460 | } | |
| 461 | } | |
| 462 | ||
| 463 | static void chr4_0( running_machine &machine, int bank, int source ) | |
| 464 | { | |
| 465 | chr4_x(machine, 0, bank, source); | |
| 466 | } | |
| 467 | ||
| 468 | static void chr4_4( running_machine &machine, int bank, int source ) | |
| 469 | { | |
| 470 | chr4_x(machine, 4, bank, source); | |
| 471 | } | |
| 472 | ||
| 473 | static void chr2_x( running_machine &machine, int start, int bank, int source ) | |
| 474 | { | |
| 475 | nes_state *state = machine.driver_data<nes_state>(); | |
| 476 | int i; | |
| 477 | ||
| 478 | chr_sanity_check(machine, source); | |
| 479 | ||
| 480 | if (source == CHRRAM) | |
| 481 | { | |
| 482 | bank &= ((state->m_vram_chunks << 2) - 1); | |
| 483 | for (i = 0; i < 2; i++) | |
| 484 | { | |
| 485 | state->m_chr_map[i + start].source = source; | |
| 486 | state->m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses! | |
| 487 | state->m_chr_map[i + start].access = &state->m_vram[state->m_chr_map[i + start].origin]; | |
| 488 | } | |
| 489 | } | |
| 490 | else | |
| 491 | { | |
| 492 | bank &= ((state->m_chr_chunks << 2) - 1); | |
| 493 | for (i = 0; i < 2; i++) | |
| 494 | { | |
| 495 | state->m_chr_map[i + start].source = source; | |
| 496 | state->m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses! | |
| 497 | state->m_chr_map[i + start].access = &state->m_vrom[state->m_chr_map[i + start].origin]; | |
| 498 | } | |
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | static void chr2_0( running_machine &machine, int bank, int source ) | |
| 503 | { | |
| 504 | chr2_x(machine, 0, bank, source); | |
| 505 | } | |
| 506 | ||
| 507 | static void chr2_2( running_machine &machine, int bank, int source ) | |
| 508 | { | |
| 509 | chr2_x(machine, 2, bank, source); | |
| 510 | } | |
| 511 | ||
| 512 | static void chr2_4( running_machine &machine, int bank, int source ) | |
| 513 | { | |
| 514 | chr2_x(machine, 4, bank, source); | |
| 515 | } | |
| 516 | ||
| 517 | static void chr2_6( running_machine &machine, int bank, int source ) | |
| 518 | { | |
| 519 | chr2_x(machine, 6, bank, source); | |
| 520 | } | |
| 521 | ||
| 522 | static void chr1_x( running_machine &machine, int start, int bank, int source ) | |
| 523 | { | |
| 524 | nes_state *state = machine.driver_data<nes_state>(); | |
| 525 | ||
| 526 | chr_sanity_check(machine, source); | |
| 527 | ||
| 528 | if (source == CHRRAM) | |
| 529 | { | |
| 530 | bank &= ((state->m_vram_chunks << 3) - 1); | |
| 531 | state->m_chr_map[start].source = source; | |
| 532 | state->m_chr_map[start].origin = (bank * 0x400); // for save state uses! | |
| 533 | state->m_chr_map[start].access = &state->m_vram[state->m_chr_map[start].origin]; | |
| 534 | } | |
| 535 | else | |
| 536 | { | |
| 537 | bank &= ((state->m_chr_chunks << 3) - 1); | |
| 538 | state->m_chr_map[start].source = source; | |
| 539 | state->m_chr_map[start].origin = (bank * 0x400); // for save state uses! | |
| 540 | state->m_chr_map[start].access = &state->m_vrom[state->m_chr_map[start].origin]; | |
| 541 | } | |
| 542 | } | |
| 543 | ||
| 544 | static void chr1_0 (running_machine &machine, int bank, int source) | |
| 545 | { | |
| 546 | chr1_x(machine, 0, bank, source); | |
| 547 | } | |
| 548 | ||
| 549 | static void chr1_1( running_machine &machine, int bank, int source ) | |
| 550 | { | |
| 551 | chr1_x(machine, 1, bank, source); | |
| 552 | } | |
| 553 | ||
| 554 | static void chr1_2( running_machine &machine, int bank, int source ) | |
| 555 | { | |
| 556 | chr1_x(machine, 2, bank, source); | |
| 557 | } | |
| 558 | ||
| 559 | static void chr1_3( running_machine &machine, int bank, int source ) | |
| 560 | { | |
| 561 | chr1_x(machine, 3, bank, source); | |
| 562 | } | |
| 563 | ||
| 564 | static void chr1_4( running_machine &machine, int bank, int source ) | |
| 565 | { | |
| 566 | chr1_x(machine, 4, bank, source); | |
| 567 | } | |
| 568 | ||
| 569 | static void chr1_5( running_machine &machine, int bank, int source ) | |
| 570 | { | |
| 571 | chr1_x(machine, 5, bank, source); | |
| 572 | } | |
| 573 | ||
| 574 | static void chr1_6( running_machine &machine, int bank, int source ) | |
| 575 | { | |
| 576 | chr1_x(machine, 6, bank, source); | |
| 577 | } | |
| 578 | ||
| 579 | static void chr1_7( running_machine &machine, int bank, int source ) | |
| 580 | { | |
| 581 | chr1_x(machine, 7, bank, source); | |
| 582 | } | |
| 583 | ||
| 584 | ||
| 585 | /* NameTable paging and mirroring */ | |
| 586 | ||
| 587 | static void set_nt_page( running_machine &machine, int page, int source, int bank, int writable ) | |
| 588 | { | |
| 589 | nes_state *state = machine.driver_data<nes_state>(); | |
| 590 | UINT8* base_ptr; | |
| 591 | ||
| 592 | switch (source) | |
| 593 | { | |
| 594 | case CART_NTRAM: | |
| 595 | base_ptr = state->m_extended_ntram; | |
| 596 | break; | |
| 597 | case MMC5FILL: | |
| 598 | base_ptr = NULL; | |
| 599 | break; | |
| 600 | case ROM: | |
| 601 | base_ptr = state->m_vrom; | |
| 602 | break; | |
| 603 | case EXRAM: | |
| 604 | base_ptr = state->m_mapper_ram; | |
| 605 | break; | |
| 606 | case CIRAM: | |
| 607 | default: | |
| 608 | base_ptr = state->m_ciram; | |
| 609 | break; | |
| 610 | } | |
| 611 | ||
| 612 | page &= 3; /* mask down to the 4 logical pages */ | |
| 613 | state->m_nt_page[page].source = source; | |
| 614 | ||
| 615 | if (base_ptr != NULL) | |
| 616 | { | |
| 617 | state->m_nt_page[page].origin = bank * 0x400; | |
| 618 | state->m_nt_page[page].access = base_ptr + state->m_nt_page[page].origin; | |
| 619 | } | |
| 620 | ||
| 621 | state->m_nt_page[page].writable = writable; | |
| 622 | } | |
| 623 | ||
| 624 | void set_nt_mirroring( running_machine &machine, int mirroring ) | |
| 625 | { | |
| 626 | /* setup our videomem handlers based on mirroring */ | |
| 627 | switch (mirroring) | |
| 628 | { | |
| 629 | case PPU_MIRROR_VERT: | |
| 630 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 631 | set_nt_page(machine, 1, CIRAM, 1, 1); | |
| 632 | set_nt_page(machine, 2, CIRAM, 0, 1); | |
| 633 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 634 | break; | |
| 635 | ||
| 636 | case PPU_MIRROR_HORZ: | |
| 637 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 638 | set_nt_page(machine, 1, CIRAM, 0, 1); | |
| 639 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 640 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 641 | break; | |
| 642 | ||
| 643 | case PPU_MIRROR_HIGH: | |
| 644 | set_nt_page(machine, 0, CIRAM, 1, 1); | |
| 645 | set_nt_page(machine, 1, CIRAM, 1, 1); | |
| 646 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 647 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 648 | break; | |
| 649 | ||
| 650 | case PPU_MIRROR_LOW: | |
| 651 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 652 | set_nt_page(machine, 1, CIRAM, 0, 1); | |
| 653 | set_nt_page(machine, 2, CIRAM, 0, 1); | |
| 654 | set_nt_page(machine, 3, CIRAM, 0, 1); | |
| 655 | break; | |
| 656 | ||
| 657 | case PPU_MIRROR_NONE: | |
| 658 | case PPU_MIRROR_4SCREEN: | |
| 659 | default: | |
| 660 | /* external RAM needs to be used somehow. */ | |
| 661 | /* but as a default, we'll arbitrarily set vertical so as not to crash*/ | |
| 662 | /* mappers should use set_nt_page and assign which pages are which */ | |
| 663 | ||
| 664 | logerror("Mapper set 4-screen mirroring without supplying external nametable memory!\n"); | |
| 665 | ||
| 666 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 667 | set_nt_page(machine, 1, CIRAM, 0, 1); | |
| 668 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 669 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 670 | break; | |
| 671 | } | |
| 672 | } | |
| 673 | ||
| 674 | /* Other custom mirroring helpers are defined below: Waixing games use waixing_set_mirror (which swaps | |
| 675 | MIRROR_HIGH and MIRROR_LOW compared to the above) and Sachen games use sachen_set_mirror (which has | |
| 676 | a slightly different MIRROR_HIGH, with page 0 set to 0) */ | |
| 677 | ||
| 678 | ||
| 679 | /************************************************************* | |
| 680 | ||
| 681 | Support for xml list | |
| 682 | ||
| 683 | *************************************************************/ | |
| 684 | ||
| 685 | /* Include emulation of NES PCBs for softlist */ | |
| 686 | #include "machine/nes_pcb.c" | |
| 687 | ||
| 688 | ||
| 689 | /************************************************************* | |
| 690 | ||
| 691 | Support for .unf Files | |
| 692 | ||
| 693 | *************************************************************/ | |
| 694 | ||
| 695 | /* Include emulation of UNIF Boards for .unf files */ | |
| 696 | #include "machine/nes_unif.c" | |
| 697 | ||
| 698 | ||
| 699 | /************************************************************* | |
| 700 | ||
| 701 | Support for .nes Files | |
| 702 | ||
| 703 | *************************************************************/ | |
| 704 | ||
| 705 | /* Include emulation of iNES Mappers for .nes files */ | |
| 706 | #include "machine/nes_ines.c" | |
| 707 |
| r11531 | r11532 | |
|---|---|---|
| 1 | #ifndef __MMC_H | |
| 2 | #define __MMC_H | |
| 3 | ||
| 4 | /* Boards */ | |
| 5 | enum | |
| 6 | { | |
| 7 | STD_NROM = 0, | |
| 8 | STD_AXROM, STD_BXROM, STD_CNROM, STD_CPROM, | |
| 9 | STD_DXROM, STD_EXROM, STD_FXROM, STD_GXROM, | |
| 10 | STD_HKROM, STD_JXROM, STD_MXROM, STD_NXROM, | |
| 11 | STD_PXROM, STD_SXROM, STD_TXROM, STD_TXSROM, | |
| 12 | STD_TKROM, STD_TQROM, STD_TVROM, | |
| 13 | STD_UN1ROM, STD_UXROM, | |
| 14 | HVC_FAMBASIC, NES_QJ, PAL_ZZ, UXROM_CC, | |
| 15 | STD_DRROM, STD_SXROM_A, STD_SOROM, STD_SOROM_A, | |
| 16 | /* Discrete components boards (by various manufacturer) */ | |
| 17 | DIS_74X161X138, DIS_74X139X74, | |
| 18 | DIS_74X377, DIS_74X161X161X32, | |
| 19 | /* Active Enterprises */ | |
| 20 | ACTENT_ACT52, | |
| 21 | /* AGCI */ | |
| 22 | AGCI_50282, | |
| 23 | /* AVE */ | |
| 24 | AVE_NINA01, AVE_NINA06, | |
| 25 | /* Bandai */ | |
| 26 | BANDAI_JUMP2, BANDAI_PT554, | |
| 27 | BANDAI_DATACH, BANDAI_KARAOKE, BANDAI_OEKAKIDS, | |
| 28 | BANDAI_FCG, BANDAI_LZ93, BANDAI_LZ93EX, | |
| 29 | /* Caltron */ | |
| 30 | CALTRON_6IN1, | |
| 31 | /* Camerica */ | |
| 32 | CAMERICA_BF9093, CAMERICA_BF9097, CAMERICA_BF9096, | |
| 33 | CAMERICA_GOLDENFIVE, GG_NROM, | |
| 34 | /* Dreamtech */ | |
| 35 | DREAMTECH_BOARD, | |
| 36 | /* Irem */ | |
| 37 | IREM_G101, IREM_H3001, IREM_LROG017, | |
| 38 | IREM_TAM_S1, IREM_HOLYDIV, | |
| 39 | /* Jaleco */ | |
| 40 | JALECO_SS88006, JALECO_JF11, JALECO_JF13, | |
| 41 | JALECO_JF16, JALECO_JF17, JALECO_JF19, | |
| 42 | /* Konami */ | |
| 43 | KONAMI_VRC1, KONAMI_VRC2, KONAMI_VRC3, | |
| 44 | KONAMI_VRC4, KONAMI_VRC6, KONAMI_VRC7, | |
| 45 | /* Namcot */ | |
| 46 | NAMCOT_163, NAMCOT_3453, | |
| 47 | NAMCOT_3425, NAMCOT_34X3, NAMCOT_3446, | |
| 48 | /* NTDEC */ | |
| 49 | NTDEC_ASDER, NTDEC_FIGHTINGHERO, | |
| 50 | /* Rex Soft */ | |
| 51 | REXSOFT_SL1632, REXSOFT_DBZ5, | |
| 52 | /* Sachen */ | |
| 53 | SACHEN_8259A, SACHEN_8259B, SACHEN_8259C, SACHEN_8259D, | |
| 54 | SACHEN_SA009, SACHEN_SA0036, SACHEN_SA0037, | |
| 55 | SACHEN_SA72007, SACHEN_SA72008, SACHEN_TCA01, | |
| 56 | SACHEN_TCU01, SACHEN_TCU02, | |
| 57 | SACHEN_74LS374, SACHEN_74LS374_A, | |
| 58 | /* Sunsoft */ | |
| 59 | SUNSOFT_1, SUNSOFT_2, SUNSOFT_3, SUNSOFT_4, | |
| 60 | SUNSOFT_DCS, SUNSOFT_5B, SUNSOFT_FME7, | |
| 61 | /* Taito */ | |
| 62 | TAITO_TC0190FMC, TAITO_TC0190FMCP, | |
| 63 | TAITO_X1_005, TAITO_X1_005_A, TAITO_X1_017, | |
| 64 | /* Tengen */ | |
| 65 | TENGEN_800008, TENGEN_800032, TENGEN_800037, | |
| 66 | /* TXC */ | |
| 67 | TXC_22211A, TXC_22211B, TXC_22211C, | |
| 68 | TXC_MXMDHTWO, TXC_TW, TXC_STRIKEWOLF, | |
| 69 | /* Multigame Carts */ | |
| 70 | BMC_64IN1NR, BMC_190IN1, BMC_A65AS, BMC_GS2004, BMC_GS2013, | |
| 71 | BMC_HIK8IN1, BMC_NOVELDIAMOND, BMC_S24IN1SC03, BMC_T262, | |
| 72 | BMC_WS, BMC_SUPERBIG_7IN1, BMC_SUPERHIK_4IN1, BMC_BALLGAMES_11IN1, | |
| 73 | BMC_MARIOPARTY_7IN1, BMC_SUPER_700IN1, BMC_FAMILY_4646B, | |
| 74 | BMC_36IN1, BMC_21IN1, BMC_150IN1, BMC_35IN1, BMC_64IN1, | |
| 75 | BMC_15IN1, BMC_SUPERHIK_300IN1, BMC_9999999IN1, BMC_SUPERGUN_20IN1, | |
| 76 | BMC_GOLDENCARD_6IN1, BMC_72IN1, BMC_SUPER_42IN1, BMC_76IN1, | |
| 77 | BMC_1200IN1, BMC_31IN1, BMC_22GAMES, BMC_20IN1, BMC_110IN1, | |
| 78 | BMC_GKA, BMC_GKB, BMC_VT5201, BMC_BENSHENG_BS5, BMC_810544, | |
| 79 | BMC_NTD_03, BMC_G63IN1, BMC_FK23C, BMC_FK23CA, BMC_PJOY84, | |
| 80 | /* Unlicensed */ | |
| 81 | UNL_8237, UNL_CC21, UNL_AX5705, UNL_KOF97, | |
| 82 | UNL_N625092, UNL_SC127, UNL_SMB2J, UNL_T230, | |
| 83 | UNL_UXROM, UNL_MK2, UNL_XZY, UNL_KOF96, | |
| 84 | UNL_SUPERFIGHTER3, UNL_RACERMATE, UNL_EDU2K, | |
| 85 | UNL_SHJY3, UNL_STUDYNGAME, UNL_603_5052, UNL_H2288, | |
| 86 | /* Bootleg boards */ | |
| 87 | BTL_SMB2A, BTL_MARIOBABY, BTL_AISENSHINICOL, BTL_TOBIDASE, | |
| 88 | BTL_SMB2B, BTL_SMB3, BTL_SUPERBROS11, BTL_DRAGONNINJA, | |
| 89 | BTL_PIKACHUY2K, | |
| 90 | /* Misc: these are needed to convert mappers to boards, I will sort them later */ | |
| 91 | OPENCORP_DAOU306, HES_BOARD, HES6IN1_BOARD, RUMBLESTATION_BOARD, | |
| 92 | MAGICSERIES_MD, KASING_BOARD, FUTUREMEDIA_BOARD, FUKUTAKE_BOARD, SOMERI_SL12, | |
| 93 | HENGEDIANZI_BOARD, HENGEDIANZI_XJZB, SUBOR_TYPE0, SUBOR_TYPE1, | |
| 94 | KAISER_KS7058, KAISER_KS7032, KAISER_KS7022, KAISER_KS7017, KAISER_KS202, CONY_BOARD, | |
| 95 | CNE_DECATHLON, CNE_FSB, CNE_SHLZ, RCM_GS2015, RCM_TETRISFAMILY, | |
| 96 | WAIXING_TYPE_A, WAIXING_TYPE_A_1, WAIXING_TYPE_B, WAIXING_TYPE_C, WAIXING_TYPE_D, | |
| 97 | WAIXING_TYPE_E, WAIXING_TYPE_F, WAIXING_TYPE_G, WAIXING_TYPE_H, | |
| 98 | WAIXING_TYPE_I, WAIXING_TYPE_J, | |
| 99 | WAIXING_SGZLZ, WAIXING_SGZ, WAIXING_ZS, WAIXING_SECURITY, WAIXING_SH2, | |
| 100 | WAIXING_DQ8, WAIXING_FFV, WAIXING_PS2, SUPERGAME_LIONKING, SUPERGAME_BOOGERMAN, | |
| 101 | KAY_PANDAPRINCE, HOSENKAN_BOARD, NITRA_TDA, GOUDER_37017, NANJING_BOARD, | |
| 102 | WHIRLWIND_2706, | |
| 103 | /* FFE boards, for mappers 6, 8, 17 */ | |
| 104 | FFE_MAPPER6, FFE_MAPPER8, FFE_MAPPER17, | |
| 105 | /* Unsupported (for place-holder boards, with no working emulation) & no-board (at init) */ | |
| 106 | UNSUPPORTED_BOARD, UNKNOWN_BOARD, NO_BOARD | |
| 107 | }; | |
| 108 | ||
| 109 | // these are used to setup the proper PCB ID, for each supported type of files | |
| 110 | int nes_get_pcb_id(running_machine &machine, const char *feature); // for softlist | |
| 111 | void unif_mapr_setup(running_machine &machine, const char *board); // for UNIF files | |
| 112 | int nes_get_mmc_id(running_machine &machine, int mapper); // for iNES files | |
| 113 | ||
| 114 | // these are used to setup handlers and callbacks necessary to the emulation (resp. at start and reset) | |
| 115 | void pcb_handlers_setup(running_machine &machine); | |
| 116 | int nes_pcb_reset(running_machine &machine); | |
| 117 | ||
| 118 | ||
| 119 | WRITE8_HANDLER( nes_low_mapper_w ); | |
| 120 | READ8_HANDLER( nes_low_mapper_r ); | |
| 121 | WRITE8_HANDLER( nes_chr_w ); | |
| 122 | READ8_HANDLER( nes_chr_r ); | |
| 123 | WRITE8_HANDLER( nes_nt_w ); | |
| 124 | READ8_HANDLER( nes_nt_r ); | |
| 125 | ||
| 126 | WRITE8_HANDLER( smb2jb_extra_w ); | |
| 127 | WRITE8_HANDLER( ks7017_extra_w ); | |
| 128 | READ8_HANDLER( ks7017_extra_r ); | |
| 129 | WRITE8_HANDLER( unl_6035052_extra_w ); | |
| 130 | READ8_HANDLER( unl_6035052_extra_r ); | |
| 131 | READ8_HANDLER( waixing_sh2_chr_r ); | |
| 132 | ||
| 133 | //TEMPORARY PPU STUFF | |
| 134 | ||
| 135 | /* mirroring types */ | |
| 136 | #define PPU_MIRROR_NONE 0 | |
| 137 | #define PPU_MIRROR_VERT 1 | |
| 138 | #define PPU_MIRROR_HORZ 2 | |
| 139 | #define PPU_MIRROR_HIGH 3 | |
| 140 | #define PPU_MIRROR_LOW 4 | |
| 141 | #define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror | |
| 142 | ||
| 143 | void set_nt_mirroring(running_machine &machine, int mirroring); | |
| 144 | ||
| 145 | ||
| 146 | #endif |
| r11531 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES MMC Emulation | |
| 4 | ||
| 5 | Support for iNES Mappers | |
| 6 | ||
| 7 | ****************************************************************************************/ | |
| 8 | ||
| 9 | typedef struct _nes_mmc nes_mmc; | |
| 10 | struct _nes_mmc | |
| 11 | { | |
| 12 | int iNesMapper; /* iNES Mapper # */ | |
| 13 | int pcb_id; | |
| 14 | }; | |
| 15 | ||
| 16 | /************************************************************* | |
| 17 | ||
| 18 | Mapper 6 | |
| 19 | ||
| 20 | Known Boards: FFE4 Copier Board | |
| 21 | Games: Hacked versions of games | |
| 22 | ||
| 23 | In MESS: Supported? Not sure if we could also have ExRAM or not... | |
| 24 | However, priority is pretty low for this mapper. | |
| 25 | ||
| 26 | *************************************************************/ | |
| 27 | ||
| 28 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 29 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 30 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 31 | static void ffe_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 32 | { | |
| 33 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 34 | ||
| 35 | /* 114 is the number of cycles per scanline */ | |
| 36 | /* TODO: change to reflect the actual number of cycles spent */ | |
| 37 | if (state->m_IRQ_enable) | |
| 38 | { | |
| 39 | if ((0xffff - state->m_IRQ_count) < 114) | |
| 40 | { | |
| 41 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 42 | state->m_IRQ_count = 0xffff; | |
| 43 | state->m_IRQ_enable = 0; | |
| 44 | } | |
| 45 | state->m_IRQ_count -= 114; | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | static WRITE8_HANDLER( mapper6_l_w ) | |
| 50 | { | |
| 51 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 52 | LOG_MMC(("mapper6_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 53 | ||
| 54 | switch (offset) | |
| 55 | { | |
| 56 | case 0x1fe: | |
| 57 | state->m_mmc_latch1 = data & 0x80; | |
| 58 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 59 | break; | |
| 60 | case 0x1ff: | |
| 61 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 62 | break; | |
| 63 | ||
| 64 | case 0x401: | |
| 65 | state->m_IRQ_enable = data & 0x01; | |
| 66 | break; | |
| 67 | case 0x402: | |
| 68 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 69 | break; | |
| 70 | case 0x403: | |
| 71 | state->m_IRQ_enable = 1; | |
| 72 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 73 | break; | |
| 74 | } | |
| 75 | } | |
| 76 | ||
| 77 | static WRITE8_HANDLER( mapper6_w ) | |
| 78 | { | |
| 79 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 80 | LOG_MMC(("mapper6_w, offset: %04x, data: %02x\n", offset, data)); | |
| 81 | ||
| 82 | if (!state->m_mmc_latch1) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank? | |
| 83 | { | |
| 84 | prg16_89ab(space->machine(), data >> 2); | |
| 85 | // chr8(space->machine(), data & 0x03, ???); | |
| 86 | // due to lack of info on the exact behavior, we simply act as if mmc_latch1=1 | |
| 87 | if (state->m_mmc_chr_source == CHRROM) | |
| 88 | chr8(space->machine(), data & 0x03, CHRROM); | |
| 89 | } | |
| 90 | else if (state->m_mmc_chr_source == CHRROM) // otherwise, we can use CHRROM (when present) | |
| 91 | chr8(space->machine(), data, CHRROM); | |
| 92 | } | |
| 93 | ||
| 94 | /************************************************************* | |
| 95 | ||
| 96 | Mapper 8 | |
| 97 | ||
| 98 | Known Boards: FFE3 Copier Board | |
| 99 | Games: Hacked versions of games | |
| 100 | ||
| 101 | In MESS: Supported? (I have no games to test this) | |
| 102 | ||
| 103 | *************************************************************/ | |
| 104 | ||
| 105 | static WRITE8_HANDLER( mapper8_w ) | |
| 106 | { | |
| 107 | LOG_MMC(("mapper8_w, offset: %04x, data: %02x\n", offset, data)); | |
| 108 | ||
| 109 | chr8(space->machine(), data & 0x07, CHRROM); | |
| 110 | prg16_89ab(space->machine(), data >> 3); | |
| 111 | } | |
| 112 | ||
| 113 | /************************************************************* | |
| 114 | ||
| 115 | Mapper 17 | |
| 116 | ||
| 117 | Known Boards: FFE8 Copier Board | |
| 118 | Games: Hacked versions of games | |
| 119 | ||
| 120 | In MESS: Supported?. IRQ support is just a guess (used to | |
| 121 | use MMC3 IRQ but it was wrong and it never enabled it) | |
| 122 | ||
| 123 | *************************************************************/ | |
| 124 | ||
| 125 | static WRITE8_HANDLER( mapper17_l_w ) | |
| 126 | { | |
| 127 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 128 | LOG_MMC(("mapper17_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 129 | ||
| 130 | switch (offset) | |
| 131 | { | |
| 132 | case 0x1fe: | |
| 133 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 134 | break; | |
| 135 | case 0x1ff: | |
| 136 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 137 | break; | |
| 138 | ||
| 139 | case 0x401: | |
| 140 | state->m_IRQ_enable = data & 0x01; | |
| 141 | break; | |
| 142 | case 0x402: | |
| 143 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 144 | break; | |
| 145 | case 0x403: | |
| 146 | state->m_IRQ_enable = 1; | |
| 147 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 148 | break; | |
| 149 | ||
| 150 | case 0x404: | |
| 151 | prg8_89(space->machine(), data); | |
| 152 | break; | |
| 153 | case 0x405: | |
| 154 | prg8_ab(space->machine(), data); | |
| 155 | break; | |
| 156 | case 0x406: | |
| 157 | prg8_cd(space->machine(), data); | |
| 158 | break; | |
| 159 | case 0x407: | |
| 160 | prg8_ef(space->machine(), data); | |
| 161 | break; | |
| 162 | ||
| 163 | case 0x410: | |
| 164 | case 0x411: | |
| 165 | case 0x412: | |
| 166 | case 0x413: | |
| 167 | case 0x414: | |
| 168 | case 0x415: | |
| 169 | case 0x416: | |
| 170 | case 0x417: | |
| 171 | chr1_x(space->machine(), offset & 7, data, CHRROM); | |
| 172 | break; | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | /************************************************************* | |
| 177 | ||
| 178 | mmc_list | |
| 179 | ||
| 180 | Supported mappers and corresponding pcb id | |
| 181 | ||
| 182 | *************************************************************/ | |
| 183 | ||
| 184 | static const nes_mmc mmc_list[] = | |
| 185 | { | |
| 186 | /* INES DESC LOW_W, LOW_R, MED_W, HIGH_W, PPU_latch, scanline CB, hblank CB */ | |
| 187 | { 0, STD_NROM }, | |
| 188 | { 1, STD_SXROM }, | |
| 189 | { 2, STD_UXROM }, | |
| 190 | { 3, STD_CNROM }, | |
| 191 | { 4, STD_TXROM }, | |
| 192 | { 5, STD_EXROM }, | |
| 193 | { 6, FFE_MAPPER6 }, | |
| 194 | { 7, STD_AXROM }, | |
| 195 | { 8, FFE_MAPPER8 }, | |
| 196 | { 9, STD_PXROM }, | |
| 197 | { 10, STD_FXROM }, | |
| 198 | { 11, DIS_74X377 }, | |
| 199 | { 12, REXSOFT_DBZ5 }, | |
| 200 | { 13, STD_CPROM }, | |
| 201 | { 14, REXSOFT_SL1632 }, | |
| 202 | { 15, WAIXING_PS2 }, | |
| 203 | { 16, BANDAI_LZ93EX }, // with 24c02 | |
| 204 | { 17, FFE_MAPPER17 }, | |
| 205 | { 18, JALECO_SS88006 }, | |
| 206 | { 19, NAMCOT_163 }, | |
| 207 | { 21, KONAMI_VRC4 }, | |
| 208 | { 22, KONAMI_VRC2 }, | |
| 209 | { 23, KONAMI_VRC2 }, | |
| 210 | { 24, KONAMI_VRC6 }, | |
| 211 | { 25, KONAMI_VRC4 }, | |
| 212 | { 26, KONAMI_VRC6 }, | |
| 213 | // 27 World Hero board - Unsupported | |
| 214 | // 28 Unused | |
| 215 | // 29 Unused | |
| 216 | // 30 Unused | |
| 217 | // 31 Unused | |
| 218 | { 32, IREM_G101 }, | |
| 219 | { 33, TAITO_TC0190FMC }, | |
| 220 | { 34, STD_BXROM }, | |
| 221 | { 35, UNL_SC127 }, | |
| 222 | { 36, TXC_STRIKEWOLF }, | |
| 223 | { 37, PAL_ZZ }, | |
| 224 | { 38, DIS_74X161X138 }, | |
| 225 | { 39, UNL_STUDYNGAME }, | |
| 226 | { 40, BTL_SMB2A }, | |
| 227 | { 41, CALTRON_6IN1 }, | |
| 228 | { 42, BTL_MARIOBABY }, // ai senshi nicol? | |
| 229 | { 43, UNL_SMB2J }, | |
| 230 | { 44, BMC_SUPERBIG_7IN1 }, | |
| 231 | { 45, BMC_HIK8IN1 }, | |
| 232 | { 46, RUMBLESTATION_BOARD }, | |
| 233 | { 47, NES_QJ }, | |
| 234 | { 48, TAITO_TC0190FMCP }, | |
| 235 | { 49, BMC_SUPERHIK_4IN1 }, | |
| 236 | { 50, BTL_SMB2B }, | |
| 237 | { 51, BMC_BALLGAMES_11IN1 }, | |
| 238 | { 52, BMC_MARIOPARTY_7IN1 }, | |
| 239 | // 53 Supervision 16-in-1 - Unsupported | |
| 240 | { 54, BMC_NOVELDIAMOND }, | |
| 241 | // 55 Genius SMB - No info (nor images) available | |
| 242 | { 56, KAISER_KS202 }, | |
| 243 | { 57, BMC_GKA }, | |
| 244 | { 58, BMC_GKB }, | |
| 245 | // 59 Unused | |
| 246 | // 60 4-in-1, 35-in-1 Reset based | |
| 247 | { 61, RCM_TETRISFAMILY }, | |
| 248 | { 62, BMC_SUPER_700IN1 }, | |
| 249 | // 63 CH001 X-in-1 - No info (nor images) available | |
| 250 | { 64, TENGEN_800032 }, | |
| 251 | { 65, IREM_H3001 }, | |
| 252 | { 66, STD_GXROM }, | |
| 253 | { 67, SUNSOFT_3 }, | |
| 254 | { 68, STD_NXROM }, | |
| 255 | { 69, STD_JXROM }, | |
| 256 | { 70, DIS_74X161X161X32 }, | |
| 257 | { 71, CAMERICA_BF9093 }, | |
| 258 | { 72, JALECO_JF17 }, | |
| 259 | { 73, KONAMI_VRC3 }, | |
| 260 | { 74, WAIXING_TYPE_A }, | |
| 261 | { 75, KONAMI_VRC1 }, | |
| 262 | { 76, NAMCOT_3446 }, | |
| 263 | { 77, IREM_LROG017 }, | |
| 264 | { 78, IREM_HOLYDIV }, | |
| 265 | { 79, AVE_NINA06 }, | |
| 266 | { 80, TAITO_X1_005 }, | |
| 267 | // 81 Unused | |
| 268 | { 82, TAITO_X1_017 }, | |
| 269 | { 83, CONY_BOARD }, | |
| 270 | // 84 Pasofami hacked images? | |
| 271 | { 85, KONAMI_VRC7 }, | |
| 272 | { 86, JALECO_JF13 }, | |
| 273 | { 87, DIS_74X139X74 }, | |
| 274 | { 88, NAMCOT_34X3 }, | |
| 275 | { 89, SUNSOFT_2 }, | |
| 276 | // 90 JY Company Type A (Aladdin, Final Fight 3, Super Mario World, Tekken 2) - Unsupported | |
| 277 | { 91, UNL_MK2 }, | |
| 278 | { 92, JALECO_JF19 }, | |
| 279 | { 93, SUNSOFT_2 }, | |
| 280 | { 94, STD_UN1ROM }, | |
| 281 | { 95, NAMCOT_3425 }, | |
| 282 | { 96, BANDAI_OEKAKIDS }, | |
| 283 | { 97, IREM_TAM_S1 }, | |
| 284 | // 98 Unused | |
| 285 | // 99 VS. system - Not going to be implemented (use MAME instead) | |
| 286 | // 100 images hacked to work with nesticle? | |
| 287 | // 101 Unused (Urusei Yatsura had been assigned to this mapper, but it's Mapper 87) | |
| 288 | // 102 Unused | |
| 289 | // 103 Bootleg cart 2708 (Doki Doki Panic - FDS Conversion) - Unsupported | |
| 290 | { 104, CAMERICA_GOLDENFIVE }, | |
| 291 | // 105 Nintendo World Championship - Unsupported | |
| 292 | { 106, BTL_SMB3 }, | |
| 293 | { 107, MAGICSERIES_MD }, | |
| 294 | { 108, WHIRLWIND_2706 }, | |
| 295 | // 109 Unused | |
| 296 | // 110 Unused | |
| 297 | // 111 Ninja Ryuukenden Chinese? - Unsupported | |
| 298 | { 112, NTDEC_ASDER }, | |
| 299 | { 113, HES_BOARD }, | |
| 300 | { 114, SUPERGAME_LIONKING }, | |
| 301 | { 115, KASING_BOARD }, | |
| 302 | { 116, SOMERI_SL12 }, | |
| 303 | { 117, FUTUREMEDIA_BOARD }, | |
| 304 | { 118, STD_TXSROM }, | |
| 305 | { 119, STD_TQROM }, | |
| 306 | { 120, BTL_TOBIDASE }, | |
| 307 | { 121, KAY_PANDAPRINCE }, | |
| 308 | // 122 Unused | |
| 309 | { 123, UNL_H2288 }, | |
| 310 | // 124 Unused | |
| 311 | // 125 Unused | |
| 312 | { 126, BMC_PJOY84 }, | |
| 313 | // 127 Unused | |
| 314 | // 128 Unused | |
| 315 | // 129 Unused | |
| 316 | // 130 Unused | |
| 317 | // 131 Unused | |
| 318 | { 132, TXC_22211B }, | |
| 319 | { 133, SACHEN_SA72008 }, | |
| 320 | { 134, BMC_FAMILY_4646B }, | |
| 321 | // 135 Unused | |
| 322 | { 136, SACHEN_TCU02 }, | |
| 323 | { 137, SACHEN_8259D }, | |
| 324 | { 138, SACHEN_8259B }, | |
| 325 | { 139, SACHEN_8259C }, | |
| 326 | { 140, JALECO_JF11 }, | |
| 327 | { 141, SACHEN_8259A }, | |
| 328 | { 142, KAISER_KS7032}, | |
| 329 | { 143, SACHEN_TCA01 }, | |
| 330 | { 144, AGCI_50282 }, | |
| 331 | { 145, SACHEN_SA72007 }, | |
| 332 | { 146, AVE_NINA06 }, // basically same as Mapper 79 (Nina006) | |
| 333 | { 147, SACHEN_TCU01 }, | |
| 334 | { 148, SACHEN_SA0037 }, | |
| 335 | { 149, SACHEN_SA0036 }, | |
| 336 | { 150, SACHEN_74LS374 }, | |
| 337 | // 151 VS. system by Konami - Not going to be implemented (use MAME instead) | |
| 338 | { 152, DIS_74X161X161X32 }, | |
| 339 | { 153, BANDAI_LZ93 }, | |
| 340 | { 154, NAMCOT_3453 }, | |
| 341 | { 155, STD_SXROM_A }, // diff compared to MMC1 concern WRAM | |
| 342 | { 156, OPENCORP_DAOU306 }, | |
| 343 | { 157, BANDAI_DATACH }, // no Datach Reader -> we fall back to mapper 16 | |
| 344 | { 158, TENGEN_800037 }, | |
| 345 | { 159, BANDAI_LZ93EX }, // with 24c01 | |
| 346 | { 160, SACHEN_SA009 }, | |
| 347 | // 161 Unused | |
| 348 | // 162 Unused | |
| 349 | { 163, NANJING_BOARD}, | |
| 350 | { 164, WAIXING_FFV }, | |
| 351 | { 165, WAIXING_SH2 }, | |
| 352 | { 166, SUBOR_TYPE1 }, | |
| 353 | { 167, SUBOR_TYPE0 }, | |
| 354 | { 168, UNL_RACERMATE }, | |
| 355 | // 169 Unused | |
| 356 | // 170 Fujiya | |
| 357 | { 171, KAISER_KS7058 }, | |
| 358 | { 172, TXC_22211B }, | |
| 359 | { 173, TXC_22211C }, | |
| 360 | // 174 Unused | |
| 361 | { 175, KAISER_KS7022}, | |
| 362 | { 176, UNL_XZY }, | |
| 363 | { 177, HENGEDIANZI_BOARD }, | |
| 364 | { 178, WAIXING_SGZLZ }, | |
| 365 | { 179, HENGEDIANZI_XJZB }, | |
| 366 | { 180, UXROM_CC }, | |
| 367 | // 181 Unused | |
| 368 | { 182, HOSENKAN_BOARD }, | |
| 369 | // 183 FDS bootleg (Shui Guan Pipe) - Unsupported | |
| 370 | { 184, SUNSOFT_1 }, | |
| 371 | { 185, STD_CNROM }, | |
| 372 | { 186, FUKUTAKE_BOARD }, | |
| 373 | { 187, UNL_KOF96 }, | |
| 374 | { 188, BANDAI_KARAOKE }, | |
| 375 | { 189, TXC_TW }, | |
| 376 | // 190 Unused | |
| 377 | { 191, WAIXING_TYPE_B }, | |
| 378 | { 192, WAIXING_TYPE_C }, | |
| 379 | { 193, NTDEC_FIGHTINGHERO }, | |
| 380 | { 194, WAIXING_TYPE_D }, | |
| 381 | { 195, WAIXING_TYPE_E }, | |
| 382 | { 196, BTL_SUPERBROS11 }, | |
| 383 | { 197, UNL_SUPERFIGHTER3 }, | |
| 384 | { 198, WAIXING_TYPE_F }, | |
| 385 | { 199, WAIXING_TYPE_G }, | |
| 386 | { 200, BMC_36IN1 }, | |
| 387 | { 201, BMC_21IN1 }, | |
| 388 | { 202, BMC_150IN1 }, | |
| 389 | { 203, BMC_35IN1 }, | |
| 390 | { 204, BMC_64IN1 }, | |
| 391 | { 205, BMC_15IN1 }, | |
| 392 | { 206, STD_DXROM }, | |
| 393 | { 207, TAITO_X1_005_A }, | |
| 394 | { 208, GOUDER_37017 }, | |
| 395 | // 209 JY Company Type B (Power Rangers 3 & 4, Shin Samurai Spirits 2) - Unsupported | |
| 396 | // 210 Some emu uses this as Mapper 19 without some features | |
| 397 | // 211 JY Company Type C (Tiny Toon Adventures 6, Donkey Kong Country 4) - Unsupported | |
| 398 | { 212, BMC_SUPERHIK_300IN1 }, | |
| 399 | { 213, BMC_9999999IN1 }, | |
| 400 | { 214, BMC_SUPERGUN_20IN1 }, | |
| 401 | { 215, SUPERGAME_BOOGERMAN }, | |
| 402 | { 216, RCM_GS2015 }, | |
| 403 | { 217, BMC_GOLDENCARD_6IN1 }, | |
| 404 | // 218 Unused | |
| 405 | // 219 Bootleg A9746 - Unsupported | |
| 406 | // 220 Unused | |
| 407 | { 221, UNL_N625092 }, | |
| 408 | { 222, BTL_DRAGONNINJA }, | |
| 409 | { 223, WAIXING_TYPE_I }, // (according to NEStopia source, it's MMC3 with more WRAM) | |
| 410 | { 224, WAIXING_TYPE_J }, // (according to NEStopia source, it's MMC3 with more WRAM) | |
| 411 | { 225, BMC_72IN1 }, | |
| 412 | { 226, BMC_76IN1 }, | |
| 413 | { 227, BMC_1200IN1 }, | |
| 414 | { 228, ACTENT_ACT52 }, | |
| 415 | { 229, BMC_31IN1 }, | |
| 416 | { 230, BMC_22GAMES }, | |
| 417 | { 231, BMC_20IN1 }, | |
| 418 | { 232, CAMERICA_BF9096 }, | |
| 419 | // 233 Super 22 Games - Unsupported | |
| 420 | // 234 AVE Maxi 15 - Unsupported | |
| 421 | // 235 Golden Game x-in-1 - Unsupported | |
| 422 | // 236 Game 800-in-1 - Unsupported | |
| 423 | // 237 Unused | |
| 424 | { 238, UNL_603_5052 }, | |
| 425 | // 239 Unused | |
| 426 | { 240, CNE_SHLZ }, | |
| 427 | { 241, TXC_MXMDHTWO }, | |
| 428 | { 242, WAIXING_ZS }, | |
| 429 | { 243, SACHEN_74LS374_A }, | |
| 430 | { 244, CNE_DECATHLON }, | |
| 431 | { 245, WAIXING_TYPE_H }, | |
| 432 | { 246, CNE_FSB }, | |
| 433 | // 247 Unused | |
| 434 | // 248 Unused | |
| 435 | { 249, WAIXING_SECURITY }, | |
| 436 | { 250, NITRA_TDA }, | |
| 437 | // 251 Shen Hua Jian Yun III?? - Unsupported | |
| 438 | { 252, WAIXING_SGZ }, | |
| 439 | // 253 Super 8-in-1 99 King Fighter?? - Unsupported | |
| 440 | { 254, BTL_PIKACHUY2K }, | |
| 441 | { 255, BMC_110IN1 }, | |
| 442 | }; | |
| 443 | ||
| 444 | const nes_mmc *nes_mapper_lookup( int mapper ) | |
| 445 | { | |
| 446 | int i; | |
| 447 | ||
| 448 | for (i = 0; i < ARRAY_LENGTH(mmc_list); i++) | |
| 449 | { | |
| 450 | if (mmc_list[i].iNesMapper == mapper) | |
| 451 | return &mmc_list[i]; | |
| 452 | } | |
| 453 | ||
| 454 | return NULL; | |
| 455 | } | |
| 456 | ||
| 457 | int nes_get_mmc_id( running_machine &machine, int mapper ) | |
| 458 | { | |
| 459 | const nes_mmc *mmc = nes_mapper_lookup(mapper); | |
| 460 | ||
| 461 | if (mmc == NULL) | |
| 462 | fatalerror("Unimplemented Mapper %d", mapper); | |
| 463 | ||
| 464 | return mmc->pcb_id; | |
| 465 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | snescart.c | |
| 4 | ||
| 5 | Machine file to handle cart loading in the Nintendo Super NES emulation. | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "includes/snes.h" | |
| 11 | #include "imagedev/cartslot.h" | |
| 12 | #include "snescart.h" | |
| 13 | ||
| 14 | #define SNES_CART_DEBUG 0 | |
| 15 | ||
| 16 | /****** Strings for Cart Header Logging ******/ | |
| 17 | ||
| 18 | #define UNK "Unknown" | |
| 19 | ||
| 20 | /* Some known type of cart */ | |
| 21 | static const char *const types[] = | |
| 22 | { | |
| 23 | "ROM", | |
| 24 | "ROM, DSP-1", | |
| 25 | "ROM, DSP-2", | |
| 26 | "ROM, DSP-3", | |
| 27 | "ROM, DSP-4", | |
| 28 | "ROM, Super FX / FX2", | |
| 29 | "ROM, SA-1", | |
| 30 | "ROM, S-DD1", | |
| 31 | "ROM, OBC-1", | |
| 32 | "ROM, S-RTC", | |
| 33 | "ROM, Z80GB (Super Game Boy)", | |
| 34 | "ROM, C4", | |
| 35 | "ROM, Seta ST-010", | |
| 36 | "ROM, Seta ST-011", | |
| 37 | "ROM, Seta ST-018", | |
| 38 | "ROM, SPC7110", | |
| 39 | "ROM, SPC7110, RTC", | |
| 40 | UNK, // to add: Satellaview BS-X detection | |
| 41 | }; | |
| 42 | ||
| 43 | /* Some known countries */ | |
| 44 | static const char *const countries[] = | |
| 45 | { | |
| 46 | /* 0*/ "Japan (NTSC)", "USA & Canada (NTSC)", "Europe, Oceania & Asia (PAL)", "Sweden (PAL)", | |
| 47 | /* 4*/ "Finland (PAL)", "Denmark (PAL)", "France (PAL)", "Holland (PAL)", | |
| 48 | /* 8*/ "Spain (PAL)", "Germany, Austria & Switzerland (PAL)", "Italy (PAL)", "Hong Kong & China (PAL)", | |
| 49 | /* c*/ "Indonesia (PAL)", "South Korea (NTSC)", UNK, UNK, | |
| 50 | }; | |
| 51 | ||
| 52 | /* Some known companies (integrations to the list from Snes9x) */ | |
| 53 | static const char *const companies[] = | |
| 54 | { | |
| 55 | /* 0*/ "Invalid", "Nintendo", "Ajinomoto", "Imagineer-Zoom", "Chris Gray Enterprises Inc.", "Zamuse", "Falcom", UNK, | |
| 56 | /* 8*/ "Capcom", "HOT-B", "Jaleco", "Coconuts", "Rage Software", "Micronet", "Technos", "Mebio Software", | |
| 57 | /*10*/ "SHOUEi System", "Starfish", "Gremlin Graphics", "Electronic Arts", "NCS / Masaya", "COBRA Team", "Human/Field", "KOEI", | |
| 58 | /*18*/ "Hudson Soft", "Game Village", "Yanoman", UNK, "Tecmo", UNK, "Open System", "Virgin Games", | |
| 59 | /*20*/ "KSS", "Sunsoft", "POW", "Micro World", UNK, UNK, "Enix", "Loriciel/Electro Brain", | |
| 60 | /*28*/ "Kemco", "Seta Co.,Ltd.", "Culture Brain", "Irem Japan", "Pal Soft", "Visit Co.,Ltd.", "INTEC Inc.", "System Sacom Corp.", | |
| 61 | /*30*/ "Viacom New Media", "Carrozzeria", "Dynamic", "Nintendo", "Magifact", "Hect", UNK, UNK, | |
| 62 | /*38*/ "Capcom Europe", "Accolade Europe", UNK, "Arcade Zone", "Empire Software", "Loriciel", "Gremlin Graphics", UNK, | |
| 63 | /*40*/ "Seika Corp.", "UBI Soft", UNK, UNK, "LifeFitness Exertainment", UNK, "System 3", "Spectrum Holobyte", | |
| 64 | /*48*/ UNK, "Irem", UNK, "Raya Systems/Sculptured Software", "Renovation Products", "Malibu Games/Black Pearl", UNK, "U.S. Gold", | |
| 65 | /*50*/ "Absolute Entertainment", "Acclaim", "Activision", "American Sammy", "GameTek", "Hi Tech Expressions", "LJN Toys", UNK, | |
| 66 | /*58*/ UNK, UNK, "Mindscape", "Romstar, Inc.", UNK, "Tradewest", UNK, "American Softworks Corp.", | |
| 67 | /*60*/ "Titus", "Virgin Interactive Entertainment", "Maxis", "Origin/FCI/Pony Canyon", UNK, UNK, UNK, "Ocean", | |
| 68 | /*68*/ UNK, "Electronic Arts", UNK, "Laser Beam", UNK, UNK, "Elite", "Electro Brain", | |
| 69 | /*70*/ "Infogrames", "Interplay", "LucasArts", "Parker Brothers", "Konami", "STORM", UNK, UNK, | |
| 70 | /*78*/ "THQ Software", "Accolade Inc.", "Triffix Entertainment", UNK, "Microprose", UNK, UNK, "Kemco", | |
| 71 | /*80*/ "Misawa", "Teichio", "Namco Ltd.", "Lozc", "Koei", UNK, "Tokuma Shoten Intermedia", "Tsukuda Original", | |
| 72 | /*88*/ "DATAM-Polystar", UNK, UNK, "Bullet-Proof Software", "Vic Tokai", UNK, "Character Soft", "I\'\'Max", | |
| 73 | /*90*/ "Takara", "CHUN Soft", "Video System Co., Ltd.", "BEC", UNK, "Varie", "Yonezawa / S'Pal Corp.", "Kaneco", | |
| 74 | /*98*/ UNK, "Pack in Video", "Nichibutsu", "TECMO", "Imagineer Co.", UNK, UNK, UNK, | |
| 75 | /*a0*/ "Telenet", "Hori", UNK, UNK, "Konami", "K.Amusement Leasing Co.", UNK, "Takara", | |
| 76 | /*a8*/ UNK, "Technos Jap.", "JVC", UNK, "Toei Animation", "Toho", UNK, "Namco Ltd.", | |
| 77 | /*b0*/ "Media Rings Corp.", "ASCII Co. Activison", "Bandai", UNK, "Enix America", UNK, "Halken", UNK, | |
| 78 | /*b8*/ UNK, UNK, "Culture Brain", "Sunsoft", "Toshiba EMI", "Sony Imagesoft", UNK, "Sammy", | |
| 79 | /*c0*/ "Taito", UNK, "Kemco", "Square", "Tokuma Soft", "Data East", "Tonkin House", UNK, | |
| 80 | /*c8*/ "KOEI", UNK, "Konami USA", "NTVIC", UNK, "Meldac", "Pony Canyon", "Sotsu Agency/Sunrise", | |
| 81 | /*d0*/ "Disco/Taito", "Sofel", "Quest Corp.", "Sigma", "Ask Kodansha Co., Ltd.", UNK, "Naxat", UNK, | |
| 82 | /*d8*/ "Capcom Co., Ltd.", "Banpresto", "Tomy", "Acclaim", UNK, "NCS", "Human Entertainment", "Altron", | |
| 83 | /*e0*/ "Jaleco", UNK, "Yutaka", UNK, "T&ESoft", "EPOCH Co.,Ltd.", UNK, "Athena", | |
| 84 | /*e8*/ "Asmik", "Natsume", "King Records", "Atlus", "Sony Music Entertainment", UNK, "IGS", UNK, | |
| 85 | /*f0*/ UNK, "Motown Software", "Left Field Entertainment", "Beam Software", "Tec Magik", UNK, UNK, UNK, | |
| 86 | /*f8*/ UNK, "Cybersoft", UNK, "Psygnosis", UNK, UNK, "Davidson", UNK, | |
| 87 | }; | |
| 88 | ||
| 89 | ||
| 90 | /* We use this to convert the company_id in the header to int value to be passed in companies[] */ | |
| 91 | static int char_to_int_conv( char id ) | |
| 92 | { | |
| 93 | int value; | |
| 94 | ||
| 95 | if (id == '1') value = 0x01; | |
| 96 | else if (id == '2') value = 0x02; | |
| 97 | else if (id == '3') value = 0x03; | |
| 98 | else if (id == '4') value = 0x04; | |
| 99 | else if (id == '5') value = 0x05; | |
| 100 | else if (id == '6') value = 0x06; | |
| 101 | else if (id == '7') value = 0x07; | |
| 102 | else if (id == '8') value = 0x08; | |
| 103 | else if (id == '9') value = 0x09; | |
| 104 | else if (id == 'A') value = 0x0a; | |
| 105 | else if (id == 'B') value = 0x0b; | |
| 106 | else if (id == 'C') value = 0x0c; | |
| 107 | else if (id == 'D') value = 0x0d; | |
| 108 | else if (id == 'E') value = 0x0e; | |
| 109 | else if (id == 'F') value = 0x0f; | |
| 110 | else value = 0x00; | |
| 111 | ||
| 112 | return value; | |
| 113 | } | |
| 114 | ||
| 115 | ||
| 116 | /*************************************************************************** | |
| 117 | ||
| 118 | SRAM handling | |
| 119 | ||
| 120 | ***************************************************************************/ | |
| 121 | ||
| 122 | /* Loads the battery backed RAM into the appropriate memory area */ | |
| 123 | static void snes_load_sram(running_machine &machine) | |
| 124 | { | |
| 125 | snes_state *state = machine.driver_data<snes_state>(); | |
| 126 | UINT8 ii; | |
| 127 | UINT8 *battery_ram, *ptr; | |
| 128 | ||
| 129 | battery_ram = (UINT8*)malloc(state->m_cart[0].sram_max); | |
| 130 | ptr = battery_ram; | |
| 131 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart")); | |
| 132 | image->battery_load(battery_ram, state->m_cart[0].sram_max, 0xff); | |
| 133 | ||
| 134 | if (state->m_cart[0].mode == SNES_MODE_20) | |
| 135 | { | |
| 136 | UINT32 size = state->m_cart[0].small_sram ? 0x8000 : 0x10000; | |
| 137 | ||
| 138 | /* There could be some larger image needing banks 0x70 to 0x7f at address 0x8000 for ROM | |
| 139 | * mirroring. These should be treated separately or data would be overwritten by SRAM */ | |
| 140 | for (ii = 0; ii < 16; ii++) | |
| 141 | { | |
| 142 | /* loading */ | |
| 143 | memmove(&snes_ram[0x700000 + (ii * 0x010000)], ptr, size); | |
| 144 | /* mirroring */ | |
| 145 | memcpy(&snes_ram[0xf00000 + (ii * 0x010000)], &snes_ram[0x700000 + (ii * 0x010000)], size); | |
| 146 | ptr += size; | |
| 147 | } | |
| 148 | } | |
| 149 | else if (state->m_cart[0].mode == SNES_MODE_21) | |
| 150 | { | |
| 151 | for (ii = 0; ii < 16; ii++) | |
| 152 | { | |
| 153 | /* loading */ | |
| 154 | memmove(&snes_ram[0x306000 + (ii * 0x010000)], ptr, 0x2000); | |
| 155 | /* mirroring */ | |
| 156 | memcpy(&snes_ram[0xb06000 + (ii * 0x010000)], &snes_ram[0x306000 + (ii * 0x010000)], 0x2000); | |
| 157 | ptr += 0x2000; | |
| 158 | } | |
| 159 | } | |
| 160 | else if (state->m_cart[0].mode == SNES_MODE_25) | |
| 161 | { | |
| 162 | for (ii = 0; ii < 16; ii++) | |
| 163 | { | |
| 164 | memmove(&snes_ram[0xb06000 + (ii * 0x010000)], ptr, 0x2000); | |
| 165 | ptr += 0x2000; | |
| 166 | } | |
| 167 | } | |
| 168 | ||
| 169 | free(battery_ram); | |
| 170 | } | |
| 171 | ||
| 172 | /* Saves the battery backed RAM from the appropriate memory area */ | |
| 173 | static void snes_save_sram(running_machine &machine) | |
| 174 | { | |
| 175 | snes_state *state = machine.driver_data<snes_state>(); | |
| 176 | UINT8 ii; | |
| 177 | UINT8 *battery_ram, *ptr; | |
| 178 | ||
| 179 | battery_ram = (UINT8*)malloc(state->m_cart[0].sram_max); | |
| 180 | ptr = battery_ram; | |
| 181 | ||
| 182 | if (state->m_cart[0].mode == SNES_MODE_20) | |
| 183 | { | |
| 184 | UINT32 size = state->m_cart[0].small_sram ? 0x8000 : 0x10000; | |
| 185 | ||
| 186 | for (ii = 0; ii < 16; ii++) | |
| 187 | { | |
| 188 | memmove(ptr, &snes_ram[0x700000 + (ii * 0x010000)], size); | |
| 189 | ptr += size; | |
| 190 | } | |
| 191 | } | |
| 192 | else if (state->m_cart[0].mode == SNES_MODE_21) | |
| 193 | { | |
| 194 | for (ii = 0; ii < 16; ii++) | |
| 195 | { | |
| 196 | memmove(ptr, &snes_ram[0x306000 + (ii * 0x010000)], 0x2000); | |
| 197 | ptr += 0x2000; | |
| 198 | } | |
| 199 | } | |
| 200 | else if (state->m_cart[0].mode == SNES_MODE_25) | |
| 201 | { | |
| 202 | for (ii = 0; ii < 16; ii++) | |
| 203 | { | |
| 204 | memmove(ptr, &snes_ram[0xb06000 + (ii * 0x010000)], 0x2000); | |
| 205 | ptr += 0x2000; | |
| 206 | } | |
| 207 | } | |
| 208 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart")); | |
| 209 | image->battery_save(battery_ram, state->m_cart[0].sram_max); | |
| 210 | ||
| 211 | free(battery_ram); | |
| 212 | } | |
| 213 | ||
| 214 | static void snes_machine_stop(running_machine &machine) | |
| 215 | { | |
| 216 | snes_state *state = machine.driver_data<snes_state>(); | |
| 217 | ||
| 218 | /* Save SRAM */ | |
| 219 | if (state->m_cart[0].sram > 0) | |
| 220 | snes_save_sram(machine); | |
| 221 | } | |
| 222 | ||
| 223 | MACHINE_START( snes_mess ) | |
| 224 | { | |
| 225 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(snes_machine_stop),&machine)); | |
| 226 | MACHINE_START_CALL(snes); | |
| 227 | } | |
| 228 | ||
| 229 | ||
| 230 | static void sufami_load_sram(running_machine &machine, const char *cart_tag) | |
| 231 | { | |
| 232 | UINT8 ii; | |
| 233 | UINT8 *battery_ram, *ptr; | |
| 234 | int st_sram_offset = 0; | |
| 235 | ||
| 236 | battery_ram = (UINT8*)malloc(0x20000); | |
| 237 | ptr = battery_ram; | |
| 238 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device(cart_tag)); | |
| 239 | image->battery_load(battery_ram, 0x20000, 0); | |
| 240 | ||
| 241 | if (strcmp(cart_tag, "slot_a") == 0) | |
| 242 | st_sram_offset = 0x608000; | |
| 243 | ||
| 244 | if (strcmp(cart_tag, "slot_b") == 0) | |
| 245 | st_sram_offset = 0x708000; | |
| 246 | ||
| 247 | /* Cart RAM is at 0x60-0x63:0x8000-0xffff (+0x10 for slot2) */ | |
| 248 | for (ii = 0; ii < 4; ii++) | |
| 249 | { | |
| 250 | /* loading */ | |
| 251 | memcpy(&snes_ram[st_sram_offset + (ii * 0x010000)], ptr + (ii * 0x8000), 0x8000); | |
| 252 | /* mirroring */ | |
| 253 | memcpy(&snes_ram[0x800000 + st_sram_offset + (ii * 0x010000)], &snes_ram[st_sram_offset + (ii * 0x010000)], 0x8000); | |
| 254 | } | |
| 255 | ||
| 256 | free(battery_ram); | |
| 257 | } | |
| 258 | ||
| 259 | static void sufami_machine_stop(running_machine &machine) | |
| 260 | { | |
| 261 | snes_state *state = machine.driver_data<snes_state>(); | |
| 262 | UINT8 ii; | |
| 263 | UINT8 *battery_ram, *ptr; | |
| 264 | ||
| 265 | battery_ram = (UINT8*)malloc(0x20000); | |
| 266 | ptr = battery_ram; | |
| 267 | ||
| 268 | if (state->m_cart[0].slot_in_use) | |
| 269 | { | |
| 270 | for (ii = 0; ii < 4; ii++) | |
| 271 | { | |
| 272 | memmove(ptr + ii * 0x8000, &snes_ram[0x608000 + (ii * 0x010000)], 0x8000); | |
| 273 | } | |
| 274 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_a")); | |
| 275 | image->battery_save(battery_ram, 0x20000); | |
| 276 | } | |
| 277 | ||
| 278 | if (state->m_cart[1].slot_in_use) | |
| 279 | { | |
| 280 | for (ii = 0; ii < 4; ii++) | |
| 281 | { | |
| 282 | memmove(ptr + ii * 0x8000, &snes_ram[0x708000 + (ii * 0x010000)], 0x8000); | |
| 283 | } | |
| 284 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_b")); | |
| 285 | image->battery_save(battery_ram, 0x20000); | |
| 286 | } | |
| 287 | ||
| 288 | free(battery_ram); | |
| 289 | } | |
| 290 | ||
| 291 | MACHINE_START( snesst ) | |
| 292 | { | |
| 293 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(sufami_machine_stop),&machine)); | |
| 294 | MACHINE_START_CALL(snes); | |
| 295 | } | |
| 296 | ||
| 297 | ||
| 298 | /*************************************************************************** | |
| 299 | ||
| 300 | Cart handling | |
| 301 | ||
| 302 | ***************************************************************************/ | |
| 303 | ||
| 304 | /* This function assign a 'score' to data immediately after 'offset' to measure how valid they are | |
| 305 | as information block (to decide if the image is HiRom, LoRom, ExLoRom or ExHiRom) */ | |
| 306 | /* Code from bsnes, courtesy of byuu - http://byuu.cinnamonpirate.com/ */ | |
| 307 | static int snes_validate_infoblock( UINT8 *infoblock, UINT32 offset ) | |
| 308 | { | |
| 309 | int score = 0; | |
| 310 | UINT16 reset_vector = infoblock[offset + 0x3c] | (infoblock[offset + 0x3d] << 8); | |
| 311 | UINT16 checksum = infoblock[offset + 0x1e] | (infoblock[offset + 0x1f] << 8); | |
| 312 | UINT16 ichecksum = infoblock[offset + 0x1c] | (infoblock[offset + 0x1d] << 8); | |
| 313 | UINT8 reset_opcode = infoblock[(offset & ~0x7fff) | (reset_vector & 0x7fff)]; //first opcode executed upon reset | |
| 314 | UINT8 mapper = infoblock[offset + 0x15] & ~0x10; //mask off irrelevent FastROM-capable bit | |
| 315 | ||
| 316 | /* $00:[000-7fff] contains uninitialized RAM and MMIO. | |
| 317 | reset vector must point to ROM at $00:[8000-ffff] to be considered valid. */ | |
| 318 | if (reset_vector < 0x8000) | |
| 319 | return 0; | |
| 320 | ||
| 321 | /* some images duplicate the header in multiple locations, and others have completely | |
| 322 | invalid header information that cannot be relied upon. The code below will analyze | |
| 323 | the first opcode executed at the specified reset vector to determine the probability | |
| 324 | that this is the correct header. Score is assigned accordingly. */ | |
| 325 | ||
| 326 | /* most likely opcodes */ | |
| 327 | if (reset_opcode == 0x78 //sei | |
| 328 | || reset_opcode == 0x18 //clc (clc; xce) | |
| 329 | || reset_opcode == 0x38 //sec (sec; xce) | |
| 330 | || reset_opcode == 0x9c //stz $nnnn (stz $4200) | |
| 331 | || reset_opcode == 0x4c //jmp $nnnn | |
| 332 | || reset_opcode == 0x5c //jml $nnnnnn | |
| 333 | ) | |
| 334 | score += 8; | |
| 335 | ||
| 336 | /* plausible opcodes */ | |
| 337 | if (reset_opcode == 0xc2 //rep #$nn | |
| 338 | || reset_opcode == 0xe2 //sep #$nn | |
| 339 | || reset_opcode == 0xad //lda $nnnn | |
| 340 | || reset_opcode == 0xae //ldx $nnnn | |
| 341 | || reset_opcode == 0xac //ldy $nnnn | |
| 342 | || reset_opcode == 0xaf //lda $nnnnnn | |
| 343 | || reset_opcode == 0xa9 //lda #$nn | |
| 344 | || reset_opcode == 0xa2 //ldx #$nn | |
| 345 | || reset_opcode == 0xa0 //ldy #$nn | |
| 346 | || reset_opcode == 0x20 //jsr $nnnn | |
| 347 | || reset_opcode == 0x22 //jsl $nnnnnn | |
| 348 | ) | |
| 349 | score += 4; | |
| 350 | ||
| 351 | /* implausible opcodes */ | |
| 352 | if (reset_opcode == 0x40 //rti | |
| 353 | || reset_opcode == 0x60 //rts | |
| 354 | || reset_opcode == 0x6b //rtl | |
| 355 | || reset_opcode == 0xcd //cmp $nnnn | |
| 356 | || reset_opcode == 0xec //cpx $nnnn | |
| 357 | || reset_opcode == 0xcc //cpy $nnnn | |
| 358 | ) | |
| 359 | score -= 4; | |
| 360 | ||
| 361 | /* least likely opcodes */ | |
| 362 | if (reset_opcode == 0x00 //brk #$nn | |
| 363 | || reset_opcode == 0x02 //cop #$nn | |
| 364 | || reset_opcode == 0xdb //stp | |
| 365 | || reset_opcode == 0x42 //wdm | |
| 366 | || reset_opcode == 0xff //sbc $nnnnnn,x | |
| 367 | ) | |
| 368 | score -= 8; | |
| 369 | ||
| 370 | /* Sometimes, both the header and reset vector's first opcode will match ... | |
| 371 | fallback and rely on info validity in these cases to determine more likely header. */ | |
| 372 | ||
| 373 | /* a valid checksum is the biggest indicator of a valid header. */ | |
| 374 | if ((checksum + ichecksum) == 0xffff && (checksum != 0) && (ichecksum != 0)) | |
| 375 | score += 4; | |
| 376 | ||
| 377 | /* then there are the expected mapper values */ | |
| 378 | if (offset == 0x007fc0 && mapper == 0x20) // 0x20 is usually LoROM | |
| 379 | score += 2; | |
| 380 | ||
| 381 | if (offset == 0x00ffc0 && mapper == 0x21) // 0x21 is usually HiROM | |
| 382 | score += 2; | |
| 383 | ||
| 384 | if (offset == 0x007fc0 && mapper == 0x22) // 0x22 is usually ExLoROM | |
| 385 | score += 2; | |
| 386 | ||
| 387 | if (offset == 0x40ffc0 && mapper == 0x25) // 0x25 is usually ExHiROM | |
| 388 | score += 2; | |
| 389 | ||
| 390 | /* finally, there are valid values in the Company, Region etc. fields */ | |
| 391 | if (infoblock[offset + 0x1a] == 0x33) // Company field: 0x33 indicates extended header | |
| 392 | score += 2; | |
| 393 | ||
| 394 | if (infoblock[offset + 0x16] < 0x08) // ROM Type field | |
| 395 | score++; | |
| 396 | ||
| 397 | if (infoblock[offset + 0x17] < 0x10) // ROM Size field | |
| 398 | score++; | |
| 399 | ||
| 400 | if (infoblock[offset + 0x18] < 0x08) // SRAM Size field | |
| 401 | score++; | |
| 402 | ||
| 403 | if (infoblock[offset + 0x19] < 14) // Region field | |
| 404 | score++; | |
| 405 | ||
| 406 | /* do we still have a positive score? */ | |
| 407 | if (score < 0) | |
| 408 | score = 0; | |
| 409 | ||
| 410 | return score; | |
| 411 | } | |
| 412 | ||
| 413 | /* Here we add a couple of cart utilities, to avoid duplicating the code in each DEVICE_IMAGE_LOAD */ | |
| 414 | static UINT32 snes_skip_header( device_image_interface &image, UINT32 snes_rom_size ) | |
| 415 | { | |
| 416 | UINT8 header[512]; | |
| 417 | UINT32 offset = 512; | |
| 418 | ||
| 419 | /* Check for a header (512 bytes) */ | |
| 420 | if (image.software_entry() == NULL) | |
| 421 | image.fread( header, 512); | |
| 422 | else | |
| 423 | memcpy(header, image.get_software_region("rom"), 512); | |
| 424 | ||
| 425 | if ((header[8] == 0xaa) && (header[9] == 0xbb) && (header[10] == 0x04)) | |
| 426 | { | |
| 427 | /* Found an SWC identifier */ | |
| 428 | logerror("Found header (SWC) - Skipped\n"); | |
| 429 | } | |
| 430 | else if ((header[0] | (header[1] << 8)) == (((snes_rom_size - 512) / 1024) / 8)) | |
| 431 | { | |
| 432 | /* Some headers have the rom size at the start, if this matches with the actual rom size, we probably have a header */ | |
| 433 | logerror("Found header (size) - Skipped\n"); | |
| 434 | } | |
| 435 | else if ((snes_rom_size % 0x8000) == 512) | |
| 436 | { | |
| 437 | /* As a last check we'll see if there's exactly 512 bytes extra to this image. */ | |
| 438 | logerror("Found header (extra) - Skipped\n"); | |
| 439 | } | |
| 440 | else | |
| 441 | { | |
| 442 | /* No header found so go back to the start of the file */ | |
| 443 | logerror("No header found.\n"); | |
| 444 | offset = 0; | |
| 445 | } | |
| 446 | ||
| 447 | return offset; | |
| 448 | } | |
| 449 | ||
| 450 | ||
| 451 | /* This determines if a cart is in Mode 20, 21, 22 or 25; sets state->m_cart[0].mode and | |
| 452 | state->m_cart[0].sram accordingly; and returns the offset of the internal header (needed to | |
| 453 | detect BSX and ST carts) */ | |
| 454 | static UINT32 snes_find_hilo_mode( device_image_interface &image, UINT8 *buffer, UINT32 offset, int cartid ) | |
| 455 | { | |
| 456 | snes_state *state = image.device().machine().driver_data<snes_state>(); | |
| 457 | UINT8 valid_mode20, valid_mode21, valid_mode25; | |
| 458 | UINT32 retvalue; | |
| 459 | ||
| 460 | /* Now to determine if this is a lo-ROM, a hi-ROM or an extended lo/hi-ROM */ | |
| 461 | valid_mode20 = snes_validate_infoblock(buffer, 0x007fc0); | |
| 462 | valid_mode21 = snes_validate_infoblock(buffer, 0x00ffc0); | |
| 463 | valid_mode25 = snes_validate_infoblock(buffer, 0x40ffc0); | |
| 464 | ||
| 465 | /* Images larger than 32mbits are likely ExHiRom */ | |
| 466 | if (valid_mode25) | |
| 467 | valid_mode25 += 4; | |
| 468 | ||
| 469 | if ((valid_mode20 >= valid_mode21) && (valid_mode20 >= valid_mode25)) | |
| 470 | { | |
| 471 | if ((buffer[0x007fd5] == 0x32) || ((state->m_cart_size - offset) > 0x401000)) | |
| 472 | state->m_cart[cartid].mode = SNES_MODE_22; // ExLoRom | |
| 473 | else | |
| 474 | state->m_cart[cartid].mode = SNES_MODE_20; // LoRom | |
| 475 | ||
| 476 | retvalue = 0x007fc0; | |
| 477 | ||
| 478 | /* a few games require 512k, however we store twice as much to be sure to cover the various mirrors */ | |
| 479 | state->m_cart[cartid].sram_max = 0x100000; | |
| 480 | } | |
| 481 | else if (valid_mode21 >= valid_mode25) | |
| 482 | { | |
| 483 | state->m_cart[cartid].mode = SNES_MODE_21; // HiRom | |
| 484 | retvalue = 0x00ffc0; | |
| 485 | state->m_cart[cartid].sram_max = 0x20000; | |
| 486 | } | |
| 487 | else | |
| 488 | { | |
| 489 | state->m_cart[cartid].mode = SNES_MODE_25; // ExHiRom | |
| 490 | retvalue = 0x40ffc0; | |
| 491 | state->m_cart[cartid].sram_max = 0x20000; | |
| 492 | } | |
| 493 | ||
| 494 | logerror( "\t HiROM/LoROM id: %s (LoROM: %d , HiROM: %d, ExHiROM: %d)\n", | |
| 495 | (state->m_cart[cartid].mode == SNES_MODE_20) ? "LoROM" : | |
| 496 | (state->m_cart[cartid].mode == SNES_MODE_21) ? "HiROM" : | |
| 497 | (state->m_cart[cartid].mode == SNES_MODE_22) ? "ExLoROM" : | |
| 498 | (state->m_cart[cartid].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)", | |
| 499 | valid_mode20, valid_mode21, valid_mode25); | |
| 500 | ||
| 501 | return retvalue; | |
| 502 | } | |
| 503 | ||
| 504 | static int snes_find_addon_chip( running_machine &machine ) | |
| 505 | { | |
| 506 | snes_state *state = machine.driver_data<snes_state>(); | |
| 507 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 508 | int supported_type = 1; | |
| 509 | int dsp_prg_offset = 0; | |
| 510 | ||
| 511 | /* Info mostly taken from http://snesemu.black-ship.net/misc/-from%20nsrt.edgeemu.com-chipinfo.htm */ | |
| 512 | switch (snes_r_bank1(space, 0x00ffd6)) | |
| 513 | { | |
| 514 | case 0x00: | |
| 515 | case 0x01: | |
| 516 | case 0x02: | |
| 517 | state->m_has_addon_chip = HAS_NONE; | |
| 518 | break; | |
| 519 | ||
| 520 | case 0x03: | |
| 521 | if (snes_r_bank1(space, 0x00ffd5) == 0x30) | |
| 522 | { | |
| 523 | state->m_has_addon_chip = HAS_DSP4; | |
| 524 | dsp_prg_offset = SNES_DSP4_OFFSET; | |
| 525 | } | |
| 526 | else | |
| 527 | { | |
| 528 | state->m_has_addon_chip = HAS_DSP1; | |
| 529 | dsp_prg_offset = SNES_DSP1B_OFFSET; | |
| 530 | } | |
| 531 | break; | |
| 532 | ||
| 533 | case 0x04: | |
| 534 | state->m_has_addon_chip = HAS_DSP1; | |
| 535 | dsp_prg_offset = SNES_DSP1B_OFFSET; | |
| 536 | break; | |
| 537 | ||
| 538 | case 0x05: | |
| 539 | if (snes_r_bank1(space, 0x00ffd5) == 0x20) | |
| 540 | { | |
| 541 | state->m_has_addon_chip = HAS_DSP2; | |
| 542 | dsp_prg_offset = SNES_DSP2_OFFSET; | |
| 543 | } | |
| 544 | /* DSP-3 is hard to detect. We exploit the fact that the only game has been manufactured by Bandai */ | |
| 545 | else if ((snes_r_bank1(space, 0x00ffd5) == 0x30) && (snes_r_bank1(space, 0x00ffda) == 0xb2)) | |
| 546 | { | |
| 547 | state->m_has_addon_chip = HAS_DSP3; | |
| 548 | dsp_prg_offset = SNES_DSP3_OFFSET; | |
| 549 | } | |
| 550 | else | |
| 551 | { | |
| 552 | state->m_has_addon_chip = HAS_DSP1; | |
| 553 | dsp_prg_offset = SNES_DSP1B_OFFSET; | |
| 554 | } | |
| 555 | break; | |
| 556 | ||
| 557 | case 0x13: // Mario Chip 1 | |
| 558 | case 0x14: // GSU-x | |
| 559 | case 0x15: // GSU-x | |
| 560 | case 0x1a: // GSU-1 (21 MHz at start) | |
| 561 | if (snes_r_bank1(space, 0x00ffd5) == 0x20) | |
| 562 | state->m_has_addon_chip = HAS_SUPERFX; | |
| 563 | break; | |
| 564 | ||
| 565 | case 0x25: | |
| 566 | state->m_has_addon_chip = HAS_OBC1; | |
| 567 | break; | |
| 568 | ||
| 569 | case 0x32: // needed by a Sample game (according to ZSNES) | |
| 570 | case 0x34: | |
| 571 | case 0x35: | |
| 572 | if (snes_r_bank1(space, 0x00ffd5) == 0x23) | |
| 573 | { | |
| 574 | state->m_has_addon_chip = HAS_SA1; | |
| 575 | supported_type = 0; | |
| 576 | mame_printf_error("This is a SA-1 type game, currently unsupported by the driver\n"); | |
| 577 | } | |
| 578 | break; | |
| 579 | ||
| 580 | case 0x43: | |
| 581 | case 0x45: | |
| 582 | if (snes_r_bank1(space, 0x00ffd5) == 0x32) | |
| 583 | { | |
| 584 | state->m_has_addon_chip = HAS_SDD1; | |
| 585 | } | |
| 586 | break; | |
| 587 | ||
| 588 | case 0x55: | |
| 589 | if (snes_r_bank1(space, 0x00ffd5) == 0x35) | |
| 590 | { | |
| 591 | state->m_has_addon_chip = HAS_RTC; | |
| 592 | } | |
| 593 | break; | |
| 594 | ||
| 595 | case 0xe3: | |
| 596 | state->m_has_addon_chip = HAS_Z80GB; | |
| 597 | supported_type = 0; | |
| 598 | break; | |
| 599 | ||
| 600 | case 0xf3: | |
| 601 | state->m_has_addon_chip = HAS_CX4; | |
| 602 | break; | |
| 603 | ||
| 604 | case 0xf5: | |
| 605 | if (snes_r_bank1(space, 0x00ffd5) == 0x30) | |
| 606 | { | |
| 607 | state->m_has_addon_chip = HAS_ST018; | |
| 608 | supported_type = 0; | |
| 609 | } | |
| 610 | else if (snes_r_bank1(space, 0x00ffd5) == 0x3a) | |
| 611 | { | |
| 612 | state->m_has_addon_chip = HAS_SPC7110; | |
| 613 | } | |
| 614 | break; | |
| 615 | ||
| 616 | case 0xf6: | |
| 617 | /* These Seta ST-01X chips have both 0x30 at 0x00ffd5, | |
| 618 | they only differ for the 'size' at 0x00ffd7 */ | |
| 619 | if (snes_r_bank1(space, 0x00ffd7) < 0x0a) | |
| 620 | state->m_has_addon_chip = HAS_ST011; | |
| 621 | else | |
| 622 | state->m_has_addon_chip = HAS_ST010; | |
| 623 | ||
| 624 | // if we are loading the game in a driver without the ST01X DSP, revert to HAS_NONE to avoid crash | |
| 625 | if (!state->m_upd96050) | |
| 626 | state->m_has_addon_chip = HAS_NONE; | |
| 627 | break; | |
| 628 | ||
| 629 | case 0xf9: | |
| 630 | if (snes_r_bank1(space, 0x00ffd5) == 0x3a) | |
| 631 | { | |
| 632 | state->m_has_addon_chip = HAS_SPC7110_RTC; | |
| 633 | supported_type = 0; | |
| 634 | } | |
| 635 | break; | |
| 636 | ||
| 637 | default: | |
| 638 | state->m_has_addon_chip = HAS_UNK; | |
| 639 | supported_type = 0; | |
| 640 | break; | |
| 641 | } | |
| 642 | ||
| 643 | if ((state->m_has_addon_chip >= HAS_DSP1) && (state->m_has_addon_chip <= HAS_DSP4)) | |
| 644 | { | |
| 645 | UINT8 *dspsrc = (UINT8 *)machine.region("addons")->base(); | |
| 646 | UINT32 *dspprg = (UINT32 *)machine.region("dspprg")->base(); | |
| 647 | UINT16 *dspdata = (UINT16 *)machine.region("dspdata")->base(); | |
| 648 | ||
| 649 | // copy DSP program | |
| 650 | for (int i = 0; i < 0x2000; i+= 4) | |
| 651 | { | |
| 652 | *dspprg = dspsrc[dsp_prg_offset+0+i]<<24 | dspsrc[dsp_prg_offset+1+i]<<16 | dspsrc[dsp_prg_offset+2+i]<<8; | |
| 653 | dspprg++; | |
| 654 | } | |
| 655 | ||
| 656 | // copy DSP data | |
| 657 | for (int i = 0; i < 0x800; i+= 2) | |
| 658 | { | |
| 659 | *dspdata++ = dspsrc[dsp_prg_offset+0x2000+i]<<8 | dspsrc[dsp_prg_offset+0x2001+i]; | |
| 660 | } | |
| 661 | } | |
| 662 | ||
| 663 | if ((state->m_has_addon_chip == HAS_ST010) || (state->m_has_addon_chip == HAS_ST011)) | |
| 664 | { | |
| 665 | UINT8 *dspsrc = (UINT8 *)machine.region("addons")->base(); | |
| 666 | UINT32 *dspprg = (UINT32 *)machine.region("dspprg")->base(); | |
| 667 | UINT16 *dspdata = (UINT16 *)machine.region("dspdata")->base(); | |
| 668 | ||
| 669 | // copy DSP program | |
| 670 | for (int i = 0; i < 0x10000; i+= 4) | |
| 671 | { | |
| 672 | *dspprg = dspsrc[0+i]<<24 | dspsrc[1+i]<<16 | dspsrc[2+i]<<8; | |
| 673 | dspprg++; | |
| 674 | } | |
| 675 | ||
| 676 | // copy DSP data | |
| 677 | for (int i = 0; i < 0x1000; i+= 2) | |
| 678 | { | |
| 679 | *dspdata++ = dspsrc[0x10000+i]<<8 | dspsrc[0x10001+i]; | |
| 680 | } | |
| 681 | } | |
| 682 | ||
| 683 | return supported_type; | |
| 684 | } | |
| 685 | ||
| 686 | static void snes_cart_log_info( running_machine &machine, int total_blocks, int supported ) | |
| 687 | { | |
| 688 | snes_state *state = machine.driver_data<snes_state>(); | |
| 689 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 690 | char title[21], rom_id[4], company_id[2]; | |
| 691 | int i, company, has_ram = 0, has_sram = 0; | |
| 692 | ||
| 693 | /* Company */ | |
| 694 | for (i = 0; i < 2; i++) | |
| 695 | company_id[i] = snes_r_bank1(space, 0x00ffb0 + i); | |
| 696 | company = (char_to_int_conv(company_id[0]) << 4) + char_to_int_conv(company_id[1]); | |
| 697 | if (company == 0) | |
| 698 | company = snes_r_bank1(space, 0x00ffda); | |
| 699 | ||
| 700 | /* ROM ID */ | |
| 701 | for( i = 0; i < 4; i++ ) | |
| 702 | rom_id[i] = snes_r_bank1(space, 0x00ffb2 + i); | |
| 703 | ||
| 704 | /* Title */ | |
| 705 | for( i = 0; i < 21; i++ ) | |
| 706 | title[i] = snes_r_bank1(space, 0x00ffc0 + i); | |
| 707 | ||
| 708 | /* RAM */ | |
| 709 | if (((snes_r_bank1(space, 0x00ffd6) & 0xf) == 1) || | |
| 710 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 2) || | |
| 711 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 4) || | |
| 712 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 5)) | |
| 713 | has_ram = 1; | |
| 714 | ||
| 715 | /* SRAM */ | |
| 716 | if (((snes_r_bank1(space, 0x00ffd6) & 0xf) == 2) || | |
| 717 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 5) || | |
| 718 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 6)) | |
| 719 | has_sram = 1; | |
| 720 | ||
| 721 | logerror( "ROM DETAILS\n" ); | |
| 722 | logerror( "===========\n\n" ); | |
| 723 | logerror( "\tTotal blocks: %d (%dmb)\n", total_blocks, total_blocks / (state->m_cart[0].mode & 5 ? 32 : 16) ); | |
| 724 | logerror( "\tROM bank size: %s \n", | |
| 725 | (state->m_cart[0].mode == SNES_MODE_20) ? "LoROM" : | |
| 726 | (state->m_cart[0].mode == SNES_MODE_21) ? "HiROM" : | |
| 727 | (state->m_cart[0].mode == SNES_MODE_22) ? "ExLoROM" : | |
| 728 | (state->m_cart[0].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)" ); | |
| 729 | logerror( "\tCompany: %s [%.2s]\n", companies[company], company_id ); | |
| 730 | logerror( "\tROM ID: %.4s\n\n", rom_id ); | |
| 731 | ||
| 732 | logerror( "HEADER DETAILS\n" ); | |
| 733 | logerror( "==============\n\n" ); | |
| 734 | logerror( "\tName: %.21s\n", title ); | |
| 735 | logerror( "\tSpeed: %s [%d]\n", ((snes_r_bank1(space, 0x00ffd5) & 0xf0)) ? "FastROM" : "SlowROM", (snes_r_bank1(space, 0x00ffd5) & 0xf0) >> 4 ); | |
| 736 | logerror( "\tBank size: %s [%d]\n", (snes_r_bank1(space, 0x00ffd5) & 0xf) ? "HiROM" : "LoROM", snes_r_bank1(space, 0x00ffd5) & 0xf ); | |
| 737 | ||
| 738 | logerror( "\tType: %s", types[state->m_has_addon_chip]); | |
| 739 | if (has_ram) | |
| 740 | logerror( ", RAM"); | |
| 741 | if (has_sram) | |
| 742 | logerror( ", SRAM"); | |
| 743 | logerror( " [%d]\n", snes_r_bank1(space, 0x00ffd6) ); | |
| 744 | ||
| 745 | logerror( "\tSize: %d megabits [%d]\n", 1 << (snes_r_bank1(space, 0x00ffd7) - 7), snes_r_bank1(space, 0x00ffd7) ); | |
| 746 | logerror( "\tSRAM: %d kilobits [%d]\n", state->m_cart[0].sram * 8, snes_ram[0xffd8] ); | |
| 747 | logerror( "\tCountry: %s [%d]\n", countries[snes_r_bank1(space, 0x00ffd9)], snes_r_bank1(space, 0x00ffd9) ); | |
| 748 | logerror( "\tLicense: %s [%X]\n", companies[snes_r_bank1(space, 0x00ffda)], snes_r_bank1(space, 0x00ffda) ); | |
| 749 | logerror( "\tVersion: 1.%d\n", snes_r_bank1(space, 0x00ffdb) ); | |
| 750 | logerror( "\tInv Checksum: %X %X\n", snes_r_bank1(space, 0x00ffdd), snes_r_bank1(space, 0x00ffdc) ); | |
| 751 | logerror( "\tChecksum: %X %X\n", snes_r_bank1(space, 0x00ffdf), snes_r_bank1(space, 0x00ffde) ); | |
| 752 | logerror( "\tNMI Address: %2X%2Xh\n", snes_r_bank1(space, 0x00fffb), snes_r_bank1(space, 0x00fffa) ); | |
| 753 | logerror( "\tStart Address: %2X%2Xh\n\n", snes_r_bank1(space, 0x00fffd), snes_r_bank1(space, 0x00fffc) ); | |
| 754 | ||
| 755 | logerror( "\tMode: %d\n", state->m_cart[0].mode); | |
| 756 | ||
| 757 | if (!supported) | |
| 758 | logerror("WARNING: This cart type \"%s\" is not supported yet!\n", types[state->m_has_addon_chip]); | |
| 759 | } | |
| 760 | ||
| 761 | static DEVICE_IMAGE_LOAD( snes_cart ) | |
| 762 | { | |
| 763 | int supported_type = 1, i, j; | |
| 764 | running_machine &machine = image.device().machine(); | |
| 765 | snes_state *state = machine.driver_data<snes_state>(); | |
| 766 | address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM ); | |
| 767 | int total_blocks, read_blocks, has_bsx_slot = 0, st_bios = 0; | |
| 768 | UINT32 offset, int_header_offs; | |
| 769 | UINT8 *ROM = image.device().machine().region("cart")->base(); | |
| 770 | ||
| 771 | if (image.software_entry() == NULL) | |
| 772 | state->m_cart_size = image.length(); | |
| 773 | else | |
| 774 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 775 | ||
| 776 | /* Check for a header (512 bytes), and skip it if found */ | |
| 777 | offset = snes_skip_header(image, state->m_cart_size); | |
| 778 | ||
| 779 | if (image.software_entry() == NULL) | |
| 780 | { | |
| 781 | image.fseek(offset, SEEK_SET); | |
| 782 | image.fread( ROM, state->m_cart_size - offset); | |
| 783 | } | |
| 784 | else | |
| 785 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 786 | ||
| 787 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 788 | ||
| 789 | /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */ | |
| 790 | int_header_offs = snes_find_hilo_mode(image, ROM, offset, 0); | |
| 791 | ||
| 792 | /* Then, detect BS-X carts */ | |
| 793 | // Detect presence of BS-X Flash Cart | |
| 794 | if ((ROM[int_header_offs + 0x13] == 0x00 || ROM[int_header_offs + 0x13] == 0xff) && | |
| 795 | ROM[int_header_offs + 0x14] == 0x00) | |
| 796 | { | |
| 797 | UINT8 n15 = ROM[int_header_offs + 0x15]; | |
| 798 | if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) | |
| 799 | { | |
| 800 | if (ROM[int_header_offs + 0x1a] == 0x33 || ROM[int_header_offs + 0x1a] == 0xff) | |
| 801 | { | |
| 802 | // BS-X Flash Cart | |
| 803 | state->m_cart[0].mode = SNES_MODE_BSX; | |
| 804 | } | |
| 805 | } | |
| 806 | } | |
| 807 | ||
| 808 | // Detect presence of BS-X flash cartridge connector | |
| 809 | if ((ROM[int_header_offs - 14] == 'Z') && (ROM[int_header_offs - 11] == 'J')) | |
| 810 | { | |
| 811 | UINT8 n13 = ROM[int_header_offs - 13]; | |
| 812 | if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) | |
| 813 | { | |
| 814 | if (ROM[int_header_offs + 0x1a] == 0x33 || | |
| 815 | (ROM[int_header_offs - 10] == 0x00 && ROM[int_header_offs - 4] == 0x00)) | |
| 816 | { | |
| 817 | has_bsx_slot = 1; | |
| 818 | } | |
| 819 | } | |
| 820 | } | |
| 821 | ||
| 822 | // If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart | |
| 823 | if (has_bsx_slot) | |
| 824 | { | |
| 825 | if (!memcmp(ROM + int_header_offs, "Satellaview BS-X ", 21)) | |
| 826 | { | |
| 827 | //BS-X Base Cart | |
| 828 | state->m_cart[0].mode = SNES_MODE_BSX; | |
| 829 | // handle RAM | |
| 830 | } | |
| 831 | else | |
| 832 | { | |
| 833 | state->m_cart[0].mode = (int_header_offs ==0x007fc0) ? SNES_MODE_BSLO : SNES_MODE_BSHI; | |
| 834 | // handle RAM? | |
| 835 | } | |
| 836 | } | |
| 837 | ||
| 838 | /* Then, detect Sufami Turbo carts */ | |
| 839 | if (!memcmp(ROM, "BANDAI SFC-ADX", 14)) | |
| 840 | { | |
| 841 | state->m_cart[0].mode = SNES_MODE_ST; | |
| 842 | if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14)) | |
| 843 | st_bios = 1; | |
| 844 | } | |
| 845 | ||
| 846 | if (SNES_CART_DEBUG) mame_printf_error("mode %d\n", state->m_cart[0].mode); | |
| 847 | ||
| 848 | /* FIXME: Insert crc check here? */ | |
| 849 | ||
| 850 | /* How many blocks of data are available to be loaded? */ | |
| 851 | total_blocks = ((state->m_cart_size - offset) / (state->m_cart[0].mode & 0xa5 ? 0x8000 : 0x10000)); | |
| 852 | read_blocks = 0; | |
| 853 | ||
| 854 | if (SNES_CART_DEBUG) mame_printf_error("blocks %d\n", total_blocks); | |
| 855 | ||
| 856 | /* Loading all the data blocks from cart, we only partially cover banks 0x00 to 0x7f. Therefore, we | |
| 857 | * have to mirror the blocks until we reach the end. E.g. for a 11Mbits image (44 blocks), we proceed | |
| 858 | * as follows: | |
| 859 | * 11 Mbits = 8 Mbits (blocks 1->32) + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44). | |
| 860 | * Hence, we fill memory up to 16 Mbits (banks 0x00 to 0x3f) mirroring as follows | |
| 861 | * 8 Mbits (blocks 1->32) + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44) + 1 Mbit (blocks 41->44) | |
| 862 | * + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44) + 1 Mbit (blocks 41->44) | |
| 863 | * and we repeat the same blocks in the second half of the banks (banks 0x40 to 0x7f). | |
| 864 | * This is likely what happens in the real SNES as well, because the unit cannot be aware of the exact | |
| 865 | * size of data in the cart (procedure confirmed by byuu) | |
| 866 | */ | |
| 867 | switch (state->m_cart[0].mode) | |
| 868 | { | |
| 869 | case SNES_MODE_21: | |
| 870 | /* HiROM carts load data in banks 0xc0 to 0xff. Each bank is fully mirrored in banks 0x40 to 0x7f | |
| 871 | * (actually up to 0x7d, because 0x7e and 0x7f are overwritten by WRAM). The top half (address | |
| 872 | * range 0x8000 - 0xffff) of each bank is also mirrored in banks 0x00 to 0x3f and 0x80 to 0xbf. | |
| 873 | */ | |
| 874 | /* SPC7110 games needs this different loading routine */ | |
| 875 | if ((ROM[0x00ffd6] == 0xf9 || ROM[0x00ffd6] == 0xf5) && (ROM[0x00ffd5] == 0x3a)) | |
| 876 | { | |
| 877 | while (read_blocks < 16 && read_blocks < total_blocks) | |
| 878 | { | |
| 879 | /* Loading data */ | |
| 880 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 881 | /* Mirroring */ | |
| 882 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 883 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 884 | read_blocks++; | |
| 885 | } | |
| 886 | } | |
| 887 | else | |
| 888 | { | |
| 889 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 890 | { | |
| 891 | /* Loading data */ | |
| 892 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 893 | /* Mirroring */ | |
| 894 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 895 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0xc00000 + read_blocks * 0x10000], 0x10000); | |
| 896 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 897 | read_blocks++; | |
| 898 | } | |
| 899 | /* Filling banks up to 0xff and their mirrors */ | |
| 900 | while (read_blocks % 64) | |
| 901 | { | |
| 902 | int j = 0, repeat_blocks; | |
| 903 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 904 | j++; | |
| 905 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 906 | ||
| 907 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &snes_ram[0xc00000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 908 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 909 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 910 | memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[0x800000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 911 | read_blocks += repeat_blocks; | |
| 912 | } | |
| 913 | } | |
| 914 | break; | |
| 915 | ||
| 916 | case SNES_MODE_25: | |
| 917 | /* Extendend HiROM carts start to load data in banks 0xc0 to 0xff. However, they exceed the | |
| 918 | * available space in these banks, and continue loading at banks 0x40 to 0x7f. The top half | |
| 919 | * (address range 0x8000 - 0xffff) of each bank is also mirrored either to banks 0x00 to 0x3f | |
| 920 | * (for data in banks 0x40 to 0x7f) or to banks 0x80 to 0xbf (for data in banks 0xc0 to 0xff). | |
| 921 | * Notice that banks 0x7e and 0x7f are overwritten by WRAM, but they could contain data at | |
| 922 | * address > 0x8000 because the mirrors at 0x3e and 0x3f are not overwritten. | |
| 923 | */ | |
| 924 | /* Reading the first 64 blocks */ | |
| 925 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 926 | { | |
| 927 | /* Loading data */ | |
| 928 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 929 | /* Mirroring */ | |
| 930 | memcpy( &snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 931 | read_blocks++; | |
| 932 | } | |
| 933 | /* ExHiROMs are supposed to be larger than 32Mbits! */ | |
| 934 | if (read_blocks < 64) | |
| 935 | { | |
| 936 | logerror("This image has been identified as ExHiROM, but it's too small!\n"); | |
| 937 | logerror("Please verify if it's corrupted. If it's not please report this as a bug.\n"); | |
| 938 | return IMAGE_INIT_FAIL; | |
| 939 | } | |
| 940 | /* Scaling down the counter */ | |
| 941 | read_blocks -= 64; | |
| 942 | /* Reading the next blocks */ | |
| 943 | while (read_blocks < 64 && read_blocks < (total_blocks - 64)) | |
| 944 | { | |
| 945 | /* Loading data */ | |
| 946 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &ROM[0x400000 + read_blocks * 0x10000], 0x10000); | |
| 947 | /* Mirroring */ | |
| 948 | memcpy(&snes_ram[0x8000 + read_blocks * 0x10000], &snes_ram[0x408000 + read_blocks * 0x10000], 0x8000); | |
| 949 | read_blocks++; | |
| 950 | } | |
| 951 | /* Filling banks up to 0x7f and their mirrors */ | |
| 952 | while (read_blocks % 64) | |
| 953 | { | |
| 954 | int j = 0, repeat_blocks; | |
| 955 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 956 | j++; | |
| 957 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 958 | ||
| 959 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 960 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 961 | read_blocks += repeat_blocks; | |
| 962 | } | |
| 963 | break; | |
| 964 | ||
| 965 | case SNES_MODE_22: | |
| 966 | /* "Extendend LoROM" carts have their data loaded in banks 0x00 to 0x3f at address 0x8000. | |
| 967 | * These are then mirrored in banks 0x40 to 0x7f, both at address 0x0000 and at address | |
| 968 | * 0x8000, in banks 0x80 to 0xbf at address 0x8000 and in banks 0xc0 to 0xff, both at address | |
| 969 | * 0x0000 and at address 0x8000. Notice that SDD-1 games (Star Ocean and Street Fighter Zero 2) | |
| 970 | * use SNES_MODE_22 | |
| 971 | */ | |
| 972 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 973 | { | |
| 974 | /* Loading and mirroring data */ | |
| 975 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 976 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 977 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 978 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 979 | read_blocks++; | |
| 980 | } | |
| 981 | /* Filling banks up to 0x3f and their mirrors */ | |
| 982 | while (read_blocks % 64) | |
| 983 | { | |
| 984 | int j = 0, repeat_blocks; | |
| 985 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 986 | j++; | |
| 987 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 988 | ||
| 989 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 990 | memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[0x800000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 991 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 992 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &snes_ram[0xc00000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 993 | read_blocks += repeat_blocks; | |
| 994 | } | |
| 995 | break; | |
| 996 | ||
| 997 | case SNES_MODE_ST: | |
| 998 | if (!st_bios) | |
| 999 | { | |
| 1000 | mame_printf_error("This is a Sufami Turbo data cart and cannot be loaded for snes/snespal in MESS.\n"); | |
| 1001 | mame_printf_error("Please use snesst driver to load it, instead.\n"); | |
| 1002 | return IMAGE_INIT_FAIL; | |
| 1003 | } | |
| 1004 | else | |
| 1005 | { | |
| 1006 | // The Base ST cart consists of 8 * 0x8000 block which have to be loaded (and mirrored) | |
| 1007 | // at 0x00-0x1f:0x8000-0xffff and 0x80-0x9f:0x8000-0xffff | |
| 1008 | for (i = 0; i < 8; i++) | |
| 1009 | { | |
| 1010 | /* Loading data */ | |
| 1011 | memcpy(&snes_ram[0x008000 + i * 0x10000], &ROM[0x000000 + i * 0x8000], 0x8000); | |
| 1012 | /* Mirroring */ | |
| 1013 | memcpy(&snes_ram[0x808000 + i * 0x10000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1014 | ||
| 1015 | /* Additional mirrors (to fill snes_ram up to 0x1fffff) */ | |
| 1016 | for (j = 1; j < 4; j++) | |
| 1017 | { | |
| 1018 | memcpy(&snes_ram[0x008000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1019 | memcpy(&snes_ram[0x808000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1020 | } | |
| 1021 | } | |
| 1022 | } | |
| 1023 | break; | |
| 1024 | ||
| 1025 | case SNES_MODE_BSX: | |
| 1026 | case SNES_MODE_BSLO: | |
| 1027 | case SNES_MODE_BSHI: | |
| 1028 | /* not handled yet */ | |
| 1029 | mame_printf_error("This is a BS-X Satellaview image: MESS does not support these yet, sorry.\n"); | |
| 1030 | #if 0 | |
| 1031 | // shall we force incompatibility of flash carts without a base unit? | |
| 1032 | if (!has_bsx_slot) | |
| 1033 | { | |
| 1034 | mame_printf_error("This is a BS-X flash cart and cannot be loaded in snes/snespal.\n"); | |
| 1035 | // mame_printf_error("Please use snesbsx driver to load it, instead.\n"); | |
| 1036 | return IMAGE_INIT_FAIL; | |
| 1037 | } | |
| 1038 | #endif | |
| 1039 | break; | |
| 1040 | ||
| 1041 | default: | |
| 1042 | case SNES_MODE_20: | |
| 1043 | /* LoROM carts load data in banks 0x00 to 0x7f at address 0x8000 (actually up to 0x7d, because 0x7e and | |
| 1044 | * 0x7f are overwritten by WRAM). Each block is also mirrored in banks 0x80 to 0xff (up to 0xff for real) | |
| 1045 | */ | |
| 1046 | /* SuperFX games needs this different loading routine */ | |
| 1047 | if (((ROM[0x007fd6] >= 0x13 && ROM[0x007fd6] <= 0x15) || ROM[0x007fd6] == 0x1a) && (ROM[0x007fd5] == 0x20)) | |
| 1048 | { | |
| 1049 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 1050 | { | |
| 1051 | /* Loading data primary: banks 0-3f from 8000-ffff*/ | |
| 1052 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1053 | /* Mirroring at banks 80-bf from 8000-ffff */ | |
| 1054 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000); | |
| 1055 | /* Mirroring at banks 40-5f and c0-df */ | |
| 1056 | memcpy(&snes_ram[0x400000 + read_blocks * 0x8000], &snes_ram[0x8000 + (read_blocks * 0x10000)], total_blocks * 0x8000); | |
| 1057 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x8000], &snes_ram[0x8000 + (read_blocks * 0x10000)], total_blocks * 0x8000); | |
| 1058 | ||
| 1059 | read_blocks++; | |
| 1060 | } | |
| 1061 | /* SuperFX games are supposed to contain 64 blocks! */ | |
| 1062 | if (read_blocks < total_blocks) | |
| 1063 | { | |
| 1064 | logerror("This image has been identified as a SuperFX game, but it's too large!\n"); | |
| 1065 | logerror("Please verify if it's corrupted. If it's not please report this as a bug.\n"); | |
| 1066 | return IMAGE_INIT_FAIL; | |
| 1067 | } | |
| 1068 | } | |
| 1069 | else | |
| 1070 | { | |
| 1071 | while (read_blocks < 128 && read_blocks < total_blocks) | |
| 1072 | { | |
| 1073 | /* Loading data */ | |
| 1074 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1075 | /* Mirroring */ | |
| 1076 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000); | |
| 1077 | read_blocks++; | |
| 1078 | } | |
| 1079 | /* Filling banks up to 0x7f and their mirrors */ | |
| 1080 | while (read_blocks % 128) | |
| 1081 | { | |
| 1082 | int j = 0, repeat_blocks; | |
| 1083 | while ((read_blocks % (128 >> j)) && j < 7) | |
| 1084 | j++; | |
| 1085 | repeat_blocks = read_blocks % (128 >> (j - 1)); | |
| 1086 | ||
| 1087 | memcpy( &snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1088 | memcpy( &snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1089 | read_blocks += repeat_blocks; | |
| 1090 | } | |
| 1091 | } | |
| 1092 | break; | |
| 1093 | } | |
| 1094 | ||
| 1095 | /* Detect special chips */ | |
| 1096 | supported_type = snes_find_addon_chip(machine); | |
| 1097 | ||
| 1098 | /* Find the amount of cart ram (even if we call it sram...) */ | |
| 1099 | if (image.software_entry() == NULL) | |
| 1100 | { | |
| 1101 | if ((state->m_has_addon_chip != HAS_SUPERFX)) | |
| 1102 | state->m_cart[0].sram = snes_r_bank1(space, 0x00ffd8); | |
| 1103 | else | |
| 1104 | state->m_cart[0].sram = (snes_r_bank1(space, 0x00ffbd) & 0x07); | |
| 1105 | ||
| 1106 | if (state->m_cart[0].sram > 0) | |
| 1107 | { | |
| 1108 | state->m_cart[0].sram = (1024 << state->m_cart[0].sram); | |
| 1109 | if (state->m_cart[0].sram > state->m_cart[0].sram_max) | |
| 1110 | state->m_cart[0].sram = state->m_cart[0].sram_max; | |
| 1111 | } | |
| 1112 | // printf("size %x\n", state->m_cart[0].sram); | |
| 1113 | } | |
| 1114 | else | |
| 1115 | { | |
| 1116 | // if we are loading from softlist, take sram from the xml | |
| 1117 | state->m_cart[0].sram = image.get_software_region("sram") ? image.get_software_region_length("sram") : 0; | |
| 1118 | ||
| 1119 | if (state->m_cart[0].sram > 0) | |
| 1120 | { | |
| 1121 | if (state->m_cart[0].sram > state->m_cart[0].sram_max) | |
| 1122 | fatalerror("Found more SRAM than max allowed (found: %x, max: %x), check xml file!\n", state->m_cart[0].sram, state->m_cart[0].sram_max); | |
| 1123 | } | |
| 1124 | // TODO: Eventually sram handlers should point to the allocated cart:sram region! | |
| 1125 | // For now, we only use the region as a placeholder to carry size info... | |
| 1126 | // printf("size %x\n", state->m_cart[0].sram); | |
| 1127 | } | |
| 1128 | ||
| 1129 | /* adjust size for very large carts */ | |
| 1130 | if (state->m_cart[0].mode == SNES_MODE_20 && ((state->m_cart_size - offset) > 0x200000 || state->m_cart[0].sram > (32 * 1024))) | |
| 1131 | state->m_cart[0].small_sram = 1; | |
| 1132 | else | |
| 1133 | state->m_cart[0].small_sram = 0; | |
| 1134 | ||
| 1135 | /* Log snes_cart information */ | |
| 1136 | snes_cart_log_info(machine, total_blocks, supported_type); | |
| 1137 | ||
| 1138 | /* Load SRAM */ | |
| 1139 | snes_load_sram(machine); | |
| 1140 | ||
| 1141 | /* All done */ | |
| 1142 | return IMAGE_INIT_PASS; | |
| 1143 | } | |
| 1144 | ||
| 1145 | static DEVICE_IMAGE_LOAD( sufami_cart ) | |
| 1146 | { | |
| 1147 | running_machine &machine = image.device().machine(); | |
| 1148 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1149 | int total_blocks, read_blocks; | |
| 1150 | int st_bios = 0, slot_id = 0; | |
| 1151 | UINT32 offset, st_data_offset = 0; | |
| 1152 | UINT8 *ROM = image.device().machine().region(image.device().tag())->base(); | |
| 1153 | ||
| 1154 | snes_ram = machine.region("maincpu")->base(); | |
| 1155 | ||
| 1156 | if (strcmp(image.device().tag(), "slot_a") == 0) | |
| 1157 | { | |
| 1158 | st_data_offset = 0x200000; | |
| 1159 | slot_id = 0; | |
| 1160 | } | |
| 1161 | ||
| 1162 | if (strcmp(image.device().tag(), "slot_b") == 0) | |
| 1163 | { | |
| 1164 | st_data_offset = 0x400000; | |
| 1165 | slot_id = 1; | |
| 1166 | } | |
| 1167 | ||
| 1168 | if (image.software_entry() == NULL) | |
| 1169 | state->m_cart_size = image.length(); | |
| 1170 | else | |
| 1171 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 1172 | ||
| 1173 | /* Check for a header (512 bytes), and skip it if found */ | |
| 1174 | offset = snes_skip_header(image, state->m_cart_size); | |
| 1175 | ||
| 1176 | if (image.software_entry() == NULL) | |
| 1177 | { | |
| 1178 | image.fseek(offset, SEEK_SET); | |
| 1179 | image.fread( ROM, state->m_cart_size - offset); | |
| 1180 | } | |
| 1181 | else | |
| 1182 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 1183 | ||
| 1184 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 1185 | ||
| 1186 | /* Detect Sufami Turbo carts */ | |
| 1187 | if (!memcmp(ROM, "BANDAI SFC-ADX", 14)) | |
| 1188 | { | |
| 1189 | state->m_cart[slot_id].mode = SNES_MODE_ST; | |
| 1190 | if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14)) | |
| 1191 | st_bios = 1; | |
| 1192 | } | |
| 1193 | else | |
| 1194 | { | |
| 1195 | mame_printf_error("This is not a Sufami Turbo data pack.\n"); | |
| 1196 | mame_printf_error("This image cannot be loaded in snesst (Use snes or snespal drivers, instead).\n"); | |
| 1197 | return IMAGE_INIT_FAIL; | |
| 1198 | } | |
| 1199 | ||
| 1200 | if (st_bios == 1) | |
| 1201 | { | |
| 1202 | mame_printf_error("This is the Sufami Turbo BIOS and not a Sufami Turbo data pack.\n"); | |
| 1203 | mame_printf_error("This image cannot be loaded in snesst.\n"); | |
| 1204 | return IMAGE_INIT_FAIL; | |
| 1205 | } | |
| 1206 | ||
| 1207 | /* FIXME: Insert crc check here? */ | |
| 1208 | ||
| 1209 | /* How many blocks of data are available to be loaded? */ | |
| 1210 | total_blocks = (state->m_cart_size - offset) / 0x8000; | |
| 1211 | read_blocks = 0; | |
| 1212 | ||
| 1213 | if (SNES_CART_DEBUG) | |
| 1214 | mame_printf_error("blocks %d\n", total_blocks); | |
| 1215 | ||
| 1216 | // actually load the cart | |
| 1217 | while (read_blocks < 32 && read_blocks < total_blocks) | |
| 1218 | { | |
| 1219 | /* Loading data */ | |
| 1220 | // CART (either A or B) | |
| 1221 | memcpy(&snes_ram[0x008000 + st_data_offset + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1222 | /* Mirroring */ | |
| 1223 | memcpy(&snes_ram[0x808000 + st_data_offset + read_blocks * 0x10000], &snes_ram[0x8000 + st_data_offset + (read_blocks * 0x10000)], 0x8000); | |
| 1224 | ||
| 1225 | read_blocks++; | |
| 1226 | } | |
| 1227 | ||
| 1228 | /* Filling banks up to 0x1f and their mirrors */ | |
| 1229 | while (read_blocks % 32) | |
| 1230 | { | |
| 1231 | int j = 0, repeat_blocks; | |
| 1232 | while ((read_blocks % (32 >> j)) && j < 5) | |
| 1233 | j++; | |
| 1234 | repeat_blocks = read_blocks % (32 >> (j - 1)); | |
| 1235 | ||
| 1236 | memcpy(&snes_ram[st_data_offset + read_blocks * 0x10000], &snes_ram[st_data_offset + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1237 | memcpy(&snes_ram[0x800000 + st_data_offset + read_blocks * 0x10000], &snes_ram[st_data_offset + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1238 | read_blocks += repeat_blocks; | |
| 1239 | } | |
| 1240 | ||
| 1241 | sufami_load_sram(machine, image.device().tag()); | |
| 1242 | ||
| 1243 | state->m_cart[slot_id].slot_in_use = 1; // aknowledge the cart in this slot, for saving sram at exit | |
| 1244 | ||
| 1245 | auto_free(image.device().machine(), ROM); | |
| 1246 | ||
| 1247 | return IMAGE_INIT_PASS; | |
| 1248 | } | |
| 1249 | ||
| 1250 | static DEVICE_IMAGE_LOAD( bsx_cart ) | |
| 1251 | { | |
| 1252 | running_machine &machine = image.device().machine(); | |
| 1253 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1254 | int total_blocks, read_blocks; | |
| 1255 | int has_bsx_slot = 0; | |
| 1256 | UINT32 offset, int_header_offs; | |
| 1257 | UINT8 *ROM = image.device().machine().region("cart")->base(); | |
| 1258 | ||
| 1259 | if (image.software_entry() == NULL) | |
| 1260 | state->m_cart_size = image.length(); | |
| 1261 | else | |
| 1262 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 1263 | ||
| 1264 | /* Check for a header (512 bytes), and skip it if found */ | |
| 1265 | offset = snes_skip_header(image, state->m_cart_size); | |
| 1266 | ||
| 1267 | if (image.software_entry() == NULL) | |
| 1268 | { | |
| 1269 | image.fseek(offset, SEEK_SET); | |
| 1270 | image.fread( ROM, state->m_cart_size - offset); | |
| 1271 | } | |
| 1272 | else | |
| 1273 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 1274 | ||
| 1275 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 1276 | ||
| 1277 | /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */ | |
| 1278 | int_header_offs = snes_find_hilo_mode(image, ROM, offset, 0); | |
| 1279 | ||
| 1280 | // Detect presence of BS-X flash cartridge connector | |
| 1281 | if ((ROM[int_header_offs - 14] == 'Z') && (ROM[int_header_offs - 11] == 'J')) | |
| 1282 | { | |
| 1283 | UINT8 n13 = ROM[int_header_offs - 13]; | |
| 1284 | if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) | |
| 1285 | { | |
| 1286 | if (ROM[int_header_offs + 0x1a] == 0x33 || | |
| 1287 | (ROM[int_header_offs - 10] == 0x00 && ROM[int_header_offs - 4] == 0x00)) | |
| 1288 | { | |
| 1289 | has_bsx_slot = 1; | |
| 1290 | } | |
| 1291 | } | |
| 1292 | } | |
| 1293 | ||
| 1294 | // If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart | |
| 1295 | if (has_bsx_slot) | |
| 1296 | { | |
| 1297 | if (!memcmp(ROM + int_header_offs, "Satellaview BS-X ", 21)) | |
| 1298 | { | |
| 1299 | //BS-X Base Cart | |
| 1300 | state->m_cart[0].mode = SNES_MODE_BSX; | |
| 1301 | // handle RAM | |
| 1302 | } | |
| 1303 | else | |
| 1304 | { | |
| 1305 | state->m_cart[0].mode = (int_header_offs ==0x007fc0) ? SNES_MODE_BSLO : SNES_MODE_BSHI; | |
| 1306 | // handle RAM? | |
| 1307 | } | |
| 1308 | } | |
| 1309 | else | |
| 1310 | { | |
| 1311 | mame_printf_error("This is not a BS-X compatible cart.\n"); | |
| 1312 | mame_printf_error("This image cannot be loaded in the first cartslot of snesbsx.\n"); | |
| 1313 | return IMAGE_INIT_FAIL; | |
| 1314 | } | |
| 1315 | ||
| 1316 | ||
| 1317 | /* FIXME: Insert crc check here? */ | |
| 1318 | ||
| 1319 | /* How many blocks of data are available to be loaded? */ | |
| 1320 | total_blocks = (state->m_cart_size - offset) / 0x8000; | |
| 1321 | read_blocks = 0; | |
| 1322 | ||
| 1323 | if (SNES_CART_DEBUG) mame_printf_error("blocks %d\n", total_blocks); | |
| 1324 | ||
| 1325 | // actually load the cart | |
| 1326 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 1327 | { | |
| 1328 | /* Loading data */ | |
| 1329 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1330 | /* Mirroring */ | |
| 1331 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000); | |
| 1332 | ||
| 1333 | read_blocks++; | |
| 1334 | } | |
| 1335 | ||
| 1336 | /* Filling banks up to 0x3f and their mirrors */ | |
| 1337 | while (read_blocks % 64) | |
| 1338 | { | |
| 1339 | int j = 0, repeat_blocks; | |
| 1340 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 1341 | j++; | |
| 1342 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 1343 | ||
| 1344 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1345 | memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1346 | read_blocks += repeat_blocks; | |
| 1347 | } | |
| 1348 | ||
| 1349 | return IMAGE_INIT_PASS; | |
| 1350 | } | |
| 1351 | ||
| 1352 | static DEVICE_IMAGE_LOAD( bsx2slot_cart ) | |
| 1353 | { | |
| 1354 | running_machine &machine = image.device().machine(); | |
| 1355 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1356 | UINT32 offset, int_header_offs; | |
| 1357 | UINT8 *ROM = image.device().machine().region("flash")->base(); | |
| 1358 | ||
| 1359 | if (image.software_entry() == NULL) | |
| 1360 | state->m_cart_size = image.length(); | |
| 1361 | else | |
| 1362 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 1363 | ||
| 1364 | /* Check for a header (512 bytes), and skip it if found */ | |
| 1365 | offset = snes_skip_header(image, state->m_cart_size); | |
| 1366 | ||
| 1367 | if (image.software_entry() == NULL) | |
| 1368 | { | |
| 1369 | image.fseek(offset, SEEK_SET); | |
| 1370 | image.fread( ROM, state->m_cart_size - offset); | |
| 1371 | } | |
| 1372 | else | |
| 1373 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 1374 | ||
| 1375 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 1376 | ||
| 1377 | /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */ | |
| 1378 | int_header_offs = snes_find_hilo_mode(image, ROM, offset, 1); | |
| 1379 | ||
| 1380 | // Detect presence of BS-X Flash Cart | |
| 1381 | if ((ROM[int_header_offs + 0x13] == 0x00 || ROM[int_header_offs + 0x13] == 0xff) && | |
| 1382 | ROM[int_header_offs + 0x14] == 0x00) | |
| 1383 | { | |
| 1384 | UINT8 n15 = ROM[int_header_offs + 0x15]; | |
| 1385 | if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) | |
| 1386 | { | |
| 1387 | if (ROM[int_header_offs + 0x1a] == 0x33 || ROM[int_header_offs + 0x1a] == 0xff) | |
| 1388 | { | |
| 1389 | // BS-X Flash Cart | |
| 1390 | state->m_cart[1].mode = SNES_MODE_BSX; | |
| 1391 | } | |
| 1392 | } | |
| 1393 | } | |
| 1394 | ||
| 1395 | if (state->m_cart[1].mode != SNES_MODE_BSX) | |
| 1396 | { | |
| 1397 | mame_printf_error("This is not a BS-X flash cart.\n"); | |
| 1398 | mame_printf_error("This image cannot be loaded in the second cartslot of snesbsx.\n"); | |
| 1399 | return IMAGE_INIT_FAIL; | |
| 1400 | } | |
| 1401 | ||
| 1402 | // actually load the cart | |
| 1403 | return IMAGE_INIT_PASS; | |
| 1404 | } | |
| 1405 | ||
| 1406 | MACHINE_CONFIG_FRAGMENT( snes_cartslot ) | |
| 1407 | MCFG_CARTSLOT_ADD("cart") | |
| 1408 | MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin") | |
| 1409 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1410 | MCFG_CARTSLOT_INTERFACE("snes_cart") | |
| 1411 | MCFG_CARTSLOT_LOAD(snes_cart) | |
| 1412 | MCFG_SOFTWARE_LIST_ADD("cart_list","snes") | |
| 1413 | MACHINE_CONFIG_END | |
| 1414 | ||
| 1415 | // This (hackily) emulates a SNES unit with a Sufami Turbo Unit cart inserted: | |
| 1416 | // hence, the user can mount two data cart in the two slots available on the ST Unit | |
| 1417 | MACHINE_CONFIG_FRAGMENT( sufami_cartslot ) | |
| 1418 | MCFG_CARTSLOT_ADD("slot_a") | |
| 1419 | MCFG_CARTSLOT_EXTENSION_LIST("st,sfc") | |
| 1420 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1421 | MCFG_CARTSLOT_INTERFACE("sufami_cart") | |
| 1422 | MCFG_CARTSLOT_LOAD(sufami_cart) | |
| 1423 | ||
| 1424 | MCFG_CARTSLOT_ADD("slot_b") | |
| 1425 | MCFG_CARTSLOT_EXTENSION_LIST("st,sfc") | |
| 1426 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1427 | MCFG_CARTSLOT_INTERFACE("sufami_cart") | |
| 1428 | MCFG_CARTSLOT_LOAD(sufami_cart) | |
| 1429 | ||
| 1430 | // MCFG_SOFTWARE_LIST_ADD("cart_list","snes") | |
| 1431 | MACHINE_CONFIG_END | |
| 1432 | ||
| 1433 | // This (hackily) emulates a SNES unit where you want to load a BS-X compatible cart: | |
| 1434 | // hence, the user can mount a SNES cart in the first slot (either a BS-X BIOS cart, or a | |
| 1435 | // BS-X compatible one, e.g. Same Game), and there is a second slot for the 8M data pack | |
| 1436 | // (in a real SNES this would have been inserted in the smaller slot on the cart itself) | |
| 1437 | MACHINE_CONFIG_FRAGMENT( bsx_cartslot ) | |
| 1438 | MCFG_CARTSLOT_ADD("cart") | |
| 1439 | MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin") | |
| 1440 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1441 | MCFG_CARTSLOT_INTERFACE("snes_cart") | |
| 1442 | MCFG_CARTSLOT_LOAD(bsx_cart) | |
| 1443 | ||
| 1444 | MCFG_CARTSLOT_ADD("slot2") | |
| 1445 | MCFG_CARTSLOT_EXTENSION_LIST("bs,sfc") | |
| 1446 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1447 | MCFG_CARTSLOT_INTERFACE("bsx_cart") | |
| 1448 | MCFG_CARTSLOT_LOAD(bsx2slot_cart) | |
| 1449 | ||
| 1450 | // MCFG_SOFTWARE_LIST_ADD("cart_list","snes") | |
| 1451 | MACHINE_CONFIG_END | |
| 1452 | ||
| 1453 | DRIVER_INIT( snes_mess ) | |
| 1454 | { | |
| 1455 | snes_ram = machine.region("maincpu")->base(); | |
| 1456 | memset(snes_ram, 0, 0x1000000); | |
| 1457 | } | |
| 1458 | ||
| 1459 | DRIVER_INIT( snesst ) | |
| 1460 | { | |
| 1461 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1462 | UINT8 *STBIOS = machine.region("sufami")->base(); | |
| 1463 | int i, j; | |
| 1464 | ||
| 1465 | state->m_cart[0].slot_in_use = 0; | |
| 1466 | state->m_cart[1].slot_in_use = 0; | |
| 1467 | ||
| 1468 | DRIVER_INIT_CALL(snes_mess); | |
| 1469 | ||
| 1470 | // the Base ST cart consists of 8 * 0x8000 block which have to be loaded (and mirrored) | |
| 1471 | // at 0x00-0x1f:0x8000-0xffff and 0x80-0x9f:0x8000-0xffff | |
| 1472 | for (i = 0; i < 8; i++) | |
| 1473 | { | |
| 1474 | /* Loading data */ | |
| 1475 | memcpy(&snes_ram[0x008000 + i * 0x10000], &STBIOS[0x000000 + i * 0x8000], 0x8000); | |
| 1476 | /* Mirroring */ | |
| 1477 | memcpy(&snes_ram[0x808000 + i * 0x10000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1478 | ||
| 1479 | /* Additional mirrors (to fill snes_ram up to 0x1fffff) */ | |
| 1480 | for (j = 1; j < 4; j++) | |
| 1481 | { | |
| 1482 | memcpy(&snes_ram[0x008000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1483 | memcpy(&snes_ram[0x808000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1484 | } | |
| 1485 | } | |
| 1486 | ||
| 1487 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | snescart.h | |
| 3 | ||
| 4 | */ | |
| 5 | ||
| 6 | #ifndef _SNESCART_H | |
| 7 | #define _SNESCART_H | |
| 8 | ||
| 9 | #include "imagedev/cartslot.h" | |
| 10 | ||
| 11 | MACHINE_START( snes_mess ); | |
| 12 | MACHINE_START( snesst ); | |
| 13 | ||
| 14 | DRIVER_INIT( snes_mess ); | |
| 15 | DRIVER_INIT( snesst ); | |
| 16 | ||
| 17 | MACHINE_CONFIG_EXTERN( snes_cartslot ); | |
| 18 | MACHINE_CONFIG_EXTERN( sufami_cartslot ); | |
| 19 | MACHINE_CONFIG_EXTERN( bsx_cartslot ); | |
| 20 | ||
| 21 | #endif /* _SNESCART_H */ | |
| 22 |
| r11531 | r11532 | |
|---|---|---|
| 1 | /************************************************************ | |
| 2 | ||
| 3 | PC Engine CD HW notes: | |
| 4 | ||
| 5 | CD Interface Register 0x00 - CDC status | |
| 6 | x--- ---- busy signal | |
| 7 | -x-- ---- request signal | |
| 8 | ---x ---- cd signal | |
| 9 | ---- x--- i/o signal | |
| 10 | ||
| 11 | CD Interface Register 0x03 - BRAM lock / CD status | |
| 12 | -x-- ---- acknowledge signal | |
| 13 | --x- ---- done signal | |
| 14 | ---x ---- bram signal | |
| 15 | ---- x--- ADPCM 2 | |
| 16 | ---- -x-- ADPCM 1 | |
| 17 | ---- --x- CDDA left/right speaker select | |
| 18 | ||
| 19 | CD Interface Register 0x05 - CD-DA Volume low 8-bit port | |
| 20 | ||
| 21 | CD Interface Register 0x06 - CD-DA Volume high 8-bit port | |
| 22 | ||
| 23 | CD Interface Register 0x07 - BRAM unlock / CD status | |
| 24 | x--- ---- Enables BRAM | |
| 25 | ||
| 26 | CD Interface Register 0x0c - ADPCM status | |
| 27 | x--- ---- ADPCM is reading data | |
| 28 | ---- x--- ADPCM playback (0) stopped (1) currently playing | |
| 29 | ---- -x-- pending ADPCM data write | |
| 30 | ---- ---x ADPCM playback (1) stopped (0) currently playing | |
| 31 | ||
| 32 | CD Interface Register 0x0d - ADPCM address control | |
| 33 | x--- ---- ADPCM reset | |
| 34 | -x-- ---- ADPCM play | |
| 35 | --x- ---- ADPCM repeat | |
| 36 | ---x ---- ADPCM set length | |
| 37 | ---- x--- ADPCM set read address | |
| 38 | ---- --xx ADPCM set write address | |
| 39 | (note: some games reads bit 5 and wants it to be low otherwise they hangs, surely NOT an ADPCM repeat flag read because it doesn't make sense) | |
| 40 | ||
| 41 | CD Interface Register 0x0e - ADPCM playback rate | |
| 42 | ||
| 43 | CD Interface Register 0x0f - ADPCM fade in/out register | |
| 44 | ---- xxxx command setting: | |
| 45 | 0x00 ADPCM/CD-DA Fade-in | |
| 46 | 0x01 CD-DA fade-in | |
| 47 | 0x08 CD-DA fade-out (short) ADPCM fade-in | |
| 48 | 0x09 CD-DA fade-out (long) | |
| 49 | 0x0a ADPCM fade-out (long) | |
| 50 | 0x0c CD-DA fade-out (short) ADPCM fade-in | |
| 51 | 0x0d CD-DA fade-out (short) | |
| 52 | 0x0e ADPCM fade-out (short) | |
| 53 | ||
| 54 | *************************************************************/ | |
| 55 | ||
| 56 | #include "emu.h" | |
| 57 | #include "coreutil.h" | |
| 58 | #include "cpu/h6280/h6280.h" | |
| 59 | #include "includes/pce.h" | |
| 60 | #include "imagedev/chd_cd.h" | |
| 61 | #include "sound/msm5205.h" | |
| 62 | #include "sound/cdda.h" | |
| 63 | #include "hashfile.h" | |
| 64 | ||
| 65 | ||
| 66 | #define PCE_BRAM_SIZE 0x800 | |
| 67 | #define PCE_ADPCM_RAM_SIZE 0x10000 | |
| 68 | #define PCE_ACARD_RAM_SIZE 0x200000 | |
| 69 | #define PCE_CD_COMMAND_BUFFER_SIZE 0x100 | |
| 70 | ||
| 71 | #define PCE_CD_IRQ_TRANSFER_READY 0x40 | |
| 72 | #define PCE_CD_IRQ_TRANSFER_DONE 0x20 | |
| 73 | #define PCE_CD_IRQ_SAMPLE_FULL_PLAY 0x08 | |
| 74 | #define PCE_CD_IRQ_SAMPLE_HALF_PLAY 0x04 | |
| 75 | ||
| 76 | #define PCE_CD_ADPCM_PLAY_FLAG 0x08 | |
| 77 | #define PCE_CD_ADPCM_STOP_FLAG 0x01 | |
| 78 | ||
| 79 | #define PCE_CD_DATA_FRAMES_PER_SECOND 75 | |
| 80 | ||
| 81 | enum { | |
| 82 | PCE_CD_CDDA_OFF=0, | |
| 83 | PCE_CD_CDDA_PLAYING, | |
| 84 | PCE_CD_CDDA_PAUSED | |
| 85 | }; | |
| 86 | ||
| 87 | ||
| 88 | /* CD Unit RAM */ | |
| 89 | ||
| 90 | /* MSM5205 ADPCM decoder definition */ | |
| 91 | static void pce_cd_msm5205_int(device_t *device); | |
| 92 | const msm5205_interface pce_cd_msm5205_interface = { | |
| 93 | pce_cd_msm5205_int, /* interrupt function */ | |
| 94 | MSM5205_S48_4B /* 1/48 prescaler, 4bit data */ | |
| 95 | }; | |
| 96 | ||
| 97 | ||
| 98 | /* joystick related data*/ | |
| 99 | ||
| 100 | #define JOY_CLOCK 0x01 | |
| 101 | #define JOY_RESET 0x02 | |
| 102 | ||
| 103 | ||
| 104 | /* prototypes */ | |
| 105 | static void pce_cd_init( running_machine &machine ); | |
| 106 | static void pce_cd_set_irq_line( running_machine &machine, int num, int state ); | |
| 107 | static TIMER_CALLBACK( pce_cd_adpcm_dma_timer_callback ); | |
| 108 | static TIMER_CALLBACK( pce_cd_cdda_fadeout_callback ); | |
| 109 | static TIMER_CALLBACK( pce_cd_cdda_fadein_callback ); | |
| 110 | static TIMER_CALLBACK( pce_cd_adpcm_fadeout_callback ); | |
| 111 | static TIMER_CALLBACK( pce_cd_adpcm_fadein_callback ); | |
| 112 | ||
| 113 | static WRITE8_HANDLER( pce_sf2_banking_w ) | |
| 114 | { | |
| 115 | memory_set_bankptr( space->machine(), "bank2", space->machine().region("user1")->base() + offset * 0x080000 + 0x080000 ); | |
| 116 | memory_set_bankptr( space->machine(), "bank3", space->machine().region("user1")->base() + offset * 0x080000 + 0x088000 ); | |
| 117 | memory_set_bankptr( space->machine(), "bank4", space->machine().region("user1")->base() + offset * 0x080000 + 0x0D0000 ); | |
| 118 | } | |
| 119 | ||
| 120 | static WRITE8_HANDLER( pce_cartridge_ram_w ) | |
| 121 | { | |
| 122 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 123 | state->m_cartridge_ram[offset] = data; | |
| 124 | } | |
| 125 | ||
| 126 | DEVICE_IMAGE_LOAD(pce_cart) | |
| 127 | { | |
| 128 | pce_state *state = image.device().machine().driver_data<pce_state>(); | |
| 129 | UINT32 size; | |
| 130 | int split_rom = 0, offset = 0; | |
| 131 | const char *extrainfo = NULL; | |
| 132 | unsigned char *ROM; | |
| 133 | logerror("*** DEVICE_IMAGE_LOAD(pce_cart) : %s\n", image.filename()); | |
| 134 | ||
| 135 | /* open file to get size */ | |
| 136 | ROM = image.device().machine().region("user1")->base(); | |
| 137 | ||
| 138 | if (image.software_entry() == NULL) | |
| 139 | size = image.length(); | |
| 140 | else | |
| 141 | size = image.get_software_region_length("rom"); | |
| 142 | ||
| 143 | /* handle header accordingly */ | |
| 144 | if ((size / 512) & 1) | |
| 145 | { | |
| 146 | logerror("*** DEVICE_IMAGE_LOAD(pce_cart) : Header present\n"); | |
| 147 | size -= 512; | |
| 148 | offset = 512; | |
| 149 | } | |
| 150 | ||
| 151 | if (size > PCE_ROM_MAXSIZE) | |
| 152 | size = PCE_ROM_MAXSIZE; | |
| 153 | ||
| 154 | if (image.software_entry() == NULL) | |
| 155 | { | |
| 156 | image.fseek(offset, SEEK_SET); | |
| 157 | image.fread( ROM, size); | |
| 158 | extrainfo = hashfile_extrainfo(image); | |
| 159 | } | |
| 160 | else | |
| 161 | memcpy(ROM, image.get_software_region("rom") + offset, size); | |
| 162 | ||
| 163 | if (extrainfo) | |
| 164 | { | |
| 165 | logerror("extrainfo: %s\n", extrainfo); | |
| 166 | if (strstr(extrainfo, "ROM_SPLIT")) | |
| 167 | split_rom = 1; | |
| 168 | } | |
| 169 | ||
| 170 | if (ROM[0x1fff] < 0xe0) | |
| 171 | { | |
| 172 | int i; | |
| 173 | UINT8 decrypted[256]; | |
| 174 | ||
| 175 | logerror( "*** DEVICE_IMAGE_LOAD(pce_cart) : ROM image seems encrypted, decrypting...\n" ); | |
| 176 | ||
| 177 | /* Initialize decryption table */ | |
| 178 | for (i = 0; i < 256; i++) | |
| 179 | decrypted[i] = ((i & 0x01) << 7) | ((i & 0x02) << 5) | ((i & 0x04) << 3) | ((i & 0x08) << 1) | ((i & 0x10) >> 1) | ((i & 0x20 ) >> 3) | ((i & 0x40) >> 5) | ((i & 0x80) >> 7); | |
| 180 | ||
| 181 | /* Decrypt ROM image */ | |
| 182 | for (i = 0; i < size; i++) | |
| 183 | ROM[i] = decrypted[ROM[i]]; | |
| 184 | } | |
| 185 | ||
| 186 | /* check if we're dealing with a split rom image */ | |
| 187 | if (size == 384 * 1024) | |
| 188 | { | |
| 189 | split_rom = 1; | |
| 190 | /* Mirror the upper 128KB part of the image */ | |
| 191 | memcpy(ROM + 0x060000, ROM + 0x040000, 0x020000); /* Set up 060000 - 07FFFF mirror */ | |
| 192 | } | |
| 193 | ||
| 194 | /* set up the memory for a split rom image */ | |
| 195 | if (split_rom) | |
| 196 | { | |
| 197 | logerror("Split rom detected, setting up memory accordingly\n"); | |
| 198 | /* Set up ROM address space as follows: */ | |
| 199 | /* 000000 - 03FFFF : ROM data 000000 - 03FFFF */ | |
| 200 | /* 040000 - 07FFFF : ROM data 000000 - 03FFFF */ | |
| 201 | /* 080000 - 0BFFFF : ROM data 040000 - 07FFFF */ | |
| 202 | /* 0C0000 - 0FFFFF : ROM data 040000 - 07FFFF */ | |
| 203 | memcpy(ROM + 0x080000, ROM + 0x040000, 0x040000); /* Set up 080000 - 0BFFFF region */ | |
| 204 | memcpy(ROM + 0x0C0000, ROM + 0x040000, 0x040000); /* Set up 0C0000 - 0FFFFF region */ | |
| 205 | memcpy(ROM + 0x040000, ROM, 0x040000); /* Set up 040000 - 07FFFF region */ | |
| 206 | } | |
| 207 | else | |
| 208 | { | |
| 209 | /* mirror 256KB rom data */ | |
| 210 | if (size <= 0x040000) | |
| 211 | memcpy(ROM + 0x040000, ROM, 0x040000); | |
| 212 | ||
| 213 | /* mirror 512KB rom data */ | |
| 214 | if (size <= 0x080000) | |
| 215 | memcpy(ROM + 0x080000, ROM, 0x080000); | |
| 216 | } | |
| 217 | ||
| 218 | memory_set_bankptr(image.device().machine(), "bank1", ROM); | |
| 219 | memory_set_bankptr(image.device().machine(), "bank2", ROM + 0x080000); | |
| 220 | memory_set_bankptr(image.device().machine(), "bank3", ROM + 0x088000); | |
| 221 | memory_set_bankptr(image.device().machine(), "bank4", ROM + 0x0d0000); | |
| 222 | ||
| 223 | /* Check for Street fighter 2 */ | |
| 224 | if (size == PCE_ROM_MAXSIZE) | |
| 225 | { | |
| 226 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x01ff0, 0x01ff3, FUNC(pce_sf2_banking_w)); | |
| 227 | } | |
| 228 | ||
| 229 | /* Check for Populous */ | |
| 230 | if (!memcmp(ROM + 0x1F26, "POPULOUS", 8)) | |
| 231 | { | |
| 232 | state->m_cartridge_ram = auto_alloc_array(image.device().machine(), UINT8, 0x8000); | |
| 233 | memory_set_bankptr(image.device().machine(), "bank2", state->m_cartridge_ram); | |
| 234 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x080000, 0x087FFF, FUNC(pce_cartridge_ram_w)); | |
| 235 | } | |
| 236 | ||
| 237 | /* Check for CD system card */ | |
| 238 | state->m_sys3_card = 0; | |
| 239 | if (!memcmp(ROM + 0x3FFB6, "PC Engine CD-ROM SYSTEM", 23)) | |
| 240 | { | |
| 241 | /* Check if 192KB additional system card ram should be used */ | |
| 242 | if(!memcmp(ROM + 0x29D1, "VER. 3.", 7)) { state->m_sys3_card = 1; } // JP version | |
| 243 | else if(!memcmp(ROM + 0x29C4, "VER. 3.", 7 )) { state->m_sys3_card = 3; } // US version | |
| 244 | ||
| 245 | if(state->m_sys3_card) | |
| 246 | { | |
| 247 | state->m_cartridge_ram = auto_alloc_array(image.device().machine(), UINT8, 0x30000); | |
| 248 | memory_set_bankptr(image.device().machine(), "bank4", state->m_cartridge_ram); | |
| 249 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x0D0000, 0x0FFFFF, FUNC(pce_cartridge_ram_w)); | |
| 250 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x080000, 0x087FFF, FUNC(pce_cd_acard_wram_r),FUNC(pce_cd_acard_wram_w)); | |
| 251 | } | |
| 252 | } | |
| 253 | return 0; | |
| 254 | } | |
| 255 | ||
| 256 | #ifdef MESS | |
| 257 | DRIVER_INIT( pce ) | |
| 258 | { | |
| 259 | pce_state *state = machine.driver_data<pce_state>(); | |
| 260 | state->m_io_port_options = PCE_JOY_SIG | CONST_SIG; | |
| 261 | } | |
| 262 | #endif | |
| 263 | ||
| 264 | DRIVER_INIT( tg16 ) | |
| 265 | { | |
| 266 | pce_state *state = machine.driver_data<pce_state>(); | |
| 267 | state->m_io_port_options = TG_16_JOY_SIG | CONST_SIG; | |
| 268 | } | |
| 269 | ||
| 270 | DRIVER_INIT( sgx ) | |
| 271 | { | |
| 272 | pce_state *state = machine.driver_data<pce_state>(); | |
| 273 | state->m_io_port_options = PCE_JOY_SIG | CONST_SIG; | |
| 274 | } | |
| 275 | ||
| 276 | MACHINE_START( pce ) | |
| 277 | { | |
| 278 | pce_cd_init( machine ); | |
| 279 | } | |
| 280 | ||
| 281 | #ifdef MESS | |
| 282 | MACHINE_RESET( pce ) | |
| 283 | { | |
| 284 | pce_state *state = machine.driver_data<pce_state>(); | |
| 285 | pce_cd_t &pce_cd = state->m_cd; | |
| 286 | int joy_i; | |
| 287 | ||
| 288 | for (joy_i = 0; joy_i < 5; joy_i++) | |
| 289 | state->m_joy_6b_packet[joy_i] = 0; | |
| 290 | ||
| 291 | pce_cd.adpcm_read_buf = 0; | |
| 292 | pce_cd.adpcm_write_buf = 0; | |
| 293 | ||
| 294 | // TODO: add CD-DA stop command here | |
| 295 | ||
| 296 | pce_cd.regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG; | |
| 297 | pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG; | |
| 298 | //pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c) | (PCE_CD_SAMPLE_STOP_PLAY); | |
| 299 | ||
| 300 | /* Note: Arcade Card BIOS contents are the same as System 3, only internal HW differs. | |
| 301 | We use a category to select between modes (some games can be run in either S-CD or A-CD modes) */ | |
| 302 | state->m_acard = input_port_read(machine, "A_CARD") & 1; | |
| 303 | } | |
| 304 | ||
| 305 | /* todo: how many input ports does the PCE have? */ | |
| 306 | WRITE8_HANDLER ( pce_joystick_w ) | |
| 307 | { | |
| 308 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 309 | int joy_i; | |
| 310 | UINT8 joy_type = input_port_read(space->machine(),"JOY_TYPE"); | |
| 311 | ||
| 312 | h6280io_set_buffer(&space->device(), data); | |
| 313 | ||
| 314 | /* bump counter on a low-to-high transition of bit 1 */ | |
| 315 | if ((!state->m_joystick_data_select) && (data & JOY_CLOCK)) | |
| 316 | { | |
| 317 | state->m_joystick_port_select = (state->m_joystick_port_select + 1) & 0x07; | |
| 318 | } | |
| 319 | ||
| 320 | /* do we want buttons or direction? */ | |
| 321 | state->m_joystick_data_select = data & JOY_CLOCK; | |
| 322 | ||
| 323 | /* clear counter if bit 2 is set */ | |
| 324 | if (data & JOY_RESET) | |
| 325 | { | |
| 326 | state->m_joystick_port_select = 0; | |
| 327 | ||
| 328 | for (joy_i = 0; joy_i < 5; joy_i++) | |
| 329 | { | |
| 330 | if (((joy_type >> (joy_i*2)) & 3) == 2) | |
| 331 | state->m_joy_6b_packet[joy_i] ^= 1; | |
| 332 | } | |
| 333 | } | |
| 334 | } | |
| 335 | ||
| 336 | READ8_HANDLER ( pce_joystick_r ) | |
| 337 | { | |
| 338 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 339 | static const char *const joyname[4][5] = { | |
| 340 | { "JOY_P1", "JOY_P2", "JOY_P3", "JOY_P4", "JOY_P5" }, | |
| 341 | { }, | |
| 342 | { "JOY6B_P1", "JOY6B_P2", "JOY6B_P3", "JOY6B_P4", "JOY6B_P5" }, | |
| 343 | { } | |
| 344 | }; | |
| 345 | UINT8 joy_type = input_port_read(space->machine(), "JOY_TYPE"); | |
| 346 | UINT8 ret, data; | |
| 347 | ||
| 348 | if (state->m_joystick_port_select <= 4) | |
| 349 | { | |
| 350 | switch((joy_type >> (state->m_joystick_port_select*2)) & 3) | |
| 351 | { | |
| 352 | case 0: //2-buttons pad | |
| 353 | data = input_port_read(space->machine(), joyname[0][state->m_joystick_port_select]); | |
| 354 | break; | |
| 355 | case 2: //6-buttons pad | |
| 356 | /* | |
| 357 | Two packets: | |
| 358 | 1st packet: directions + I, II, Run, Select | |
| 359 | 2nd packet: 6 buttons "header" (high 4 bits active low) + III, IV, V, VI | |
| 360 | Note that six buttons pad just doesn't work with (almost?) every single 2-button-only games, it's really just an after-thought and it is like this | |
| 361 | on real HW. | |
| 362 | */ | |
| 363 | data = input_port_read(space->machine(), joyname[2][state->m_joystick_port_select]) >> (state->m_joy_6b_packet[state->m_joystick_port_select]*8); | |
| 364 | break; | |
| 365 | default: | |
| 366 | data = 0xff; | |
| 367 | break; | |
| 368 | } | |
| 369 | } | |
| 370 | else | |
| 371 | data = 0xff; | |
| 372 | ||
| 373 | ||
| 374 | if (state->m_joystick_data_select) | |
| 375 | data >>= 4; | |
| 376 | ||
| 377 | ret = (data & 0x0f) | state->m_io_port_options; | |
| 378 | #ifdef UNIFIED_PCE | |
| 379 | ret &= ~0x40; | |
| 380 | #endif | |
| 381 | ||
| 382 | return (ret); | |
| 383 | } | |
| 384 | #endif | |
| 385 | NVRAM_HANDLER( pce ) | |
| 386 | { | |
| 387 | pce_state *state = machine.driver_data<pce_state>(); | |
| 388 | pce_cd_t &pce_cd = state->m_cd; | |
| 389 | if (read_or_write) | |
| 390 | { | |
| 391 | file->write(pce_cd.bram, PCE_BRAM_SIZE); | |
| 392 | } | |
| 393 | else | |
| 394 | { | |
| 395 | /* load battery backed memory from disk */ | |
| 396 | if (file) | |
| 397 | file->read(pce_cd.bram, PCE_BRAM_SIZE); | |
| 398 | } | |
| 399 | } | |
| 400 | ||
| 401 | static void pce_set_cd_bram( running_machine &machine ) | |
| 402 | { | |
| 403 | pce_state *state = machine.driver_data<pce_state>(); | |
| 404 | pce_cd_t &pce_cd = state->m_cd; | |
| 405 | memory_set_bankptr( machine, "bank10", pce_cd.bram + ( pce_cd.bram_locked ? PCE_BRAM_SIZE : 0 ) ); | |
| 406 | } | |
| 407 | ||
| 408 | static void adpcm_stop(running_machine &machine) | |
| 409 | { | |
| 410 | pce_state *state = machine.driver_data<pce_state>(); | |
| 411 | pce_cd_t &pce_cd = state->m_cd; | |
| 412 | pce_cd.regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG; | |
| 413 | pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG; | |
| 414 | //pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c) | (PCE_CD_SAMPLE_STOP_PLAY); | |
| 415 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE ); | |
| 416 | pce_cd.regs[0x0d] &= ~0x60; | |
| 417 | pce_cd.msm_idle = 1; | |
| 418 | } | |
| 419 | ||
| 420 | static void adpcm_play(running_machine &machine) | |
| 421 | { | |
| 422 | pce_state *state = machine.driver_data<pce_state>(); | |
| 423 | pce_cd_t &pce_cd = state->m_cd; | |
| 424 | pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_STOP_FLAG; | |
| 425 | pce_cd.regs[0x0c] |= PCE_CD_ADPCM_PLAY_FLAG; | |
| 426 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE ); | |
| 427 | pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c); | |
| 428 | pce_cd.msm_idle = 0; | |
| 429 | } | |
| 430 | ||
| 431 | ||
| 432 | /* Callback for new data from the MSM5205. | |
| 433 | The PCE cd unit actually divides the clock signal supplied to | |
| 434 | the MSM5205. Currently we can only use static clocks for the | |
| 435 | MSM5205. | |
| 436 | */ | |
| 437 | static void pce_cd_msm5205_int(device_t *device) | |
| 438 | { | |
| 439 | pce_state *state = device->machine().driver_data<pce_state>(); | |
| 440 | pce_cd_t &pce_cd = state->m_cd; | |
| 441 | UINT8 msm_data; | |
| 442 | ||
| 443 | // popmessage("%08x %08x %08x %02x %02x",pce_cd.msm_start_addr,pce_cd.msm_end_addr,pce_cd.msm_half_addr,pce_cd.regs[0x0c],pce_cd.regs[0x0d]); | |
| 444 | ||
| 445 | if ( pce_cd.msm_idle ) | |
| 446 | return; | |
| 447 | ||
| 448 | /* Supply new ADPCM data */ | |
| 449 | msm_data = (pce_cd.msm_nibble) ? (pce_cd.adpcm_ram[pce_cd.msm_start_addr] & 0x0f) : ((pce_cd.adpcm_ram[pce_cd.msm_start_addr] & 0xf0) >> 4); | |
| 450 | ||
| 451 | msm5205_data_w(device, msm_data); | |
| 452 | pce_cd.msm_nibble ^= 1; | |
| 453 | ||
| 454 | if(pce_cd.msm_nibble == 0) | |
| 455 | { | |
| 456 | pce_cd.msm_start_addr++; | |
| 457 | ||
| 458 | if(pce_cd.msm_start_addr == pce_cd.msm_half_addr) | |
| 459 | { | |
| 460 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE ); | |
| 461 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE ); | |
| 462 | } | |
| 463 | ||
| 464 | if(pce_cd.msm_start_addr > pce_cd.msm_end_addr) | |
| 465 | { | |
| 466 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE ); | |
| 467 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE ); | |
| 468 | adpcm_stop(device->machine()); | |
| 469 | msm5205_reset_w(device, 1); | |
| 470 | } | |
| 471 | } | |
| 472 | } | |
| 473 | ||
| 474 | #define SCSI_STATUS_OK 0x00 | |
| 475 | #define SCSI_CHECK_CONDITION 0x02 | |
| 476 | ||
| 477 | static void pce_cd_reply_status_byte( pce_state *state, UINT8 status ) | |
| 478 | { | |
| 479 | pce_cd_t &pce_cd = state->m_cd; | |
| 480 | logerror("Setting CD in reply_status_byte\n"); | |
| 481 | pce_cd.scsi_CD = pce_cd.scsi_IO = pce_cd.scsi_REQ = 1; | |
| 482 | pce_cd.scsi_MSG = 0; | |
| 483 | pce_cd.message_after_status = 1; | |
| 484 | pce_cd.status_sent = pce_cd.message_sent = 0; | |
| 485 | ||
| 486 | if ( status == SCSI_STATUS_OK ) | |
| 487 | { | |
| 488 | pce_cd.regs[0x01] = 0x00; | |
| 489 | } | |
| 490 | else | |
| 491 | { | |
| 492 | pce_cd.regs[0x01] = 0x01; | |
| 493 | } | |
| 494 | } | |
| 495 | ||
| 496 | /* 0x00 - TEST UNIT READY */ | |
| 497 | static void pce_cd_test_unit_ready( running_machine &machine ) | |
| 498 | { | |
| 499 | pce_state *state = machine.driver_data<pce_state>(); | |
| 500 | pce_cd_t &pce_cd = state->m_cd; | |
| 501 | logerror("test unit ready\n"); | |
| 502 | if ( pce_cd.cd ) | |
| 503 | { | |
| 504 | logerror( "Sending STATUS_OK status\n" ); | |
| 505 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 506 | } | |
| 507 | else | |
| 508 | { | |
| 509 | logerror( "Sending CHECK_CONDITION status\n" ); | |
| 510 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 511 | } | |
| 512 | } | |
| 513 | ||
| 514 | /* 0x08 - READ (6) */ | |
| 515 | static void pce_cd_read_6( running_machine &machine ) | |
| 516 | { | |
| 517 | pce_state *state = machine.driver_data<pce_state>(); | |
| 518 | pce_cd_t &pce_cd = state->m_cd; | |
| 519 | UINT32 frame = ( ( pce_cd.command_buffer[1] & 0x1F ) << 16 ) | ( pce_cd.command_buffer[2] << 8 ) | pce_cd.command_buffer[3]; | |
| 520 | UINT32 frame_count = pce_cd.command_buffer[4]; | |
| 521 | ||
| 522 | /* Check for presence of a CD */ | |
| 523 | if ( ! pce_cd.cd ) | |
| 524 | { | |
| 525 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 526 | return; | |
| 527 | } | |
| 528 | ||
| 529 | if ( pce_cd.cdda_status != PCE_CD_CDDA_OFF ) | |
| 530 | { | |
| 531 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 532 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 533 | pce_cd.end_mark = 0; | |
| 534 | } | |
| 535 | ||
| 536 | pce_cd.current_frame = frame; | |
| 537 | pce_cd.end_frame = frame + frame_count; | |
| 538 | ||
| 539 | if ( frame_count == 0 ) | |
| 540 | { | |
| 541 | /* Star Breaker uses this */ | |
| 542 | popmessage("Read Sector frame count == 0, contact MESSdev"); | |
| 543 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 544 | } | |
| 545 | else | |
| 546 | { | |
| 547 | pce_cd.data_timer->adjust(attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND ), 0, attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND )); | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | /* 0xD8 - SET AUDIO PLAYBACK START POSITION (NEC) */ | |
| 552 | static void pce_cd_nec_set_audio_start_position( running_machine &machine ) | |
| 553 | { | |
| 554 | pce_state *state = machine.driver_data<pce_state>(); | |
| 555 | pce_cd_t &pce_cd = state->m_cd; | |
| 556 | UINT32 frame = 0; | |
| 557 | ||
| 558 | if ( ! pce_cd.cd ) | |
| 559 | { | |
| 560 | /* Throw some error here */ | |
| 561 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 562 | return; | |
| 563 | } | |
| 564 | ||
| 565 | switch( pce_cd.command_buffer[9] & 0xC0 ) | |
| 566 | { | |
| 567 | case 0x00: | |
| 568 | popmessage("CD-DA set start mode 0x00, contact MESSdev"); | |
| 569 | frame = ( pce_cd.command_buffer[3] << 16 ) | ( pce_cd.command_buffer[4] << 8 ) | pce_cd.command_buffer[5]; | |
| 570 | break; | |
| 571 | case 0x40: | |
| 572 | { | |
| 573 | UINT8 m,s,f; | |
| 574 | ||
| 575 | m = bcd_2_dec( pce_cd.command_buffer[2]); | |
| 576 | s = bcd_2_dec( pce_cd.command_buffer[3]); | |
| 577 | f = bcd_2_dec( pce_cd.command_buffer[4]); | |
| 578 | ||
| 579 | frame = f + 75 * (s + m * 60); | |
| 580 | if(frame >= 525) // TODO: seven seconds gap? O_o | |
| 581 | frame -= 525; | |
| 582 | break; | |
| 583 | } | |
| 584 | case 0x80: | |
| 585 | frame = pce_cd.toc->tracks[ bcd_2_dec( pce_cd.command_buffer[2] ) - 1 ].physframeofs; | |
| 586 | break; | |
| 587 | default: | |
| 588 | popmessage("CD-DA set start mode 0xc0, contact MESSdev"); | |
| 589 | //assert( NULL == pce_cd_nec_set_audio_start_position ); | |
| 590 | break; | |
| 591 | } | |
| 592 | ||
| 593 | pce_cd.current_frame = frame; | |
| 594 | ||
| 595 | if ( pce_cd.cdda_status == PCE_CD_CDDA_PAUSED ) | |
| 596 | { | |
| 597 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 598 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 599 | pce_cd.end_frame = pce_cd.last_frame; | |
| 600 | pce_cd.end_mark = 0; | |
| 601 | } | |
| 602 | else | |
| 603 | { | |
| 604 | if(pce_cd.command_buffer[1] & 0x03) | |
| 605 | { | |
| 606 | pce_cd.cdda_status = PCE_CD_CDDA_PLAYING; | |
| 607 | pce_cd.end_frame = pce_cd.last_frame; //get the end of the CD | |
| 608 | cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); | |
| 609 | pce_cd.cdda_play_mode = (pce_cd.command_buffer[1] & 0x02) ? 2 : 3; // mode 2 sets IRQ at end | |
| 610 | pce_cd.end_mark = (pce_cd.command_buffer[1] & 0x02) ? 1 : 0; | |
| 611 | } | |
| 612 | else | |
| 613 | { | |
| 614 | pce_cd.cdda_status = PCE_CD_CDDA_PLAYING; | |
| 615 | pce_cd.end_frame = pce_cd.toc->tracks[ cdrom_get_track(pce_cd.cd, pce_cd.current_frame) + 1 ].physframeofs; //get the end of THIS track | |
| 616 | cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); | |
| 617 | pce_cd.end_mark = 0; | |
| 618 | pce_cd.cdda_play_mode = 3; | |
| 619 | } | |
| 620 | } | |
| 621 | ||
| 622 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 623 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); | |
| 624 | } | |
| 625 | ||
| 626 | /* 0xD9 - SET AUDIO PLAYBACK END POSITION (NEC) */ | |
| 627 | static void pce_cd_nec_set_audio_stop_position( running_machine &machine ) | |
| 628 | { | |
| 629 | pce_state *state = machine.driver_data<pce_state>(); | |
| 630 | pce_cd_t &pce_cd = state->m_cd; | |
| 631 | UINT32 frame = 0; | |
| 632 | ||
| 633 | if ( ! pce_cd.cd ) | |
| 634 | { | |
| 635 | /* Throw some error here */ | |
| 636 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 637 | return; | |
| 638 | } | |
| 639 | ||
| 640 | switch( pce_cd.command_buffer[9] & 0xC0 ) | |
| 641 | { | |
| 642 | case 0x00: | |
| 643 | popmessage("CD-DA set end mode 0x00, contact MESSdev"); | |
| 644 | frame = ( pce_cd.command_buffer[3] << 16 ) | ( pce_cd.command_buffer[4] << 8 ) | pce_cd.command_buffer[5]; | |
| 645 | break; | |
| 646 | case 0x40: | |
| 647 | { | |
| 648 | UINT8 m,s,f; | |
| 649 | ||
| 650 | m = bcd_2_dec( pce_cd.command_buffer[2]); | |
| 651 | s = bcd_2_dec( pce_cd.command_buffer[3]); | |
| 652 | f = bcd_2_dec( pce_cd.command_buffer[4]); | |
| 653 | ||
| 654 | frame = f + 75 * (s + m * 60); | |
| 655 | if(frame >= 525) // TODO: seven seconds gap? O_o | |
| 656 | frame -= 525; | |
| 657 | break; | |
| 658 | } | |
| 659 | case 0x80: | |
| 660 | frame = pce_cd.toc->tracks[ bcd_2_dec( pce_cd.command_buffer[2] ) - 1 ].physframeofs; | |
| 661 | break; | |
| 662 | default: | |
| 663 | popmessage("CD-DA set end mode 0xc0, contact MESSdev"); | |
| 664 | //assert( NULL == pce_cd_nec_set_audio_start_position ); | |
| 665 | break; | |
| 666 | } | |
| 667 | ||
| 668 | pce_cd.end_frame = frame; | |
| 669 | pce_cd.cdda_play_mode = pce_cd.command_buffer[1] & 0x03; | |
| 670 | ||
| 671 | if ( pce_cd.cdda_play_mode ) | |
| 672 | { | |
| 673 | if ( pce_cd.cdda_status == PCE_CD_CDDA_PAUSED ) | |
| 674 | { | |
| 675 | cdda_pause_audio( machine.device( "cdda" ), 0 ); | |
| 676 | } | |
| 677 | else | |
| 678 | { | |
| 679 | cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); | |
| 680 | pce_cd.end_mark = 1; | |
| 681 | } | |
| 682 | pce_cd.cdda_status = PCE_CD_CDDA_PLAYING; | |
| 683 | } | |
| 684 | else | |
| 685 | { | |
| 686 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 687 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 688 | pce_cd.end_frame = pce_cd.last_frame; | |
| 689 | pce_cd.end_mark = 0; | |
| 690 | // assert( NULL == pce_cd_nec_set_audio_stop_position ); | |
| 691 | } | |
| 692 | ||
| 693 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 694 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); | |
| 695 | } | |
| 696 | ||
| 697 | /* 0xDA - PAUSE (NEC) */ | |
| 698 | static void pce_cd_nec_pause( running_machine &machine ) | |
| 699 | { | |
| 700 | pce_state *state = machine.driver_data<pce_state>(); | |
| 701 | pce_cd_t &pce_cd = state->m_cd; | |
| 702 | ||
| 703 | /* If no cd mounted throw an error */ | |
| 704 | if ( ! pce_cd.cd ) | |
| 705 | { | |
| 706 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 707 | return; | |
| 708 | } | |
| 709 | ||
| 710 | /* If there was no cdda playing, throw an error */ | |
| 711 | if ( pce_cd.cdda_status == PCE_CD_CDDA_OFF ) | |
| 712 | { | |
| 713 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 714 | return; | |
| 715 | } | |
| 716 | ||
| 717 | pce_cd.cdda_status = PCE_CD_CDDA_PAUSED; | |
| 718 | pce_cd.current_frame = cdda_get_audio_lba( machine.device( "cdda" ) ); | |
| 719 | cdda_pause_audio( machine.device( "cdda" ), 1 ); | |
| 720 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 721 | } | |
| 722 | ||
| 723 | /* 0xDD - READ SUBCHANNEL Q (NEC) */ | |
| 724 | static void pce_cd_nec_get_subq( running_machine &machine ) | |
| 725 | { | |
| 726 | pce_state *state = machine.driver_data<pce_state>(); | |
| 727 | pce_cd_t &pce_cd = state->m_cd; | |
| 728 | /* WP - I do not have access to chds with subchannel information yet, so I'm faking something here */ | |
| 729 | UINT32 msf_abs, msf_rel, track, frame; | |
| 730 | ||
| 731 | if ( ! pce_cd.cd ) | |
| 732 | { | |
| 733 | /* Throw some error here */ | |
| 734 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 735 | return; | |
| 736 | } | |
| 737 | ||
| 738 | frame = pce_cd.current_frame; | |
| 739 | ||
| 740 | switch( pce_cd.cdda_status ) | |
| 741 | { | |
| 742 | case PCE_CD_CDDA_PAUSED: | |
| 743 | pce_cd.data_buffer[0] = 2; | |
| 744 | frame = cdda_get_audio_lba( machine.device( "cdda" ) ); | |
| 745 | break; | |
| 746 | case PCE_CD_CDDA_PLAYING: | |
| 747 | pce_cd.data_buffer[0] = 0; | |
| 748 | frame = cdda_get_audio_lba( machine.device( "cdda" ) ); | |
| 749 | break; | |
| 750 | default: | |
| 751 | pce_cd.data_buffer[0] = 3; | |
| 752 | break; | |
| 753 | } | |
| 754 | ||
| 755 | msf_abs = lba_to_msf( frame ); | |
| 756 | track = cdrom_get_track( pce_cd.cd, frame ); | |
| 757 | msf_rel = lba_to_msf( frame - cdrom_get_track_start( pce_cd.cd, track ) ); | |
| 758 | ||
| 759 | pce_cd.data_buffer[1] = 0; | |
| 760 | pce_cd.data_buffer[2] = dec_2_bcd( track+1 ); /* track */ | |
| 761 | pce_cd.data_buffer[3] = 1; /* index */ | |
| 762 | pce_cd.data_buffer[4] = ( msf_rel >> 16 ) & 0xFF; /* M (relative) */ | |
| 763 | pce_cd.data_buffer[5] = ( msf_rel >> 8 ) & 0xFF; /* S (relative) */ | |
| 764 | pce_cd.data_buffer[6] = msf_rel & 0xFF; /* F (relative) */ | |
| 765 | pce_cd.data_buffer[7] = ( msf_abs >> 16 ) & 0xFF; /* M (absolute) */ | |
| 766 | pce_cd.data_buffer[8] = ( msf_abs >> 8 ) & 0xFF; /* S (absolute) */ | |
| 767 | pce_cd.data_buffer[9] = msf_abs & 0xFF; /* F (absolute) */ | |
| 768 | pce_cd.data_buffer_size = 10; | |
| 769 | ||
| 770 | pce_cd.data_buffer_index = 0; | |
| 771 | pce_cd.data_transferred = 1; | |
| 772 | pce_cd.scsi_IO = 1; | |
| 773 | pce_cd.scsi_CD = 0; | |
| 774 | } | |
| 775 | ||
| 776 | /* 0xDE - GET DIR INFO (NEC) */ | |
| 777 | static void pce_cd_nec_get_dir_info( running_machine &machine ) | |
| 778 | { | |
| 779 | pce_state *state = machine.driver_data<pce_state>(); | |
| 780 | pce_cd_t &pce_cd = state->m_cd; | |
| 781 | UINT32 frame, msf, track = 0; | |
| 782 | const cdrom_toc *toc; | |
| 783 | logerror("nec get dir info\n"); | |
| 784 | ||
| 785 | if ( ! pce_cd.cd ) | |
| 786 | { | |
| 787 | /* Throw some error here */ | |
| 788 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 789 | } | |
| 790 | ||
| 791 | toc = cdrom_get_toc( pce_cd.cd ); | |
| 792 | ||
| 793 | switch( pce_cd.command_buffer[1] ) | |
| 794 | { | |
| 795 | case 0x00: /* Get first and last track numbers */ | |
| 796 | pce_cd.data_buffer[0] = dec_2_bcd(1); | |
| 797 | pce_cd.data_buffer[1] = dec_2_bcd(toc->numtrks); | |
| 798 | pce_cd.data_buffer_size = 2; | |
| 799 | break; | |
| 800 | case 0x01: /* Get total disk size in MSF format */ | |
| 801 | frame = toc->tracks[toc->numtrks-1].physframeofs; | |
| 802 | frame += toc->tracks[toc->numtrks-1].frames; | |
| 803 | msf = lba_to_msf( frame + 150 ); | |
| 804 | ||
| 805 | pce_cd.data_buffer[0] = ( msf >> 16 ) & 0xFF; /* M */ | |
| 806 | pce_cd.data_buffer[1] = ( msf >> 8 ) & 0xFF; /* S */ | |
| 807 | pce_cd.data_buffer[2] = msf & 0xFF; /* F */ | |
| 808 | pce_cd.data_buffer_size = 3; | |
| 809 | break; | |
| 810 | case 0x02: /* Get track information */ | |
| 811 | if ( pce_cd.command_buffer[2] == 0xAA ) | |
| 812 | { | |
| 813 | frame = toc->tracks[toc->numtrks-1].physframeofs; | |
| 814 | frame += toc->tracks[toc->numtrks-1].frames; | |
| 815 | pce_cd.data_buffer[3] = 0x04; /* correct? */ | |
| 816 | } else | |
| 817 | { | |
| 818 | track = MAX( bcd_2_dec( pce_cd.command_buffer[2] ), 1 ); | |
| 819 | frame = toc->tracks[track-1].physframeofs; | |
| 820 | pce_cd.data_buffer[3] = ( toc->tracks[track-1].trktype == CD_TRACK_AUDIO ) ? 0x00 : 0x04; | |
| 821 | } | |
| 822 | logerror("track = %d, frame = %d\n", track, frame ); | |
| 823 | msf = lba_to_msf( frame + 150 ); | |
| 824 | pce_cd.data_buffer[0] = ( msf >> 16 ) & 0xFF; /* M */ | |
| 825 | pce_cd.data_buffer[1] = ( msf >> 8 ) & 0xFF; /* S */ | |
| 826 | pce_cd.data_buffer[2] = msf & 0xFF; /* F */ | |
| 827 | pce_cd.data_buffer_size = 4; | |
| 828 | break; | |
| 829 | default: | |
| 830 | // assert( pce_cd_nec_get_dir_info == NULL ); // Not implemented yet | |
| 831 | break; | |
| 832 | } | |
| 833 | ||
| 834 | pce_cd.data_buffer_index = 0; | |
| 835 | pce_cd.data_transferred = 1; | |
| 836 | pce_cd.scsi_IO = 1; | |
| 837 | pce_cd.scsi_CD = 0; | |
| 838 | } | |
| 839 | ||
| 840 | static void pce_cd_end_of_list( running_machine &machine ) | |
| 841 | { | |
| 842 | pce_state *state = machine.driver_data<pce_state>(); | |
| 843 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 844 | } | |
| 845 | ||
| 846 | static void pce_cd_handle_data_output( running_machine &machine ) | |
| 847 | { | |
| 848 | pce_state *state = machine.driver_data<pce_state>(); | |
| 849 | pce_cd_t &pce_cd = state->m_cd; | |
| 850 | static const struct { | |
| 851 | UINT8 command_byte; | |
| 852 | UINT8 command_size; | |
| 853 | void (*command_handler)(running_machine &machine); | |
| 854 | } pce_cd_commands[] = { | |
| 855 | { 0x00, 6, pce_cd_test_unit_ready }, /* TEST UNIT READY */ | |
| 856 | { 0x08, 6, pce_cd_read_6 }, /* READ (6) */ | |
| 857 | { 0xD8,10, pce_cd_nec_set_audio_start_position }, /* NEC SET AUDIO PLAYBACK START POSITION */ | |
| 858 | { 0xD9,10, pce_cd_nec_set_audio_stop_position }, /* NEC SET AUDIO PLAYBACK END POSITION */ | |
| 859 | { 0xDA,10, pce_cd_nec_pause }, /* NEC PAUSE */ | |
| 860 | { 0xDD,10, pce_cd_nec_get_subq }, /* NEC GET SUBCHANNEL Q */ | |
| 861 | { 0xDE,10, pce_cd_nec_get_dir_info }, /* NEC GET DIR INFO */ | |
| 862 | { 0xFF, 1, pce_cd_end_of_list } /* end of list marker */ | |
| 863 | }; | |
| 864 | ||
| 865 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 866 | { | |
| 867 | /* Command byte received */ | |
| 868 | logerror( "Command byte $%02X received\n", pce_cd.regs[0x01] ); | |
| 869 | ||
| 870 | /* Check for buffer overflow */ | |
| 871 | assert( pce_cd.command_buffer_index < PCE_CD_COMMAND_BUFFER_SIZE ); | |
| 872 | ||
| 873 | pce_cd.command_buffer[pce_cd.command_buffer_index] = pce_cd.regs[0x01]; | |
| 874 | pce_cd.command_buffer_index++; | |
| 875 | pce_cd.scsi_REQ = 0; | |
| 876 | } | |
| 877 | ||
| 878 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.command_buffer_index ) | |
| 879 | { | |
| 880 | int i = 0; | |
| 881 | ||
| 882 | logerror( "Check if command done\n" ); | |
| 883 | ||
| 884 | for( i = 0; pce_cd.command_buffer[0] > pce_cd_commands[i].command_byte; i++ ); | |
| 885 | ||
| 886 | /* Check for unknown commands */ | |
| 887 | if ( pce_cd.command_buffer[0] != pce_cd_commands[i].command_byte ) | |
| 888 | { | |
| 889 | logerror("Unrecognized command: %02X\n", pce_cd.command_buffer[0] ); | |
| 890 | if(pce_cd.command_buffer[0] == 0x03) | |
| 891 | popmessage("CD command 0x03 issued (Request Sense), contact MESSdev"); | |
| 892 | } | |
| 893 | assert( pce_cd.command_buffer[0] == pce_cd_commands[i].command_byte ); | |
| 894 | ||
| 895 | if ( pce_cd.command_buffer_index == pce_cd_commands[i].command_size ) | |
| 896 | { | |
| 897 | (pce_cd_commands[i].command_handler)( machine ); | |
| 898 | pce_cd.command_buffer_index = 0; | |
| 899 | } | |
| 900 | else | |
| 901 | { | |
| 902 | pce_cd.scsi_REQ = 1; | |
| 903 | } | |
| 904 | } | |
| 905 | } | |
| 906 | ||
| 907 | static void pce_cd_handle_data_input( running_machine &machine ) | |
| 908 | { | |
| 909 | pce_state *state = machine.driver_data<pce_state>(); | |
| 910 | pce_cd_t &pce_cd = state->m_cd; | |
| 911 | if ( pce_cd.scsi_CD ) | |
| 912 | { | |
| 913 | /* Command / Status byte */ | |
| 914 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 915 | { | |
| 916 | logerror( "status sent\n" ); | |
| 917 | pce_cd.scsi_REQ = 0; | |
| 918 | pce_cd.status_sent = 1; | |
| 919 | } | |
| 920 | ||
| 921 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.status_sent ) | |
| 922 | { | |
| 923 | pce_cd.status_sent = 0; | |
| 924 | if ( pce_cd.message_after_status ) | |
| 925 | { | |
| 926 | logerror( "message after status\n" ); | |
| 927 | pce_cd.message_after_status = 0; | |
| 928 | pce_cd.scsi_MSG = pce_cd.scsi_REQ = 1; | |
| 929 | pce_cd.regs[0x01] = 0; | |
| 930 | } | |
| 931 | } | |
| 932 | } | |
| 933 | else | |
| 934 | { | |
| 935 | /* Data */ | |
| 936 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 937 | { | |
| 938 | pce_cd.scsi_REQ = 0; | |
| 939 | } | |
| 940 | ||
| 941 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK ) | |
| 942 | { | |
| 943 | if ( pce_cd.data_buffer_index == pce_cd.data_buffer_size ) | |
| 944 | { | |
| 945 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE ); | |
| 946 | if ( pce_cd.data_transferred ) | |
| 947 | { | |
| 948 | pce_cd.data_transferred = 0; | |
| 949 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 950 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); | |
| 951 | } | |
| 952 | } | |
| 953 | else | |
| 954 | { | |
| 955 | logerror("Transfer byte from offset %d\n", pce_cd.data_buffer_index); | |
| 956 | pce_cd.regs[0x01] = pce_cd.data_buffer[pce_cd.data_buffer_index]; | |
| 957 | pce_cd.data_buffer_index++; | |
| 958 | pce_cd.scsi_REQ = 1; | |
| 959 | } | |
| 960 | } | |
| 961 | } | |
| 962 | } | |
| 963 | ||
| 964 | static void pce_cd_handle_message_output( pce_state *state ) | |
| 965 | { | |
| 966 | pce_cd_t &pce_cd = state->m_cd; | |
| 967 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 968 | { | |
| 969 | pce_cd.scsi_REQ = 0; | |
| 970 | } | |
| 971 | } | |
| 972 | ||
| 973 | static void pce_cd_handle_message_input( pce_state *state ) | |
| 974 | { | |
| 975 | pce_cd_t &pce_cd = state->m_cd; | |
| 976 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 977 | { | |
| 978 | pce_cd.scsi_REQ = 0; | |
| 979 | pce_cd.message_sent = 1; | |
| 980 | } | |
| 981 | ||
| 982 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.message_sent ) | |
| 983 | { | |
| 984 | pce_cd.message_sent = 0; | |
| 985 | pce_cd.scsi_BSY = 0; | |
| 986 | } | |
| 987 | } | |
| 988 | ||
| 989 | /* Update internal CD statuses */ | |
| 990 | static void pce_cd_update( running_machine &machine ) | |
| 991 | { | |
| 992 | pce_state *state = machine.driver_data<pce_state>(); | |
| 993 | pce_cd_t &pce_cd = state->m_cd; | |
| 994 | /* Check for reset of CD unit */ | |
| 995 | if ( pce_cd.scsi_RST != pce_cd.scsi_last_RST ) | |
| 996 | { | |
| 997 | if ( pce_cd.scsi_RST ) | |
| 998 | { | |
| 999 | logerror("Performing CD reset\n"); | |
| 1000 | /* Reset internal data */ | |
| 1001 | pce_cd.scsi_BSY = pce_cd.scsi_SEL = pce_cd.scsi_CD = pce_cd.scsi_IO = 0; | |
| 1002 | pce_cd.scsi_MSG = pce_cd.scsi_REQ = pce_cd.scsi_ATN = 0; | |
| 1003 | pce_cd.cd_motor_on = 0; | |
| 1004 | pce_cd.selected = 0; | |
| 1005 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 1006 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 1007 | pce_cd.adpcm_dma_timer->adjust(attotime::never); // stop ADPCM DMA here | |
| 1008 | } | |
| 1009 | pce_cd.scsi_last_RST = pce_cd.scsi_RST; | |
| 1010 | } | |
| 1011 | ||
| 1012 | /* Check if bus can be freed */ | |
| 1013 | if ( ! pce_cd.scsi_SEL && ! pce_cd.scsi_BSY && pce_cd.selected ) | |
| 1014 | { | |
| 1015 | logerror( "freeing bus\n" ); | |
| 1016 | pce_cd.selected = 0; | |
| 1017 | pce_cd.scsi_CD = pce_cd.scsi_MSG = pce_cd.scsi_IO = pce_cd.scsi_REQ = 0; | |
| 1018 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, CLEAR_LINE ); | |
| 1019 | } | |
| 1020 | ||
| 1021 | /* Select the CD device */ | |
| 1022 | if ( pce_cd.scsi_SEL ) | |
| 1023 | { | |
| 1024 | if ( ! pce_cd.selected ) | |
| 1025 | { | |
| 1026 | pce_cd.selected = 1; | |
| 1027 | logerror("Setting CD in device selection\n"); | |
| 1028 | pce_cd.scsi_BSY = pce_cd.scsi_REQ = pce_cd.scsi_CD = 1; | |
| 1029 | pce_cd.scsi_MSG = pce_cd.scsi_IO = 0; | |
| 1030 | } | |
| 1031 | } | |
| 1032 | ||
| 1033 | if ( pce_cd.scsi_ATN ) | |
| 1034 | { | |
| 1035 | } | |
| 1036 | else | |
| 1037 | { | |
| 1038 | /* Check for data and pessage phases */ | |
| 1039 | if ( pce_cd.scsi_BSY ) | |
| 1040 | { | |
| 1041 | if ( pce_cd.scsi_MSG ) | |
| 1042 | { | |
| 1043 | /* message phase */ | |
| 1044 | if ( pce_cd.scsi_IO ) | |
| 1045 | { | |
| 1046 | pce_cd_handle_message_input(state); | |
| 1047 | } | |
| 1048 | else | |
| 1049 | { | |
| 1050 | pce_cd_handle_message_output(state); | |
| 1051 | } | |
| 1052 | } | |
| 1053 | else | |
| 1054 | { | |
| 1055 | /* data phase */ | |
| 1056 | if ( pce_cd.scsi_IO ) | |
| 1057 | { | |
| 1058 | /* Reading data from target */ | |
| 1059 | pce_cd_handle_data_input( machine ); | |
| 1060 | } | |
| 1061 | else | |
| 1062 | { | |
| 1063 | /* Sending data to target */ | |
| 1064 | pce_cd_handle_data_output( machine ); | |
| 1065 | } | |
| 1066 | } | |
| 1067 | } | |
| 1068 | } | |
| 1069 | ||
| 1070 | /* FIXME: presumably CD-DA needs an irq interface for this */ | |
| 1071 | if(cdda_audio_ended(machine.device("cdda")) && pce_cd.end_mark == 1) | |
| 1072 | { | |
| 1073 | switch(pce_cd.cdda_play_mode & 3) | |
| 1074 | { | |
| 1075 | case 1: cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); pce_cd.end_mark = 1; break; //play with repeat | |
| 1076 | case 2: pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); pce_cd.end_mark = 0; break; //irq when finished | |
| 1077 | case 3: pce_cd.end_mark = 0; break; //play without repeat | |
| 1078 | } | |
| 1079 | } | |
| 1080 | } | |
| 1081 | ||
| 1082 | static void pce_cd_set_irq_line( running_machine &machine, int num, int state ) | |
| 1083 | { | |
| 1084 | pce_state *drvstate = machine.driver_data<pce_state>(); | |
| 1085 | pce_cd_t &pce_cd = drvstate->m_cd; | |
| 1086 | switch( num ) | |
| 1087 | { | |
| 1088 | case PCE_CD_IRQ_TRANSFER_DONE: | |
| 1089 | if ( state == ASSERT_LINE ) | |
| 1090 | { | |
| 1091 | pce_cd.regs[0x03] |= PCE_CD_IRQ_TRANSFER_DONE; | |
| 1092 | } | |
| 1093 | else | |
| 1094 | { | |
| 1095 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_TRANSFER_DONE; | |
| 1096 | } | |
| 1097 | break; | |
| 1098 | case PCE_CD_IRQ_TRANSFER_READY: | |
| 1099 | if ( state == ASSERT_LINE ) | |
| 1100 | { | |
| 1101 | pce_cd.regs[0x03] |= PCE_CD_IRQ_TRANSFER_READY; | |
| 1102 | } | |
| 1103 | else | |
| 1104 | { | |
| 1105 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_TRANSFER_READY; | |
| 1106 | } | |
| 1107 | break; | |
| 1108 | case PCE_CD_IRQ_SAMPLE_FULL_PLAY: | |
| 1109 | if ( state == ASSERT_LINE ) | |
| 1110 | { | |
| 1111 | pce_cd.regs[0x03] |= PCE_CD_IRQ_SAMPLE_FULL_PLAY; | |
| 1112 | //printf("x %02x %02x\n",pce_cd.regs[0x02],pce_cd.regs[0x03]); | |
| 1113 | } | |
| 1114 | else | |
| 1115 | { | |
| 1116 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_SAMPLE_FULL_PLAY; | |
| 1117 | } | |
| 1118 | break; | |
| 1119 | case PCE_CD_IRQ_SAMPLE_HALF_PLAY: | |
| 1120 | if ( state == ASSERT_LINE ) | |
| 1121 | { | |
| 1122 | pce_cd.regs[0x03] |= PCE_CD_IRQ_SAMPLE_HALF_PLAY; | |
| 1123 | //printf("y %02x %02x\n",pce_cd.regs[0x02],pce_cd.regs[0x03]); | |
| 1124 | } | |
| 1125 | else | |
| 1126 | { | |
| 1127 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_SAMPLE_HALF_PLAY; | |
| 1128 | } | |
| 1129 | break; | |
| 1130 | default: | |
| 1131 | break; | |
| 1132 | } | |
| 1133 | ||
| 1134 | if ( pce_cd.regs[0x02] & pce_cd.regs[0x03] & ( PCE_CD_IRQ_TRANSFER_DONE | PCE_CD_IRQ_TRANSFER_READY | PCE_CD_IRQ_SAMPLE_HALF_PLAY | PCE_CD_IRQ_SAMPLE_FULL_PLAY) ) | |
| 1135 | { | |
| 1136 | cputag_set_input_line(machine, "maincpu", 1, ASSERT_LINE ); | |
| 1137 | } | |
| 1138 | else | |
| 1139 | { | |
| 1140 | cputag_set_input_line(machine, "maincpu", 1, CLEAR_LINE ); | |
| 1141 | } | |
| 1142 | } | |
| 1143 | ||
| 1144 | static TIMER_CALLBACK( pce_cd_data_timer_callback ) | |
| 1145 | { | |
| 1146 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1147 | pce_cd_t &pce_cd = state->m_cd; | |
| 1148 | if ( pce_cd.data_buffer_index == pce_cd.data_buffer_size ) | |
| 1149 | { | |
| 1150 | /* Read next data sector */ | |
| 1151 | logerror("read sector %d\n", pce_cd.current_frame ); | |
| 1152 | if ( ! cdrom_read_data( pce_cd.cd, pce_cd.current_frame, pce_cd.data_buffer, CD_TRACK_MODE1 ) ) | |
| 1153 | { | |
| 1154 | logerror("Mode1 CD read failed for frame #%d\n", pce_cd.current_frame ); | |
| 1155 | } | |
| 1156 | else | |
| 1157 | { | |
| 1158 | logerror("Succesfully read mode1 frame #%d\n", pce_cd.current_frame ); | |
| 1159 | } | |
| 1160 | ||
| 1161 | pce_cd.data_buffer_index = 0; | |
| 1162 | pce_cd.data_buffer_size = 2048; | |
| 1163 | pce_cd.current_frame++; | |
| 1164 | ||
| 1165 | pce_cd.scsi_IO = 1; | |
| 1166 | pce_cd.scsi_CD = 0; | |
| 1167 | ||
| 1168 | if ( pce_cd.current_frame == pce_cd.end_frame ) | |
| 1169 | { | |
| 1170 | /* We are done, disable the timer */ | |
| 1171 | logerror("Last frame read from CD\n"); | |
| 1172 | pce_cd.data_transferred = 1; | |
| 1173 | pce_cd.data_timer->adjust(attotime::never); | |
| 1174 | } | |
| 1175 | else | |
| 1176 | { | |
| 1177 | pce_cd.data_transferred = 0; | |
| 1178 | } | |
| 1179 | } | |
| 1180 | } | |
| 1181 | ||
| 1182 | static void pce_cd_init( running_machine &machine ) | |
| 1183 | { | |
| 1184 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1185 | pce_cd_t &pce_cd = state->m_cd; | |
| 1186 | device_t *device; | |
| 1187 | ||
| 1188 | /* Initialize pce_cd struct */ | |
| 1189 | memset( &pce_cd, 0, sizeof(pce_cd) ); | |
| 1190 | ||
| 1191 | /* Initialize BRAM */ | |
| 1192 | pce_cd.bram = auto_alloc_array(machine, UINT8, PCE_BRAM_SIZE * 2 ); | |
| 1193 | memset( pce_cd.bram, 0, PCE_BRAM_SIZE ); | |
| 1194 | memset( pce_cd.bram + PCE_BRAM_SIZE, 0xFF, PCE_BRAM_SIZE ); | |
| 1195 | pce_cd.bram_locked = 1; | |
| 1196 | pce_set_cd_bram(machine); | |
| 1197 | ||
| 1198 | /* set up adpcm related things */ | |
| 1199 | pce_cd.adpcm_ram = auto_alloc_array(machine, UINT8, PCE_ADPCM_RAM_SIZE ); | |
| 1200 | memset( pce_cd.adpcm_ram, 0, PCE_ADPCM_RAM_SIZE ); | |
| 1201 | pce_cd.adpcm_clock_divider = 1; | |
| 1202 | msm5205_change_clock_w(machine.device("msm5205"), (PCE_CD_CLOCK / 6) / pce_cd.adpcm_clock_divider); | |
| 1203 | ||
| 1204 | /* Set up cd command buffer */ | |
| 1205 | pce_cd.command_buffer = auto_alloc_array(machine, UINT8, PCE_CD_COMMAND_BUFFER_SIZE ); | |
| 1206 | memset( pce_cd.command_buffer, 0, PCE_CD_COMMAND_BUFFER_SIZE ); | |
| 1207 | pce_cd.command_buffer_index = 0; | |
| 1208 | ||
| 1209 | /* Set up Arcade Card RAM buffer */ | |
| 1210 | pce_cd.acard_ram = auto_alloc_array(machine, UINT8, PCE_ACARD_RAM_SIZE ); | |
| 1211 | memset( pce_cd.acard_ram, 0, PCE_ACARD_RAM_SIZE ); | |
| 1212 | ||
| 1213 | pce_cd.data_buffer = auto_alloc_array(machine, UINT8, 8192 ); | |
| 1214 | memset( pce_cd.data_buffer, 0, 8192 ); | |
| 1215 | pce_cd.data_buffer_size = 0; | |
| 1216 | pce_cd.data_buffer_index = 0; | |
| 1217 | ||
| 1218 | pce_cd.subcode_buffer = auto_alloc_array(machine, UINT8, 96 ); | |
| 1219 | ||
| 1220 | device = machine.device("cdrom"); | |
| 1221 | if ( device ) | |
| 1222 | { | |
| 1223 | pce_cd.cd = cd_get_cdrom_file(device); | |
| 1224 | if ( pce_cd.cd ) | |
| 1225 | { | |
| 1226 | pce_cd.toc = cdrom_get_toc( pce_cd.cd ); | |
| 1227 | cdda_set_cdrom( machine.device("cdda"), pce_cd.cd ); | |
| 1228 | pce_cd.last_frame = cdrom_get_track_start( pce_cd.cd, cdrom_get_last_track( pce_cd.cd ) - 1 ); | |
| 1229 | pce_cd.last_frame += pce_cd.toc->tracks[ cdrom_get_last_track( pce_cd.cd ) - 1 ].frames; | |
| 1230 | pce_cd.end_frame = pce_cd.last_frame; | |
| 1231 | } | |
| 1232 | } | |
| 1233 | ||
| 1234 | pce_cd.data_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_data_timer_callback)); | |
| 1235 | pce_cd.data_timer->adjust(attotime::never); | |
| 1236 | pce_cd.adpcm_dma_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_dma_timer_callback)); | |
| 1237 | pce_cd.adpcm_dma_timer->adjust(attotime::never); | |
| 1238 | ||
| 1239 | pce_cd.cdda_fadeout_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_cdda_fadeout_callback)); | |
| 1240 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1241 | pce_cd.cdda_fadein_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_cdda_fadein_callback)); | |
| 1242 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1243 | ||
| 1244 | pce_cd.adpcm_fadeout_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_fadeout_callback)); | |
| 1245 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1246 | pce_cd.adpcm_fadein_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_fadein_callback)); | |
| 1247 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1248 | } | |
| 1249 | ||
| 1250 | WRITE8_HANDLER( pce_cd_bram_w ) | |
| 1251 | { | |
| 1252 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1253 | pce_cd_t &pce_cd = state->m_cd; | |
| 1254 | if ( ! pce_cd.bram_locked ) | |
| 1255 | { | |
| 1256 | pce_cd.bram[ offset ] = data; | |
| 1257 | } | |
| 1258 | } | |
| 1259 | ||
| 1260 | static void pce_cd_set_adpcm_ram_byte(running_machine &machine, UINT8 val) | |
| 1261 | { | |
| 1262 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1263 | pce_cd_t &pce_cd = state->m_cd; | |
| 1264 | if(pce_cd.adpcm_write_buf > 0) | |
| 1265 | { | |
| 1266 | pce_cd.adpcm_write_buf--; | |
| 1267 | } | |
| 1268 | else | |
| 1269 | { | |
| 1270 | pce_cd.adpcm_ram[pce_cd.adpcm_write_ptr] = val; | |
| 1271 | pce_cd.adpcm_write_ptr = ((pce_cd.adpcm_write_ptr + 1) & 0xffff); | |
| 1272 | //TODO: length + 1 | |
| 1273 | } | |
| 1274 | } | |
| 1275 | ||
| 1276 | static TIMER_CALLBACK( pce_cd_cdda_fadeout_callback ) | |
| 1277 | { | |
| 1278 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1279 | pce_cd_t &pce_cd = state->m_cd; | |
| 1280 | pce_cd.cdda_volume-= 0.1; | |
| 1281 | ||
| 1282 | if(pce_cd.cdda_volume <= 0) | |
| 1283 | { | |
| 1284 | pce_cd.cdda_volume = 0.0; | |
| 1285 | cdda_set_volume(machine.device("cdda"), 0.0); | |
| 1286 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1287 | } | |
| 1288 | else | |
| 1289 | { | |
| 1290 | cdda_set_volume(machine.device("cdda"), pce_cd.cdda_volume); | |
| 1291 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(param), param); | |
| 1292 | } | |
| 1293 | } | |
| 1294 | ||
| 1295 | static TIMER_CALLBACK( pce_cd_cdda_fadein_callback ) | |
| 1296 | { | |
| 1297 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1298 | pce_cd_t &pce_cd = state->m_cd; | |
| 1299 | pce_cd.cdda_volume+= 0.1; | |
| 1300 | ||
| 1301 | if(pce_cd.cdda_volume >= 100.0) | |
| 1302 | { | |
| 1303 | pce_cd.cdda_volume = 100.0; | |
| 1304 | cdda_set_volume(machine.device("cdda"), 100.0); | |
| 1305 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1306 | } | |
| 1307 | else | |
| 1308 | { | |
| 1309 | cdda_set_volume(machine.device("cdda"), pce_cd.cdda_volume); | |
| 1310 | pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(param), param); | |
| 1311 | } | |
| 1312 | } | |
| 1313 | ||
| 1314 | static TIMER_CALLBACK( pce_cd_adpcm_fadeout_callback ) | |
| 1315 | { | |
| 1316 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1317 | pce_cd_t &pce_cd = state->m_cd; | |
| 1318 | pce_cd.adpcm_volume-= 0.1; | |
| 1319 | ||
| 1320 | if(pce_cd.adpcm_volume <= 0) | |
| 1321 | { | |
| 1322 | pce_cd.adpcm_volume = 0.0; | |
| 1323 | msm5205_set_volume(machine.device("msm5205"), 0.0); | |
| 1324 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1325 | } | |
| 1326 | else | |
| 1327 | { | |
| 1328 | msm5205_set_volume(machine.device("msm5205"), pce_cd.adpcm_volume); | |
| 1329 | pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(param), param); | |
| 1330 | } | |
| 1331 | } | |
| 1332 | ||
| 1333 | static TIMER_CALLBACK( pce_cd_adpcm_fadein_callback ) | |
| 1334 | { | |
| 1335 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1336 | pce_cd_t &pce_cd = state->m_cd; | |
| 1337 | pce_cd.adpcm_volume+= 0.1; | |
| 1338 | ||
| 1339 | if(pce_cd.adpcm_volume >= 100.0) | |
| 1340 | { | |
| 1341 | pce_cd.adpcm_volume = 100.0; | |
| 1342 | msm5205_set_volume(machine.device("msm5205"), 100.0); | |
| 1343 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1344 | } | |
| 1345 | else | |
| 1346 | { | |
| 1347 | msm5205_set_volume(machine.device("msm5205"), pce_cd.adpcm_volume); | |
| 1348 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(param), param); | |
| 1349 | } | |
| 1350 | } | |
| 1351 | ||
| 1352 | ||
| 1353 | WRITE8_HANDLER( pce_cd_intf_w ) | |
| 1354 | { | |
| 1355 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1356 | pce_cd_t &pce_cd = state->m_cd; | |
| 1357 | pce_cd_update(space->machine()); | |
| 1358 | ||
| 1359 | if(offset & 0x200 && state->m_sys3_card && state->m_acard) // route Arcade Card handling ports | |
| 1360 | return pce_cd_acard_w(space,offset,data); | |
| 1361 | ||
| 1362 | logerror("%04X: write to CD interface offset %02X, data %02X\n", cpu_get_pc(&space->device()), offset, data ); | |
| 1363 | ||
| 1364 | switch( offset & 0xf ) | |
| 1365 | { | |
| 1366 | case 0x00: /* CDC status */ | |
| 1367 | /* select device (which bits??) */ | |
| 1368 | pce_cd.scsi_SEL = 1; | |
| 1369 | pce_cd_update(space->machine()); | |
| 1370 | pce_cd.scsi_SEL = 0; | |
| 1371 | pce_cd.adpcm_dma_timer->adjust(attotime::never); // stop ADPCM DMA here | |
| 1372 | /* any write here clears CD transfer irqs */ | |
| 1373 | pce_cd.regs[0x03] &= ~0x70; | |
| 1374 | cputag_set_input_line(space->machine(), "maincpu", 1, CLEAR_LINE ); | |
| 1375 | break; | |
| 1376 | case 0x01: /* CDC command / status / data */ | |
| 1377 | break; | |
| 1378 | case 0x02: /* ADPCM / CD control / IRQ enable/disable */ | |
| 1379 | /* bit 6 - transfer ready irq */ | |
| 1380 | /* bit 5 - transfer done irq */ | |
| 1381 | /* bit 4 - ?? irq */ | |
| 1382 | /* bit 3 - ?? irq */ | |
| 1383 | /* bit 2 - ?? irq */ | |
| 1384 | pce_cd.scsi_ACK = data & 0x80; | |
| 1385 | /* Don't set or reset any irq lines, but just verify the current state */ | |
| 1386 | pce_cd_set_irq_line( space->machine(), 0, 0 ); | |
| 1387 | break; | |
| 1388 | case 0x03: /* BRAM lock / CD status / IRQ - Read Only register */ | |
| 1389 | break; | |
| 1390 | case 0x04: /* CD reset */ | |
| 1391 | pce_cd.scsi_RST = data & 0x02; | |
| 1392 | break; | |
| 1393 | case 0x05: /* Convert PCM data / PCM data */ | |
| 1394 | case 0x06: /* PCM data */ | |
| 1395 | break; | |
| 1396 | case 0x07: /* BRAM unlock / CD status */ | |
| 1397 | if ( data & 0x80 ) | |
| 1398 | { | |
| 1399 | pce_cd.bram_locked = 0; | |
| 1400 | pce_set_cd_bram(space->machine()); | |
| 1401 | } | |
| 1402 | break; | |
| 1403 | case 0x08: /* ADPCM address (LSB) / CD data */ | |
| 1404 | break; | |
| 1405 | case 0x09: /* ADPCM address (MSB) */ | |
| 1406 | break; | |
| 1407 | case 0x0A: /* ADPCM RAM data port */ | |
| 1408 | pce_cd_set_adpcm_ram_byte(space->machine(), data); | |
| 1409 | break; | |
| 1410 | case 0x0B: /* ADPCM DMA control */ | |
| 1411 | if ( data & 0x03 ) | |
| 1412 | { | |
| 1413 | /* Start CD to ADPCM transfer */ | |
| 1414 | pce_cd.adpcm_dma_timer->adjust(attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND * 2048 ), 0, attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND * 2048 ) ); | |
| 1415 | pce_cd.regs[0x0c] |= 4; | |
| 1416 | } | |
| 1417 | break; | |
| 1418 | case 0x0C: /* ADPCM status */ | |
| 1419 | break; | |
| 1420 | case 0x0D: /* ADPCM address control */ | |
| 1421 | if ( ( pce_cd.regs[0x0D] & 0x80 ) && ! ( data & 0x80 ) ) // ADPCM reset | |
| 1422 | { | |
| 1423 | /* Reset ADPCM hardware */ | |
| 1424 | pce_cd.adpcm_read_ptr = 0; | |
| 1425 | pce_cd.adpcm_write_ptr = 0; | |
| 1426 | pce_cd.msm_start_addr = 0; | |
| 1427 | pce_cd.msm_end_addr = 0; | |
| 1428 | pce_cd.msm_half_addr = 0; | |
| 1429 | pce_cd.msm_nibble = 0; | |
| 1430 | adpcm_stop(space->machine()); | |
| 1431 | msm5205_reset_w( space->machine().device( "msm5205"), 1 ); | |
| 1432 | } | |
| 1433 | ||
| 1434 | if(data & 0x20) | |
| 1435 | pce_cd.msm_half_addr = (pce_cd.adpcm_read_ptr + (pce_cd.adpcm_length / ((data & 0x40) ? 2 : 1))) & 0xffff; | |
| 1436 | ||
| 1437 | if ( ( data & 0x40) && ((pce_cd.regs[0x0D] & 0x40) == 0) ) // ADPCM play | |
| 1438 | { | |
| 1439 | pce_cd.msm_start_addr = (pce_cd.adpcm_read_ptr); | |
| 1440 | pce_cd.msm_end_addr = (pce_cd.adpcm_read_ptr + pce_cd.adpcm_length) & 0xffff; | |
| 1441 | pce_cd.msm_nibble = 0; | |
| 1442 | adpcm_play(space->machine()); | |
| 1443 | msm5205_reset_w( space->machine().device( "msm5205"), 0 ); | |
| 1444 | ||
| 1445 | //popmessage("%08x %08x",pce_cd.adpcm_read_ptr,pce_cd.adpcm_length); | |
| 1446 | } | |
| 1447 | else if ( (data & 0x40) == 0 ) | |
| 1448 | { | |
| 1449 | /* used by Buster Bros to cancel an in-flight sample */ | |
| 1450 | adpcm_stop(space->machine()); | |
| 1451 | msm5205_reset_w( space->machine().device( "msm5205"), 1 ); | |
| 1452 | } | |
| 1453 | ||
| 1454 | if ( data & 0x10 ) //ADPCM set length | |
| 1455 | { | |
| 1456 | pce_cd.adpcm_length = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08]; | |
| 1457 | } | |
| 1458 | if ( data & 0x08 ) //ADPCM set read address | |
| 1459 | { | |
| 1460 | pce_cd.adpcm_read_ptr = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08]; | |
| 1461 | pce_cd.adpcm_read_buf = 2; | |
| 1462 | } | |
| 1463 | if ( ( data & 0x02 ) == 0x02 ) //ADPCM set write address | |
| 1464 | { | |
| 1465 | pce_cd.adpcm_write_ptr = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08]; | |
| 1466 | pce_cd.adpcm_write_buf = data & 1; | |
| 1467 | } | |
| 1468 | break; | |
| 1469 | case 0x0E: /* ADPCM playback rate */ | |
| 1470 | pce_cd.adpcm_clock_divider = 0x10 - ( data & 0x0F ); | |
| 1471 | msm5205_change_clock_w(space->machine().device("msm5205"), (PCE_CD_CLOCK / 6) / pce_cd.adpcm_clock_divider); | |
| 1472 | break; | |
| 1473 | case 0x0F: /* ADPCM and CD audio fade timer */ | |
| 1474 | /* TODO: timers needs HW tests */ | |
| 1475 | if(pce_cd.regs[0xf] != data) | |
| 1476 | { | |
| 1477 | switch(data & 0xf) | |
| 1478 | { | |
| 1479 | case 0x00: //CD-DA / ADPCM enable (100 msecs) | |
| 1480 | pce_cd.cdda_volume = 0.0; | |
| 1481 | pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1482 | pce_cd.adpcm_volume = 0.0; | |
| 1483 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1484 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1485 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1486 | break; | |
| 1487 | case 0x01: //CD-DA enable (100 msecs) | |
| 1488 | pce_cd.cdda_volume = 0.0; | |
| 1489 | pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1490 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1491 | break; | |
| 1492 | case 0x08: //CD-DA short (1500 msecs) fade out / ADPCM enable | |
| 1493 | pce_cd.cdda_volume = 100.0; | |
| 1494 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1495 | pce_cd.adpcm_volume = 0.0; | |
| 1496 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1497 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1498 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1499 | break; | |
| 1500 | case 0x09: //CD-DA long (5000 msecs) fade out | |
| 1501 | pce_cd.cdda_volume = 100.0; | |
| 1502 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(5000), 5000); | |
| 1503 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1504 | break; | |
| 1505 | case 0x0a: //ADPCM long (5000 msecs) fade out | |
| 1506 | pce_cd.adpcm_volume = 100.0; | |
| 1507 | pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(5000), 5000); | |
| 1508 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1509 | break; | |
| 1510 | case 0x0c: //CD-DA short (1500 msecs) fade out / ADPCM enable | |
| 1511 | pce_cd.cdda_volume = 100.0; | |
| 1512 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1513 | pce_cd.adpcm_volume = 0.0; | |
| 1514 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1515 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1516 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1517 | break; | |
| 1518 | case 0x0d: //CD-DA short (1500 msecs) fade out | |
| 1519 | pce_cd.cdda_volume = 100.0; | |
| 1520 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1521 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1522 | break; | |
| 1523 | case 0x0e: //ADPCM short (1500 msecs) fade out | |
| 1524 | pce_cd.adpcm_volume = 100.0; | |
| 1525 | pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1526 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1527 | break; | |
| 1528 | default: | |
| 1529 | popmessage("CD-DA / ADPCM Fade effect mode %02x, contact MESSdev",data & 0x0f); | |
| 1530 | break; | |
| 1531 | } | |
| 1532 | } | |
| 1533 | break; | |
| 1534 | default: | |
| 1535 | return; | |
| 1536 | } | |
| 1537 | pce_cd.regs[offset & 0xf] = data; | |
| 1538 | pce_cd_update(space->machine()); | |
| 1539 | } | |
| 1540 | ||
| 1541 | static TIMER_CALLBACK( pce_cd_clear_ack ) | |
| 1542 | { | |
| 1543 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1544 | pce_cd_t &pce_cd = state->m_cd; | |
| 1545 | pce_cd_update(machine); | |
| 1546 | pce_cd.scsi_ACK = 0; | |
| 1547 | pce_cd_update(machine); | |
| 1548 | if ( pce_cd.scsi_CD ) | |
| 1549 | { | |
| 1550 | pce_cd.regs[0x0B] &= 0xFE; | |
| 1551 | } | |
| 1552 | } | |
| 1553 | ||
| 1554 | static UINT8 pce_cd_get_cd_data_byte(running_machine &machine) | |
| 1555 | { | |
| 1556 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1557 | pce_cd_t &pce_cd = state->m_cd; | |
| 1558 | UINT8 data = pce_cd.regs[0x01]; | |
| 1559 | if ( pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && ! pce_cd.scsi_CD ) | |
| 1560 | { | |
| 1561 | if ( pce_cd.scsi_IO ) | |
| 1562 | { | |
| 1563 | pce_cd.scsi_ACK = 1; | |
| 1564 | machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(15), FUNC(pce_cd_clear_ack)); | |
| 1565 | } | |
| 1566 | } | |
| 1567 | return data; | |
| 1568 | } | |
| 1569 | ||
| 1570 | ||
| 1571 | static TIMER_CALLBACK( pce_cd_adpcm_dma_timer_callback ) | |
| 1572 | { | |
| 1573 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1574 | pce_cd_t &pce_cd = state->m_cd; | |
| 1575 | if ( pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && ! pce_cd.scsi_CD && pce_cd.scsi_IO ) | |
| 1576 | { | |
| 1577 | pce_cd.adpcm_ram[pce_cd.adpcm_write_ptr] = pce_cd_get_cd_data_byte(machine); | |
| 1578 | pce_cd.adpcm_write_ptr = ( pce_cd.adpcm_write_ptr + 1 ) & 0xFFFF; | |
| 1579 | ||
| 1580 | pce_cd.regs[0x0c] &= ~4; | |
| 1581 | } | |
| 1582 | } | |
| 1583 | ||
| 1584 | static UINT8 pce_cd_get_adpcm_ram_byte(running_machine &machine) | |
| 1585 | { | |
| 1586 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1587 | pce_cd_t &pce_cd = state->m_cd; | |
| 1588 | if(pce_cd.adpcm_read_buf > 0) | |
| 1589 | { | |
| 1590 | pce_cd.adpcm_read_buf--; | |
| 1591 | return 0; | |
| 1592 | } | |
| 1593 | else | |
| 1594 | { | |
| 1595 | UINT8 res; | |
| 1596 | ||
| 1597 | res = pce_cd.adpcm_ram[pce_cd.adpcm_read_ptr]; | |
| 1598 | pce_cd.adpcm_read_ptr = ((pce_cd.adpcm_read_ptr + 1) & 0xffff); | |
| 1599 | ||
| 1600 | return res; | |
| 1601 | } | |
| 1602 | } | |
| 1603 | ||
| 1604 | READ8_HANDLER( pce_cd_intf_r ) | |
| 1605 | { | |
| 1606 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1607 | pce_cd_t &pce_cd = state->m_cd; | |
| 1608 | UINT8 data = pce_cd.regs[offset & 0x0F]; | |
| 1609 | ||
| 1610 | pce_cd_update(space->machine()); | |
| 1611 | ||
| 1612 | if(offset & 0x200 && state->m_sys3_card && state->m_acard) // route Arcade Card handling ports | |
| 1613 | return pce_cd_acard_r(space,offset); | |
| 1614 | ||
| 1615 | logerror("%04X: read from CD interface offset %02X\n", cpu_get_pc(&space->device()), offset ); | |
| 1616 | ||
| 1617 | if((offset & 0xc0) == 0xc0 && state->m_sys3_card) //System 3 Card header handling | |
| 1618 | { | |
| 1619 | switch(offset & 0xcf) | |
| 1620 | { | |
| 1621 | case 0xc1: return 0xaa; | |
| 1622 | case 0xc2: return 0x55; | |
| 1623 | case 0xc3: return 0x00; | |
| 1624 | case 0xc5: return (state->m_sys3_card & 2) ? 0x55 : 0xaa; | |
| 1625 | case 0xc6: return (state->m_sys3_card & 2) ? 0xaa : 0x55; | |
| 1626 | case 0xc7: return 0x03; | |
| 1627 | } | |
| 1628 | } | |
| 1629 | ||
| 1630 | switch( offset & 0xf ) | |
| 1631 | { | |
| 1632 | case 0x00: /* CDC status */ | |
| 1633 | data &= 0x07; | |
| 1634 | data |= pce_cd.scsi_BSY ? 0x80 : 0; | |
| 1635 | data |= pce_cd.scsi_REQ ? 0x40 : 0; | |
| 1636 | data |= pce_cd.scsi_MSG ? 0x20 : 0; | |
| 1637 | data |= pce_cd.scsi_CD ? 0x10 : 0; | |
| 1638 | data |= pce_cd.scsi_IO ? 0x08 : 0; | |
| 1639 | break; | |
| 1640 | case 0x01: /* CDC command / status / data */ | |
| 1641 | break; | |
| 1642 | case 0x02: /* ADPCM / CD control */ | |
| 1643 | break; | |
| 1644 | case 0x03: /* BRAM lock / CD status */ | |
| 1645 | /* bit 4 set when CD motor is on */ | |
| 1646 | /* bit 2 set when less than half of the ADPCM data is remaining ?? */ | |
| 1647 | pce_cd.bram_locked = 1; | |
| 1648 | pce_set_cd_bram(space->machine()); | |
| 1649 | data = data & 0x6E; | |
| 1650 | data |= ( pce_cd.cd_motor_on ? 0x10 : 0 ); | |
| 1651 | pce_cd.regs[0x03] ^= 0x02; /* TODO: get rid of this hack */ | |
| 1652 | break; | |
| 1653 | case 0x04: /* CD reset */ | |
| 1654 | break; | |
| 1655 | case 0x05: /* Convert PCM data / PCM data */ | |
| 1656 | case 0x06: /* PCM data */ | |
| 1657 | break; | |
| 1658 | case 0x07: /* BRAM unlock / CD status */ | |
| 1659 | data = ( pce_cd.bram_locked ? ( data & 0x7F ) : ( data | 0x80 ) ); | |
| 1660 | break; | |
| 1661 | case 0x08: /* ADPCM address (LSB) / CD data */ | |
| 1662 | data = pce_cd_get_cd_data_byte(space->machine()); | |
| 1663 | break; | |
| 1664 | case 0x0A: /* ADPCM RAM data port */ | |
| 1665 | data = pce_cd_get_adpcm_ram_byte(space->machine()); | |
| 1666 | break; | |
| 1667 | case 0x0B: /* ADPCM DMA control */ | |
| 1668 | break; | |
| 1669 | case 0x0C: /* ADPCM status */ | |
| 1670 | break; | |
| 1671 | case 0x0D: /* ADPCM address control */ | |
| 1672 | break; | |
| 1673 | /* These are read-only registers */ | |
| 1674 | case 0x09: /* ADPCM address (MSB) */ | |
| 1675 | case 0x0E: /* ADPCM playback rate */ | |
| 1676 | case 0x0F: /* ADPCM and CD audio fade timer */ | |
| 1677 | return 0; | |
| 1678 | default: | |
| 1679 | data = 0xFF; | |
| 1680 | break; | |
| 1681 | } | |
| 1682 | ||
| 1683 | return data; | |
| 1684 | } | |
| 1685 | ||
| 1686 | ||
| 1687 | /* | |
| 1688 | ||
| 1689 | PC Engine Arcade Card emulation | |
| 1690 | ||
| 1691 | */ | |
| 1692 | ||
| 1693 | READ8_HANDLER( pce_cd_acard_r ) | |
| 1694 | { | |
| 1695 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1696 | pce_cd_t &pce_cd = state->m_cd; | |
| 1697 | UINT8 r_num; | |
| 1698 | ||
| 1699 | if((offset & 0x2e0) == 0x2e0) | |
| 1700 | { | |
| 1701 | switch(offset & 0x2ef) | |
| 1702 | { | |
| 1703 | case 0x2e0: return (pce_cd.acard_shift >> 0) & 0xff; | |
| 1704 | case 0x2e1: return (pce_cd.acard_shift >> 8) & 0xff; | |
| 1705 | case 0x2e2: return (pce_cd.acard_shift >> 16) & 0xff; | |
| 1706 | case 0x2e3: return (pce_cd.acard_shift >> 24) & 0xff; | |
| 1707 | case 0x2e4: return (pce_cd.acard_shift_reg); | |
| 1708 | case 0x2e5: return pce_cd.acard_latch; | |
| 1709 | case 0x2ee: return 0x10; | |
| 1710 | case 0x2ef: return 0x51; | |
| 1711 | } | |
| 1712 | ||
| 1713 | return 0; | |
| 1714 | } | |
| 1715 | ||
| 1716 | r_num = (offset & 0x30) >> 4; | |
| 1717 | ||
| 1718 | switch(offset & 0x0f) | |
| 1719 | { | |
| 1720 | case 0x00: | |
| 1721 | case 0x01: | |
| 1722 | { | |
| 1723 | UINT8 res; | |
| 1724 | if(pce_cd.acard_ctrl[r_num] & 2) | |
| 1725 | res = pce_cd.acard_ram[(pce_cd.acard_base_addr[r_num] + pce_cd.acard_addr_offset[r_num]) & 0x1fffff]; | |
| 1726 | else | |
| 1727 | res = pce_cd.acard_ram[pce_cd.acard_base_addr[r_num] & 0x1fffff]; | |
| 1728 | ||
| 1729 | if(pce_cd.acard_ctrl[r_num] & 0x1) | |
| 1730 | { | |
| 1731 | if(pce_cd.acard_ctrl[r_num] & 0x10) | |
| 1732 | { | |
| 1733 | pce_cd.acard_base_addr[r_num] += pce_cd.acard_addr_inc[r_num]; | |
| 1734 | pce_cd.acard_base_addr[r_num] &= 0xffffff; | |
| 1735 | } | |
| 1736 | else | |
| 1737 | { | |
| 1738 | pce_cd.acard_addr_offset[r_num] += pce_cd.acard_addr_inc[r_num]; | |
| 1739 | } | |
| 1740 | } | |
| 1741 | ||
| 1742 | return res; | |
| 1743 | } | |
| 1744 | case 0x02: return (pce_cd.acard_base_addr[r_num] >> 0) & 0xff; | |
| 1745 | case 0x03: return (pce_cd.acard_base_addr[r_num] >> 8) & 0xff; | |
| 1746 | case 0x04: return (pce_cd.acard_base_addr[r_num] >> 16) & 0xff; | |
| 1747 | case 0x05: return (pce_cd.acard_addr_offset[r_num] >> 0) & 0xff; | |
| 1748 | case 0x06: return (pce_cd.acard_addr_offset[r_num] >> 8) & 0xff; | |
| 1749 | case 0x07: return (pce_cd.acard_addr_inc[r_num] >> 0) & 0xff; | |
| 1750 | case 0x08: return (pce_cd.acard_addr_inc[r_num] >> 8) & 0xff; | |
| 1751 | case 0x09: return pce_cd.acard_ctrl[r_num]; | |
| 1752 | default: return 0; | |
| 1753 | } | |
| 1754 | ||
| 1755 | return 0; | |
| 1756 | } | |
| 1757 | ||
| 1758 | WRITE8_HANDLER( pce_cd_acard_w ) | |
| 1759 | { | |
| 1760 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1761 | pce_cd_t &pce_cd = state->m_cd; | |
| 1762 | UINT8 w_num; | |
| 1763 | ||
| 1764 | if((offset & 0x2e0) == 0x2e0) | |
| 1765 | { | |
| 1766 | switch(offset & 0x0f) | |
| 1767 | { | |
| 1768 | case 0: pce_cd.acard_shift = (data & 0xff) | (pce_cd.acard_shift & 0xffffff00); break; | |
| 1769 | case 1: pce_cd.acard_shift = (data << 8) | (pce_cd.acard_shift & 0xffff00ff); break; | |
| 1770 | case 2: pce_cd.acard_shift = (data << 16) | (pce_cd.acard_shift & 0xff00ffff); break; | |
| 1771 | case 3: pce_cd.acard_shift = (data << 24) | (pce_cd.acard_shift & 0x00ffffff); break; | |
| 1772 | case 4: | |
| 1773 | { | |
| 1774 | pce_cd.acard_shift_reg = data & 0x0f; | |
| 1775 | ||
| 1776 | if(pce_cd.acard_shift_reg != 0) | |
| 1777 | { | |
| 1778 | pce_cd.acard_shift = (pce_cd.acard_shift_reg < 8) ? | |
| 1779 | (pce_cd.acard_shift << pce_cd.acard_shift_reg) | |
| 1780 | : (pce_cd.acard_shift >> (16 - pce_cd.acard_shift_reg)); | |
| 1781 | } | |
| 1782 | } | |
| 1783 | break; | |
| 1784 | case 5: pce_cd.acard_latch = data; break; | |
| 1785 | } | |
| 1786 | } | |
| 1787 | else | |
| 1788 | { | |
| 1789 | w_num = (offset & 0x30) >> 4; | |
| 1790 | ||
| 1791 | switch(offset & 0x0f) | |
| 1792 | { | |
| 1793 | case 0x00: | |
| 1794 | case 0x01: | |
| 1795 | if(pce_cd.acard_ctrl[w_num] & 2) | |
| 1796 | pce_cd.acard_ram[(pce_cd.acard_base_addr[w_num] + pce_cd.acard_addr_offset[w_num]) & 0x1fffff] = data; | |
| 1797 | else | |
| 1798 | pce_cd.acard_ram[pce_cd.acard_base_addr[w_num] & 0x1FFFFF] = data; | |
| 1799 | ||
| 1800 | if(pce_cd.acard_ctrl[w_num] & 0x1) | |
| 1801 | { | |
| 1802 | if(pce_cd.acard_ctrl[w_num] & 0x10) | |
| 1803 | { | |
| 1804 | pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_inc[w_num]; | |
| 1805 | pce_cd.acard_base_addr[w_num] &= 0xffffff; | |
| 1806 | } | |
| 1807 | else | |
| 1808 | { | |
| 1809 | pce_cd.acard_addr_offset[w_num] += pce_cd.acard_addr_inc[w_num]; | |
| 1810 | } | |
| 1811 | } | |
| 1812 | ||
| 1813 | break; | |
| 1814 | ||
| 1815 | case 0x02: pce_cd.acard_base_addr[w_num] = (data & 0xff) | (pce_cd.acard_base_addr[w_num] & 0xffff00); break; | |
| 1816 | case 0x03: pce_cd.acard_base_addr[w_num] = (data << 8) | (pce_cd.acard_base_addr[w_num] & 0xff00ff); break; | |
| 1817 | case 0x04: pce_cd.acard_base_addr[w_num] = (data << 16) | (pce_cd.acard_base_addr[w_num] & 0x00ffff); break; | |
| 1818 | case 0x05: pce_cd.acard_addr_offset[w_num] = (data & 0xff) | (pce_cd.acard_addr_offset[w_num] & 0xff00); break; | |
| 1819 | case 0x06: | |
| 1820 | pce_cd.acard_addr_offset[w_num] = (data << 8) | (pce_cd.acard_addr_offset[w_num] & 0x00ff); | |
| 1821 | ||
| 1822 | if((pce_cd.acard_ctrl[w_num] & 0x60) == 0x40) | |
| 1823 | { | |
| 1824 | pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_offset[w_num] + ((pce_cd.acard_ctrl[w_num] & 0x08) ? 0xff0000 : 0); | |
| 1825 | pce_cd.acard_base_addr[w_num] &= 0xffffff; | |
| 1826 | } | |
| 1827 | break; | |
| 1828 | case 0x07: pce_cd.acard_addr_inc[w_num] = (data & 0xff) | (pce_cd.acard_addr_inc[w_num] & 0xff00); break; | |
| 1829 | case 0x08: pce_cd.acard_addr_inc[w_num] = (data << 8) | (pce_cd.acard_addr_inc[w_num] & 0x00ff); break; | |
| 1830 | case 0x09: pce_cd.acard_ctrl[w_num] = data & 0x7f; break; | |
| 1831 | case 0x0a: | |
| 1832 | if((pce_cd.acard_ctrl[w_num] & 0x60) == 0x60) | |
| 1833 | { | |
| 1834 | pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_offset[w_num]; | |
| 1835 | pce_cd.acard_base_addr[w_num] &= 0xffffff; | |
| 1836 | } | |
| 1837 | break; | |
| 1838 | } | |
| 1839 | } | |
| 1840 | } | |
| 1841 | ||
| 1842 | READ8_HANDLER( pce_cd_acard_wram_r ) | |
| 1843 | { | |
| 1844 | return pce_cd_intf_r(space,0x200 | (offset & 0x6000) >> 9); | |
| 1845 | } | |
| 1846 | ||
| 1847 | WRITE8_HANDLER( pce_cd_acard_wram_w ) | |
| 1848 | { | |
| 1849 | pce_cd_intf_w(space,0x200 | (offset & 0x6000) >> 9,data); | |
| 1850 | } | |
| 1851 |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Atari 400/800 | |
| 4 | ||
| 5 | Floppy Disk Controller code | |
| 6 | ||
| 7 | Juergen Buchmueller, June 1998 | |
| 8 | ||
| 9 | ***************************************************************************/ | |
| 10 | ||
| 11 | #include <ctype.h> | |
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "cpu/m6502/m6502.h" | |
| 15 | #include "includes/atari.h" | |
| 16 | #include "ataridev.h" | |
| 17 | #include "sound/pokey.h" | |
| 18 | #include "machine/6821pia.h" | |
| 19 | #include "imagedev/flopdrv.h" | |
| 20 | #include "image.h" | |
| 21 | ||
| 22 | #define VERBOSE_SERIAL 0 | |
| 23 | #define VERBOSE_CHKSUM 0 | |
| 24 | ||
| 25 | typedef struct _atari_drive atari_drive; | |
| 26 | struct _atari_drive | |
| 27 | { | |
| 28 | UINT8 *image; /* malloc'd image */ | |
| 29 | int type; /* type of image (XFD, ATR, DSK) */ | |
| 30 | int mode; /* 0 read only, != 0 read/write */ | |
| 31 | int density; /* 0 SD, 1 MD, 2 DD */ | |
| 32 | int header_skip; /* number of bytes in format header */ | |
| 33 | int tracks; /* number of tracks (35,40,77,80) */ | |
| 34 | int heads; /* number of heads (1,2) */ | |
| 35 | int spt; /* sectors per track (18,26) */ | |
| 36 | int seclen; /* sector length (128,256) */ | |
| 37 | int bseclen; /* boot sector length (sectors 1..3) */ | |
| 38 | int sectors; /* total sectors, ie. tracks x heads x spt */ | |
| 39 | }; | |
| 40 | ||
| 41 | typedef struct _atari_fdc_t atari_fdc_t; | |
| 42 | struct _atari_fdc_t | |
| 43 | { | |
| 44 | int serout_count; | |
| 45 | int serout_offs; | |
| 46 | UINT8 serout_buff[512]; | |
| 47 | UINT8 serout_chksum; | |
| 48 | int serout_delay; | |
| 49 | ||
| 50 | int serin_count; | |
| 51 | int serin_offs; | |
| 52 | UINT8 serin_buff[512]; | |
| 53 | UINT8 serin_chksum; | |
| 54 | int serin_delay; | |
| 55 | ||
| 56 | atari_drive drv[4]; | |
| 57 | }; | |
| 58 | ||
| 59 | /************************************* | |
| 60 | * | |
| 61 | * Disk stuff | |
| 62 | * | |
| 63 | *************************************/ | |
| 64 | ||
| 65 | #define FORMAT_XFD 0 | |
| 66 | #define FORMAT_ATR 1 | |
| 67 | #define FORMAT_DSK 2 | |
| 68 | ||
| 69 | /***************************************************************************** | |
| 70 | INLINE FUNCTIONS | |
| 71 | *****************************************************************************/ | |
| 72 | INLINE atari_fdc_t *get_safe_token(device_t *device) | |
| 73 | { | |
| 74 | assert(device != NULL); | |
| 75 | assert(device->type() == ATARI_FDC); | |
| 76 | ||
| 77 | return (atari_fdc_t *)downcast<legacy_device_base *>(device)->token(); | |
| 78 | } | |
| 79 | ||
| 80 | /***************************************************************************** | |
| 81 | * This is the structure I used in my own Atari 800 emulator some years ago | |
| 82 | * Though it's a bit overloaded, I used it as it is the maximum of all | |
| 83 | * supported formats: | |
| 84 | * XFD no header at all | |
| 85 | * ATR 16 bytes header | |
| 86 | * DSK this struct | |
| 87 | * It is used to determine the format of a XFD image by it's size only | |
| 88 | *****************************************************************************/ | |
| 89 | ||
| 90 | typedef struct _dsk_format dsk_format; | |
| 91 | struct _dsk_format | |
| 92 | { | |
| 93 | UINT8 density; | |
| 94 | UINT8 tracks; | |
| 95 | UINT8 door; | |
| 96 | UINT8 sta1; | |
| 97 | UINT8 spt; | |
| 98 | UINT8 doublesided; | |
| 99 | UINT8 highdensity; | |
| 100 | UINT8 seclen_hi; | |
| 101 | UINT8 seclen_lo; | |
| 102 | UINT8 status; | |
| 103 | UINT8 sta2; | |
| 104 | UINT8 sta3; | |
| 105 | UINT8 sta4; | |
| 106 | UINT8 cr; | |
| 107 | UINT8 info[65+1]; | |
| 108 | }; | |
| 109 | ||
| 110 | /* combined with the size the image should have */ | |
| 111 | typedef struct _xfd_format xfd_format; | |
| 112 | struct _xfd_format | |
| 113 | { | |
| 114 | int size; | |
| 115 | dsk_format dsk; | |
| 116 | }; | |
| 117 | ||
| 118 | /* here's a table of known xfd formats */ | |
| 119 | static const xfd_format xfd_formats[] = | |
| 120 | { | |
| 121 | {35 * 18 * 1 * 128, {0,35,1,0,18,0,0,0,128,255,0,0,0,13,"35 SS/SD"}}, | |
| 122 | {35 * 26 * 1 * 128, {1,35,1,0,26,0,4,0,128,255,0,0,0,13,"35 SS/MD"}}, | |
| 123 | {(35 * 18 * 1 - 3) * 256 + 3 * 128, {2,35,1,0,18,0,4,1, 0,255,0,0,0,13,"35 SS/DD"}}, | |
| 124 | {40 * 18 * 1 * 128, {0,40,1,0,18,0,0,0,128,255,0,0,0,13,"40 SS/SD"}}, | |
| 125 | {40 * 26 * 1 * 128, {1,40,1,0,26,0,4,0,128,255,0,0,0,13,"40 SS/MD"}}, | |
| 126 | {(40 * 18 * 1 - 3) * 256 + 3 * 128, {2,40,1,0,18,0,4,1, 0,255,0,0,0,13,"40 SS/DD"}}, | |
| 127 | {40 * 18 * 2 * 128, {0,40,1,0,18,1,0,0,128,255,0,0,0,13,"40 DS/SD"}}, | |
| 128 | {40 * 26 * 2 * 128, {1,40,1,0,26,1,4,0,128,255,0,0,0,13,"40 DS/MD"}}, | |
| 129 | {(40 * 18 * 2 - 3) * 256 + 3 * 128, {2,40,1,0,18,1,4,1, 0,255,0,0,0,13,"40 DS/DD"}}, | |
| 130 | {77 * 18 * 1 * 128, {0,77,1,0,18,0,0,0,128,255,0,0,0,13,"77 SS/SD"}}, | |
| 131 | {77 * 26 * 1 * 128, {1,77,1,0,26,0,4,0,128,255,0,0,0,13,"77 SS/MD"}}, | |
| 132 | {(77 * 18 * 1 - 3) * 256 + 3 * 128, {2,77,1,0,18,0,4,1, 0,255,0,0,0,13,"77 SS/DD"}}, | |
| 133 | {77 * 18 * 2 * 128, {0,77,1,0,18,1,0,0,128,255,0,0,0,13,"77 DS/SD"}}, | |
| 134 | {77 * 26 * 2 * 128, {1,77,1,0,26,1,4,0,128,255,0,0,0,13,"77 DS/MD"}}, | |
| 135 | {(77 * 18 * 2 - 3) * 256 + 3 * 128, {2,77,1,0,18,1,4,1, 0,255,0,0,0,13,"77 DS/DD"}}, | |
| 136 | {80 * 18 * 2 * 128, {0,80,1,0,18,1,0,0,128,255,0,0,0,13,"80 DS/SD"}}, | |
| 137 | {80 * 26 * 2 * 128, {1,80,1,0,26,1,4,0,128,255,0,0,0,13,"80 DS/MD"}}, | |
| 138 | {(80 * 18 * 2 - 3) * 256 + 3 * 128, {2,80,1,0,18,1,4,1, 0,255,0,0,0,13,"80 DS/DD"}}, | |
| 139 | {0, {0,}} | |
| 140 | }; | |
| 141 | ||
| 142 | /***************************************************************************** | |
| 143 | * | |
| 144 | * Open a floppy image for drive 'drive' if it is not yet openend | |
| 145 | * and a name was given. Determine the image geometry depending on the | |
| 146 | * type of image and store the results into the global drv[] structure | |
| 147 | * | |
| 148 | *****************************************************************************/ | |
| 149 | ||
| 150 | #define MAXSIZE 5760 * 256 + 80 | |
| 151 | static void atari_load_proc(device_image_interface &image) | |
| 152 | { | |
| 153 | atari_fdc_t *fdc = get_safe_token(image.device().owner()); | |
| 154 | int id = floppy_get_drive(image); | |
| 155 | int size, i; | |
| 156 | const char *ext; | |
| 157 | ||
| 158 | fdc->drv[id].image = (UINT8*)image.image_malloc(MAXSIZE); | |
| 159 | if (!fdc->drv[id].image) | |
| 160 | return; | |
| 161 | ||
| 162 | /* tell whether the image is writable */ | |
| 163 | fdc->drv[id].mode = !image.is_readonly(); | |
| 164 | /* set up image if it has been created */ | |
| 165 | if (image.has_been_created()) | |
| 166 | { | |
| 167 | int sector; | |
| 168 | char buff[256]; | |
| 169 | memset(buff, 0, sizeof(buff)); | |
| 170 | /* default to 720 sectors */ | |
| 171 | for( sector = 0; sector < 720; sector++ ) | |
| 172 | image.fwrite(buff, 256); | |
| 173 | image.fseek(0, SEEK_SET); | |
| 174 | } | |
| 175 | ||
| 176 | size = image.fread(fdc->drv[id].image, MAXSIZE); | |
| 177 | if( size <= 0 ) | |
| 178 | { | |
| 179 | fdc->drv[id].image = NULL; | |
| 180 | return; | |
| 181 | } | |
| 182 | /* re allocate the buffer; we don't want to be too lazy ;) */ | |
| 183 | fdc->drv[id].image = (UINT8*)image.image_realloc(fdc->drv[id].image, size); | |
| 184 | ||
| 185 | ext = image.filetype(); | |
| 186 | /* no extension: assume XFD format (no header) */ | |
| 187 | if (!ext) | |
| 188 | { | |
| 189 | fdc->drv[id].type = FORMAT_XFD; | |
| 190 | fdc->drv[id].header_skip = 0; | |
| 191 | } | |
| 192 | else | |
| 193 | /* XFD extension */ | |
| 194 | if( toupper(ext[0])=='X' && toupper(ext[1])=='F' && toupper(ext[2])=='D' ) | |
| 195 | { | |
| 196 | fdc->drv[id].type = FORMAT_XFD; | |
| 197 | fdc->drv[id].header_skip = 0; | |
| 198 | } | |
| 199 | else | |
| 200 | /* ATR extension */ | |
| 201 | if( toupper(ext[0])=='A' && toupper(ext[1])=='T' && toupper(ext[2])=='R' ) | |
| 202 | { | |
| 203 | fdc->drv[id].type = FORMAT_ATR; | |
| 204 | fdc->drv[id].header_skip = 16; | |
| 205 | } | |
| 206 | else | |
| 207 | /* DSK extension */ | |
| 208 | if( toupper(ext[0])=='D' && toupper(ext[1])=='S' && toupper(ext[2])=='K' ) | |
| 209 | { | |
| 210 | fdc->drv[id].type = FORMAT_DSK; | |
| 211 | fdc->drv[id].header_skip = sizeof(dsk_format); | |
| 212 | } | |
| 213 | else | |
| 214 | { | |
| 215 | fdc->drv[id].type = FORMAT_XFD; | |
| 216 | fdc->drv[id].header_skip = 0; | |
| 217 | } | |
| 218 | ||
| 219 | if( fdc->drv[id].type == FORMAT_ATR && | |
| 220 | (fdc->drv[id].image[0] != 0x96 || fdc->drv[id].image[1] != 0x02) ) | |
| 221 | { | |
| 222 | fdc->drv[id].type = FORMAT_XFD; | |
| 223 | fdc->drv[id].header_skip = 0; | |
| 224 | } | |
| 225 | ||
| 226 | switch (fdc->drv[id].type) | |
| 227 | { | |
| 228 | /* XFD or unknown format: find a matching size from the table */ | |
| 229 | case FORMAT_XFD: | |
| 230 | for( i = 0; xfd_formats[i].size; i++ ) | |
| 231 | { | |
| 232 | if( size == xfd_formats[i].size ) | |
| 233 | { | |
| 234 | fdc->drv[id].density = xfd_formats[i].dsk.density; | |
| 235 | fdc->drv[id].tracks = xfd_formats[i].dsk.tracks; | |
| 236 | fdc->drv[id].spt = xfd_formats[i].dsk.spt; | |
| 237 | fdc->drv[id].heads = (xfd_formats[i].dsk.doublesided) ? 2 : 1; | |
| 238 | fdc->drv[id].bseclen = 128; | |
| 239 | fdc->drv[id].seclen = 256 * xfd_formats[i].dsk.seclen_hi + xfd_formats[i].dsk.seclen_lo; | |
| 240 | fdc->drv[id].sectors = fdc->drv[id].tracks * fdc->drv[id].heads * fdc->drv[id].spt; | |
| 241 | break; | |
| 242 | } | |
| 243 | } | |
| 244 | break; | |
| 245 | /* ATR format: find a size including the 16 bytes header */ | |
| 246 | case FORMAT_ATR: | |
| 247 | { | |
| 248 | int s; | |
| 249 | ||
| 250 | fdc->drv[id].bseclen = 128; | |
| 251 | /* get sectors from ATR header */ | |
| 252 | s = (size - 16) / 128; | |
| 253 | /* 3 + odd number of sectors ? */ | |
| 254 | if ( fdc->drv[id].image[4] == 128 || (s % 18) == 0 || (s % 26) == 0 || ((s - 3) % 1) != 0 ) | |
| 255 | { | |
| 256 | fdc->drv[id].sectors = s; | |
| 257 | fdc->drv[id].seclen = 128; | |
| 258 | /* sector size 128 or count not evenly dividable by 26 ? */ | |
| 259 | if( fdc->drv[id].seclen == 128 || (s % 26) != 0 ) | |
| 260 | { | |
| 261 | /* yup! single density */ | |
| 262 | fdc->drv[id].density = 0; | |
| 263 | fdc->drv[id].spt = 18; | |
| 264 | fdc->drv[id].heads = 1; | |
| 265 | fdc->drv[id].tracks = s / 18; | |
| 266 | if( s % 18 != 0 ) | |
| 267 | fdc->drv[id].tracks += 1; | |
| 268 | if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 ) | |
| 269 | { | |
| 270 | fdc->drv[id].heads = 2; | |
| 271 | fdc->drv[id].tracks /= 2; | |
| 272 | } | |
| 273 | } | |
| 274 | else | |
| 275 | { | |
| 276 | /* yes: medium density */ | |
| 277 | fdc->drv[id].density = 0; | |
| 278 | fdc->drv[id].spt = 26; | |
| 279 | fdc->drv[id].heads = 1; | |
| 280 | fdc->drv[id].tracks = s / 26; | |
| 281 | if( s % 26 != 0 ) | |
| 282 | fdc->drv[id].tracks += 1; | |
| 283 | if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 ) | |
| 284 | { | |
| 285 | fdc->drv[id].heads = 2; | |
| 286 | fdc->drv[id].tracks /= 2; | |
| 287 | } | |
| 288 | } | |
| 289 | } | |
| 290 | else | |
| 291 | { | |
| 292 | /* it's double density */ | |
| 293 | s = (s - 3) / 2 + 3; | |
| 294 | fdc->drv[id].sectors = s; | |
| 295 | fdc->drv[id].density = 2; | |
| 296 | fdc->drv[id].seclen = 256; | |
| 297 | fdc->drv[id].spt = 18; | |
| 298 | fdc->drv[id].heads = 1; | |
| 299 | fdc->drv[id].tracks = s / 18; | |
| 300 | if( s % 18 != 0 ) | |
| 301 | fdc->drv[id].tracks += 1; | |
| 302 | if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 ) | |
| 303 | { | |
| 304 | fdc->drv[id].heads = 2; | |
| 305 | fdc->drv[id].tracks /= 2; | |
| 306 | } | |
| 307 | } | |
| 308 | } | |
| 309 | break; | |
| 310 | /* DSK format: it's all in the header */ | |
| 311 | case FORMAT_DSK: | |
| 312 | { | |
| 313 | dsk_format *dsk = (dsk_format *) fdc->drv[id].image; | |
| 314 | ||
| 315 | fdc->drv[id].tracks = dsk->tracks; | |
| 316 | fdc->drv[id].spt = dsk->spt; | |
| 317 | fdc->drv[id].heads = (dsk->doublesided) ? 2 : 1; | |
| 318 | fdc->drv[id].seclen = 256 * dsk->seclen_hi + dsk->seclen_lo; | |
| 319 | fdc->drv[id].bseclen = fdc->drv[id].seclen; | |
| 320 | fdc->drv[id].sectors = fdc->drv[id].tracks * fdc->drv[id].heads * fdc->drv[id].spt; | |
| 321 | } | |
| 322 | break; | |
| 323 | } | |
| 324 | logerror("atari opened floppy '%s', %d sectors (%d %s%s) %d bytes/sector\n", | |
| 325 | image.filename(), | |
| 326 | fdc->drv[id].sectors, | |
| 327 | fdc->drv[id].tracks, | |
| 328 | (fdc->drv[id].heads == 1) ? "SS" : "DS", | |
| 329 | (fdc->drv[id].density == 0) ? "SD" : (fdc->drv[id].density == 1) ? "MD" : "DD", | |
| 330 | fdc->drv[id].seclen); | |
| 331 | return; | |
| 332 | } | |
| 333 | ||
| 334 | ||
| 335 | ||
| 336 | /***************************************************************************** | |
| 337 | * | |
| 338 | * This is a description of the data flow between Atari (A) and the | |
| 339 | * Floppy (F) for the supported commands. | |
| 340 | * | |
| 341 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 342 | * '1' 'S' 00 00 get status | |
| 343 | * F->A ACK CPL 04 FF E0 00 CKS | |
| 344 | * ^ ^ | |
| 345 | * | | | |
| 346 | * | bit 7 : door closed | |
| 347 | * | | |
| 348 | * bit7 : MD 128 bytes/sector, 26 sectors/track | |
| 349 | * bit5 : DD 256 bytes/sector, 18 sectors/track | |
| 350 | * else : SD 128 bytes/sector, 18 sectors/track | |
| 351 | * | |
| 352 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 353 | * '1' 'R' SECL SECH read sector | |
| 354 | * F->A ACK command acknowledge | |
| 355 | * *** now read the sector | |
| 356 | * F->A CPL complete: sector read | |
| 357 | * F->A 128/256 byte CKS | |
| 358 | * | |
| 359 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 360 | * '1' 'W' SECL SECH write with verify | |
| 361 | * F->A ACK command acknowledge | |
| 362 | * A->F 128/256 data CKS | |
| 363 | * F->A CPL complete: CKS okay | |
| 364 | * execute writing the sector | |
| 365 | * F->A CPL complete: sector written | |
| 366 | * | |
| 367 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 368 | * '1' 'P' SECL SECH put sector | |
| 369 | * F->A ACK command acknowledge | |
| 370 | * A->F 128/256 data CKS | |
| 371 | * F->A CPL complete: CKS okay | |
| 372 | * execute writing the sector | |
| 373 | * F->A CPL complete: sector written | |
| 374 | * | |
| 375 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 376 | * '1' '!' xx xx single density format | |
| 377 | * F->A ACK command acknowledge | |
| 378 | * execute formatting | |
| 379 | * F->A CPL complete: format | |
| 380 | * F->A 128/256 byte CKS bad sector table | |
| 381 | * | |
| 382 | * | |
| 383 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 384 | * '1' '"' xx xx double density format | |
| 385 | * F->A ACK command acknowledge | |
| 386 | * execute formatting | |
| 387 | * F->A CPL complete: format | |
| 388 | * F->A 128/256 byte CKS bad sector table | |
| 389 | * | |
| 390 | *****************************************************************************/ | |
| 391 | static void make_chksum(UINT8 * chksum, UINT8 data) | |
| 392 | { | |
| 393 | UINT8 newone; | |
| 394 | newone= *chksum + data; | |
| 395 | if (newone < *chksum) | |
| 396 | newone++; | |
| 397 | ||
| 398 | if (VERBOSE_CHKSUM) | |
| 399 | logerror("atari chksum old $%02x + data $%02x -> new $%02x\n", *chksum, data, newone); | |
| 400 | ||
| 401 | *chksum = newone; | |
| 402 | } | |
| 403 | ||
| 404 | static void clr_serout(device_t *device,int expect_data) | |
| 405 | { | |
| 406 | atari_fdc_t *fdc = get_safe_token(device); | |
| 407 | ||
| 408 | fdc->serout_chksum = 0; | |
| 409 | fdc->serout_offs = 0; | |
| 410 | fdc->serout_count = expect_data + 1; | |
| 411 | } | |
| 412 | ||
| 413 | static void add_serout(device_t *device,int expect_data) | |
| 414 | { | |
| 415 | atari_fdc_t *fdc = get_safe_token(device); | |
| 416 | ||
| 417 | fdc->serout_chksum = 0; | |
| 418 | fdc->serout_count = expect_data + 1; | |
| 419 | } | |
| 420 | ||
| 421 | static void clr_serin(device_t *device, int ser_delay) | |
| 422 | { | |
| 423 | atari_fdc_t *fdc = get_safe_token(device); | |
| 424 | device_t *pokey = device->machine().device("pokey"); | |
| 425 | fdc->serin_chksum = 0; | |
| 426 | fdc->serin_offs = 0; | |
| 427 | fdc->serin_count = 0; | |
| 428 | pokey_serin_ready(pokey, ser_delay * 40); | |
| 429 | } | |
| 430 | ||
| 431 | static void add_serin(device_t *device,UINT8 data, int with_checksum) | |
| 432 | { | |
| 433 | atari_fdc_t *fdc = get_safe_token(device); | |
| 434 | fdc->serin_buff[fdc->serin_count++] = data; | |
| 435 | if (with_checksum) | |
| 436 | make_chksum(&fdc->serin_chksum, data); | |
| 437 | } | |
| 438 | ||
| 439 | static void ATTR_PRINTF(2,3) atari_set_frame_message(device_t *device,const char *fmt, ...) | |
| 440 | { | |
| 441 | va_list arg; | |
| 442 | va_start(arg, fmt); | |
| 443 | ||
| 444 | vsprintf(atari_frame_message, fmt, arg); | |
| 445 | atari_frame_counter = 30; /* FIXME */ | |
| 446 | ||
| 447 | va_end(arg); | |
| 448 | } | |
| 449 | ||
| 450 | static void a800_serial_command(device_t *device) | |
| 451 | { | |
| 452 | int i, drive, sector, offset; | |
| 453 | atari_fdc_t *fdc = get_safe_token(device); | |
| 454 | ||
| 455 | if( !fdc->serout_offs ) | |
| 456 | { | |
| 457 | if (VERBOSE_SERIAL) | |
| 458 | logerror("atari serout command offset = 0\n"); | |
| 459 | return; | |
| 460 | } | |
| 461 | clr_serin(device, 10); | |
| 462 | ||
| 463 | if (VERBOSE_SERIAL) | |
| 464 | { | |
| 465 | logerror("atari serout command %d: %02X %02X %02X %02X %02X : %02X ", | |
| 466 | fdc->serout_offs, | |
| 467 | fdc->serout_buff[0], fdc->serout_buff[1], fdc->serout_buff[2], | |
| 468 | fdc->serout_buff[3], fdc->serout_buff[4], fdc->serout_chksum); | |
| 469 | } | |
| 470 | ||
| 471 | if (fdc->serout_chksum == 0) | |
| 472 | { | |
| 473 | if (VERBOSE_SERIAL) | |
| 474 | logerror("OK\n"); | |
| 475 | ||
| 476 | drive = fdc->serout_buff[0] - '1'; /* drive # */ | |
| 477 | /* sector # */ | |
| 478 | if (drive < 0 || drive > 3) /* ignore unknown drives */ | |
| 479 | { | |
| 480 | logerror("atari unsupported drive #%d\n", drive+1); | |
| 481 | atari_set_frame_message(device, "DRIVE #%d not supported", drive+1); | |
| 482 | return; | |
| 483 | } | |
| 484 | ||
| 485 | /* extract sector number from the command buffer */ | |
| 486 | sector = fdc->serout_buff[2] + 256 * fdc->serout_buff[3]; | |
| 487 | ||
| 488 | switch (fdc->serout_buff[1]) /* command ? */ | |
| 489 | { | |
| 490 | case 'S': /* status */ | |
| 491 | atari_set_frame_message(device, "DRIVE #%d STATUS", drive+1); | |
| 492 | ||
| 493 | if (VERBOSE_SERIAL) | |
| 494 | logerror("atari status\n"); | |
| 495 | ||
| 496 | add_serin(device,'A',0); | |
| 497 | add_serin(device,'C',0); | |
| 498 | if (!fdc->drv[drive].mode) /* read only mode ? */ | |
| 499 | { | |
| 500 | if (fdc->drv[drive].spt == 26) | |
| 501 | add_serin(device,0x80,1); /* MD: 0x80 */ | |
| 502 | else | |
| 503 | if (fdc->drv[drive].seclen == 128) | |
| 504 | add_serin(device,0x00,1); /* SD: 0x00 */ | |
| 505 | else | |
| 506 | add_serin(device,0x20,1); /* DD: 0x20 */ | |
| 507 | } | |
| 508 | else | |
| 509 | { | |
| 510 | if (fdc->drv[drive].spt == 26) | |
| 511 | add_serin(device,0x84,1); /* MD: 0x84 */ | |
| 512 | else | |
| 513 | if (fdc->drv[drive].seclen == 128) | |
| 514 | add_serin(device,0x04,1); /* SD: 0x04 */ | |
| 515 | else | |
| 516 | add_serin(device,0x24,1); /* DD: 0x24 */ | |
| 517 | } | |
| 518 | if (fdc->drv[drive].image) | |
| 519 | add_serin(device,0xff,1); /* door closed: 0xff */ | |
| 520 | else | |
| 521 | add_serin(device,0x7f,1); /* door open: 0x7f */ | |
| 522 | add_serin(device,0xe0,1); /* dunno */ | |
| 523 | add_serin(device,0x00,1); /* dunno */ | |
| 524 | add_serin(device,fdc->serin_chksum,0); | |
| 525 | break; | |
| 526 | ||
| 527 | case 'R': /* read sector */ | |
| 528 | if (VERBOSE_SERIAL) | |
| 529 | logerror("atari read sector #%d\n", sector); | |
| 530 | ||
| 531 | if( sector < 1 || sector > fdc->drv[drive].sectors ) | |
| 532 | { | |
| 533 | atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - ERR", drive+1, sector); | |
| 534 | ||
| 535 | if (VERBOSE_SERIAL) | |
| 536 | logerror("atari bad sector #\n"); | |
| 537 | ||
| 538 | add_serin(device,'E',0); | |
| 539 | break; | |
| 540 | } | |
| 541 | add_serin(device,'A',0); /* acknowledge */ | |
| 542 | add_serin(device,'C',0); /* completed */ | |
| 543 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 544 | { | |
| 545 | atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - SD", drive+1, sector); | |
| 546 | offset = (sector - 1) * fdc->drv[drive].bseclen + fdc->drv[drive].header_skip; | |
| 547 | for (i = 0; i < 128; i++) | |
| 548 | add_serin(device,fdc->drv[drive].image[offset++],1); | |
| 549 | } | |
| 550 | else | |
| 551 | { | |
| 552 | atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 553 | offset = (sector - 1) * fdc->drv[drive].seclen + fdc->drv[drive].header_skip; | |
| 554 | for (i = 0; i < fdc->drv[drive].seclen; i++) | |
| 555 | add_serin(device,fdc->drv[drive].image[offset++],1); | |
| 556 | } | |
| 557 | add_serin(device,fdc->serin_chksum,0); | |
| 558 | break; | |
| 559 | ||
| 560 | case 'W': /* write sector with verify */ | |
| 561 | if (VERBOSE_SERIAL) | |
| 562 | logerror("atari write sector #%d\n", sector); | |
| 563 | ||
| 564 | add_serin(device,'A',0); | |
| 565 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 566 | { | |
| 567 | add_serout(device,fdc->drv[drive].bseclen); | |
| 568 | atari_set_frame_message(device, "DRIVE #%d WRITE SECTOR #%3d - SD", drive+1, sector); | |
| 569 | } | |
| 570 | else | |
| 571 | { | |
| 572 | add_serout(device,fdc->drv[drive].seclen); | |
| 573 | atari_set_frame_message(device, "DRIVE #%d WRITE SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 574 | } | |
| 575 | break; | |
| 576 | ||
| 577 | case 'P': /* put sector (no verify) */ | |
| 578 | if (VERBOSE_SERIAL) | |
| 579 | logerror("atari put sector #%d\n", sector); | |
| 580 | ||
| 581 | add_serin(device,'A',0); | |
| 582 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 583 | { | |
| 584 | add_serout(device,fdc->drv[drive].bseclen); | |
| 585 | atari_set_frame_message(device, "DRIVE #%d PUT SECTOR #%3d - SD", drive+1, sector); | |
| 586 | } | |
| 587 | else | |
| 588 | { | |
| 589 | add_serout(device,fdc->drv[drive].seclen); | |
| 590 | atari_set_frame_message(device, "DRIVE #%d PUT SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 591 | } | |
| 592 | break; | |
| 593 | ||
| 594 | case '!': /* SD format */ | |
| 595 | if (VERBOSE_SERIAL) | |
| 596 | logerror("atari format SD drive #%d\n", drive+1); | |
| 597 | ||
| 598 | atari_set_frame_message(device, "DRIVE #%d FORMAT SD", drive+1); | |
| 599 | add_serin(device,'A',0); /* acknowledge */ | |
| 600 | add_serin(device,'C',0); /* completed */ | |
| 601 | for (i = 0; i < 128; i++) | |
| 602 | add_serin(device,0,1); | |
| 603 | add_serin(device,fdc->serin_chksum,0); | |
| 604 | break; | |
| 605 | ||
| 606 | case '"': /* DD format */ | |
| 607 | if (VERBOSE_SERIAL) | |
| 608 | logerror("atari format DD drive #%d\n", drive+1); | |
| 609 | ||
| 610 | atari_set_frame_message(device, "DRIVE #%d FORMAT DD", drive+1); | |
| 611 | add_serin(device,'A',0); /* acknowledge */ | |
| 612 | add_serin(device,'C',0); /* completed */ | |
| 613 | for (i = 0; i < 256; i++) | |
| 614 | add_serin(device,0,1); | |
| 615 | add_serin(device,fdc->serin_chksum,0); | |
| 616 | break; | |
| 617 | ||
| 618 | default: | |
| 619 | if (VERBOSE_SERIAL) | |
| 620 | logerror("atari unknown command #%c\n", fdc->serout_buff[1]); | |
| 621 | ||
| 622 | atari_set_frame_message(device, "DRIVE #%d UNKNOWN CMD '%c'", drive+1, fdc->serout_buff[1]); | |
| 623 | add_serin(device,'N',0); /* negative acknowledge */ | |
| 624 | } | |
| 625 | } | |
| 626 | else | |
| 627 | { | |
| 628 | atari_set_frame_message(device, "serial cmd chksum error"); | |
| 629 | if (VERBOSE_SERIAL) | |
| 630 | logerror("BAD\n"); | |
| 631 | ||
| 632 | add_serin(device,'E',0); | |
| 633 | } | |
| 634 | if (VERBOSE_SERIAL) | |
| 635 | logerror("atari %d bytes to read\n", fdc->serin_count); | |
| 636 | } | |
| 637 | ||
| 638 | static void a800_serial_write(device_t *device) | |
| 639 | { | |
| 640 | int i, drive, sector, offset; | |
| 641 | atari_fdc_t *fdc = get_safe_token(device); | |
| 642 | ||
| 643 | if (VERBOSE_SERIAL) | |
| 644 | { | |
| 645 | logerror("atari serout %d bytes written : %02X ", | |
| 646 | fdc->serout_offs, fdc->serout_chksum); | |
| 647 | } | |
| 648 | ||
| 649 | clr_serin(device, 80); | |
| 650 | if (fdc->serout_chksum == 0) | |
| 651 | { | |
| 652 | if (VERBOSE_SERIAL) | |
| 653 | logerror("OK\n"); | |
| 654 | ||
| 655 | add_serin(device,'C',0); | |
| 656 | /* write the sector */ | |
| 657 | drive = fdc->serout_buff[0] - '1'; /* drive # */ | |
| 658 | /* not write protected and image available ? */ | |
| 659 | if (fdc->drv[drive].mode && fdc->drv[drive].image) | |
| 660 | { | |
| 661 | /* extract sector number from the command buffer */ | |
| 662 | sector = fdc->serout_buff[2] + 256 * fdc->serout_buff[3]; | |
| 663 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 664 | { | |
| 665 | offset = (sector - 1) * fdc->drv[drive].bseclen + fdc->drv[drive].header_skip; | |
| 666 | ||
| 667 | if (VERBOSE_SERIAL) | |
| 668 | logerror("atari storing 128 byte sector %d at offset 0x%08X", sector, offset ); | |
| 669 | ||
| 670 | for (i = 0; i < 128; i++) | |
| 671 | fdc->drv[drive].image[offset++] = fdc->serout_buff[5+i]; | |
| 672 | atari_set_frame_message(device, "DRIVE #%d WROTE SECTOR #%3d - SD", drive+1, sector); | |
| 673 | } | |
| 674 | else | |
| 675 | { | |
| 676 | offset = (sector - 1) * fdc->drv[drive].seclen + fdc->drv[drive].header_skip; | |
| 677 | ||
| 678 | if (VERBOSE_SERIAL) | |
| 679 | logerror("atari storing %d byte sector %d at offset 0x%08X", fdc->drv[drive].seclen, sector, offset ); | |
| 680 | ||
| 681 | for (i = 0; i < fdc->drv[drive].seclen; i++) | |
| 682 | fdc->drv[drive].image[offset++] = fdc->serout_buff[5+i]; | |
| 683 | atari_set_frame_message(device, "DRIVE #%d WROTE SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 684 | } | |
| 685 | add_serin(device,'C',0); | |
| 686 | } | |
| 687 | else | |
| 688 | { | |
| 689 | add_serin(device,'E',0); | |
| 690 | } | |
| 691 | } | |
| 692 | else | |
| 693 | { | |
| 694 | if (VERBOSE_SERIAL) | |
| 695 | logerror("BAD\n"); | |
| 696 | ||
| 697 | add_serin(device,'E',0); | |
| 698 | } | |
| 699 | } | |
| 700 | ||
| 701 | READ8_DEVICE_HANDLER ( atari_serin_r ) | |
| 702 | { | |
| 703 | int data = 0x00; | |
| 704 | int ser_delay = 0; | |
| 705 | atari_fdc_t *fdc = get_safe_token(device); | |
| 706 | ||
| 707 | if (fdc->serin_count) | |
| 708 | { | |
| 709 | device_t *pokey = device->machine().device("pokey"); | |
| 710 | ||
| 711 | data = fdc->serin_buff[fdc->serin_offs]; | |
| 712 | ser_delay = 2 * 40; | |
| 713 | if (fdc->serin_offs < 3) | |
| 714 | { | |
| 715 | ser_delay = 4 * 40; | |
| 716 | if (fdc->serin_offs < 2) | |
| 717 | ser_delay = 200 * 40; | |
| 718 | } | |
| 719 | fdc->serin_offs++; | |
| 720 | if (--fdc->serin_count == 0) | |
| 721 | fdc->serin_offs = 0; | |
| 722 | else | |
| 723 | pokey_serin_ready(pokey, ser_delay); | |
| 724 | } | |
| 725 | ||
| 726 | if (VERBOSE_SERIAL) | |
| 727 | logerror("atari serin[$%04x] -> $%02x; delay %d\n", fdc->serin_offs, data, ser_delay); | |
| 728 | ||
| 729 | return data; | |
| 730 | } | |
| 731 | ||
| 732 | WRITE8_DEVICE_HANDLER ( atari_serout_w ) | |
| 733 | { | |
| 734 | pia6821_device *pia = device->machine().device<pia6821_device>( "pia" ); | |
| 735 | atari_fdc_t *fdc = get_safe_token(device); | |
| 736 | ||
| 737 | /* ignore serial commands if no floppy image is specified */ | |
| 738 | if( !fdc->drv[0].image ) | |
| 739 | return; | |
| 740 | if (fdc->serout_count) | |
| 741 | { | |
| 742 | /* store data */ | |
| 743 | fdc->serout_buff[fdc->serout_offs] = data; | |
| 744 | ||
| 745 | if (VERBOSE_SERIAL) | |
| 746 | logerror("atari serout[$%04x] <- $%02x; count %d\n", fdc->serout_offs, data, fdc->serout_count); | |
| 747 | ||
| 748 | fdc->serout_offs++; | |
| 749 | if (--fdc->serout_count == 0) | |
| 750 | { | |
| 751 | /* exclusive or written checksum with calculated */ | |
| 752 | fdc->serout_chksum ^= data; | |
| 753 | /* if the attention line is high, this should be data */ | |
| 754 | if (pia->irq_b_state()) | |
| 755 | a800_serial_write(device); | |
| 756 | } | |
| 757 | else | |
| 758 | { | |
| 759 | make_chksum(&fdc->serout_chksum, data); | |
| 760 | } | |
| 761 | } | |
| 762 | } | |
| 763 | ||
| 764 | WRITE_LINE_DEVICE_HANDLER(atarifdc_pia_cb2_w) | |
| 765 | { | |
| 766 | atari_fdc_t *fdc = get_safe_token(device); | |
| 767 | if (!state) | |
| 768 | { | |
| 769 | clr_serout(device,4); /* expect 4 command bytes + checksum */ | |
| 770 | } | |
| 771 | else | |
| 772 | { | |
| 773 | fdc->serin_delay = 0; | |
| 774 | a800_serial_command(device); | |
| 775 | } | |
| 776 | } | |
| 777 | ||
| 778 | static FLOPPY_IDENTIFY( atari_dsk_identify ) | |
| 779 | { | |
| 780 | *vote = 100; | |
| 781 | return FLOPPY_ERROR_SUCCESS; | |
| 782 | } | |
| 783 | ||
| 784 | ||
| 785 | static FLOPPY_CONSTRUCT( atari_dsk_construct ) | |
| 786 | { | |
| 787 | return FLOPPY_ERROR_SUCCESS; | |
| 788 | } | |
| 789 | ||
| 790 | FLOPPY_OPTIONS_START( atari_only ) | |
| 791 | FLOPPY_OPTION( | |
| 792 | atari_dsk, | |
| 793 | "atr,dsk,xfd", | |
| 794 | "Atari floppy disk image", | |
| 795 | atari_dsk_identify, | |
| 796 | atari_dsk_construct, | |
| 797 | NULL, | |
| 798 | NULL | |
| 799 | ) | |
| 800 | FLOPPY_OPTIONS_END0 | |
| 801 | ||
| 802 | static const floppy_config atari_floppy_config = | |
| 803 | { | |
| 804 | DEVCB_NULL, | |
| 805 | DEVCB_NULL, | |
| 806 | DEVCB_NULL, | |
| 807 | DEVCB_NULL, | |
| 808 | DEVCB_NULL, | |
| 809 | FLOPPY_STANDARD_5_25_DSHD, | |
| 810 | FLOPPY_OPTIONS_NAME(atari_only), | |
| 811 | NULL | |
| 812 | }; | |
| 813 | ||
| 814 | static MACHINE_CONFIG_FRAGMENT( atari_fdc ) | |
| 815 | MCFG_FLOPPY_4_DRIVES_ADD(atari_floppy_config) | |
| 816 | MACHINE_CONFIG_END | |
| 817 | ||
| 818 | device_t *atari_floppy_get_device_child(device_t *device,int drive) | |
| 819 | { | |
| 820 | switch(drive) { | |
| 821 | case 0 : return device->subdevice(FLOPPY_0); | |
| 822 | case 1 : return device->subdevice(FLOPPY_1); | |
| 823 | case 2 : return device->subdevice(FLOPPY_2); | |
| 824 | case 3 : return device->subdevice(FLOPPY_3); | |
| 825 | } | |
| 826 | return NULL; | |
| 827 | } | |
| 828 | ||
| 829 | static DEVICE_START(atari_fdc) | |
| 830 | { | |
| 831 | int id; | |
| 832 | for(id=0;id<4;id++) | |
| 833 | { | |
| 834 | floppy_install_load_proc(atari_floppy_get_device_child(device, id), atari_load_proc); | |
| 835 | } | |
| 836 | } | |
| 837 | ||
| 838 | static DEVICE_RESET(atari_fdc) | |
| 839 | { | |
| 840 | } | |
| 841 | ||
| 842 | DEVICE_GET_INFO( atari_fdc ) | |
| 843 | { | |
| 844 | switch (state) | |
| 845 | { | |
| 846 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 847 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; | |
| 848 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(atari_fdc_t); break; | |
| 849 | ||
| 850 | /* --- the following bits of info are returned as pointers --- */ | |
| 851 | case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(atari_fdc); break; | |
| 852 | ||
| 853 | /* --- the following bits of info are returned as pointers to data or functions --- */ | |
| 854 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(atari_fdc); break; | |
| 855 | case DEVINFO_FCT_STOP: /* Nothing */ break; | |
| 856 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(atari_fdc); break; | |
| 857 | ||
| 858 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 859 | case DEVINFO_STR_NAME: strcpy(info->s, "Atari FDC"); break; | |
| 860 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Atari FDC"); break; | |
| 861 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; | |
| 862 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; | |
| 863 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; | |
| 864 | } | |
| 865 | } | |
| 866 | ||
| 867 | DEFINE_LEGACY_DEVICE(ATARI_FDC, atari_fdc); |
| r11531 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * includes/nes.h | |
| 4 | * | |
| 5 | * Nintendo Entertainment System (Famicom) | |
| 6 | * | |
| 7 | ****************************************************************************/ | |
| 8 | ||
| 9 | #ifndef NES_H_ | |
| 10 | #define NES_H_ | |
| 11 | ||
| 12 | ||
| 13 | /*************************************************************************** | |
| 14 | CONSTANTS | |
| 15 | ***************************************************************************/ | |
| 16 | ||
| 17 | #define NTSC_CLOCK N2A03_DEFAULTCLOCK /* 1.789772 MHz */ | |
| 18 | #define PAL_CLOCK (26601712.0/16) /* 1.662607 MHz */ | |
| 19 | ||
| 20 | #define NES_BATTERY_SIZE 0x2000 | |
| 21 | ||
| 22 | ||
| 23 | /*************************************************************************** | |
| 24 | TYPE DEFINITIONS | |
| 25 | ***************************************************************************/ | |
| 26 | ||
| 27 | struct nes_input | |
| 28 | { | |
| 29 | UINT32 shift; | |
| 30 | UINT32 i0, i1, i2; | |
| 31 | }; | |
| 32 | ||
| 33 | /*PPU fast banking constants and structures */ | |
| 34 | ||
| 35 | #define CHRROM 0 | |
| 36 | #define CHRRAM 1 | |
| 37 | ||
| 38 | typedef struct | |
| 39 | { | |
| 40 | int source; //defines source of base pointer | |
| 41 | int origin; //defines offset of 0x400 byte segment at base pointer | |
| 42 | UINT8* access; //source translated + origin -> valid pointer! | |
| 43 | } chr_bank; | |
| 44 | ||
| 45 | /*PPU nametable fast banking constants and structures */ | |
| 46 | ||
| 47 | #define CIRAM 0 | |
| 48 | #define ROM 1 | |
| 49 | #define EXRAM 2 | |
| 50 | #define MMC5FILL 3 | |
| 51 | #define CART_NTRAM 4 | |
| 52 | ||
| 53 | #define NES_BATTERY 0 | |
| 54 | #define NES_WRAM 1 | |
| 55 | ||
| 56 | typedef struct | |
| 57 | { | |
| 58 | int source; /* defines source of base pointer */ | |
| 59 | int origin; /* defines offset of 0x400 byte segment at base pointer */ | |
| 60 | int writable; /* ExRAM, at least, can be write-protected AND used as nametable */ | |
| 61 | UINT8* access; /* direct access when possible */ | |
| 62 | } name_table; | |
| 63 | ||
| 64 | typedef void (*nes_prg_callback)(running_machine &machine, int start, int bank); | |
| 65 | typedef void (*nes_chr_callback)(running_machine &machine, int start, int bank, int source); | |
| 66 | ||
| 67 | class nes_state : public driver_device | |
| 68 | { | |
| 69 | public: | |
| 70 | nes_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 71 | : driver_device(mconfig, type, tag) { } | |
| 72 | ||
| 73 | /* input_related - this part has to be cleaned up (e.g. in_2 and in_3 are not really necessary here...) */ | |
| 74 | nes_input m_in_0, m_in_1, m_in_2, m_in_3; | |
| 75 | UINT8 m_fck_scan, m_fck_mode; | |
| 76 | ||
| 77 | int m_prg_bank[5]; | |
| 78 | chr_bank m_chr_map[8]; //quick banking structure, because some of this changes multiple times per scanline! | |
| 79 | name_table m_nt_page[4]; //quick banking structure for a maximum of 4K of RAM/ROM/ExRAM | |
| 80 | ||
| 81 | int m_chr_open_bus; | |
| 82 | int m_prgram_bank5_start, m_battery_bank5_start, m_empty_bank5_start; | |
| 83 | ||
| 84 | UINT8 m_ce_mask, m_ce_state; | |
| 85 | UINT8 m_vrc_ls_prg_a, m_vrc_ls_prg_b, m_vrc_ls_chr; | |
| 86 | ||
| 87 | int m_MMC5_floodtile; | |
| 88 | int m_MMC5_floodattr; | |
| 89 | int m_mmc5_vram_control; | |
| 90 | UINT8 m_mmc5_high_chr; | |
| 91 | UINT8 m_mmc5_split_scr; | |
| 92 | UINT8 *m_extended_ntram; | |
| 93 | ||
| 94 | UINT8 m_mmc5_last_chr_a; | |
| 95 | UINT16 m_mmc5_vrom_regA[8]; | |
| 96 | UINT16 m_mmc5_vrom_regB[4]; | |
| 97 | UINT8 m_mmc5_prg_regs[4]; | |
| 98 | UINT8 m_mmc5_bank_security; | |
| 99 | UINT8 m_mmc5_prg_mode; | |
| 100 | UINT8 m_mmc5_chr_mode; | |
| 101 | UINT8 m_mmc5_chr_high; | |
| 102 | UINT8 m_mmc5_split_ctrl; | |
| 103 | UINT8 m_mmc5_split_yst; | |
| 104 | UINT8 m_mmc5_split_bank; | |
| 105 | ||
| 106 | /* video-related */ | |
| 107 | int m_nes_vram_sprite[8]; /* Used only by mmc5 for now */ | |
| 108 | int m_last_frame_flip; | |
| 109 | ||
| 110 | /* misc */ | |
| 111 | write8_space_func m_mmc_write_low; | |
| 112 | const char *m_mmc_write_low_name; | |
| 113 | write8_space_func m_mmc_write_mid; | |
| 114 | const char *m_mmc_write_mid_name; | |
| 115 | write8_space_func m_mmc_write; | |
| 116 | const char *m_mmc_write_name; | |
| 117 | read8_space_func m_mmc_read_low; | |
| 118 | const char *m_mmc_read_low_name; | |
| 119 | read8_space_func m_mmc_read_mid; | |
| 120 | const char *m_mmc_read_mid_name; | |
| 121 | read8_space_func m_mmc_read; | |
| 122 | const char *m_mmc_read_name; | |
| 123 | emu_timer *m_irq_timer; | |
| 124 | ||
| 125 | nes_prg_callback m_mmc3_prg_cb; // these are used to simplify a lot emulation of some MMC3 pirate clones | |
| 126 | nes_chr_callback m_mmc3_chr_cb; | |
| 127 | ||
| 128 | /* devices */ | |
| 129 | device_t *m_maincpu; | |
| 130 | device_t *m_ppu; | |
| 131 | device_t *m_sound; | |
| 132 | device_t *m_cart; | |
| 133 | ||
| 134 | /* misc region to be allocated at init */ | |
| 135 | // variables which don't change at run-time | |
| 136 | UINT8 *m_rom; | |
| 137 | UINT8 *m_vrom; | |
| 138 | UINT8 *m_vram; | |
| 139 | UINT8 *m_wram; | |
| 140 | UINT8 *m_ciram; //PPU nametable RAM - external to PPU! | |
| 141 | UINT8 *m_battery_ram; | |
| 142 | UINT8 *m_mapper_ram; | |
| 143 | UINT8 *m_mapper_bram; | |
| 144 | ||
| 145 | /***** Mapper-related variables *****/ | |
| 146 | ||
| 147 | // common ones | |
| 148 | int m_IRQ_enable, m_IRQ_enable_latch; | |
| 149 | UINT16 m_IRQ_count, m_IRQ_count_latch; | |
| 150 | UINT8 m_IRQ_toggle; | |
| 151 | UINT8 m_IRQ_reset; | |
| 152 | UINT8 m_IRQ_status; | |
| 153 | UINT8 m_IRQ_mode; | |
| 154 | UINT8 m_IRQ_clear; | |
| 155 | int m_mult1, m_mult2; | |
| 156 | ||
| 157 | UINT8 m_mmc_chr_source; // This is set at init to CHRROM or CHRRAM. a few mappers can swap between | |
| 158 | // the two (this is done in the specific handlers). | |
| 159 | ||
| 160 | UINT8 m_mmc_cmd1, m_mmc_cmd2; // These represent registers where the mapper writes important values | |
| 161 | UINT8 m_mmc_count; // This is used as counter in mappers like 1 and 45 | |
| 162 | ||
| 163 | int m_mmc_prg_base, m_mmc_prg_mask; // MMC3 based multigame carts select a block of banks by using these (and then act like normal MMC3), | |
| 164 | int m_mmc_chr_base, m_mmc_chr_mask; // while MMC3 and clones (mapper 118 & 119) simply set them as 0 and 0xff resp. | |
| 165 | ||
| 166 | UINT8 m_mmc_prg_bank[6]; // Many mappers writes only some bits of the selected bank (for both PRG and CHR), | |
| 167 | UINT8 m_mmc_vrom_bank[16]; // hence these are handy to latch bank values. | |
| 168 | ||
| 169 | UINT16 m_MMC5_vrom_bank[12]; // MMC5 has 10bit wide VROM regs! | |
| 170 | UINT8 m_mmc_extra_bank[16]; // some MMC3 clone have 2 series of PRG/CHR banks... | |
| 171 | // we collect them all here: first 4 elements PRG banks, then 6/8 CHR banks | |
| 172 | ||
| 173 | UINT8 m_mmc_latch1, m_mmc_latch2; | |
| 174 | UINT8 m_mmc_reg[16]; | |
| 175 | ||
| 176 | UINT8 m_mmc_dipsetting; | |
| 177 | ||
| 178 | // misc mapper related variables which should be merged with the above one, where possible | |
| 179 | int m_mmc1_reg_write_enable; | |
| 180 | int m_mmc1_latch; | |
| 181 | int m_mmc1_count; | |
| 182 | ||
| 183 | int m_mmc3_latch; | |
| 184 | int m_mmc3_wram_protect; | |
| 185 | int m_mmc3_alt_irq; | |
| 186 | ||
| 187 | int m_MMC5_rom_bank_mode; | |
| 188 | int m_MMC5_vrom_bank_mode; | |
| 189 | int m_MMC5_vram_protect; | |
| 190 | int m_MMC5_scanline; | |
| 191 | int m_vrom_page_a; | |
| 192 | int m_vrom_page_b; | |
| 193 | // int vrom_next[4]; | |
| 194 | ||
| 195 | UINT8 m_mmc6_reg; | |
| 196 | ||
| 197 | // these might be unified in single mmc_reg[] array, together with state->m_mmc_cmd1 & state->m_mmc_cmd2 | |
| 198 | // but be careful that MMC3 clones often use state->m_mmc_cmd1/state->m_mmc_cmd2 (from base MMC3) AND additional regs below! | |
| 199 | UINT8 m_mapper83_reg[10]; | |
| 200 | UINT8 m_mapper83_low_reg[4]; | |
| 201 | UINT8 m_txc_reg[4]; // used by mappers 132, 172 & 173 | |
| 202 | UINT8 m_subor_reg[4]; // used by mappers 166 & 167 | |
| 203 | UINT8 m_sachen_reg[8]; // used by mappers 137, 138, 139 & 141 | |
| 204 | UINT8 m_map52_reg_written; | |
| 205 | UINT8 m_map114_reg, m_map114_reg_enabled; | |
| 206 | ||
| 207 | /***** NES-cart related *****/ | |
| 208 | ||
| 209 | /* load-time cart variables which remain constant */ | |
| 210 | UINT16 m_prg_chunks; // iNES 2.0 allows for more chunks (a recently dumped multigame cart has 256 chunks of both PRG & CHR!) | |
| 211 | UINT16 m_chr_chunks; | |
| 212 | UINT16 m_vram_chunks; | |
| 213 | UINT8 m_trainer; | |
| 214 | UINT8 m_battery; // if there is PRG RAM with battery backup | |
| 215 | UINT32 m_battery_size; | |
| 216 | UINT8 m_prg_ram; // if there is PRG RAM with no backup | |
| 217 | UINT32 m_wram_size; | |
| 218 | UINT32 m_mapper_ram_size; | |
| 219 | UINT32 m_mapper_bram_size; | |
| 220 | ||
| 221 | /* system variables which don't change at run-time */ | |
| 222 | UINT16 m_mapper; // for iNES | |
| 223 | UINT16 m_pcb_id; // for UNIF & xml | |
| 224 | UINT8 m_four_screen_vram; | |
| 225 | UINT8 m_hard_mirroring; | |
| 226 | UINT8 m_crc_hack; // this is needed to detect different boards sharing the same Mappers (shame on .nes format) | |
| 227 | UINT8 m_ines20; | |
| 228 | ||
| 229 | /***** FDS-floppy related *****/ | |
| 230 | ||
| 231 | int m_disk_expansion; | |
| 232 | ||
| 233 | UINT8 m_fds_sides; | |
| 234 | UINT8 *m_fds_data; // here, we store a copy of the disk | |
| 235 | UINT8 *m_fds_ram; // here, we emulate the RAM adapter | |
| 236 | ||
| 237 | /* Variables which can change */ | |
| 238 | UINT8 m_fds_motor_on; | |
| 239 | UINT8 m_fds_door_closed; | |
| 240 | UINT8 m_fds_current_side; | |
| 241 | UINT32 m_fds_head_position; | |
| 242 | UINT8 m_fds_status0; | |
| 243 | UINT8 m_fds_read_mode; | |
| 244 | UINT8 m_fds_write_reg; | |
| 245 | ||
| 246 | /* these are used in the mapper 20 handlers */ | |
| 247 | int m_fds_last_side; | |
| 248 | int m_fds_count; | |
| 249 | }; | |
| 250 | ||
| 251 | ||
| 252 | /*----------- defined in machine/nes.c -----------*/ | |
| 253 | ||
| 254 | WRITE8_HANDLER ( nes_IN0_w ); | |
| 255 | WRITE8_HANDLER ( nes_IN1_w ); | |
| 256 | ||
| 257 | /* protos */ | |
| 258 | ||
| 259 | DEVICE_IMAGE_LOAD(nes_cart); | |
| 260 | DEVICE_START(nes_disk); | |
| 261 | DEVICE_IMAGE_LOAD(nes_disk); | |
| 262 | DEVICE_IMAGE_UNLOAD(nes_disk); | |
| 263 | ||
| 264 | MACHINE_START( nes ); | |
| 265 | MACHINE_RESET( nes ); | |
| 266 | ||
| 267 | DRIVER_INIT( famicom ); | |
| 268 | ||
| 269 | READ8_HANDLER( nes_IN0_r ); | |
| 270 | READ8_HANDLER( nes_IN1_r ); | |
| 271 | ||
| 272 | int nes_ppu_vidaccess( device_t *device, int address, int data ); | |
| 273 | ||
| 274 | void nes_partialhash(hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions); | |
| 275 | ||
| 276 | /*----------- defined in video/nes.c -----------*/ | |
| 277 | ||
| 278 | PALETTE_INIT( nes ); | |
| 279 | VIDEO_START( nes ); | |
| 280 | SCREEN_UPDATE( nes ); | |
| 281 | ||
| 282 | ||
| 283 | #endif /* NES_H_ */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * includes/pce.h | |
| 4 | * | |
| 5 | * NEC PC Engine/TurboGrafx16 | |
| 6 | * | |
| 7 | ****************************************************************************/ | |
| 8 | ||
| 9 | #ifndef PCE_H_ | |
| 10 | #define PCE_H_ | |
| 11 | ||
| 12 | #include "cdrom.h" | |
| 13 | #include "sound/msm5205.h" | |
| 14 | ||
| 15 | #define C6280_TAG "c6280" | |
| 16 | ||
| 17 | #define MAIN_CLOCK 21477270 | |
| 18 | #define PCE_CD_CLOCK 9216000 | |
| 19 | ||
| 20 | #define PCE_HEADER_SIZE 512 | |
| 21 | ||
| 22 | #define TG_16_JOY_SIG 0x00 | |
| 23 | #define PCE_JOY_SIG 0x40 | |
| 24 | #define NO_CD_SIG 0x80 | |
| 25 | #define CD_SIG 0x00 | |
| 26 | /* these might be used to indicate something, but they always seem to return 1 */ | |
| 27 | #define CONST_SIG 0x30 | |
| 28 | ||
| 29 | /* the largest possible cartridge image (street fighter 2 - 2.5MB) */ | |
| 30 | #define PCE_ROM_MAXSIZE 0x280000 | |
| 31 | ||
| 32 | typedef struct | |
| 33 | { | |
| 34 | UINT8 regs[16]; | |
| 35 | UINT8 *bram; | |
| 36 | UINT8 *adpcm_ram; | |
| 37 | int bram_locked; | |
| 38 | int adpcm_read_ptr; | |
| 39 | UINT8 adpcm_read_buf; | |
| 40 | int adpcm_write_ptr; | |
| 41 | UINT8 adpcm_write_buf; | |
| 42 | int adpcm_length; | |
| 43 | int adpcm_clock_divider; | |
| 44 | UINT32 msm_start_addr; | |
| 45 | UINT32 msm_end_addr; | |
| 46 | UINT32 msm_half_addr; | |
| 47 | UINT8 msm_nibble; | |
| 48 | UINT8 msm_idle; | |
| 49 | ||
| 50 | /* SCSI signals */ | |
| 51 | int scsi_BSY; /* Busy. Bus in use */ | |
| 52 | int scsi_SEL; /* Select. Initiator has won arbitration and has selected a target */ | |
| 53 | int scsi_CD; /* Control/Data. Target is sending control (data) information */ | |
| 54 | int scsi_IO; /* Input/Output. Target is sending (receiving) information */ | |
| 55 | int scsi_MSG; /* Message. Target is sending or receiving a message */ | |
| 56 | int scsi_REQ; /* Request. Target is requesting a data transfer */ | |
| 57 | int scsi_ACK; /* Acknowledge. Initiator acknowledges that it is ready for a data transfer */ | |
| 58 | int scsi_ATN; /* Attention. Initiator has a message ready for the target */ | |
| 59 | int scsi_RST; /* Reset. Initiator forces all targets and any other initiators to do a warm reset */ | |
| 60 | int scsi_last_RST; /* To catch setting of RST signal */ | |
| 61 | int cd_motor_on; | |
| 62 | int selected; | |
| 63 | UINT8 *command_buffer; | |
| 64 | int command_buffer_index; | |
| 65 | int status_sent; | |
| 66 | int message_after_status; | |
| 67 | int message_sent; | |
| 68 | UINT8 *data_buffer; | |
| 69 | int data_buffer_size; | |
| 70 | int data_buffer_index; | |
| 71 | int data_transferred; | |
| 72 | ||
| 73 | /* Arcade Card specific */ | |
| 74 | UINT8 *acard_ram; | |
| 75 | UINT8 acard_latch; | |
| 76 | UINT8 acard_ctrl[4]; | |
| 77 | UINT32 acard_base_addr[4]; | |
| 78 | UINT16 acard_addr_offset[4]; | |
| 79 | UINT16 acard_addr_inc[4]; | |
| 80 | UINT32 acard_shift; | |
| 81 | UINT8 acard_shift_reg; | |
| 82 | ||
| 83 | UINT32 current_frame; | |
| 84 | UINT32 end_frame; | |
| 85 | UINT32 last_frame; | |
| 86 | UINT8 cdda_status; | |
| 87 | UINT8 cdda_play_mode; | |
| 88 | UINT8 *subcode_buffer; | |
| 89 | UINT8 end_mark; | |
| 90 | cdrom_file *cd; | |
| 91 | const cdrom_toc* toc; | |
| 92 | emu_timer *data_timer; | |
| 93 | emu_timer *adpcm_dma_timer; | |
| 94 | ||
| 95 | emu_timer *cdda_fadeout_timer; | |
| 96 | emu_timer *cdda_fadein_timer; | |
| 97 | double cdda_volume; | |
| 98 | emu_timer *adpcm_fadeout_timer; | |
| 99 | emu_timer *adpcm_fadein_timer; | |
| 100 | double adpcm_volume; | |
| 101 | } pce_cd_t; | |
| 102 | ||
| 103 | ||
| 104 | class pce_state : public driver_device | |
| 105 | { | |
| 106 | public: | |
| 107 | pce_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 108 | : driver_device(mconfig, type, tag) { } | |
| 109 | ||
| 110 | unsigned char *m_user_ram; | |
| 111 | UINT8 *m_cd_ram; | |
| 112 | UINT8 m_io_port_options; | |
| 113 | UINT8 m_sys3_card; | |
| 114 | UINT8 m_acard; | |
| 115 | pce_cd_t m_cd; | |
| 116 | UINT8 *m_cartridge_ram; | |
| 117 | int m_joystick_port_select; | |
| 118 | int m_joystick_data_select; | |
| 119 | UINT8 m_joy_6b_packet[5]; | |
| 120 | }; | |
| 121 | ||
| 122 | ||
| 123 | /*----------- defined in machine/pce.c -----------*/ | |
| 124 | ||
| 125 | DEVICE_IMAGE_LOAD(pce_cart); | |
| 126 | NVRAM_HANDLER( pce ); | |
| 127 | WRITE8_HANDLER ( pce_joystick_w ); | |
| 128 | READ8_HANDLER ( pce_joystick_r ); | |
| 129 | ||
| 130 | extern const msm5205_interface pce_cd_msm5205_interface; | |
| 131 | WRITE8_HANDLER( pce_cd_bram_w ); | |
| 132 | WRITE8_HANDLER( pce_cd_intf_w ); | |
| 133 | READ8_HANDLER( pce_cd_intf_r ); | |
| 134 | WRITE8_HANDLER( pce_cd_acard_w ); | |
| 135 | READ8_HANDLER( pce_cd_acard_r ); | |
| 136 | WRITE8_HANDLER( pce_cd_acard_wram_w ); | |
| 137 | READ8_HANDLER( pce_cd_acard_wram_r ); | |
| 138 | ||
| 139 | DRIVER_INIT( pce ); | |
| 140 | DRIVER_INIT( tg16 ); | |
| 141 | DRIVER_INIT( sgx ); | |
| 142 | MACHINE_START( pce ); | |
| 143 | MACHINE_RESET( pce ); | |
| 144 | ||
| 145 | ||
| 146 | #endif /* PCE_H_ */ |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | video/nes.c | |
| 4 | ||
| 5 | Routines to control the unique NES video hardware/PPU. | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "video/ppu2c0x.h" | |
| 11 | #include "includes/nes.h" | |
| 12 | #include "machine/nes_mmc.h" | |
| 13 | ||
| 14 | static void nes_vh_reset( running_machine &machine ) | |
| 15 | { | |
| 16 | nes_state *state = machine.driver_data<nes_state>(); | |
| 17 | ppu2c0x_set_vidaccess_callback(machine.device("ppu"), nes_ppu_vidaccess); | |
| 18 | ||
| 19 | if (state->m_four_screen_vram) | |
| 20 | set_nt_mirroring(machine, PPU_MIRROR_4SCREEN); | |
| 21 | else | |
| 22 | { | |
| 23 | switch (state->m_hard_mirroring) | |
| 24 | { | |
| 25 | case PPU_MIRROR_HORZ: | |
| 26 | case PPU_MIRROR_VERT: | |
| 27 | case PPU_MIRROR_HIGH: | |
| 28 | case PPU_MIRROR_LOW: | |
| 29 | set_nt_mirroring(machine, state->m_hard_mirroring); | |
| 30 | break; | |
| 31 | default: | |
| 32 | set_nt_mirroring(machine, PPU_MIRROR_NONE); | |
| 33 | break; | |
| 34 | } | |
| 35 | } | |
| 36 | } | |
| 37 | ||
| 38 | VIDEO_START( nes ) | |
| 39 | { | |
| 40 | nes_state *state = machine.driver_data<nes_state>(); | |
| 41 | ||
| 42 | state->m_last_frame_flip = 0; | |
| 43 | ||
| 44 | machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(nes_vh_reset),&machine)); | |
| 45 | } | |
| 46 | ||
| 47 | PALETTE_INIT( nes ) | |
| 48 | { | |
| 49 | ppu2c0x_init_palette(machine, 0); | |
| 50 | } | |
| 51 | ||
| 52 | ||
| 53 | /*************************************************************************** | |
| 54 | ||
| 55 | Display refresh | |
| 56 | ||
| 57 | ***************************************************************************/ | |
| 58 | ||
| 59 | SCREEN_UPDATE( nes ) | |
| 60 | { | |
| 61 | nes_state *state = screen->machine().driver_data<nes_state>(); | |
| 62 | ||
| 63 | /* render the ppu */ | |
| 64 | ppu2c0x_render(state->m_ppu, bitmap, 0, 0, 0, 0); | |
| 65 | ||
| 66 | /* if this is a disk system game, check for the flip-disk key */ | |
| 67 | if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD) | |
| 68 | { | |
| 69 | // latch this input so it doesn't go at warp speed | |
| 70 | if ((input_port_read(screen->machine(), "FLIPDISK") & 0x01) && (!state->m_last_frame_flip)) | |
| 71 | { | |
| 72 | state->m_last_frame_flip = 1; | |
| 73 | state->m_fds_current_side++; | |
| 74 | if (state->m_fds_current_side > state->m_fds_sides) | |
| 75 | state->m_fds_current_side = 0; | |
| 76 | ||
| 77 | if (state->m_fds_current_side == 0) | |
| 78 | popmessage("No disk inserted."); | |
| 79 | else | |
| 80 | popmessage("Disk set to side %d", state->m_fds_current_side); | |
| 81 | } | |
| 82 | ||
| 83 | if (!(input_port_read(screen->machine(), "FLIPDISK") & 0x01)) | |
| 84 | state->m_last_frame_flip = 0; | |
| 85 | } | |
| 86 | return 0; | |
| 87 | } |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Neo-Geo AES hardware | |
| 4 | ||
| 5 | Credits (from MAME neogeo.c, since this is just a minor edit of that driver): | |
| 6 | * This driver was made possible by the research done by | |
| 7 | Charles MacDonald. For a detailed description of the Neo-Geo | |
| 8 | hardware, please visit his page at: | |
| 9 | http://cgfm2.emuviews.com/temp/mvstech.txt | |
| 10 | * Presented to you by the Shin Emu Keikaku team. | |
| 11 | * The following people have all spent probably far | |
| 12 | too much time on this: | |
| 13 | AVDB | |
| 14 | Bryan McPhail | |
| 15 | Fuzz | |
| 16 | Ernesto Corvi | |
| 17 | Andrew Prime | |
| 18 | Zsolt Vasvari | |
| 19 | ||
| 20 | MESS cartridge support by R. Belmont based on work by Michael Zapf | |
| 21 | ||
| 22 | Current status: | |
| 23 | - Cartridges run. | |
| 24 | ||
| 25 | ToDo : | |
| 26 | - Change input code to allow selection of the mahjong panel in PORT_CATEGORY. | |
| 27 | - Clean up code, to reduce duplication of MAME source | |
| 28 | ||
| 29 | ****************************************************************************/ | |
| 30 | ||
| 31 | #include "emu.h" | |
| 32 | #include "cpu/m68000/m68000.h" | |
| 33 | #include "includes/neogeo.h" | |
| 34 | #include "machine/pd4990a.h" | |
| 35 | #include "cpu/z80/z80.h" | |
| 36 | #include "sound/2610intf.h" | |
| 37 | #include "machine/aescart.h" | |
| 38 | #include "imagedev/cartslot.h" | |
| 39 | #ifdef MESS | |
| 40 | #include "neogeo.lh" | |
| 41 | #else | |
| 42 | extern const char layout_neogeo[]; | |
| 43 | #endif | |
| 44 | ||
| 45 | ||
| 46 | // CD-ROM / DMA control registers | |
| 47 | typedef struct | |
| 48 | { | |
| 49 | UINT8 area_sel; | |
| 50 | UINT8 pcm_bank_sel; | |
| 51 | UINT8 spr_bank_sel; | |
| 52 | UINT32 addr_source; // target if in fill mode | |
| 53 | UINT32 addr_target; | |
| 54 | UINT16 fill_word; | |
| 55 | UINT32 word_count; | |
| 56 | UINT16 dma_mode[10]; | |
| 57 | } neocd_ctrl_t; | |
| 58 | ||
| 59 | class ng_aes_state : public neogeo_state | |
| 60 | { | |
| 61 | public: | |
| 62 | ng_aes_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 63 | : neogeo_state(mconfig, type, tag) { } | |
| 64 | ||
| 65 | UINT8 *m_memcard_data; | |
| 66 | neocd_ctrl_t m_neocd_ctrl; | |
| 67 | }; | |
| 68 | ||
| 69 | ||
| 70 | ||
| 71 | #define LOG_VIDEO_SYSTEM (0) | |
| 72 | #define LOG_CPU_COMM (0) | |
| 73 | #define LOG_MAIN_CPU_BANKING (1) | |
| 74 | #define LOG_AUDIO_CPU_BANKING (1) | |
| 75 | ||
| 76 | #define NEOCD_AREA_SPR 0 | |
| 77 | #define NEOCD_AREA_PCM 1 | |
| 78 | #define NEOCD_AREA_AUDIO 4 | |
| 79 | #define NEOCD_AREA_FIX 5 | |
| 80 | ||
| 81 | /************************************* | |
| 82 | * | |
| 83 | * Global variables | |
| 84 | * | |
| 85 | *************************************/ | |
| 86 | ||
| 87 | //static UINT16 *save_ram; | |
| 88 | ||
| 89 | UINT16* neocd_work_ram; | |
| 90 | ||
| 91 | /************************************* | |
| 92 | * | |
| 93 | * Forward declarations | |
| 94 | * | |
| 95 | *************************************/ | |
| 96 | ||
| 97 | //static void set_output_latch(running_machine &machine, UINT8 data); | |
| 98 | //static void set_output_data(running_machine &machine, UINT8 data); | |
| 99 | ||
| 100 | ||
| 101 | /************************************* | |
| 102 | * | |
| 103 | * Main CPU interrupt generation | |
| 104 | * | |
| 105 | *************************************/ | |
| 106 | ||
| 107 | #define IRQ2CTRL_ENABLE (0x10) | |
| 108 | #define IRQ2CTRL_LOAD_RELATIVE (0x20) | |
| 109 | #define IRQ2CTRL_AUTOLOAD_VBLANK (0x40) | |
| 110 | #define IRQ2CTRL_AUTOLOAD_REPEAT (0x80) | |
| 111 | ||
| 112 | ||
| 113 | static void adjust_display_position_interrupt_timer( running_machine &machine ) | |
| 114 | { | |
| 115 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 116 | ||
| 117 | if ((state->m_display_counter + 1) != 0) | |
| 118 | { | |
| 119 | attotime period = (attotime::from_hz(NEOGEO_PIXEL_CLOCK) * (state->m_display_counter + 1)); | |
| 120 | if (LOG_VIDEO_SYSTEM) logerror("adjust_display_position_interrupt_timer current y: %02x current x: %02x target y: %x target x: %x\n", machine.primary_screen->vpos(), machine.primary_screen->hpos(), (state->m_display_counter + 1) / NEOGEO_HTOTAL, (state->m_display_counter + 1) % NEOGEO_HTOTAL); | |
| 121 | ||
| 122 | state->m_display_position_interrupt_timer->adjust(period); | |
| 123 | } | |
| 124 | } | |
| 125 | ||
| 126 | #ifdef MESS | |
| 127 | void neogeo_set_display_position_interrupt_control( running_machine &machine, UINT16 data ) | |
| 128 | { | |
| 129 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 130 | state->m_display_position_interrupt_control = data; | |
| 131 | } | |
| 132 | ||
| 133 | ||
| 134 | void neogeo_set_display_counter_msb( address_space *space, UINT16 data ) | |
| 135 | { | |
| 136 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 137 | ||
| 138 | state->m_display_counter = (state->m_display_counter & 0x0000ffff) | ((UINT32)data << 16); | |
| 139 | ||
| 140 | if (LOG_VIDEO_SYSTEM) logerror("PC %06x: set_display_counter %08x\n", cpu_get_pc(&space->device()), state->m_display_counter); | |
| 141 | } | |
| 142 | ||
| 143 | ||
| 144 | void neogeo_set_display_counter_lsb( address_space *space, UINT16 data ) | |
| 145 | { | |
| 146 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 147 | ||
| 148 | state->m_display_counter = (state->m_display_counter & 0xffff0000) | data; | |
| 149 | ||
| 150 | if (LOG_VIDEO_SYSTEM) logerror("PC %06x: set_display_counter %08x\n", cpu_get_pc(&space->device()), state->m_display_counter); | |
| 151 | ||
| 152 | if (state->m_display_position_interrupt_control & IRQ2CTRL_LOAD_RELATIVE) | |
| 153 | { | |
| 154 | if (LOG_VIDEO_SYSTEM) logerror("AUTOLOAD_RELATIVE "); | |
| 155 | adjust_display_position_interrupt_timer(space->machine()); | |
| 156 | } | |
| 157 | } | |
| 158 | #endif | |
| 159 | ||
| 160 | static void update_interrupts( running_machine &machine ) | |
| 161 | { | |
| 162 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 163 | ||
| 164 | if(strcmp((char*)machine.system().name,"aes") != 0) | |
| 165 | { // raster and vblank IRQs are swapped on the NeoCD. | |
| 166 | cputag_set_input_line(machine, "maincpu", 2, state->m_vblank_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 167 | cputag_set_input_line(machine, "maincpu", 1, state->m_display_position_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 168 | cputag_set_input_line(machine, "maincpu", 3, state->m_irq3_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 169 | } | |
| 170 | else | |
| 171 | { | |
| 172 | cputag_set_input_line(machine, "maincpu", 1, state->m_vblank_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 173 | cputag_set_input_line(machine, "maincpu", 2, state->m_display_position_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 174 | cputag_set_input_line(machine, "maincpu", 3, state->m_irq3_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 175 | } | |
| 176 | } | |
| 177 | ||
| 178 | #ifdef MESS | |
| 179 | void neogeo_acknowledge_interrupt( running_machine &machine, UINT16 data ) | |
| 180 | { | |
| 181 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 182 | ||
| 183 | if (data & 0x01) | |
| 184 | state->m_irq3_pending = 0; | |
| 185 | if (data & 0x02) | |
| 186 | state->m_display_position_interrupt_pending = 0; | |
| 187 | if (data & 0x04) | |
| 188 | state->m_vblank_interrupt_pending = 0; | |
| 189 | ||
| 190 | update_interrupts(machine); | |
| 191 | } | |
| 192 | #endif | |
| 193 | ||
| 194 | static TIMER_CALLBACK( display_position_interrupt_callback ) | |
| 195 | { | |
| 196 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 197 | ||
| 198 | if (LOG_VIDEO_SYSTEM) logerror("--- Scanline @ %d,%d\n", machine.primary_screen->vpos(), machine.primary_screen->hpos()); | |
| 199 | ||
| 200 | if (state->m_display_position_interrupt_control & IRQ2CTRL_ENABLE) | |
| 201 | { | |
| 202 | if (LOG_VIDEO_SYSTEM) logerror("*** Scanline interrupt (IRQ2) *** y: %02x x: %02x\n", machine.primary_screen->vpos(), machine.primary_screen->hpos()); | |
| 203 | state->m_display_position_interrupt_pending = 1; | |
| 204 | ||
| 205 | update_interrupts(machine); | |
| 206 | } | |
| 207 | ||
| 208 | if (state->m_display_position_interrupt_control & IRQ2CTRL_AUTOLOAD_REPEAT) | |
| 209 | { | |
| 210 | if (LOG_VIDEO_SYSTEM) logerror("AUTOLOAD_REPEAT "); | |
| 211 | adjust_display_position_interrupt_timer(machine); | |
| 212 | } | |
| 213 | } | |
| 214 | ||
| 215 | ||
| 216 | static TIMER_CALLBACK( display_position_vblank_callback ) | |
| 217 | { | |
| 218 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 219 | ||
| 220 | if (state->m_display_position_interrupt_control & IRQ2CTRL_AUTOLOAD_VBLANK) | |
| 221 | { | |
| 222 | if (LOG_VIDEO_SYSTEM) logerror("AUTOLOAD_VBLANK "); | |
| 223 | adjust_display_position_interrupt_timer(machine); | |
| 224 | } | |
| 225 | ||
| 226 | /* set timer for next screen */ | |
| 227 | state->m_display_position_vblank_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, NEOGEO_VBLANK_RELOAD_HPOS)); | |
| 228 | } | |
| 229 | ||
| 230 | ||
| 231 | static TIMER_CALLBACK( vblank_interrupt_callback ) | |
| 232 | { | |
| 233 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 234 | ||
| 235 | if (LOG_VIDEO_SYSTEM) logerror("+++ VBLANK @ %d,%d\n", machine.primary_screen->vpos(), machine.primary_screen->hpos()); | |
| 236 | ||
| 237 | /* add a timer tick to the pd4990a */ | |
| 238 | upd4990a_addretrace(state->m_upd4990a); | |
| 239 | ||
| 240 | state->m_vblank_interrupt_pending = 1; | |
| 241 | ||
| 242 | update_interrupts(machine); | |
| 243 | ||
| 244 | /* set timer for next screen */ | |
| 245 | state->m_vblank_interrupt_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, 0)); | |
| 246 | } | |
| 247 | ||
| 248 | ||
| 249 | static void create_interrupt_timers( running_machine &machine ) | |
| 250 | { | |
| 251 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 252 | state->m_display_position_interrupt_timer = machine.scheduler().timer_alloc(FUNC(display_position_interrupt_callback)); | |
| 253 | state->m_display_position_vblank_timer = machine.scheduler().timer_alloc(FUNC(display_position_vblank_callback)); | |
| 254 | state->m_vblank_interrupt_timer = machine.scheduler().timer_alloc(FUNC(vblank_interrupt_callback)); | |
| 255 | } | |
| 256 | ||
| 257 | ||
| 258 | static void start_interrupt_timers( running_machine &machine ) | |
| 259 | { | |
| 260 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 261 | state->m_vblank_interrupt_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, 0)); | |
| 262 | state->m_display_position_vblank_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, NEOGEO_VBLANK_RELOAD_HPOS)); | |
| 263 | } | |
| 264 | ||
| 265 | ||
| 266 | ||
| 267 | /************************************* | |
| 268 | * | |
| 269 | * Audio CPU interrupt generation | |
| 270 | * | |
| 271 | *************************************/ | |
| 272 | ||
| 273 | static void audio_cpu_irq(device_t *device, int assert) | |
| 274 | { | |
| 275 | neogeo_state *state = device->machine().driver_data<neogeo_state>(); | |
| 276 | device_set_input_line(state->m_audiocpu, 0, assert ? ASSERT_LINE : CLEAR_LINE); | |
| 277 | } | |
| 278 | ||
| 279 | ||
| 280 | static void audio_cpu_assert_nmi(running_machine &machine) | |
| 281 | { | |
| 282 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 283 | device_set_input_line(state->m_audiocpu, INPUT_LINE_NMI, ASSERT_LINE); | |
| 284 | } | |
| 285 | ||
| 286 | ||
| 287 | static WRITE8_HANDLER( audio_cpu_clear_nmi_w ) | |
| 288 | { | |
| 289 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 290 | device_set_input_line(state->m_audiocpu, INPUT_LINE_NMI, CLEAR_LINE); | |
| 291 | } | |
| 292 | ||
| 293 | ||
| 294 | ||
| 295 | /************************************* | |
| 296 | * | |
| 297 | * Input ports / Controllers | |
| 298 | * | |
| 299 | *************************************/ | |
| 300 | ||
| 301 | static void select_controller( running_machine &machine, UINT8 data ) | |
| 302 | { | |
| 303 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 304 | state->m_controller_select = data; | |
| 305 | } | |
| 306 | ||
| 307 | ||
| 308 | #if 0 | |
| 309 | static CUSTOM_INPUT( multiplexed_controller_r ) | |
| 310 | { | |
| 311 | int port = (FPTR)param; | |
| 312 | ||
| 313 | static const char *const cntrl[2][2] = | |
| 314 | { | |
| 315 | { "IN0-0", "IN0-1" }, { "IN1-0", "IN1-1" } | |
| 316 | }; | |
| 317 | ||
| 318 | return input_port_read_safe(field.machine(), cntrl[port][controller_select & 0x01], 0x00); | |
| 319 | } | |
| 320 | ||
| 321 | ||
| 322 | static CUSTOM_INPUT( mahjong_controller_r ) | |
| 323 | { | |
| 324 | UINT32 ret; | |
| 325 | ||
| 326 | /* | |
| 327 | cpu #0 (PC=00C18B9A): unmapped memory word write to 00380000 = 0012 & 00FF | |
| 328 | cpu #0 (PC=00C18BB6): unmapped memory word write to 00380000 = 001B & 00FF | |
| 329 | cpu #0 (PC=00C18D54): unmapped memory word write to 00380000 = 0024 & 00FF | |
| 330 | cpu #0 (PC=00C18D6C): unmapped memory word write to 00380000 = 0009 & 00FF | |
| 331 | cpu #0 (PC=00C18C40): unmapped memory word write to 00380000 = 0000 & 00FF | |
| 332 | */ | |
| 333 | switch (controller_select) | |
| 334 | { | |
| 335 | default: | |
| 336 | case 0x00: ret = 0x0000; break; /* nothing? */ | |
| 337 | case 0x09: ret = input_port_read(field.machine(), "MAHJONG1"); break; | |
| 338 | case 0x12: ret = input_port_read(field.machine(), "MAHJONG2"); break; | |
| 339 | case 0x1b: ret = input_port_read(field.machine(), "MAHJONG3"); break; /* player 1 normal inputs? */ | |
| 340 | case 0x24: ret = input_port_read(field.machine(), "MAHJONG4"); break; | |
| 341 | } | |
| 342 | ||
| 343 | return ret; | |
| 344 | } | |
| 345 | ||
| 346 | #endif | |
| 347 | ||
| 348 | static WRITE16_HANDLER( io_control_w ) | |
| 349 | { | |
| 350 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 351 | switch (offset) | |
| 352 | { | |
| 353 | case 0x00: select_controller(space->machine(), data & 0x00ff); break; | |
| 354 | // case 0x18: set_output_latch(space->machine(), data & 0x00ff); break; | |
| 355 | // case 0x20: set_output_data(space->machine(), data & 0x00ff); break; | |
| 356 | case 0x28: upd4990a_control_16_w(state->m_upd4990a, 0, data, mem_mask); break; | |
| 357 | // case 0x30: break; // coin counters | |
| 358 | // case 0x31: break; // coin counters | |
| 359 | // case 0x32: break; // coin lockout | |
| 360 | // case 0x33: break; // coui lockout | |
| 361 | ||
| 362 | default: | |
| 363 | logerror("PC: %x Unmapped I/O control write. Offset: %x Data: %x\n", cpu_get_pc(&space->device()), offset, data); | |
| 364 | break; | |
| 365 | } | |
| 366 | } | |
| 367 | ||
| 368 | ||
| 369 | ||
| 370 | /************************************* | |
| 371 | * | |
| 372 | * Unmapped memory access | |
| 373 | * | |
| 374 | *************************************/ | |
| 375 | #ifdef MESS | |
| 376 | READ16_HANDLER( neogeo_unmapped_r ) | |
| 377 | { | |
| 378 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 379 | UINT16 ret; | |
| 380 | ||
| 381 | /* unmapped memory returns the last word on the data bus, which is almost always the opcode | |
| 382 | of the next instruction due to prefetch */ | |
| 383 | ||
| 384 | /* prevent recursion */ | |
| 385 | if (state->m_recurse) | |
| 386 | ret = 0xffff; | |
| 387 | else | |
| 388 | { | |
| 389 | state->m_recurse = 1; | |
| 390 | ret = space->read_word(cpu_get_pc(&space->device())); | |
| 391 | state->m_recurse = 0; | |
| 392 | } | |
| 393 | ||
| 394 | return ret; | |
| 395 | } | |
| 396 | #endif | |
| 397 | ||
| 398 | ||
| 399 | ||
| 400 | /************************************* | |
| 401 | * | |
| 402 | * uPD4990A calendar chip | |
| 403 | * | |
| 404 | *************************************/ | |
| 405 | #if 0 | |
| 406 | static void calendar_init(running_machine &machine) | |
| 407 | { | |
| 408 | /* set the celander IC to 'right now' */ | |
| 409 | system_time systime; | |
| 410 | system_tm time; | |
| 411 | ||
| 412 | machine.base_datetime(&systime); | |
| 413 | time = systime.local_time; | |
| 414 | ||
| 415 | pd4990a.seconds = ((time.second / 10) << 4) + (time.second % 10); | |
| 416 | pd4990a.minutes = ((time.minute / 10) << 4) + (time.minute % 10); | |
| 417 | pd4990a.hours = ((time.hour / 10) <<4 ) + (time.hour % 10); | |
| 418 | pd4990a.days = ((time.mday / 10) << 4) + (time.mday % 10); | |
| 419 | pd4990a.month = time.month + 1; | |
| 420 | pd4990a.year = ((((time.year - 1900) % 100) / 10) << 4) + ((time.year - 1900) % 10); | |
| 421 | pd4990a.weekday = time.weekday; | |
| 422 | } | |
| 423 | ||
| 424 | ||
| 425 | static void calendar_clock(void) | |
| 426 | { | |
| 427 | // pd4990a_addretrace(); | |
| 428 | } | |
| 429 | #endif | |
| 430 | ||
| 431 | static CUSTOM_INPUT( get_calendar_status ) | |
| 432 | { | |
| 433 | neogeo_state *state = field.machine().driver_data<neogeo_state>(); | |
| 434 | return (upd4990a_databit_r(state->m_upd4990a, 0) << 1) | upd4990a_testbit_r(state->m_upd4990a, 0); | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | ||
| 439 | /************************************* | |
| 440 | * | |
| 441 | * NVRAM (Save RAM) | |
| 442 | * | |
| 443 | *************************************/ | |
| 444 | #if 0 | |
| 445 | static NVRAM_HANDLER( neogeo ) | |
| 446 | { | |
| 447 | if (read_or_write) | |
| 448 | /* save the SRAM settings */ | |
| 449 | mame_fwrite(file, save_ram, 0x2000); | |
| 450 | else | |
| 451 | { | |
| 452 | /* load the SRAM settings */ | |
| 453 | if (file) | |
| 454 | mame_fread(file, save_ram, 0x2000); | |
| 455 | else | |
| 456 | memset(save_ram, 0, 0x10000); | |
| 457 | } | |
| 458 | } | |
| 459 | ||
| 460 | ||
| 461 | static void set_save_ram_unlock( running_machine &machine, UINT8 data ) | |
| 462 | { | |
| 463 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 464 | state->m_save_ram_unlocked = data; | |
| 465 | } | |
| 466 | ||
| 467 | ||
| 468 | static WRITE16_HANDLER( save_ram_w ) | |
| 469 | { | |
| 470 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 471 | ||
| 472 | if (state->m_save_ram_unlocked) | |
| 473 | COMBINE_DATA(&save_ram[offset]); | |
| 474 | } | |
| 475 | #endif | |
| 476 | ||
| 477 | ||
| 478 | /************************************* | |
| 479 | * | |
| 480 | * Memory card | |
| 481 | * | |
| 482 | *************************************/ | |
| 483 | ||
| 484 | #define MEMCARD_SIZE 0x0800 | |
| 485 | ||
| 486 | static CUSTOM_INPUT( get_memcard_status ) | |
| 487 | { | |
| 488 | /* D0 and D1 are memcard presence indicators, D2 indicates memcard | |
| 489 | write protect status (we are always write enabled) */ | |
| 490 | if(strcmp((char*)field.machine().system().name,"aes") != 0) | |
| 491 | return 0x00; // On the Neo Geo CD, the memory card is internal and therefore always present. | |
| 492 | else | |
| 493 | return (memcard_present(field.machine()) == -1) ? 0x07 : 0x00; | |
| 494 | } | |
| 495 | ||
| 496 | static READ16_HANDLER( memcard_r ) | |
| 497 | { | |
| 498 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 499 | UINT16 ret; | |
| 500 | ||
| 501 | if (memcard_present(space->machine()) != -1) | |
| 502 | ret = state->m_memcard_data[offset] | 0xff00; | |
| 503 | else | |
| 504 | ret = 0xffff; | |
| 505 | ||
| 506 | return ret; | |
| 507 | } | |
| 508 | ||
| 509 | ||
| 510 | static WRITE16_HANDLER( memcard_w ) | |
| 511 | { | |
| 512 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 513 | if (ACCESSING_BITS_0_7) | |
| 514 | { | |
| 515 | if (memcard_present(space->machine()) != -1) | |
| 516 | state->m_memcard_data[offset] = data; | |
| 517 | } | |
| 518 | } | |
| 519 | ||
| 520 | /* The NeoCD has an 8kB internal memory card, instead of memcard slots like the MVS and AES */ | |
| 521 | static READ16_HANDLER( neocd_memcard_r ) | |
| 522 | { | |
| 523 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 524 | return state->m_memcard_data[offset] | 0xff00; | |
| 525 | } | |
| 526 | ||
| 527 | ||
| 528 | static WRITE16_HANDLER( neocd_memcard_w ) | |
| 529 | { | |
| 530 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 531 | if (ACCESSING_BITS_0_7) | |
| 532 | { | |
| 533 | state->m_memcard_data[offset] = data; | |
| 534 | } | |
| 535 | } | |
| 536 | ||
| 537 | static MEMCARD_HANDLER( neogeo ) | |
| 538 | { | |
| 539 | ng_aes_state *state = machine.driver_data<ng_aes_state>(); | |
| 540 | switch (action) | |
| 541 | { | |
| 542 | case MEMCARD_CREATE: | |
| 543 | memset(state->m_memcard_data, 0, MEMCARD_SIZE); | |
| 544 | file.write(state->m_memcard_data, MEMCARD_SIZE); | |
| 545 | break; | |
| 546 | ||
| 547 | case MEMCARD_INSERT: | |
| 548 | file.read(state->m_memcard_data, MEMCARD_SIZE); | |
| 549 | break; | |
| 550 | ||
| 551 | case MEMCARD_EJECT: | |
| 552 | file.write(state->m_memcard_data, MEMCARD_SIZE); | |
| 553 | break; | |
| 554 | } | |
| 555 | } | |
| 556 | ||
| 557 | ||
| 558 | ||
| 559 | /************************************* | |
| 560 | * | |
| 561 | * Inter-CPU communications | |
| 562 | * | |
| 563 | *************************************/ | |
| 564 | ||
| 565 | static WRITE16_HANDLER( audio_command_w ) | |
| 566 | { | |
| 567 | /* accessing the LSB only is not mapped */ | |
| 568 | if (mem_mask != 0x00ff) | |
| 569 | { | |
| 570 | soundlatch_w(space, 0, data >> 8); | |
| 571 | ||
| 572 | audio_cpu_assert_nmi(space->machine()); | |
| 573 | ||
| 574 | /* boost the interleave to let the audio CPU read the command */ | |
| 575 | space->machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(50)); | |
| 576 | ||
| 577 | if (LOG_CPU_COMM) logerror("MAIN CPU PC %06x: audio_command_w %04x - %04x\n", cpu_get_pc(&space->device()), data, mem_mask); | |
| 578 | } | |
| 579 | } | |
| 580 | ||
| 581 | ||
| 582 | static READ8_HANDLER( audio_command_r ) | |
| 583 | { | |
| 584 | UINT8 ret = soundlatch_r(space, 0); | |
| 585 | ||
| 586 | if (LOG_CPU_COMM) logerror(" AUD CPU PC %04x: audio_command_r %02x\n", cpu_get_pc(&space->device()), ret); | |
| 587 | ||
| 588 | /* this is a guess */ | |
| 589 | audio_cpu_clear_nmi_w(space, 0, 0); | |
| 590 | ||
| 591 | return ret; | |
| 592 | } | |
| 593 | ||
| 594 | ||
| 595 | static WRITE8_HANDLER( audio_result_w ) | |
| 596 | { | |
| 597 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 598 | ||
| 599 | if (LOG_CPU_COMM && (state->m_audio_result != data)) logerror(" AUD CPU PC %04x: audio_result_w %02x\n", cpu_get_pc(&space->device()), data); | |
| 600 | ||
| 601 | state->m_audio_result = data; | |
| 602 | } | |
| 603 | ||
| 604 | ||
| 605 | static CUSTOM_INPUT( get_audio_result ) | |
| 606 | { | |
| 607 | neogeo_state *state = field.machine().driver_data<neogeo_state>(); | |
| 608 | UINT32 ret = state->m_audio_result; | |
| 609 | ||
| 610 | // if (LOG_CPU_COMM) logerror("MAIN CPU PC %06x: audio_result_r %02x\n", cpu_get_pc(field.machine().device("maincpu")), ret); | |
| 611 | ||
| 612 | return ret; | |
| 613 | } | |
| 614 | ||
| 615 | ||
| 616 | ||
| 617 | /************************************* | |
| 618 | * | |
| 619 | * Main CPU banking | |
| 620 | * | |
| 621 | *************************************/ | |
| 622 | ||
| 623 | static void _set_main_cpu_vector_table_source( running_machine &machine ) | |
| 624 | { | |
| 625 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 626 | memory_set_bank(machine, NEOGEO_BANK_VECTORS, state->m_main_cpu_vector_table_source); | |
| 627 | } | |
| 628 | ||
| 629 | ||
| 630 | static void set_main_cpu_vector_table_source( running_machine &machine, UINT8 data ) | |
| 631 | { | |
| 632 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 633 | state->m_main_cpu_vector_table_source = data; | |
| 634 | ||
| 635 | _set_main_cpu_vector_table_source(machine); | |
| 636 | } | |
| 637 | ||
| 638 | ||
| 639 | static void _set_main_cpu_bank_address( running_machine &machine ) | |
| 640 | { | |
| 641 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 642 | memory_set_bankptr(machine, NEOGEO_BANK_CARTRIDGE, &machine.region("maincpu")->base()[state->m_main_cpu_bank_address]); | |
| 643 | } | |
| 644 | ||
| 645 | #ifdef MESS | |
| 646 | void neogeo_set_main_cpu_bank_address( address_space *space, UINT32 bank_address ) | |
| 647 | { | |
| 648 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 649 | ||
| 650 | if (LOG_MAIN_CPU_BANKING) logerror("MAIN CPU PC %06x: neogeo_set_main_cpu_bank_address %06x\n", cpu_get_pc(&space->device()), bank_address); | |
| 651 | ||
| 652 | state->m_main_cpu_bank_address = bank_address; | |
| 653 | ||
| 654 | _set_main_cpu_bank_address(space->machine()); | |
| 655 | } | |
| 656 | #endif | |
| 657 | ||
| 658 | static WRITE16_HANDLER( main_cpu_bank_select_w ) | |
| 659 | { | |
| 660 | UINT32 bank_address; | |
| 661 | UINT32 len = space->machine().region("maincpu")->bytes(); | |
| 662 | ||
| 663 | if ((len <= 0x100000) && (data & 0x07)) | |
| 664 | logerror("PC %06x: warning: bankswitch to %02x but no banks available\n", cpu_get_pc(&space->device()), data); | |
| 665 | else | |
| 666 | { | |
| 667 | bank_address = ((data & 0x07) + 1) * 0x100000; | |
| 668 | ||
| 669 | if (bank_address >= len) | |
| 670 | { | |
| 671 | logerror("PC %06x: warning: bankswitch to empty bank %02x\n", cpu_get_pc(&space->device()), data); | |
| 672 | bank_address = 0x100000; | |
| 673 | } | |
| 674 | ||
| 675 | neogeo_set_main_cpu_bank_address(space, bank_address); | |
| 676 | } | |
| 677 | } | |
| 678 | ||
| 679 | ||
| 680 | static void main_cpu_banking_init( running_machine &machine ) | |
| 681 | { | |
| 682 | address_space *mainspace = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 683 | ||
| 684 | /* create vector banks */ | |
| 685 | memory_configure_bank(machine, NEOGEO_BANK_VECTORS, 0, 1, machine.region("mainbios")->base(), 0); | |
| 686 | memory_configure_bank(machine, NEOGEO_BANK_VECTORS, 1, 1, machine.region("maincpu")->base(), 0); | |
| 687 | ||
| 688 | /* set initial main CPU bank */ | |
| 689 | if (machine.region("maincpu")->bytes() > 0x100000) | |
| 690 | neogeo_set_main_cpu_bank_address(mainspace, 0x100000); | |
| 691 | else | |
| 692 | neogeo_set_main_cpu_bank_address(mainspace, 0x000000); | |
| 693 | } | |
| 694 | ||
| 695 | ||
| 696 | ||
| 697 | /************************************* | |
| 698 | * | |
| 699 | * Audio CPU banking | |
| 700 | * | |
| 701 | *************************************/ | |
| 702 | ||
| 703 | static void set_audio_cpu_banking( running_machine &machine ) | |
| 704 | { | |
| 705 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 706 | int region; | |
| 707 | ||
| 708 | for (region = 0; region < 4; region++) | |
| 709 | memory_set_bank(machine, NEOGEO_BANK_AUDIO_CPU_CART_BANK + region, state->m_audio_cpu_banks[region]); | |
| 710 | } | |
| 711 | ||
| 712 | ||
| 713 | static void audio_cpu_bank_select( address_space *space, int region, UINT8 bank ) | |
| 714 | { | |
| 715 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 716 | ||
| 717 | if (LOG_AUDIO_CPU_BANKING) logerror("Audio CPU PC %03x: audio_cpu_bank_select: Region: %d Bank: %02x\n", cpu_get_pc(&space->device()), region, bank); | |
| 718 | ||
| 719 | state->m_audio_cpu_banks[region] = bank; | |
| 720 | ||
| 721 | set_audio_cpu_banking(space->machine()); | |
| 722 | } | |
| 723 | ||
| 724 | ||
| 725 | static READ8_HANDLER( audio_cpu_bank_select_f000_f7ff_r ) | |
| 726 | { | |
| 727 | audio_cpu_bank_select(space, 0, offset >> 8); | |
| 728 | ||
| 729 | return 0; | |
| 730 | } | |
| 731 | ||
| 732 | ||
| 733 | static READ8_HANDLER( audio_cpu_bank_select_e000_efff_r ) | |
| 734 | { | |
| 735 | audio_cpu_bank_select(space, 1, offset >> 8); | |
| 736 | ||
| 737 | return 0; | |
| 738 | } | |
| 739 | ||
| 740 | ||
| 741 | static READ8_HANDLER( audio_cpu_bank_select_c000_dfff_r ) | |
| 742 | { | |
| 743 | audio_cpu_bank_select(space, 2, offset >> 8); | |
| 744 | ||
| 745 | return 0; | |
| 746 | } | |
| 747 | ||
| 748 | ||
| 749 | static READ8_HANDLER( audio_cpu_bank_select_8000_bfff_r ) | |
| 750 | { | |
| 751 | audio_cpu_bank_select(space, 3, offset >> 8); | |
| 752 | ||
| 753 | return 0; | |
| 754 | } | |
| 755 | ||
| 756 | ||
| 757 | static void _set_audio_cpu_rom_source( address_space *space ) | |
| 758 | { | |
| 759 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 760 | ||
| 761 | /* if (!machine.region("audiobios")->base()) */ | |
| 762 | state->m_audio_cpu_rom_source = 1; | |
| 763 | ||
| 764 | memory_set_bank(space->machine(), NEOGEO_BANK_AUDIO_CPU_MAIN_BANK, state->m_audio_cpu_rom_source); | |
| 765 | ||
| 766 | /* reset CPU if the source changed -- this is a guess */ | |
| 767 | if (state->m_audio_cpu_rom_source != state->m_audio_cpu_rom_source_last) | |
| 768 | { | |
| 769 | state->m_audio_cpu_rom_source_last = state->m_audio_cpu_rom_source; | |
| 770 | ||
| 771 | cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_RESET, PULSE_LINE); | |
| 772 | ||
| 773 | if (LOG_AUDIO_CPU_BANKING) logerror("Audio CPU PC %03x: selectign %s ROM\n", cpu_get_pc(&space->device()), state->m_audio_cpu_rom_source ? "CARTRIDGE" : "BIOS"); | |
| 774 | } | |
| 775 | } | |
| 776 | ||
| 777 | ||
| 778 | static void set_audio_cpu_rom_source( address_space *space, UINT8 data ) | |
| 779 | { | |
| 780 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 781 | state->m_audio_cpu_rom_source = data; | |
| 782 | ||
| 783 | _set_audio_cpu_rom_source(space); | |
| 784 | } | |
| 785 | ||
| 786 | ||
| 787 | static void audio_cpu_banking_init( running_machine &machine ) | |
| 788 | { | |
| 789 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 790 | int region; | |
| 791 | int bank; | |
| 792 | UINT8 *rgn; | |
| 793 | UINT32 address_mask; | |
| 794 | ||
| 795 | /* audio bios/cartridge selection */ | |
| 796 | if (machine.region("audiobios")->base()) | |
| 797 | memory_configure_bank(machine, NEOGEO_BANK_AUDIO_CPU_MAIN_BANK, 0, 1, machine.region("audiobios")->base(), 0); | |
| 798 | memory_configure_bank(machine, NEOGEO_BANK_AUDIO_CPU_MAIN_BANK, 1, 1, machine.region("audiocpu")->base(), 0); | |
| 799 | ||
| 800 | /* audio banking */ | |
| 801 | address_mask = machine.region("audiocpu")->bytes() - 0x10000 - 1; | |
| 802 | ||
| 803 | rgn = machine.region("audiocpu")->base(); | |
| 804 | for (region = 0; region < 4; region++) | |
| 805 | { | |
| 806 | for (bank = 0; bank < 0x100; bank++) | |
| 807 | { | |
| 808 | UINT32 bank_address = 0x10000 + (((bank << (11 + region)) & 0x3ffff) & address_mask); | |
| 809 | memory_configure_bank(machine, NEOGEO_BANK_AUDIO_CPU_CART_BANK + region, bank, 1, &rgn[bank_address], 0); | |
| 810 | } | |
| 811 | } | |
| 812 | ||
| 813 | /* set initial audio banks -- | |
| 814 | how does this really work, or is it even neccessary? */ | |
| 815 | state->m_audio_cpu_banks[0] = 0x1e; | |
| 816 | state->m_audio_cpu_banks[1] = 0x0e; | |
| 817 | state->m_audio_cpu_banks[2] = 0x06; | |
| 818 | state->m_audio_cpu_banks[3] = 0x02; | |
| 819 | ||
| 820 | set_audio_cpu_banking(machine); | |
| 821 | ||
| 822 | state->m_audio_cpu_rom_source_last = 0; | |
| 823 | set_audio_cpu_rom_source(machine.device("maincpu")->memory().space(AS_PROGRAM), 0); | |
| 824 | } | |
| 825 | ||
| 826 | ||
| 827 | ||
| 828 | /************************************* | |
| 829 | * | |
| 830 | * System control register | |
| 831 | * | |
| 832 | *************************************/ | |
| 833 | ||
| 834 | static WRITE16_HANDLER( system_control_w ) | |
| 835 | { | |
| 836 | if (ACCESSING_BITS_0_7) | |
| 837 | { | |
| 838 | UINT8 bit = (offset >> 3) & 0x01; | |
| 839 | ||
| 840 | switch (offset & 0x07) | |
| 841 | { | |
| 842 | default: | |
| 843 | case 0x00: neogeo_set_screen_dark(space->machine(), bit); break; | |
| 844 | case 0x01: set_main_cpu_vector_table_source(space->machine(), bit); | |
| 845 | set_audio_cpu_rom_source(space, bit); /* this is a guess */ | |
| 846 | break; | |
| 847 | case 0x05: neogeo_set_fixed_layer_source(space->machine(), bit); break; | |
| 848 | // case 0x06: set_save_ram_unlock(space->machine(), bit); break; | |
| 849 | case 0x07: neogeo_set_palette_bank(space->machine(), bit); break; | |
| 850 | ||
| 851 | case 0x02: /* unknown - HC32 middle pin 1 */ | |
| 852 | case 0x03: /* unknown - uPD4990 pin ? */ | |
| 853 | case 0x04: /* unknown - HC32 middle pin 10 */ | |
| 854 | logerror("PC: %x Unmapped system control write. Offset: %x Data: %x\n", cpu_get_pc(&space->device()), offset & 0x07, bit); | |
| 855 | break; | |
| 856 | } | |
| 857 | ||
| 858 | if (LOG_VIDEO_SYSTEM && ((offset & 0x07) != 0x06)) logerror("PC: %x System control write. Offset: %x Data: %x\n", cpu_get_pc(&space->device()), offset & 0x07, bit); | |
| 859 | } | |
| 860 | } | |
| 861 | ||
| 862 | /* | |
| 863 | * CD-ROM / DMA control | |
| 864 | * | |
| 865 | * DMA | |
| 866 | ||
| 867 | FF0061 Write 0x40 means start DMA transfer | |
| 868 | FF0064 Source address (in copy mode), Target address (in filll mode) | |
| 869 | FF0068 Target address (in copy mode) | |
| 870 | FF006C Fill word | |
| 871 | FF0070 Words count | |
| 872 | FF007E \ | |
| 873 | ...... | DMA programming words? NeoGeoCD uses Sanyo Puppet LC8359 chip to | |
| 874 | FF008E / interface with CD, and do DMA transfers | |
| 875 | ||
| 876 | Memory access control | |
| 877 | ||
| 878 | FF011C DIP SWITCH (Region code) | |
| 879 | FF0105 Area Selector (5 = FIX, 0 = SPR, 4 = Z80, 1 = PCM) | |
| 880 | FF01A1 Sprite bank selector | |
| 881 | FF01A3 PCM bank selector | |
| 882 | FF0120 Prepare sprite area for transfer | |
| 883 | FF0122 Prepare PCM area for transfer | |
| 884 | FF0126 Prepare Z80 area for transfer | |
| 885 | FF0128 Prepare Fix area for transfer | |
| 886 | FF0140 Terminate work on Spr Area (Sprites must be decoded here) | |
| 887 | FF0142 Terminate work on Pcm Area | |
| 888 | FF0146 Terminate work on Z80 Area (Z80 needs to be reset) | |
| 889 | FF0148 Terminate work on Fix Area | |
| 890 | ||
| 891 | CD-ROM: | |
| 892 | 0xff0102 == 0xF0 start cd transfer | |
| 893 | int m=bcd(fast_r8(0x10f6c8)); | |
| 894 | int s=bcd(fast_r8(0x10f6c9)); | |
| 895 | int f=bcd(fast_r8(0x10f6ca)); | |
| 896 | int seccount=fast_r16(0x10f688); | |
| 897 | ||
| 898 | inisec=((m*60)+s)*75+f; | |
| 899 | inisec-=150; | |
| 900 | dstaddr=0x111204; // this must come from somewhere | |
| 901 | ||
| 902 | the value @ 0x10f688 is decremented each time a sector is read until it's 0. | |
| 903 | ||
| 904 | * | |
| 905 | */ | |
| 906 | ||
| 907 | static void neocd_do_dma(address_space* space) | |
| 908 | { | |
| 909 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 910 | // TODO: Proper DMA timing and control | |
| 911 | int count; | |
| 912 | // UINT16 word; | |
| 913 | ||
| 914 | switch(state->m_neocd_ctrl.dma_mode[0]) | |
| 915 | { | |
| 916 | case 0xffdd: | |
| 917 | for(count=0;count<state->m_neocd_ctrl.word_count;count++) | |
| 918 | { | |
| 919 | //word = space->read_word(state->m_neocd_ctrl.addr_source); | |
| 920 | space->write_word(state->m_neocd_ctrl.addr_source+(count*2),state->m_neocd_ctrl.fill_word); | |
| 921 | } | |
| 922 | logerror("CTRL: DMA word-fill transfer of %i bytes\n",count*2); | |
| 923 | break; | |
| 924 | case 0xfef5: | |
| 925 | for(count=0;count<state->m_neocd_ctrl.word_count;count++) | |
| 926 | { | |
| 927 | //word = space->read_word(state->m_neocd_ctrl.addr_source); | |
| 928 | space->write_word(state->m_neocd_ctrl.addr_source+(count*4),(state->m_neocd_ctrl.addr_source+(count*4)) >> 16); | |
| 929 | space->write_word(state->m_neocd_ctrl.addr_source+(count*4)+2,(state->m_neocd_ctrl.addr_source+(count*4)) & 0xffff); | |
| 930 | } | |
| 931 | logerror("CTRL: DMA mode 2 transfer of %i bytes\n",count*4); | |
| 932 | break; | |
| 933 | case 0xcffd: | |
| 934 | for(count=0;count<state->m_neocd_ctrl.word_count;count++) | |
| 935 | { | |
| 936 | //word = space->read_word(state->m_neocd_ctrl.addr_source); | |
| 937 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8),((state->m_neocd_ctrl.addr_source+(count*8)) >> 24) | 0xff00); | |
| 938 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8)+2,((state->m_neocd_ctrl.addr_source+(count*8)) >> 16) | 0xff00); | |
| 939 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8)+4,((state->m_neocd_ctrl.addr_source+(count*8)) >> 8) | 0xff00); | |
| 940 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8)+6,(state->m_neocd_ctrl.addr_source+(count*8)) | 0xff00); | |
| 941 | } | |
| 942 | logerror("CTRL: DMA mode 3 transfer of %i bytes\n",count*8); | |
| 943 | break; | |
| 944 | default: | |
| 945 | logerror("CTRL: Unknown DMA transfer mode %04x\n",state->m_neocd_ctrl.dma_mode[0]); | |
| 946 | } | |
| 947 | } | |
| 948 | ||
| 949 | static READ16_HANDLER( neocd_control_r ) | |
| 950 | { | |
| 951 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 952 | ||
| 953 | switch(offset) | |
| 954 | { | |
| 955 | case 0x64/2: // source address, high word | |
| 956 | return (state->m_neocd_ctrl.addr_source >> 16) & 0xffff; | |
| 957 | case 0x66/2: // source address, low word | |
| 958 | return state->m_neocd_ctrl.addr_source & 0xffff; | |
| 959 | case 0x68/2: // target address, high word | |
| 960 | return (state->m_neocd_ctrl.addr_target >> 16) & 0xffff; | |
| 961 | case 0x6a/2: // target address, low word | |
| 962 | return state->m_neocd_ctrl.addr_target & 0xffff; | |
| 963 | case 0x6c/2: // fill word | |
| 964 | return state->m_neocd_ctrl.fill_word; | |
| 965 | case 0x70/2: // word count | |
| 966 | return (state->m_neocd_ctrl.word_count >> 16) & 0xffff; | |
| 967 | case 0x72/2: | |
| 968 | return state->m_neocd_ctrl.word_count & 0xffff; | |
| 969 | case 0x7e/2: // DMA parameters | |
| 970 | case 0x80/2: | |
| 971 | case 0x82/2: | |
| 972 | case 0x84/2: | |
| 973 | case 0x86/2: | |
| 974 | case 0x88/2: | |
| 975 | case 0x8a/2: | |
| 976 | case 0x8c/2: | |
| 977 | case 0x8e/2: | |
| 978 | return state->m_neocd_ctrl.dma_mode[offset-(0x7e/2)]; | |
| 979 | break; | |
| 980 | case 0x105/2: | |
| 981 | return state->m_neocd_ctrl.area_sel; | |
| 982 | case 0x11c/2: | |
| 983 | logerror("CTRL: Read region code.\n"); | |
| 984 | return 0x0600; // we'll just force USA region for now | |
| 985 | case 0x1a0/2: | |
| 986 | return state->m_neocd_ctrl.spr_bank_sel; | |
| 987 | break; | |
| 988 | case 0x1a2/2: | |
| 989 | return state->m_neocd_ctrl.pcm_bank_sel; | |
| 990 | break; | |
| 991 | default: | |
| 992 | logerror("CTRL: Read offset %04x\n",offset); | |
| 993 | } | |
| 994 | ||
| 995 | return 0; | |
| 996 | } | |
| 997 | ||
| 998 | static WRITE16_HANDLER( neocd_control_w ) | |
| 999 | { | |
| 1000 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 1001 | switch(offset) | |
| 1002 | { | |
| 1003 | case 0x60/2: // Start DMA transfer | |
| 1004 | if((data & 0xff) == 0x40) | |
| 1005 | neocd_do_dma(space); | |
| 1006 | break; | |
| 1007 | case 0x64/2: // source address, high word | |
| 1008 | state->m_neocd_ctrl.addr_source = (state->m_neocd_ctrl.addr_source & 0x0000ffff) | (data << 16); | |
| 1009 | logerror("CTRL: Set source address to %08x\n",state->m_neocd_ctrl.addr_source); | |
| 1010 | break; | |
| 1011 | case 0x66/2: // source address, low word | |
| 1012 | state->m_neocd_ctrl.addr_source = (state->m_neocd_ctrl.addr_source & 0xffff0000) | data; | |
| 1013 | logerror("CTRL: Set source address to %08x\n",state->m_neocd_ctrl.addr_source); | |
| 1014 | break; | |
| 1015 | case 0x68/2: // target address, high word | |
| 1016 | state->m_neocd_ctrl.addr_target = (state->m_neocd_ctrl.addr_target & 0x0000ffff) | (data << 16); | |
| 1017 | logerror("CTRL: Set target address to %08x\n",state->m_neocd_ctrl.addr_target); | |
| 1018 | break; | |
| 1019 | case 0x6a/2: // target address, low word | |
| 1020 | state->m_neocd_ctrl.addr_target = (state->m_neocd_ctrl.addr_target & 0xffff0000) | data; | |
| 1021 | logerror("CTRL: Set target address to %08x\n",state->m_neocd_ctrl.addr_target); | |
| 1022 | break; | |
| 1023 | case 0x6c/2: // fill word | |
| 1024 | state->m_neocd_ctrl.fill_word = data; | |
| 1025 | logerror("CTRL: Set fill word to %04x\n",data); | |
| 1026 | break; | |
| 1027 | case 0x70/2: // word count | |
| 1028 | state->m_neocd_ctrl.word_count = (state->m_neocd_ctrl.word_count & 0x0000ffff) | (data << 16); | |
| 1029 | logerror("CTRL: Set word count to %i\n",state->m_neocd_ctrl.word_count); | |
| 1030 | break; | |
| 1031 | case 0x72/2: // word count (low word) | |
| 1032 | state->m_neocd_ctrl.word_count = (state->m_neocd_ctrl.word_count & 0xffff0000) | data; | |
| 1033 | logerror("CTRL: Set word count to %i\n",state->m_neocd_ctrl.word_count); | |
| 1034 | break; | |
| 1035 | case 0x7e/2: // DMA parameters | |
| 1036 | case 0x80/2: | |
| 1037 | case 0x82/2: | |
| 1038 | case 0x84/2: | |
| 1039 | case 0x86/2: | |
| 1040 | case 0x88/2: | |
| 1041 | case 0x8a/2: | |
| 1042 | case 0x8c/2: | |
| 1043 | case 0x8e/2: | |
| 1044 | state->m_neocd_ctrl.dma_mode[offset-(0x7e/2)] = data; | |
| 1045 | logerror("CTRL: DMA parameter %i set to %04x\n",offset-(0x7e/2),data); | |
| 1046 | break; | |
| 1047 | case 0x104/2: | |
| 1048 | state->m_neocd_ctrl.area_sel = data & 0x00ff; | |
| 1049 | logerror("CTRL: 0xExxxxx set to area %i\n",data & 0xff); | |
| 1050 | break; | |
| 1051 | case 0x140/2: // end sprite transfer | |
| 1052 | video_reset_neogeo(space->machine()); | |
| 1053 | break; | |
| 1054 | case 0x142/2: // end PCM transfer | |
| 1055 | break; | |
| 1056 | case 0x146/2: // end Z80 transfer | |
| 1057 | cputag_set_input_line(space->machine(),"audiocpu",INPUT_LINE_RESET,PULSE_LINE); | |
| 1058 | break; | |
| 1059 | case 0x148/2: // end FIX transfer | |
| 1060 | video_reset_neogeo(space->machine()); | |
| 1061 | break; | |
| 1062 | case 0x1a0/2: | |
| 1063 | state->m_neocd_ctrl.spr_bank_sel = data & 0xff; | |
| 1064 | logerror("CTRL: Sprite area set to bank %i\n",data & 0xff); | |
| 1065 | break; | |
| 1066 | case 0x1a2/2: | |
| 1067 | state->m_neocd_ctrl.pcm_bank_sel = data & 0xff; | |
| 1068 | logerror("CTRL: PCM area set to bank %i\n",data & 0xff); | |
| 1069 | break; | |
| 1070 | default: | |
| 1071 | logerror("CTRL: Write offset %04x, data %04x\n",offset*2,data); | |
| 1072 | } | |
| 1073 | } | |
| 1074 | ||
| 1075 | /* | |
| 1076 | * Handling NeoCD banked RAM | |
| 1077 | * When the Z80 space is banked in to 0xe00000, only the low byte of each word is used | |
| 1078 | */ | |
| 1079 | ||
| 1080 | static READ16_HANDLER(neocd_transfer_r) | |
| 1081 | { | |
| 1082 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 1083 | UINT16 ret = 0x0000; | |
| 1084 | UINT8* Z80 = space->machine().region("audiocpu")->base(); | |
| 1085 | UINT8* PCM = space->machine().region("ymsnd")->base(); | |
| 1086 | UINT8* FIX = space->machine().region("fixed")->base(); | |
| 1087 | UINT16* SPR = (UINT16*)space->machine().region("sprites")->base(); | |
| 1088 | ||
| 1089 | switch(state->m_neocd_ctrl.area_sel) | |
| 1090 | { | |
| 1091 | case NEOCD_AREA_AUDIO: | |
| 1092 | ret = Z80[offset & 0xffff] | 0xff00; | |
| 1093 | break; | |
| 1094 | case NEOCD_AREA_PCM: | |
| 1095 | ret = PCM[offset + (0x100000*state->m_neocd_ctrl.pcm_bank_sel)] | 0xff00; | |
| 1096 | break; | |
| 1097 | case NEOCD_AREA_SPR: | |
| 1098 | ret = SPR[offset + (0x80000*state->m_neocd_ctrl.spr_bank_sel)]; | |
| 1099 | break; | |
| 1100 | case NEOCD_AREA_FIX: | |
| 1101 | ret = FIX[offset & 0x1ffff] | 0xff00; | |
| 1102 | break; | |
| 1103 | } | |
| 1104 | ||
| 1105 | return ret; | |
| 1106 | } | |
| 1107 | ||
| 1108 | static WRITE16_HANDLER(neocd_transfer_w) | |
| 1109 | { | |
| 1110 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 1111 | UINT8* Z80 = space->machine().region("audiocpu")->base(); | |
| 1112 | UINT8* PCM = space->machine().region("ymsnd")->base(); | |
| 1113 | UINT8* FIX = space->machine().region("fixed")->base(); | |
| 1114 | UINT16* SPR = (UINT16*)space->machine().region("sprites")->base(); | |
| 1115 | ||
| 1116 | switch(state->m_neocd_ctrl.area_sel) | |
| 1117 | { | |
| 1118 | case NEOCD_AREA_AUDIO: | |
| 1119 | Z80[offset & 0xffff] = data & 0xff; | |
| 1120 | break; | |
| 1121 | case NEOCD_AREA_PCM: | |
| 1122 | PCM[offset + (0x100000*state->m_neocd_ctrl.pcm_bank_sel)] = data & 0xff; | |
| 1123 | break; | |
| 1124 | case NEOCD_AREA_SPR: | |
| 1125 | COMBINE_DATA(SPR+(offset + (0x80000*state->m_neocd_ctrl.spr_bank_sel))); | |
| 1126 | break; | |
| 1127 | case NEOCD_AREA_FIX: | |
| 1128 | FIX[offset & 0x1ffff] = data & 0xff; | |
| 1129 | break; | |
| 1130 | } | |
| 1131 | ||
| 1132 | } | |
| 1133 | ||
| 1134 | /* | |
| 1135 | * Handling selectable controller types | |
| 1136 | */ | |
| 1137 | ||
| 1138 | static READ16_HANDLER( aes_in0_r ) | |
| 1139 | { | |
| 1140 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 1141 | UINT32 ret = 0xffff; | |
| 1142 | UINT32 ctrl = input_port_read(space->machine(),"CTRLSEL"); | |
| 1143 | ||
| 1144 | switch(ctrl & 0x0f) | |
| 1145 | { | |
| 1146 | case 0x00: | |
| 1147 | ret = 0xffff; | |
| 1148 | break; | |
| 1149 | case 0x01: | |
| 1150 | ret = input_port_read(space->machine(),"IN0"); | |
| 1151 | break; | |
| 1152 | case 0x02: | |
| 1153 | switch (state->m_controller_select) | |
| 1154 | { | |
| 1155 | case 0x09: ret = input_port_read(space->machine(), "MJ01_P1"); break; | |
| 1156 | case 0x12: ret = input_port_read(space->machine(), "MJ02_P1"); break; | |
| 1157 | case 0x1b: ret = input_port_read(space->machine(), "MJ03_P1"); break; /* player 1 normal inputs? */ | |
| 1158 | case 0x24: ret = input_port_read(space->machine(), "MJ04_P1"); break; | |
| 1159 | default: | |
| 1160 | ret = input_port_read(space->machine(),"IN0"); | |
| 1161 | break; | |
| 1162 | } | |
| 1163 | break; | |
| 1164 | } | |
| 1165 | ||
| 1166 | return ret; | |
| 1167 | } | |
| 1168 | ||
| 1169 | static READ16_HANDLER( aes_in1_r ) | |
| 1170 | { | |
| 1171 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 1172 | UINT32 ret = 0xffff; | |
| 1173 | UINT32 ctrl = input_port_read(space->machine(),"CTRLSEL"); | |
| 1174 | ||
| 1175 | switch(ctrl & 0xf0) | |
| 1176 | { | |
| 1177 | case 0x00: | |
| 1178 | ret = 0xffff; | |
| 1179 | break; | |
| 1180 | case 0x10: | |
| 1181 | ret = input_port_read(space->machine(),"IN1"); | |
| 1182 | break; | |
| 1183 | case 0x20: | |
| 1184 | switch (state->m_controller_select) | |
| 1185 | { | |
| 1186 | case 0x09: ret = input_port_read(space->machine(), "MJ01_P2"); break; | |
| 1187 | case 0x12: ret = input_port_read(space->machine(), "MJ02_P2"); break; | |
| 1188 | case 0x1b: ret = input_port_read(space->machine(), "MJ03_P2"); break; /* player 2 normal inputs? */ | |
| 1189 | case 0x24: ret = input_port_read(space->machine(), "MJ04_P2"); break; | |
| 1190 | default: | |
| 1191 | ret = input_port_read(space->machine(),"IN1"); | |
| 1192 | break; | |
| 1193 | } | |
| 1194 | break; | |
| 1195 | } | |
| 1196 | ||
| 1197 | return ret; | |
| 1198 | } | |
| 1199 | ||
| 1200 | ||
| 1201 | static READ16_HANDLER(aes_in2_r) | |
| 1202 | { | |
| 1203 | UINT32 in2 = input_port_read(space->machine(),"IN2"); | |
| 1204 | UINT32 ret = in2; | |
| 1205 | UINT32 sel = input_port_read(space->machine(),"CTRLSEL"); | |
| 1206 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 1207 | ||
| 1208 | if((sel & 0x02) && (state->m_controller_select == 0x24)) | |
| 1209 | ret ^= 0x0200; | |
| 1210 | ||
| 1211 | if((sel & 0x20) && (state->m_controller_select == 0x24)) | |
| 1212 | ret ^= 0x0800; | |
| 1213 | ||
| 1214 | return ret; | |
| 1215 | } | |
| 1216 | ||
| 1217 | ||
| 1218 | /************************************* | |
| 1219 | * | |
| 1220 | * Machine initialization | |
| 1221 | * | |
| 1222 | *************************************/ | |
| 1223 | ||
| 1224 | static void aes_postload(neogeo_state *state) | |
| 1225 | { | |
| 1226 | _set_main_cpu_bank_address(state->machine()); | |
| 1227 | _set_main_cpu_vector_table_source(state->machine()); | |
| 1228 | set_audio_cpu_banking(state->machine()); | |
| 1229 | _set_audio_cpu_rom_source(state->machine().device("maincpu")->memory().space(AS_PROGRAM)); | |
| 1230 | } | |
| 1231 | ||
| 1232 | static void common_machine_start(running_machine &machine) | |
| 1233 | { | |
| 1234 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 1235 | ||
| 1236 | /* set the BIOS bank */ | |
| 1237 | memory_set_bankptr(machine, NEOGEO_BANK_BIOS, machine.region("mainbios")->base()); | |
| 1238 | ||
| 1239 | /* set the initial main CPU bank */ | |
| 1240 | main_cpu_banking_init(machine); | |
| 1241 | ||
| 1242 | /* set the initial audio CPU ROM banks */ | |
| 1243 | audio_cpu_banking_init(machine); | |
| 1244 | ||
| 1245 | create_interrupt_timers(machine); | |
| 1246 | ||
| 1247 | /* start with an IRQ3 - but NOT on a reset */ | |
| 1248 | state->m_irq3_pending = 1; | |
| 1249 | ||
| 1250 | /* get devices */ | |
| 1251 | state->m_maincpu = machine.device("maincpu"); | |
| 1252 | state->m_audiocpu = machine.device("audiocpu"); | |
| 1253 | state->m_upd4990a = machine.device("upd4990a"); | |
| 1254 | ||
| 1255 | /* register state save */ | |
| 1256 | state->save_item(NAME(state->m_display_position_interrupt_control)); | |
| 1257 | state->save_item(NAME(state->m_display_counter)); | |
| 1258 | state->save_item(NAME(state->m_vblank_interrupt_pending)); | |
| 1259 | state->save_item(NAME(state->m_display_position_interrupt_pending)); | |
| 1260 | state->save_item(NAME(state->m_irq3_pending)); | |
| 1261 | state->save_item(NAME(state->m_audio_result)); | |
| 1262 | state->save_item(NAME(state->m_controller_select)); | |
| 1263 | state->save_item(NAME(state->m_main_cpu_bank_address)); | |
| 1264 | state->save_item(NAME(state->m_main_cpu_vector_table_source)); | |
| 1265 | state->save_item(NAME(state->m_audio_cpu_banks)); | |
| 1266 | state->save_item(NAME(state->m_audio_cpu_rom_source)); | |
| 1267 | state->save_item(NAME(state->m_audio_cpu_rom_source_last)); | |
| 1268 | state->save_item(NAME(state->m_save_ram_unlocked)); | |
| 1269 | state->save_item(NAME(state->m_output_data)); | |
| 1270 | state->save_item(NAME(state->m_output_latch)); | |
| 1271 | state->save_item(NAME(state->m_el_value)); | |
| 1272 | state->save_item(NAME(state->m_led1_value)); | |
| 1273 | state->save_item(NAME(state->m_led2_value)); | |
| 1274 | state->save_item(NAME(state->m_recurse)); | |
| 1275 | ||
| 1276 | machine.save().register_postload(save_prepost_delegate(FUNC(aes_postload), state)); | |
| 1277 | } | |
| 1278 | ||
| 1279 | static MACHINE_START( neogeo ) | |
| 1280 | { | |
| 1281 | ng_aes_state *state = machine.driver_data<ng_aes_state>(); | |
| 1282 | common_machine_start(machine); | |
| 1283 | ||
| 1284 | /* initialize the memcard data structure */ | |
| 1285 | state->m_memcard_data = auto_alloc_array_clear(machine, UINT8, MEMCARD_SIZE); | |
| 1286 | state->save_pointer(NAME(state->m_memcard_data), 0x0800); | |
| 1287 | } | |
| 1288 | ||
| 1289 | static MACHINE_START(neocd) | |
| 1290 | { | |
| 1291 | ng_aes_state *state = machine.driver_data<ng_aes_state>(); | |
| 1292 | UINT8* ROM = machine.region("mainbios")->base(); | |
| 1293 | UINT8* RAM = machine.region("maincpu")->base(); | |
| 1294 | UINT8* Z80bios = machine.region("audiobios")->base(); | |
| 1295 | UINT8* FIXbios = machine.region("fixedbios")->base(); | |
| 1296 | int x; | |
| 1297 | ||
| 1298 | common_machine_start(machine); | |
| 1299 | ||
| 1300 | /* initialize the memcard data structure */ | |
| 1301 | /* NeoCD doesn't have memcard slots, rather, it has a larger internal memory which works the same */ | |
| 1302 | state->m_memcard_data = auto_alloc_array_clear(machine, UINT8, 0x2000); | |
| 1303 | state->save_pointer(NAME(state->m_memcard_data), 0x2000); | |
| 1304 | ||
| 1305 | // copy initial 68k vectors into RAM | |
| 1306 | memcpy(RAM,ROM,0x80); | |
| 1307 | ||
| 1308 | // copy Z80 code into Z80 space (from 0x20000) | |
| 1309 | for(x=0;x<0x10000;x+=2) | |
| 1310 | { | |
| 1311 | Z80bios[x] = ROM[x+0x20001]; | |
| 1312 | Z80bios[x+1] = ROM[x+0x20000]; | |
| 1313 | } | |
| 1314 | ||
| 1315 | // copy fixed tiles into FIX space (from 0x70000) | |
| 1316 | memcpy(FIXbios,ROM+0x70000,0x10000); | |
| 1317 | } | |
| 1318 | ||
| 1319 | //static DEVICE_IMAGE_LOAD(aes_cart) | |
| 1320 | //{ | |
| 1321 | // else | |
| 1322 | // return IMAGE_INIT_FAIL; | |
| 1323 | ||
| 1324 | // return IMAGE_INIT_PASS; | |
| 1325 | //} | |
| 1326 | ||
| 1327 | /************************************* | |
| 1328 | * | |
| 1329 | * Machine reset | |
| 1330 | * | |
| 1331 | *************************************/ | |
| 1332 | ||
| 1333 | static MACHINE_RESET( neogeo ) | |
| 1334 | { | |
| 1335 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 1336 | offs_t offs; | |
| 1337 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 1338 | ||
| 1339 | /* reset system control registers */ | |
| 1340 | for (offs = 0; offs < 8; offs++) | |
| 1341 | system_control_w(space, offs, 0, 0x00ff); | |
| 1342 | ||
| 1343 | machine.device("maincpu")->reset(); | |
| 1344 | ||
| 1345 | neogeo_reset_rng(machine); | |
| 1346 | ||
| 1347 | start_interrupt_timers(machine); | |
| 1348 | ||
| 1349 | /* trigger the IRQ3 that was set by MACHINE_START */ | |
| 1350 | update_interrupts(machine); | |
| 1351 | ||
| 1352 | state->m_recurse = 0; | |
| 1353 | ||
| 1354 | /* AES apparently always uses the cartridge's fixed bank mode */ | |
| 1355 | neogeo_set_fixed_layer_source(machine,1); | |
| 1356 | } | |
| 1357 | ||
| 1358 | ||
| 1359 | ||
| 1360 | /************************************* | |
| 1361 | * | |
| 1362 | * Main CPU memory handlers | |
| 1363 | * | |
| 1364 | *************************************/ | |
| 1365 | ||
| 1366 | static ADDRESS_MAP_START( main_map, AS_PROGRAM, 16 ) | |
| 1367 | AM_RANGE(0x000000, 0x00007f) AM_ROMBANK(NEOGEO_BANK_VECTORS) | |
| 1368 | AM_RANGE(0x000080, 0x0fffff) AM_ROM | |
| 1369 | AM_RANGE(0x100000, 0x10ffff) AM_MIRROR(0x0f0000) AM_RAM | |
| 1370 | /* some games have protection devices in the 0x200000 region, it appears to map to cart space, not surprising, the ROM is read here too */ | |
| 1371 | AM_RANGE(0x200000, 0x2fffff) AM_ROMBANK(NEOGEO_BANK_CARTRIDGE) | |
| 1372 | AM_RANGE(0x2ffff0, 0x2fffff) AM_WRITE(main_cpu_bank_select_w) | |
| 1373 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ff7e) AM_READ(aes_in0_r) | |
| 1374 | AM_RANGE(0x300080, 0x300081) AM_MIRROR(0x01ff7e) AM_READ_PORT("IN4") | |
| 1375 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ffe0) AM_READ(neogeo_unmapped_r) AM_WRITENOP // AES has no watchdog | |
| 1376 | AM_RANGE(0x320000, 0x320001) AM_MIRROR(0x01fffe) AM_READ_PORT("IN3") AM_WRITE(audio_command_w) | |
| 1377 | AM_RANGE(0x340000, 0x340001) AM_MIRROR(0x01fffe) AM_READ(aes_in1_r) | |
| 1378 | AM_RANGE(0x360000, 0x37ffff) AM_READ(neogeo_unmapped_r) | |
| 1379 | AM_RANGE(0x380000, 0x380001) AM_MIRROR(0x01fffe) AM_READ(aes_in2_r) | |
| 1380 | AM_RANGE(0x380000, 0x38007f) AM_MIRROR(0x01ff80) AM_WRITE(io_control_w) | |
| 1381 | AM_RANGE(0x3a0000, 0x3a001f) AM_MIRROR(0x01ffe0) AM_READWRITE(neogeo_unmapped_r, system_control_w) | |
| 1382 | AM_RANGE(0x3c0000, 0x3c0007) AM_MIRROR(0x01fff8) AM_READ(neogeo_video_register_r) | |
| 1383 | AM_RANGE(0x3c0000, 0x3c000f) AM_MIRROR(0x01fff0) AM_WRITE(neogeo_video_register_w) | |
| 1384 | AM_RANGE(0x3e0000, 0x3fffff) AM_READ(neogeo_unmapped_r) | |
| 1385 | AM_RANGE(0x400000, 0x401fff) AM_MIRROR(0x3fe000) AM_READWRITE(neogeo_paletteram_r, neogeo_paletteram_w) | |
| 1386 | AM_RANGE(0x800000, 0x800fff) AM_READWRITE(memcard_r, memcard_w) | |
| 1387 | AM_RANGE(0xc00000, 0xc1ffff) AM_MIRROR(0x0e0000) AM_ROMBANK(NEOGEO_BANK_BIOS) | |
| 1388 | AM_RANGE(0xd00000, 0xd0ffff) AM_MIRROR(0x0f0000) AM_READ(neogeo_unmapped_r) //AM_RAM_WRITE(save_ram_w) AM_BASE(&save_ram) | |
| 1389 | AM_RANGE(0xe00000, 0xffffff) AM_READ(neogeo_unmapped_r) | |
| 1390 | ADDRESS_MAP_END | |
| 1391 | ||
| 1392 | static ADDRESS_MAP_START( neocd_main_map, AS_PROGRAM, 16 ) | |
| 1393 | AM_RANGE(0x000000, 0x00007f) AM_RAMBANK(NEOGEO_BANK_VECTORS) | |
| 1394 | AM_RANGE(0x000080, 0x0fffff) AM_RAM | |
| 1395 | AM_RANGE(0x100000, 0x10ffff) AM_MIRROR(0x0f0000) AM_RAM AM_BASE(&neocd_work_ram) | |
| 1396 | /* some games have protection devices in the 0x200000 region, it appears to map to cart space, not surprising, the ROM is read here too */ | |
| 1397 | AM_RANGE(0x200000, 0x2fffff) AM_ROMBANK(NEOGEO_BANK_CARTRIDGE) | |
| 1398 | AM_RANGE(0x2ffff0, 0x2fffff) AM_WRITE(main_cpu_bank_select_w) | |
| 1399 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ff7e) AM_READ(aes_in0_r) | |
| 1400 | AM_RANGE(0x300080, 0x300081) AM_MIRROR(0x01ff7e) AM_READ_PORT("IN4") | |
| 1401 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ffe0) AM_READ(neogeo_unmapped_r) AM_WRITENOP // AES has no watchdog | |
| 1402 | AM_RANGE(0x320000, 0x320001) AM_MIRROR(0x01fffe) AM_READ_PORT("IN3") AM_WRITE(audio_command_w) | |
| 1403 | AM_RANGE(0x340000, 0x340001) AM_MIRROR(0x01fffe) AM_READ(aes_in1_r) | |
| 1404 | AM_RANGE(0x360000, 0x37ffff) AM_READ(neogeo_unmapped_r) | |
| 1405 | AM_RANGE(0x380000, 0x380001) AM_MIRROR(0x01fffe) AM_READ(aes_in2_r) | |
| 1406 | AM_RANGE(0x380000, 0x38007f) AM_MIRROR(0x01ff80) AM_WRITE(io_control_w) | |
| 1407 | AM_RANGE(0x3a0000, 0x3a001f) AM_MIRROR(0x01ffe0) AM_READWRITE(neogeo_unmapped_r, system_control_w) | |
| 1408 | AM_RANGE(0x3c0000, 0x3c0007) AM_MIRROR(0x01fff8) AM_READ(neogeo_video_register_r) | |
| 1409 | AM_RANGE(0x3c0000, 0x3c000f) AM_MIRROR(0x01fff0) AM_WRITE(neogeo_video_register_w) | |
| 1410 | AM_RANGE(0x3e0000, 0x3fffff) AM_READ(neogeo_unmapped_r) | |
| 1411 | AM_RANGE(0x400000, 0x401fff) AM_MIRROR(0x3fe000) AM_READWRITE(neogeo_paletteram_r, neogeo_paletteram_w) | |
| 1412 | AM_RANGE(0x800000, 0x803fff) AM_READWRITE(neocd_memcard_r, neocd_memcard_w) | |
| 1413 | AM_RANGE(0xc00000, 0xcfffff) AM_ROMBANK(NEOGEO_BANK_BIOS) | |
| 1414 | AM_RANGE(0xd00000, 0xd0ffff) AM_MIRROR(0x0f0000) AM_READ(neogeo_unmapped_r) //AM_RAM_WRITE(save_ram_w) AM_BASE(&save_ram) | |
| 1415 | AM_RANGE(0xe00000, 0xefffff) AM_READWRITE(neocd_transfer_r,neocd_transfer_w) | |
| 1416 | AM_RANGE(0xf00000, 0xfeffff) AM_READ(neogeo_unmapped_r) | |
| 1417 | AM_RANGE(0xff0000, 0xff01ff) AM_READWRITE(neocd_control_r, neocd_control_w) // CDROM / DMA | |
| 1418 | AM_RANGE(0xff0200, 0xffffff) AM_READ(neogeo_unmapped_r) | |
| 1419 | ADDRESS_MAP_END | |
| 1420 | ||
| 1421 | ||
| 1422 | /************************************* | |
| 1423 | * | |
| 1424 | * Audio CPU memory handlers | |
| 1425 | * | |
| 1426 | *************************************/ | |
| 1427 | ||
| 1428 | static ADDRESS_MAP_START( audio_map, AS_PROGRAM, 8 ) | |
| 1429 | AM_RANGE(0x0000, 0x7fff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_MAIN_BANK) | |
| 1430 | AM_RANGE(0x8000, 0xbfff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 3) | |
| 1431 | AM_RANGE(0xc000, 0xdfff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 2) | |
| 1432 | AM_RANGE(0xe000, 0xefff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 1) | |
| 1433 | AM_RANGE(0xf000, 0xf7ff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 0) | |
| 1434 | AM_RANGE(0xf800, 0xffff) AM_RAM | |
| 1435 | ADDRESS_MAP_END | |
| 1436 | ||
| 1437 | ||
| 1438 | ||
| 1439 | /************************************* | |
| 1440 | * | |
| 1441 | * Audio CPU port handlers | |
| 1442 | * | |
| 1443 | *************************************/ | |
| 1444 | ||
| 1445 | static ADDRESS_MAP_START( audio_io_map, AS_IO, 8 ) | |
| 1446 | /*AM_RANGE(0x00, 0x00) AM_MIRROR(0xff00) AM_READWRITE(audio_command_r, audio_cpu_clear_nmi_w);*/ /* may not and NMI clear */ | |
| 1447 | AM_RANGE(0x00, 0x00) AM_MIRROR(0xff00) AM_READ(audio_command_r) | |
| 1448 | AM_RANGE(0x04, 0x07) AM_MIRROR(0xff00) AM_DEVREADWRITE("ymsnd", ym2610_r, ym2610_w) | |
| 1449 | AM_RANGE(0x08, 0x08) AM_MIRROR(0xff00) /* write - NMI enable / acknowledge? (the data written doesn't matter) */ | |
| 1450 | AM_RANGE(0x08, 0x08) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_f000_f7ff_r) | |
| 1451 | AM_RANGE(0x09, 0x09) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_e000_efff_r) | |
| 1452 | AM_RANGE(0x0a, 0x0a) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_c000_dfff_r) | |
| 1453 | AM_RANGE(0x0b, 0x0b) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_8000_bfff_r) | |
| 1454 | AM_RANGE(0x0c, 0x0c) AM_MIRROR(0xff00) AM_WRITE(audio_result_w) | |
| 1455 | AM_RANGE(0x18, 0x18) AM_MIRROR(0xff00) /* write - NMI disable? (the data written doesn't matter) */ | |
| 1456 | ADDRESS_MAP_END | |
| 1457 | ||
| 1458 | ||
| 1459 | ||
| 1460 | /************************************* | |
| 1461 | * | |
| 1462 | * Audio interface | |
| 1463 | * | |
| 1464 | *************************************/ | |
| 1465 | ||
| 1466 | static const ym2610_interface ym2610_config = | |
| 1467 | { | |
| 1468 | audio_cpu_irq | |
| 1469 | }; | |
| 1470 | ||
| 1471 | ||
| 1472 | ||
| 1473 | /************************************* | |
| 1474 | * | |
| 1475 | * Standard Neo-Geo DIPs and | |
| 1476 | * input port definition | |
| 1477 | * | |
| 1478 | *************************************/ | |
| 1479 | ||
| 1480 | #define STANDARD_DIPS \ | |
| 1481 | PORT_DIPNAME( 0x0001, 0x0001, "Test Switch" ) PORT_DIPLOCATION("SW:1") \ | |
| 1482 | PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) \ | |
| 1483 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1484 | PORT_DIPNAME( 0x0002, 0x0002, "Coin Chutes?" ) PORT_DIPLOCATION("SW:2") \ | |
| 1485 | PORT_DIPSETTING( 0x0000, "1?" ) \ | |
| 1486 | PORT_DIPSETTING( 0x0002, "2?" ) \ | |
| 1487 | PORT_DIPNAME( 0x0004, 0x0004, "Autofire (in some games)" ) PORT_DIPLOCATION("SW:3") \ | |
| 1488 | PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) \ | |
| 1489 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1490 | PORT_DIPNAME( 0x0018, 0x0018, "COMM Setting (Cabinet No.)" ) PORT_DIPLOCATION("SW:4,5") \ | |
| 1491 | PORT_DIPSETTING( 0x0018, "1" ) \ | |
| 1492 | PORT_DIPSETTING( 0x0008, "2" ) \ | |
| 1493 | PORT_DIPSETTING( 0x0010, "3" ) \ | |
| 1494 | PORT_DIPSETTING( 0x0000, "4" ) \ | |
| 1495 | PORT_DIPNAME( 0x0020, 0x0020, "COMM Setting (Link Enable)" ) PORT_DIPLOCATION("SW:6") \ | |
| 1496 | PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) \ | |
| 1497 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1498 | PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW:7") \ | |
| 1499 | PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) \ | |
| 1500 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1501 | PORT_DIPNAME( 0x0080, 0x0080, "Freeze" ) PORT_DIPLOCATION("SW:8") \ | |
| 1502 | PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) \ | |
| 1503 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1504 | ||
| 1505 | #define STANDARD_IN2 \ | |
| 1506 | PORT_START("IN2") \ | |
| 1507 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) \ | |
| 1508 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_START1 ) \ | |
| 1509 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("1P Select") PORT_CODE(KEYCODE_5) PORT_PLAYER(1) \ | |
| 1510 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_START2 ) \ | |
| 1511 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("2P Select") PORT_CODE(KEYCODE_6) PORT_PLAYER(2) \ | |
| 1512 | PORT_BIT( 0x7000, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(get_memcard_status, NULL) \ | |
| 1513 | PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* Matrimelee expects this bit to be active high when on an AES */ | |
| 1514 | ||
| 1515 | #define STANDARD_IN3 \ | |
| 1516 | PORT_START("IN3") \ | |
| 1517 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED ) /* Coin 1 - AES has no coin slots, it's a console */ \ | |
| 1518 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) /* Coin 2 - AES has no coin slots, it's a console */ \ | |
| 1519 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNUSED ) /* Service Coin - not used, AES is a console */ \ | |
| 1520 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* having this ACTIVE_HIGH causes you to start with 2 credits using USA bios roms */ \ | |
| 1521 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* having this ACTIVE_HIGH causes you to start with 2 credits using USA bios roms */ \ | |
| 1522 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_SPECIAL ) /* what is this? */ \ | |
| 1523 | PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(get_calendar_status, NULL) \ | |
| 1524 | PORT_BIT( 0xff00, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(get_audio_result, NULL) | |
| 1525 | ||
| 1526 | ||
| 1527 | #define STANDARD_IN4 \ | |
| 1528 | PORT_START("IN4") \ | |
| 1529 | PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1530 | PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1531 | PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1532 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1533 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1534 | PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1535 | PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_SPECIAL ) /* what is this? - is 0 for 1 or 2 slot MVS (and AES?)*/ \ | |
| 1536 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Enter BIOS") PORT_CODE(KEYCODE_F2) \ | |
| 1537 | PORT_BIT( 0xff00, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1538 | ||
| 1539 | static INPUT_PORTS_START( controller ) | |
| 1540 | PORT_START("IN0") | |
| 1541 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1542 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1543 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1544 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1545 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1546 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1547 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1548 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1549 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1550 | ||
| 1551 | ||
| 1552 | PORT_START("IN1") | |
| 1553 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1554 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1555 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1556 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1557 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1558 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1559 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1560 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1561 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1562 | INPUT_PORTS_END | |
| 1563 | ||
| 1564 | static INPUT_PORTS_START( mjpanel ) | |
| 1565 | PORT_START("MJ01_P1") | |
| 1566 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1567 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_A ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1568 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_B ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1569 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_C ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1570 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_D ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1571 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_E ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1572 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_F ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1573 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_G ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1574 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1575 | ||
| 1576 | PORT_START("MJ02_P1") | |
| 1577 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1578 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_H ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1579 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_I ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1580 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_J ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1581 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_K ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1582 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_L ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1583 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_M ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1584 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_N ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1585 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1586 | ||
| 1587 | PORT_START("MJ03_P1") | |
| 1588 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1589 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1590 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1591 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1592 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1593 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1594 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1595 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1596 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1597 | ||
| 1598 | PORT_START("MJ04_P1") | |
| 1599 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1600 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1601 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1602 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1603 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1604 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1605 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1606 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1607 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1608 | ||
| 1609 | PORT_START("MJ01_P2") | |
| 1610 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1611 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_A ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1612 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_B ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1613 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_C ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1614 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_D ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1615 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_E ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1616 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_F ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1617 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_G ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1618 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1619 | ||
| 1620 | PORT_START("MJ02_P2") | |
| 1621 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1622 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_H ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1623 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_I ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1624 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_J ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1625 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_K ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1626 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_L ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1627 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_M ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1628 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_N ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1629 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1630 | ||
| 1631 | PORT_START("MJ03_P2") | |
| 1632 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1633 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1634 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1635 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1636 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1637 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1638 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1639 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1640 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1641 | ||
| 1642 | PORT_START("MJ04_P2") | |
| 1643 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1644 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1645 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1646 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1647 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1648 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1649 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1650 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1651 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1652 | ||
| 1653 | INPUT_PORTS_END | |
| 1654 | ||
| 1655 | static INPUT_PORTS_START( aes ) | |
| 1656 | // was there anyting in place of dipswitch in the home console? | |
| 1657 | /* PORT_START("IN0") | |
| 1658 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1659 | // PORT_DIPNAME( 0x0001, 0x0001, "Test Switch" ) PORT_DIPLOCATION("SW:1") | |
| 1660 | // PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) | |
| 1661 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1662 | // PORT_DIPNAME( 0x0002, 0x0002, "Coin Chutes?" ) PORT_DIPLOCATION("SW:2") | |
| 1663 | // PORT_DIPSETTING( 0x0000, "1?" ) | |
| 1664 | // PORT_DIPSETTING( 0x0002, "2?" ) | |
| 1665 | // PORT_DIPNAME( 0x0004, 0x0000, "Mahjong Control Panel (or Auto Fire)" ) PORT_DIPLOCATION("SW:3") | |
| 1666 | // PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) | |
| 1667 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1668 | // PORT_DIPNAME( 0x0018, 0x0018, "COMM Setting (Cabinet No.)" ) PORT_DIPLOCATION("SW:4,5") | |
| 1669 | // PORT_DIPSETTING( 0x0018, "1" ) | |
| 1670 | // PORT_DIPSETTING( 0x0008, "2" ) | |
| 1671 | // PORT_DIPSETTING( 0x0010, "3" ) | |
| 1672 | // PORT_DIPSETTING( 0x0000, "4" ) | |
| 1673 | // PORT_DIPNAME( 0x0020, 0x0020, "COMM Setting (Link Enable)" ) PORT_DIPLOCATION("SW:6") | |
| 1674 | // PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) | |
| 1675 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1676 | // PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW:7") | |
| 1677 | // PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) | |
| 1678 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1679 | // PORT_DIPNAME( 0x0080, 0x0080, "Freeze" ) PORT_DIPLOCATION("SW:8") | |
| 1680 | // PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) | |
| 1681 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1682 | PORT_BIT( 0xff00, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(aes_controller_r, NULL) */ | |
| 1683 | ||
| 1684 | PORT_START("CTRLSEL") /* Select Controller Type */ | |
| 1685 | PORT_CATEGORY_CLASS( 0x0f, 0x01, "P1 Controller") | |
| 1686 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 0 ) | |
| 1687 | PORT_CATEGORY_ITEM( 0x01, "NeoGeo Controller", 1 ) | |
| 1688 | PORT_CATEGORY_ITEM( 0x02, "NeoGeo Mahjong Panel", 3 ) | |
| 1689 | PORT_CATEGORY_CLASS( 0xf0, 0x10, "P2 Controller") | |
| 1690 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 0 ) | |
| 1691 | PORT_CATEGORY_ITEM( 0x10, "NeoGeo Controller", 2 ) | |
| 1692 | PORT_CATEGORY_ITEM( 0x20, "NeoGeo Mahjong Panel", 4 ) | |
| 1693 | ||
| 1694 | PORT_INCLUDE( controller ) | |
| 1695 | ||
| 1696 | PORT_INCLUDE( mjpanel ) | |
| 1697 | ||
| 1698 | // were some of these present in the AES?!? | |
| 1699 | STANDARD_IN2 | |
| 1700 | ||
| 1701 | STANDARD_IN3 | |
| 1702 | ||
| 1703 | STANDARD_IN4 | |
| 1704 | INPUT_PORTS_END | |
| 1705 | ||
| 1706 | ||
| 1707 | ||
| 1708 | /************************************* | |
| 1709 | * | |
| 1710 | * Machine driver | |
| 1711 | * | |
| 1712 | *************************************/ | |
| 1713 | ||
| 1714 | static MACHINE_CONFIG_START( neogeo, ng_aes_state ) | |
| 1715 | ||
| 1716 | /* basic machine hardware */ | |
| 1717 | MCFG_CPU_ADD("maincpu", M68000, NEOGEO_MAIN_CPU_CLOCK) | |
| 1718 | MCFG_CPU_PROGRAM_MAP(main_map) | |
| 1719 | ||
| 1720 | MCFG_CPU_ADD("audiocpu", Z80, NEOGEO_AUDIO_CPU_CLOCK) | |
| 1721 | MCFG_CPU_PROGRAM_MAP(audio_map) | |
| 1722 | MCFG_CPU_IO_MAP(audio_io_map) | |
| 1723 | ||
| 1724 | MCFG_MACHINE_START(neogeo) | |
| 1725 | MCFG_MACHINE_RESET(neogeo) | |
| 1726 | ||
| 1727 | /* video hardware */ | |
| 1728 | MCFG_VIDEO_START(neogeo) | |
| 1729 | MCFG_VIDEO_RESET(neogeo) | |
| 1730 | MCFG_DEFAULT_LAYOUT(layout_neogeo) | |
| 1731 | ||
| 1732 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 1733 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 1734 | MCFG_SCREEN_RAW_PARAMS(NEOGEO_PIXEL_CLOCK, NEOGEO_HTOTAL, NEOGEO_HBEND, NEOGEO_HBSTART, NEOGEO_VTOTAL, NEOGEO_VBEND, NEOGEO_VBSTART) | |
| 1735 | MCFG_SCREEN_UPDATE(neogeo) | |
| 1736 | ||
| 1737 | /* audio hardware */ | |
| 1738 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 1739 | ||
| 1740 | MCFG_SOUND_ADD("ymsnd", YM2610, NEOGEO_YM2610_CLOCK) | |
| 1741 | MCFG_SOUND_CONFIG(ym2610_config) | |
| 1742 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.60) | |
| 1743 | MCFG_SOUND_ROUTE(0, "rspeaker", 0.60) | |
| 1744 | MCFG_SOUND_ROUTE(1, "lspeaker", 1.0) | |
| 1745 | MCFG_SOUND_ROUTE(2, "rspeaker", 1.0) | |
| 1746 | ||
| 1747 | /* NEC uPD4990A RTC */ | |
| 1748 | MCFG_UPD4990A_ADD("upd4990a") | |
| 1749 | MACHINE_CONFIG_END | |
| 1750 | ||
| 1751 | static MACHINE_CONFIG_DERIVED( aes, neogeo ) | |
| 1752 | ||
| 1753 | MCFG_MEMCARD_HANDLER(neogeo) | |
| 1754 | ||
| 1755 | MCFG_AES_CARTRIDGE_ADD("aes_multicart") | |
| 1756 | // MCFG_CARTSLOT_ADD("cart") | |
| 1757 | // MCFG_CARTSLOT_MANDATORY | |
| 1758 | ||
| 1759 | // MCFG_CARTSLOT_LOAD(aes_cart) | |
| 1760 | ||
| 1761 | MCFG_SOFTWARE_LIST_ADD("cart_list","aes") | |
| 1762 | MACHINE_CONFIG_END | |
| 1763 | ||
| 1764 | static MACHINE_CONFIG_DERIVED( neocd, neogeo ) | |
| 1765 | ||
| 1766 | MCFG_CPU_MODIFY("maincpu") | |
| 1767 | MCFG_CPU_PROGRAM_MAP(neocd_main_map) | |
| 1768 | ||
| 1769 | MCFG_MACHINE_START(neocd) | |
| 1770 | MACHINE_CONFIG_END | |
| 1771 | ||
| 1772 | /************************************* | |
| 1773 | * | |
| 1774 | * Driver initalization | |
| 1775 | * | |
| 1776 | *************************************/ | |
| 1777 | ||
| 1778 | static DRIVER_INIT( neogeo ) | |
| 1779 | { | |
| 1780 | } | |
| 1781 | ||
| 1782 | ||
| 1783 | ROM_START( aes ) | |
| 1784 | ROM_REGION16_BE( 0x80000, "mainbios", 0 ) | |
| 1785 | ROM_SYSTEM_BIOS( 0, "jap-aes", "Japan AES" ) | |
| 1786 | ROMX_LOAD("neo-po.bin", 0x00000, 0x020000, CRC(16d0c132) SHA1(4e4a440cae46f3889d20234aebd7f8d5f522e22c), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(1)) /* AES Console (Japan) Bios */ | |
| 1787 | ROM_SYSTEM_BIOS( 1, "asia-aes", "Asia AES" ) | |
| 1788 | ROMX_LOAD("neo-epo.bin", 0x00000, 0x020000, CRC(d27a71f1) SHA1(1b3b22092f30c4d1b2c15f04d1670eb1e9fbea07), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(2)) /* AES Console (Asia?) Bios */ | |
| 1789 | // ROM_SYSTEM_BIOS( 2, "uni-bios_2_3","Universe Bios (Hack, Ver. 2.3)" ) | |
| 1790 | // ROMX_LOAD( "uni-bios_2_3.rom", 0x00000, 0x020000, CRC(27664eb5) SHA1(5b02900a3ccf3df168bdcfc98458136fd2b92ac0), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(3) ) /* Universe Bios v2.3 (hack) */ | |
| 1791 | ||
| 1792 | ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF ) | |
| 1793 | ||
| 1794 | ROM_REGION( 0x20000, "audiobios", 0 ) | |
| 1795 | ROM_LOAD( "sm1.sm1", 0x00000, 0x20000, CRC(94416d67) SHA1(42f9d7ddd6c0931fd64226a60dc73602b2819dcf) ) | |
| 1796 | ||
| 1797 | ROM_REGION( 0x90000, "audiocpu", ROMREGION_ERASEFF ) | |
| 1798 | ||
| 1799 | ROM_REGION( 0x20000, "zoomy", 0 ) | |
| 1800 | ROM_LOAD( "000-lo.lo", 0x00000, 0x20000, CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) ) | |
| 1801 | ||
| 1802 | ROM_REGION( 0x20000, "fixedbios", 0 ) | |
| 1803 | ROM_LOAD( "sfix.sfix", 0x000000, 0x20000, CRC(c2ea0cfd) SHA1(fd4a618cdcdbf849374f0a50dd8efe9dbab706c3) ) | |
| 1804 | ||
| 1805 | ROM_REGION( 0x20000, "fixed", ROMREGION_ERASEFF ) | |
| 1806 | ||
| 1807 | ROM_REGION( 0x1000000, "ymsnd", ROMREGION_ERASEFF ) | |
| 1808 | ||
| 1809 | ROM_REGION( 0x1000000, "ymsnd.deltat", ROMREGION_ERASEFF ) | |
| 1810 | ||
| 1811 | ROM_REGION( 0x900000, "sprites", ROMREGION_ERASEFF ) | |
| 1812 | ROM_END | |
| 1813 | ||
| 1814 | ROM_START( neocd ) | |
| 1815 | ROM_REGION16_BE( 0x100000, "mainbios", 0 ) | |
| 1816 | ROM_LOAD16_WORD_SWAP( "top-sp1.bin", 0x00000, 0x80000, CRC(19f0ad1a) SHA1(b3e2f8467e9a642c122428d075024a9bd1fe0679) ) | |
| 1817 | ||
| 1818 | ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF ) | |
| 1819 | ||
| 1820 | ROM_REGION( 0x100000, "audiobios", ROMREGION_ERASEFF ) | |
| 1821 | ||
| 1822 | ROM_REGION( 0x10000, "audiocpu", ROMREGION_ERASEFF ) | |
| 1823 | ||
| 1824 | ROM_REGION( 0x20000, "zoomy", 0 ) | |
| 1825 | ROM_LOAD( "000-lo.lo", 0x00000, 0x20000, CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) ) | |
| 1826 | ||
| 1827 | ROM_REGION( 0x20000, "fixedbios", ROMREGION_ERASEFF ) | |
| 1828 | ||
| 1829 | ROM_REGION( 0x20000, "fixed", ROMREGION_ERASEFF ) | |
| 1830 | ||
| 1831 | ROM_REGION( 0x400000, "ymsnd", ROMREGION_ERASEFF ) | |
| 1832 | ||
| 1833 | // NO_DELTAT_REGION | |
| 1834 | ||
| 1835 | ROM_REGION( 0x400000, "sprites", ROMREGION_ERASEFF ) | |
| 1836 | ROM_END | |
| 1837 | ||
| 1838 | ROM_START( neocdz ) | |
| 1839 | ROM_REGION16_BE( 0x100000, "mainbios", 0 ) | |
| 1840 | ROM_LOAD16_WORD_SWAP( "neocd.bin", 0x00000, 0x80000, CRC(df9de490) SHA1(7bb26d1e5d1e930515219cb18bcde5b7b23e2eda) ) | |
| 1841 | ||
| 1842 | ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF ) | |
| 1843 | ||
| 1844 | ROM_REGION( 0x20000, "audiobios", ROMREGION_ERASEFF ) | |
| 1845 | ||
| 1846 | ROM_REGION( 0x10000, "audiocpu", ROMREGION_ERASEFF ) | |
| 1847 | ||
| 1848 | ROM_REGION( 0x20000, "zoomy", 0 ) | |
| 1849 | ROM_LOAD( "000-lo.lo", 0x00000, 0x20000, CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) ) | |
| 1850 | ||
| 1851 | ROM_REGION( 0x20000, "fixedbios", ROMREGION_ERASEFF ) | |
| 1852 | ||
| 1853 | ROM_REGION( 0x20000, "fixed", ROMREGION_ERASEFF ) | |
| 1854 | ||
| 1855 | ROM_REGION( 0x400000, "ymsnd", ROMREGION_ERASEFF ) | |
| 1856 | ||
| 1857 | // NO_DELTAT_REGION | |
| 1858 | ||
| 1859 | ROM_REGION( 0x400000, "sprites", ROMREGION_ERASEFF ) | |
| 1860 | ROM_END | |
| 1861 | ||
| 1862 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 1863 | CONS( 1990, aes, 0, 0, aes, aes, neogeo, "SNK", "Neo-Geo AES", 0) | |
| 1864 | CONS( 1994, neocd, aes, 0, neocd, aes, neogeo, "SNK", "Neo-Geo CD", GAME_NOT_WORKING ) | |
| 1865 | CONS( 1996, neocdz, aes, 0, neocd, aes, neogeo, "SNK", "Neo-Geo CDZ", GAME_NOT_WORKING ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | nes.c | |
| 4 | ||
| 5 | Driver file to handle emulation of the Nintendo Entertainment System (Famicom). | |
| 6 | ||
| 7 | MESS driver by Brad Oliver (bradman@pobox.com), NES sound code by Matt Conte. | |
| 8 | Based in part on the old xNes code, by Nicolas Hamel, Chuck Mason, Brad Oliver, | |
| 9 | Richard Bannister and Jeff Mitchell. | |
| 10 | ||
| 11 | ***************************************************************************/ | |
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "video/ppu2c0x.h" | |
| 15 | #include "machine/nes_mmc.h" | |
| 16 | #include "includes/nes.h" | |
| 17 | #include "cpu/m6502/m6502.h" | |
| 18 | #include "imagedev/cartslot.h" | |
| 19 | #include "sound/nes_apu.h" | |
| 20 | #include "imagedev/flopdrv.h" | |
| 21 | #include "formats/nes_dsk.h" | |
| 22 | ||
| 23 | ||
| 24 | static READ8_DEVICE_HANDLER( psg_4015_r ) | |
| 25 | { | |
| 26 | return nes_psg_r(device, 0x15); | |
| 27 | } | |
| 28 | ||
| 29 | static WRITE8_DEVICE_HANDLER( psg_4015_w ) | |
| 30 | { | |
| 31 | nes_psg_w(device, 0x15, data); | |
| 32 | } | |
| 33 | ||
| 34 | static WRITE8_DEVICE_HANDLER( psg_4017_w ) | |
| 35 | { | |
| 36 | nes_psg_w(device, 0x17, data); | |
| 37 | } | |
| 38 | ||
| 39 | static WRITE8_HANDLER(nes_vh_sprite_dma_w) | |
| 40 | { | |
| 41 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 42 | ppu2c0x_spriteram_dma(space, state->m_ppu, data); | |
| 43 | } | |
| 44 | ||
| 45 | static ADDRESS_MAP_START( nes_map, AS_PROGRAM, 8 ) | |
| 46 | AM_RANGE(0x0000, 0x07ff) AM_RAM AM_MIRROR(0x1800) /* RAM */ | |
| 47 | AM_RANGE(0x2000, 0x3fff) AM_DEVREADWRITE("ppu", ppu2c0x_r, ppu2c0x_w) /* PPU registers */ | |
| 48 | AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("nessound", nes_psg_r, nes_psg_w) /* PSG primary registers */ | |
| 49 | AM_RANGE(0x4014, 0x4014) AM_WRITE(nes_vh_sprite_dma_w) /* stupid address space hole */ | |
| 50 | AM_RANGE(0x4015, 0x4015) AM_DEVREADWRITE("nessound", psg_4015_r, psg_4015_w) /* PSG status / first control register */ | |
| 51 | AM_RANGE(0x4016, 0x4016) AM_READWRITE(nes_IN0_r, nes_IN0_w) /* IN0 - input port 1 */ | |
| 52 | AM_RANGE(0x4017, 0x4017) AM_READ(nes_IN1_r) /* IN1 - input port 2 */ | |
| 53 | AM_RANGE(0x4017, 0x4017) AM_DEVWRITE("nessound", psg_4017_w) /* PSG second control register */ | |
| 54 | AM_RANGE(0x4100, 0x5fff) AM_READWRITE(nes_low_mapper_r, nes_low_mapper_w) /* Perform unholy acts on the machine */ | |
| 55 | ADDRESS_MAP_END | |
| 56 | ||
| 57 | ||
| 58 | static INPUT_PORTS_START( nes_controllers ) | |
| 59 | PORT_START("CTRLSEL") /* Select Controller Type */ | |
| 60 | PORT_CATEGORY_CLASS( 0x000f, 0x0001, "P1 Controller") | |
| 61 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 62 | PORT_CATEGORY_ITEM( 0x0001, "Gamepad", 1 ) | |
| 63 | PORT_CATEGORY_ITEM( 0x0002, "Zapper", 5 ) | |
| 64 | PORT_CATEGORY_ITEM( 0x0006, "Crazy Climber pad", 10 ) | |
| 65 | PORT_CATEGORY_CLASS( 0x00f0, 0x0010, "P2 Controller") | |
| 66 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 67 | PORT_CATEGORY_ITEM( 0x0010, "Gamepad", 2 ) | |
| 68 | PORT_CATEGORY_ITEM( 0x0030, "Zapper", 6 ) | |
| 69 | PORT_CATEGORY_ITEM( 0x0040, "Arkanoid paddle", 7 ) | |
| 70 | // PORT_CATEGORY_ITEM( 0x0050, "Family Trainer", 11 ) | |
| 71 | PORT_CATEGORY_CLASS( 0x0f00, 0x0000, "P3 Controller") | |
| 72 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 73 | PORT_CATEGORY_ITEM( 0x0100, "Gamepad", 3 ) | |
| 74 | PORT_CATEGORY_CLASS( 0xf000, 0x0000, "P4 Controller") | |
| 75 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 76 | PORT_CATEGORY_ITEM( 0x1000, "Gamepad", 4 ) | |
| 77 | ||
| 78 | PORT_START("PAD1") /* Joypad 1 */ | |
| 79 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 A") PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 80 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 B") PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 81 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 82 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 83 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 84 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 85 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 86 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 87 | ||
| 88 | PORT_START("PAD2") /* Joypad 2 */ | |
| 89 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 A") PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 90 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 B") PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 91 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 92 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 93 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 94 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 95 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 96 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 97 | ||
| 98 | PORT_START("PAD3") /* Joypad 3 */ | |
| 99 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3 A") PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 100 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3 B") PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 101 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 102 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 103 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 104 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 105 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 106 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 107 | ||
| 108 | PORT_START("PAD4") /* Joypad 4 */ | |
| 109 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4 A") PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 110 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4 B") PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 111 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 112 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 113 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 114 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 115 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 116 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 117 | ||
| 118 | PORT_START("ZAPPER1_X") /* P1 zapper */ | |
| 119 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_CATEGORY(5) PORT_PLAYER(1) | |
| 120 | PORT_START("ZAPPER1_Y") /* P1 zapper */ | |
| 121 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_CATEGORY(5) PORT_PLAYER(1) | |
| 122 | PORT_START("ZAPPER1_T") /* P1 zapper trigger */ | |
| 123 | PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P1 Lightgun Trigger") PORT_CATEGORY(5) PORT_PLAYER(1) | |
| 124 | ||
| 125 | PORT_START("ZAPPER2_X") /* P2 zapper */ | |
| 126 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255 ) PORT_CATEGORY(6) PORT_PLAYER(2) | |
| 127 | PORT_START("ZAPPER2_Y") /* P2 zapper */ | |
| 128 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255 ) PORT_CATEGORY(6) PORT_PLAYER(2) | |
| 129 | PORT_START("ZAPPER2_T") /* P2 zapper trigger */ | |
| 130 | PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P2 Lightgun Trigger") PORT_CATEGORY(6) PORT_PLAYER(2) | |
| 131 | ||
| 132 | PORT_START("PADDLE") /* Arkanoid paddle */ | |
| 133 | PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(3) PORT_MINMAX(0x62,0xf2) PORT_CATEGORY(7) | |
| 134 | ||
| 135 | PORT_START("CC_LEFT") | |
| 136 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 137 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 138 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 139 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 140 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_UP ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 141 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_DOWN ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 142 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 143 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 144 | ||
| 145 | PORT_START("CC_RIGHT") | |
| 146 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 147 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 148 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 149 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 150 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_UP ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 151 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_DOWN ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 152 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_LEFT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 153 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_RIGHT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 154 | ||
| 155 | INPUT_PORTS_END | |
| 156 | ||
| 157 | static INPUT_PORTS_START( nes ) | |
| 158 | PORT_INCLUDE( nes_controllers ) | |
| 159 | ||
| 160 | PORT_START("CONFIG") /* configuration */ | |
| 161 | PORT_CONFNAME( 0x01, 0x00, "Draw Top/Bottom 8 Lines") | |
| 162 | PORT_CONFSETTING( 0x01, DEF_STR(No) ) | |
| 163 | PORT_CONFSETTING( 0x00, DEF_STR(Yes) ) | |
| 164 | PORT_CONFNAME( 0x02, 0x00, "Enforce 8 Sprites/line") | |
| 165 | PORT_CONFSETTING( 0x02, DEF_STR(No) ) | |
| 166 | PORT_CONFSETTING( 0x00, DEF_STR(Yes) ) | |
| 167 | INPUT_PORTS_END | |
| 168 | ||
| 169 | static INPUT_PORTS_START( famicom ) | |
| 170 | PORT_INCLUDE( nes_controllers ) | |
| 171 | ||
| 172 | PORT_START("FLIPDISK") /* fake keys */ | |
| 173 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Change Disk Side") | |
| 174 | INPUT_PORTS_END | |
| 175 | ||
| 176 | static INPUT_PORTS_START( fc_keyboard ) | |
| 177 | PORT_START("FCKEY0") | |
| 178 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) | |
| 179 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) | |
| 180 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[') | |
| 181 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']') | |
| 182 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Kana") | |
| 183 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_RSHIFT) | |
| 184 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') | |
| 185 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Stop") PORT_CODE(KEYCODE_BACKSPACE) | |
| 186 | ||
| 187 | PORT_START("FCKEY1") | |
| 188 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) | |
| 189 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') | |
| 190 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') | |
| 191 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(';') | |
| 192 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CHAR('_') | |
| 193 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CHAR('/') | |
| 194 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') | |
| 195 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^') | |
| 196 | ||
| 197 | PORT_START("FCKEY2") | |
| 198 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) | |
| 199 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_O) PORT_CHAR('O') | |
| 200 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_L) PORT_CHAR('L') | |
| 201 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_K) PORT_CHAR('K') | |
| 202 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') | |
| 203 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') | |
| 204 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_P) PORT_CHAR('P') | |
| 205 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_0) PORT_CHAR('0') | |
| 206 | ||
| 207 | PORT_START("FCKEY3") | |
| 208 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) | |
| 209 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_I) PORT_CHAR('I') | |
| 210 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_U) PORT_CHAR('U') | |
| 211 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_J) PORT_CHAR('J') | |
| 212 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_M) PORT_CHAR('M') | |
| 213 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_N) PORT_CHAR('N') | |
| 214 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_9) PORT_CHAR('9') | |
| 215 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_8) PORT_CHAR('8') | |
| 216 | ||
| 217 | PORT_START("FCKEY4") | |
| 218 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) | |
| 219 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') | |
| 220 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_G) PORT_CHAR('G') | |
| 221 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_H) PORT_CHAR('H') | |
| 222 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_B) PORT_CHAR('B') | |
| 223 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_V) PORT_CHAR('V') | |
| 224 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_7) PORT_CHAR('7') | |
| 225 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_6) PORT_CHAR('6') | |
| 226 | ||
| 227 | PORT_START("FCKEY5") | |
| 228 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) | |
| 229 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_T) PORT_CHAR('T') | |
| 230 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_R) PORT_CHAR('R') | |
| 231 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_D) PORT_CHAR('D') | |
| 232 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F) PORT_CHAR('F') | |
| 233 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_C) PORT_CHAR('C') | |
| 234 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_5) PORT_CHAR('5') | |
| 235 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_4) PORT_CHAR('4') | |
| 236 | ||
| 237 | PORT_START("FCKEY6") | |
| 238 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) | |
| 239 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_W) PORT_CHAR('W') | |
| 240 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_S) PORT_CHAR('S') | |
| 241 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_A) PORT_CHAR('A') | |
| 242 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_X) PORT_CHAR('X') | |
| 243 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') | |
| 244 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_E) PORT_CHAR('E') | |
| 245 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_3) PORT_CHAR('3') | |
| 246 | ||
| 247 | PORT_START("FCKEY7") | |
| 248 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) | |
| 249 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(ESC)) | |
| 250 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') | |
| 251 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) | |
| 252 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) | |
| 253 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Grph") PORT_CODE(KEYCODE_LALT) | |
| 254 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_1) PORT_CHAR('1') | |
| 255 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_2) PORT_CHAR('2') | |
| 256 | ||
| 257 | PORT_START("FCKEY8") | |
| 258 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Clr") | |
| 259 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) | |
| 260 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) | |
| 261 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) | |
| 262 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) | |
| 263 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') | |
| 264 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Del") PORT_CODE(KEYCODE_DEL) | |
| 265 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Ins") PORT_CODE(KEYCODE_INSERT) | |
| 266 | ||
| 267 | INPUT_PORTS_END | |
| 268 | ||
| 269 | static INPUT_PORTS_START( subor_keyboard ) | |
| 270 | PORT_START("SUBKEY0") | |
| 271 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_4) PORT_CHAR('4') | |
| 272 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_G) PORT_CHAR('G') | |
| 273 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F) PORT_CHAR('F') | |
| 274 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_C) PORT_CHAR('C') | |
| 275 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) | |
| 276 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_E) PORT_CHAR('E') | |
| 277 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_5) PORT_CHAR('5') | |
| 278 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_V) PORT_CHAR('V') | |
| 279 | ||
| 280 | PORT_START("SUBKEY1") | |
| 281 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_2) PORT_CHAR('2') | |
| 282 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_D) PORT_CHAR('D') | |
| 283 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_S) PORT_CHAR('S') | |
| 284 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) | |
| 285 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) | |
| 286 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_W) PORT_CHAR('W') | |
| 287 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_3) PORT_CHAR('3') | |
| 288 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_X) PORT_CHAR('X') | |
| 289 | ||
| 290 | PORT_START("SUBKEY2") | |
| 291 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) | |
| 292 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) | |
| 293 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("NEXT") | |
| 294 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) | |
| 295 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) | |
| 296 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("PRIOR") | |
| 297 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) | |
| 298 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) | |
| 299 | ||
| 300 | PORT_START("SUBKEY3") | |
| 301 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_9) PORT_CHAR('9') | |
| 302 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_I) PORT_CHAR('I') | |
| 303 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_L) PORT_CHAR('L') | |
| 304 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') | |
| 305 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) | |
| 306 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_O) PORT_CHAR('O') | |
| 307 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_0) PORT_CHAR('0') | |
| 308 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') | |
| 309 | ||
| 310 | PORT_START("SUBKEY4") | |
| 311 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') | |
| 312 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) | |
| 313 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) | |
| 314 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) | |
| 315 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) | |
| 316 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') | |
| 317 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') | |
| 318 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) | |
| 319 | ||
| 320 | PORT_START("SUBKEY5") | |
| 321 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') | |
| 322 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) | |
| 323 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') | |
| 324 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') | |
| 325 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) | |
| 326 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_A) PORT_CHAR('A') | |
| 327 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_1) PORT_CHAR('1') | |
| 328 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) | |
| 329 | ||
| 330 | PORT_START("SUBKEY6") | |
| 331 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_7) PORT_CHAR('7') | |
| 332 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') | |
| 333 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_K) PORT_CHAR('K') | |
| 334 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_M) PORT_CHAR('M') | |
| 335 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) | |
| 336 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_U) PORT_CHAR('U') | |
| 337 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_8) PORT_CHAR('8') | |
| 338 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_J) PORT_CHAR('J') | |
| 339 | ||
| 340 | PORT_START("SUBKEY7") | |
| 341 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') | |
| 342 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') | |
| 343 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') | |
| 344 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') | |
| 345 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) | |
| 346 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_P) PORT_CHAR('P') | |
| 347 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') | |
| 348 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) | |
| 349 | ||
| 350 | PORT_START("SUBKEY8") | |
| 351 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_T) PORT_CHAR('T') | |
| 352 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_H) PORT_CHAR('H') | |
| 353 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_N) PORT_CHAR('N') | |
| 354 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') | |
| 355 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) | |
| 356 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_R) PORT_CHAR('R') | |
| 357 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_6) PORT_CHAR('6') | |
| 358 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_B) PORT_CHAR('B') | |
| 359 | ||
| 360 | PORT_START("SUBKEY9") | |
| 361 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(9) | |
| 362 | ||
| 363 | PORT_START("SUBKEY10") | |
| 364 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("LMENU") | |
| 365 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) | |
| 366 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) | |
| 367 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) | |
| 368 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) | |
| 369 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) | |
| 370 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) | |
| 371 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) | |
| 372 | ||
| 373 | PORT_START("SUBKEY11") | |
| 374 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_MINUS_PAD)PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) | |
| 375 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) | |
| 376 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) | |
| 377 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) | |
| 378 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) | |
| 379 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) | |
| 380 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_SLASH_PAD)PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) | |
| 381 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) | |
| 382 | ||
| 383 | PORT_START("SUBKEY12") | |
| 384 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') | |
| 385 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) | |
| 386 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("PAUSE") | |
| 387 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("SPACE2") | |
| 388 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) | |
| 389 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) | |
| 390 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) | |
| 391 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) | |
| 392 | ||
| 393 | INPUT_PORTS_END | |
| 394 | ||
| 395 | static INPUT_PORTS_START( famikey ) | |
| 396 | PORT_INCLUDE( famicom ) | |
| 397 | PORT_INCLUDE( fc_keyboard ) | |
| 398 | PORT_INCLUDE( subor_keyboard ) | |
| 399 | ||
| 400 | PORT_MODIFY("CTRLSEL") /* Select Controller Type */ | |
| 401 | PORT_CATEGORY_CLASS( 0x000f, 0x0004, "P1 Controller") | |
| 402 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 403 | PORT_CATEGORY_ITEM( 0x0001, "Gamepad", 1 ) | |
| 404 | PORT_CATEGORY_ITEM( 0x0002, "Zapper", 5 ) | |
| 405 | PORT_CATEGORY_ITEM( 0x0006, "Crazy Climber pad", 10 ) | |
| 406 | PORT_CATEGORY_ITEM( 0x0007, "FC Keyboard", 8 ) | |
| 407 | PORT_CATEGORY_ITEM( 0x0008, "Subor Keyboard", 9 ) | |
| 408 | PORT_CATEGORY_CLASS( 0x00f0, 0x0010, "P2 Controller") | |
| 409 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 410 | PORT_CATEGORY_ITEM( 0x0010, "Gamepad", 2 ) | |
| 411 | PORT_CATEGORY_ITEM( 0x0030, "Zapper", 6 ) | |
| 412 | PORT_CATEGORY_ITEM( 0x0040, "Arkanoid paddle", 7 ) | |
| 413 | // PORT_CATEGORY_ITEM( 0x0050, "Family Trainer", 11 ) | |
| 414 | PORT_CATEGORY_CLASS( 0x0f00, 0x0000, "P3 Controller") | |
| 415 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 416 | PORT_CATEGORY_ITEM( 0x0100, "Gamepad", 3 ) | |
| 417 | PORT_CATEGORY_CLASS( 0xf000, 0x0000, "P4 Controller") | |
| 418 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 419 | PORT_CATEGORY_ITEM( 0x1000, "Gamepad", 4 ) | |
| 420 | INPUT_PORTS_END | |
| 421 | ||
| 422 | #ifdef UNUSED_FUNCTION | |
| 423 | /* This layout is not changed at runtime */ | |
| 424 | gfx_layout nes_vram_charlayout = | |
| 425 | { | |
| 426 | 8,8, /* 8*8 characters */ | |
| 427 | 512, /* 512 characters */ | |
| 428 | 2, /* 2 bits per pixel */ | |
| 429 | { 8*8, 0 }, /* the two bitplanes are separated */ | |
| 430 | { 0, 1, 2, 3, 4, 5, 6, 7 }, | |
| 431 | { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, | |
| 432 | 16*8 /* every char takes 16 consecutive bytes */ | |
| 433 | }; | |
| 434 | #endif | |
| 435 | ||
| 436 | static const nes_interface nes_apu_interface = | |
| 437 | { | |
| 438 | "maincpu" | |
| 439 | }; | |
| 440 | ||
| 441 | ||
| 442 | static void ppu_nmi(device_t *device, int *ppu_regs) | |
| 443 | { | |
| 444 | cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_NMI, PULSE_LINE); | |
| 445 | } | |
| 446 | ||
| 447 | ||
| 448 | static const ppu2c0x_interface nes_ppu_interface = | |
| 449 | { | |
| 450 | 0, | |
| 451 | 0, | |
| 452 | PPU_MIRROR_NONE, | |
| 453 | ppu_nmi | |
| 454 | }; | |
| 455 | ||
| 456 | static const floppy_config nes_floppy_config = | |
| 457 | { | |
| 458 | DEVCB_NULL, | |
| 459 | DEVCB_NULL, | |
| 460 | DEVCB_NULL, | |
| 461 | DEVCB_NULL, | |
| 462 | DEVCB_NULL, | |
| 463 | FLOPPY_STANDARD_5_25_DSHD, | |
| 464 | FLOPPY_OPTIONS_NAME(nes_only), | |
| 465 | NULL | |
| 466 | }; | |
| 467 | ||
| 468 | ||
| 469 | static MACHINE_CONFIG_START( nes, nes_state ) | |
| 470 | /* basic machine hardware */ | |
| 471 | MCFG_CPU_ADD("maincpu", N2A03, NTSC_CLOCK) | |
| 472 | MCFG_CPU_PROGRAM_MAP(nes_map) | |
| 473 | ||
| 474 | MCFG_MACHINE_START( nes ) | |
| 475 | MCFG_MACHINE_RESET( nes ) | |
| 476 | ||
| 477 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 478 | MCFG_SCREEN_REFRESH_RATE(60.098) | |
| 479 | // This isn't used so much to calulate the vblank duration (the PPU code tracks that manually) but to determine | |
| 480 | // the number of cycles in each scanline for the PPU scanline timer. Since the PPU has 20 vblank scanlines + 2 | |
| 481 | // non-rendering scanlines, we compensate. This ends up being 2500 cycles for the non-rendering portion, 2273 | |
| 482 | // cycles for the actual vblank period. | |
| 483 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((113.66/(NTSC_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_NTSC-PPU_VBLANK_FIRST_SCANLINE+1+2))) | |
| 484 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 485 | MCFG_SCREEN_SIZE(32*8, 262) | |
| 486 | MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 30*8-1) | |
| 487 | MCFG_SCREEN_UPDATE(nes) | |
| 488 | ||
| 489 | MCFG_PALETTE_INIT(nes) | |
| 490 | MCFG_VIDEO_START(nes) | |
| 491 | ||
| 492 | MCFG_PALETTE_LENGTH(4*16*8) | |
| 493 | ||
| 494 | MCFG_PPU2C02_ADD( "ppu", nes_ppu_interface ) | |
| 495 | ||
| 496 | /* sound hardware */ | |
| 497 | MCFG_SPEAKER_STANDARD_MONO("mono") | |
| 498 | MCFG_SOUND_ADD("nessound", NES, NTSC_CLOCK) | |
| 499 | MCFG_SOUND_CONFIG(nes_apu_interface) | |
| 500 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) | |
| 501 | ||
| 502 | MCFG_CARTSLOT_ADD("cart") | |
| 503 | MCFG_CARTSLOT_EXTENSION_LIST("nes,unf") | |
| 504 | MCFG_CARTSLOT_MANDATORY | |
| 505 | MCFG_CARTSLOT_INTERFACE("nes_cart") | |
| 506 | MCFG_CARTSLOT_LOAD(nes_cart) | |
| 507 | MCFG_CARTSLOT_PARTIALHASH(nes_partialhash) | |
| 508 | MCFG_SOFTWARE_LIST_ADD("cart_list","nes") | |
| 509 | MACHINE_CONFIG_END | |
| 510 | ||
| 511 | static MACHINE_CONFIG_DERIVED( nespal, nes ) | |
| 512 | ||
| 513 | /* basic machine hardware */ | |
| 514 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 515 | MCFG_CPU_CLOCK( PAL_CLOCK ) | |
| 516 | ||
| 517 | MCFG_DEVICE_REMOVE( "ppu" ) | |
| 518 | MCFG_PPU2C07_ADD( "ppu", nes_ppu_interface ) | |
| 519 | ||
| 520 | /* video hardware */ | |
| 521 | MCFG_SCREEN_MODIFY("screen") | |
| 522 | MCFG_SCREEN_REFRESH_RATE(53.355) | |
| 523 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2))) | |
| 524 | MCFG_VIDEO_START(nes) | |
| 525 | ||
| 526 | /* sound hardware */ | |
| 527 | MCFG_SOUND_REPLACE("nessound", NES, PAL_CLOCK) | |
| 528 | MCFG_SOUND_CONFIG(nes_apu_interface) | |
| 529 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) | |
| 530 | MACHINE_CONFIG_END | |
| 531 | ||
| 532 | static MACHINE_CONFIG_DERIVED( dendy, nes ) | |
| 533 | ||
| 534 | /* basic machine hardware */ | |
| 535 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 536 | MCFG_CPU_CLOCK( 26601712/15 ) /* 26.601712MHz / 15 == 1.77344746666... MHz */ | |
| 537 | ||
| 538 | MCFG_DEVICE_REMOVE( "ppu" ) | |
| 539 | MCFG_PPU2C07_ADD( "ppu", nes_ppu_interface ) | |
| 540 | ||
| 541 | /* video hardware */ | |
| 542 | MCFG_SCREEN_MODIFY("screen") | |
| 543 | MCFG_SCREEN_REFRESH_RATE(50.00697796827) | |
| 544 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2))) | |
| 545 | MCFG_VIDEO_START(nes) | |
| 546 | ||
| 547 | /* sound hardware */ | |
| 548 | MCFG_SOUND_REPLACE("nessound", NES, 26601712/15) /* 26.601712MHz / 15 == 1.77344746666... MHz */ | |
| 549 | MCFG_SOUND_CONFIG(nes_apu_interface) | |
| 550 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) | |
| 551 | MACHINE_CONFIG_END | |
| 552 | ||
| 553 | static MACHINE_CONFIG_DERIVED( famicom, nes ) | |
| 554 | ||
| 555 | MCFG_CARTSLOT_MODIFY("cart") | |
| 556 | MCFG_CARTSLOT_EXTENSION_LIST("nes,unf") | |
| 557 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 558 | MCFG_CARTSLOT_LOAD(nes_cart) | |
| 559 | MCFG_CARTSLOT_PARTIALHASH(nes_partialhash) | |
| 560 | ||
| 561 | MCFG_FLOPPY_DRIVE_ADD(FLOPPY_0, nes_floppy_config) | |
| 562 | MACHINE_CONFIG_END | |
| 563 | ||
| 564 | ||
| 565 | /* rom regions are just place-holders: they get removed and re-allocated when a cart is loaded */ | |
| 566 | ROM_START( nes ) | |
| 567 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM + program banks */ | |
| 568 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 569 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 570 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 571 | ROM_END | |
| 572 | ||
| 573 | ROM_START( nespal ) | |
| 574 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM + program banks */ | |
| 575 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 576 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 577 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 578 | ROM_END | |
| 579 | ||
| 580 | ROM_START( famicom ) | |
| 581 | ROM_REGION( 0x10000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 582 | ROM_LOAD_OPTIONAL( "disksys.rom", 0xe000, 0x2000, CRC(5e607dcf) SHA1(57fe1bdee955bb48d357e463ccbf129496930b62) ) | |
| 583 | ||
| 584 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 585 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 586 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 587 | ROM_END | |
| 588 | ||
| 589 | #define rom_fami_key rom_famicom | |
| 590 | ||
| 591 | ROM_START( famitwin ) | |
| 592 | ROM_REGION( 0x10000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 593 | ROM_LOAD_OPTIONAL( "disksyst.rom", 0xe000, 0x2000, CRC(4df24a6c) SHA1(e4e41472c454f928e53eb10e0509bf7d1146ecc1) ) | |
| 594 | ||
| 595 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 596 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 597 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 598 | ROM_END | |
| 599 | ||
| 600 | ROM_START( m82 ) | |
| 601 | ROM_REGION( 0x14000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 602 | /* Banks to be mapped at 0xe000? More investigations needed... */ | |
| 603 | ROM_LOAD( "m82_v1_0.bin", 0x10000, 0x4000, CRC(7d56840a) SHA1(cbd2d14fa073273ba58367758f40d67fd8a9106d) ) | |
| 604 | ||
| 605 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 606 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 607 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 608 | ROM_END | |
| 609 | ||
| 610 | // see http://www.disgruntleddesigner.com/chrisc/drpcjr/index.html | |
| 611 | // and http://www.disgruntleddesigner.com/chrisc/drpcjr/DrPCJrMemMap.txt | |
| 612 | ROM_START( drpcjr ) | |
| 613 | ROM_REGION( 0x18000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 614 | /* 4 banks to be mapped in 0xe000-0xffff (or 8 banks to be mapped in 0xe000-0xefff & 0xf000-0xffff). | |
| 615 | Banks selected by writing at 0x4180 */ | |
| 616 | ROM_LOAD("drpcjr_bios.bin", 0x10000, 0x8000, CRC(c8fbef89) SHA1(2cb0a817b31400cdf27817d09bae7e69f41b062b) ) // bios vers. 1.0a | |
| 617 | // Not sure if we should support this: hacked version 1.5a by Chris Covell with bugfixes and GameGenie support | |
| 618 | // ROM_LOAD("drpcjr_v1_5_gg.bin", 0x10000, 0x8000, CRC(98f2033b) SHA1(93c114da787a19279d1a46667c2f69b49e25d4f1) ) | |
| 619 | ||
| 620 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 621 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 622 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 623 | ROM_END | |
| 624 | ||
| 625 | ROM_START( dendy ) | |
| 626 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM + program banks */ | |
| 627 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 628 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 629 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 630 | ROM_END | |
| 631 | ||
| 632 | /*************************************************************************** | |
| 633 | ||
| 634 | Game driver(s) | |
| 635 | ||
| 636 | ***************************************************************************/ | |
| 637 | ||
| 638 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 639 | CONS( 1985, nes, 0, 0, nes, nes, 0, "Nintendo", "Nintendo Entertainment System / Famicom (NTSC)", GAME_IMPERFECT_GRAPHICS ) | |
| 640 | CONS( 1987, nespal, nes, 0, nespal, nes, 0, "Nintendo", "Nintendo Entertainment System (PAL)", GAME_IMPERFECT_GRAPHICS ) | |
| 641 | CONS( 1983, famicom, nes, 0, famicom, famicom, famicom, "Nintendo", "Famicom (w/ Disk System add-on)", GAME_IMPERFECT_GRAPHICS ) | |
| 642 | CONS( 1983, fami_key, nes, 0, famicom, famikey, famicom, "Nintendo", "Famicom (w/ Disk System add-on + Keyboard add-on)", GAME_IMPERFECT_GRAPHICS ) | |
| 643 | CONS( 1986, famitwin, nes, 0, famicom, famicom, famicom, "Sharp", "Famicom Twin", GAME_IMPERFECT_GRAPHICS ) | |
| 644 | CONS( 198?, m82, nes, 0, nes, nes, 0, "Nintendo", "M82 Display Unit", GAME_IMPERFECT_GRAPHICS ) | |
| 645 | CONS( 1996, drpcjr, nes, 0, famicom, famicom, famicom, "Bung", "Doctor PC Jr", GAME_IMPERFECT_GRAPHICS ) | |
| 646 | CONS( 1992, dendy, nes, 0, dendy, nes, 0, "Steepler", "Dendy Classic", GAME_IMPERFECT_GRAPHICS ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | snes.c | |
| 4 | ||
| 5 | Driver file to handle emulation of the Nintendo Super NES. | |
| 6 | ||
| 7 | R. Belmont | |
| 8 | Anthony Kruize | |
| 9 | Angelo Salese | |
| 10 | Fabio Priuli | |
| 11 | byuu | |
| 12 | Based on the original MESS driver by Lee Hammerton (aka Savoury Snax) | |
| 13 | ||
| 14 | Driver is preliminary right now. | |
| 15 | ||
| 16 | The memory map included below is setup in a way to make it easier to handle | |
| 17 | Mode 20 and Mode 21 ROMs. | |
| 18 | ||
| 19 | Todo (in no particular order): | |
| 20 | - Fix additional sound bugs | |
| 21 | - Emulate extra chips - superfx, dsp2, sa-1 etc. | |
| 22 | - Add horizontal mosaic, hi-res. interlaced etc to video emulation. | |
| 23 | - Fix support for Mode 7. (In Progress) | |
| 24 | - Handle interleaved roms (maybe even multi-part roms, but how?) | |
| 25 | - Add support for running at 3.58 MHz at the appropriate time. | |
| 26 | - I'm sure there's lots more ... | |
| 27 | ||
| 28 | ***************************************************************************/ | |
| 29 | ||
| 30 | #include "emu.h" | |
| 31 | #include "audio/snes_snd.h" | |
| 32 | #include "cpu/spc700/spc700.h" | |
| 33 | #include "cpu/superfx/superfx.h" | |
| 34 | #include "cpu/g65816/g65816.h" | |
| 35 | #include "cpu/upd7725/upd7725.h" | |
| 36 | #include "includes/snes.h" | |
| 37 | #include "machine/snescart.h" | |
| 38 | #include "crsshair.h" | |
| 39 | ||
| 40 | #define MAX_SNES_CART_SIZE 0x600000 | |
| 41 | ||
| 42 | /************************************* | |
| 43 | * | |
| 44 | * Memory handlers | |
| 45 | * | |
| 46 | *************************************/ | |
| 47 | ||
| 48 | static READ8_DEVICE_HANDLER( spc_ram_100_r ) | |
| 49 | { | |
| 50 | return spc_ram_r(device, offset + 0x100); | |
| 51 | } | |
| 52 | ||
| 53 | static WRITE8_DEVICE_HANDLER( spc_ram_100_w ) | |
| 54 | { | |
| 55 | spc_ram_w(device, offset + 0x100, data); | |
| 56 | } | |
| 57 | ||
| 58 | /************************************* | |
| 59 | * | |
| 60 | * Address maps | |
| 61 | * | |
| 62 | *************************************/ | |
| 63 | ||
| 64 | static ADDRESS_MAP_START( snes_map, AS_PROGRAM, 8) | |
| 65 | AM_RANGE(0x000000, 0x2fffff) AM_READWRITE(snes_r_bank1, snes_w_bank1) /* I/O and ROM (repeats for each bank) */ | |
| 66 | AM_RANGE(0x300000, 0x3fffff) AM_READWRITE(snes_r_bank2, snes_w_bank2) /* I/O and ROM (repeats for each bank) */ | |
| 67 | AM_RANGE(0x400000, 0x5fffff) AM_READ(snes_r_bank3) /* ROM (and reserved in Mode 20) */ | |
| 68 | AM_RANGE(0x600000, 0x6fffff) AM_READWRITE(snes_r_bank4, snes_w_bank4) /* used by Mode 20 DSP-1 */ | |
| 69 | AM_RANGE(0x700000, 0x7dffff) AM_READWRITE(snes_r_bank5, snes_w_bank5) | |
| 70 | AM_RANGE(0x7e0000, 0x7fffff) AM_RAM /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ | |
| 71 | AM_RANGE(0x800000, 0xbfffff) AM_READWRITE(snes_r_bank6, snes_w_bank6) /* Mirror and ROM */ | |
| 72 | AM_RANGE(0xc00000, 0xffffff) AM_READWRITE(snes_r_bank7, snes_w_bank7) /* Mirror and ROM */ | |
| 73 | ADDRESS_MAP_END | |
| 74 | ||
| 75 | static ADDRESS_MAP_START( superfx_map, AS_PROGRAM, 8) | |
| 76 | AM_RANGE(0x000000, 0x3fffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1) | |
| 77 | AM_RANGE(0x400000, 0x5fffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2) | |
| 78 | AM_RANGE(0x600000, 0x7dffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3) | |
| 79 | AM_RANGE(0x800000, 0xbfffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1) | |
| 80 | AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2) | |
| 81 | AM_RANGE(0xe00000, 0xffffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3) | |
| 82 | ADDRESS_MAP_END | |
| 83 | ||
| 84 | static ADDRESS_MAP_START( spc_map, AS_PROGRAM, 8) | |
| 85 | AM_RANGE(0x0000, 0x00ef) AM_DEVREADWRITE("spc700", spc_ram_r, spc_ram_w) /* lower 32k ram */ | |
| 86 | AM_RANGE(0x00f0, 0x00ff) AM_DEVREADWRITE("spc700", spc_io_r, spc_io_w) /* spc io */ | |
| 87 | AM_RANGE(0x0100, 0xffff) AM_DEVWRITE("spc700", spc_ram_100_w) | |
| 88 | AM_RANGE(0x0100, 0xffbf) AM_DEVREAD("spc700", spc_ram_100_r) | |
| 89 | AM_RANGE(0xffc0, 0xffff) AM_DEVREAD("spc700", spc_ipl_r) | |
| 90 | ADDRESS_MAP_END | |
| 91 | ||
| 92 | static ADDRESS_MAP_START( dsp_prg_map, AS_PROGRAM, 32 ) | |
| 93 | AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION("dspprg", 0) | |
| 94 | ADDRESS_MAP_END | |
| 95 | ||
| 96 | static ADDRESS_MAP_START( dsp_data_map, AS_DATA, 16 ) | |
| 97 | AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION("dspdata", 0) | |
| 98 | ADDRESS_MAP_END | |
| 99 | ||
| 100 | static ADDRESS_MAP_START( setadsp_prg_map, AS_PROGRAM, 32 ) | |
| 101 | AM_RANGE(0x0000, 0x3fff) AM_ROM AM_REGION("dspprg", 0) | |
| 102 | ADDRESS_MAP_END | |
| 103 | ||
| 104 | static ADDRESS_MAP_START( setadsp_data_map, AS_DATA, 16 ) | |
| 105 | AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION("dspdata", 0) | |
| 106 | ADDRESS_MAP_END | |
| 107 | ||
| 108 | /************************************* | |
| 109 | * | |
| 110 | * Input ports | |
| 111 | * | |
| 112 | *************************************/ | |
| 113 | ||
| 114 | static CUSTOM_INPUT( snes_mouse_speed_input ) | |
| 115 | { | |
| 116 | snes_state *state = field.machine().driver_data<snes_state>(); | |
| 117 | int port = (FPTR)param; | |
| 118 | ||
| 119 | if (snes_ram[OLDJOY1] & 0x1) | |
| 120 | { | |
| 121 | state->m_mouse[port].speed++; | |
| 122 | if ((state->m_mouse[port].speed & 0x03) == 0x03) | |
| 123 | state->m_mouse[port].speed = 0; | |
| 124 | } | |
| 125 | ||
| 126 | return state->m_mouse[port].speed; | |
| 127 | } | |
| 128 | ||
| 129 | static CUSTOM_INPUT( snes_superscope_offscreen_input ) | |
| 130 | { | |
| 131 | snes_state *state = field.machine().driver_data<snes_state>(); | |
| 132 | int port = (FPTR)param; | |
| 133 | static const char *const portnames[2][3] = | |
| 134 | { | |
| 135 | { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, | |
| 136 | { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" }, | |
| 137 | }; | |
| 138 | ||
| 139 | INT16 x = input_port_read(field.machine(), portnames[port][1]); | |
| 140 | INT16 y = input_port_read(field.machine(), portnames[port][2]); | |
| 141 | ||
| 142 | /* these are the theoretical boundaries, but we currently are always onscreen... */ | |
| 143 | if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= snes_ppu.beam.last_visible_line) | |
| 144 | state->m_scope[port].offscreen = 1; | |
| 145 | else | |
| 146 | state->m_scope[port].offscreen = 0; | |
| 147 | ||
| 148 | return state->m_scope[port].offscreen; | |
| 149 | } | |
| 150 | ||
| 151 | static TIMER_CALLBACK( lightgun_tick ) | |
| 152 | { | |
| 153 | if ((input_port_read(machine, "CTRLSEL") & 0x0f) == 0x03 || (input_port_read(machine, "CTRLSEL") & 0x0f) == 0x04) | |
| 154 | { | |
| 155 | /* enable lightpen crosshair */ | |
| 156 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL); | |
| 157 | } | |
| 158 | else | |
| 159 | { | |
| 160 | /* disable lightpen crosshair */ | |
| 161 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE); | |
| 162 | } | |
| 163 | ||
| 164 | if ((input_port_read(machine, "CTRLSEL") & 0xf0) == 0x30 || (input_port_read(machine, "CTRLSEL") & 0xf0) == 0x40) | |
| 165 | { | |
| 166 | /* enable lightpen crosshair */ | |
| 167 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL); | |
| 168 | } | |
| 169 | else | |
| 170 | { | |
| 171 | /* disable lightpen crosshair */ | |
| 172 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE); | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | ||
| 177 | static INPUT_PORTS_START( snes_joypads ) | |
| 178 | PORT_START("SERIAL1_DATA1_L") | |
| 179 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 180 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 181 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P1 Button L") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 182 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P1 Button R") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 183 | PORT_START("SERIAL1_DATA1_H") | |
| 184 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 185 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 186 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 187 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START1 ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 188 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 189 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 190 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 191 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 192 | ||
| 193 | PORT_START("SERIAL2_DATA1_L") | |
| 194 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 195 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 196 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 197 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 198 | PORT_START("SERIAL2_DATA1_H") | |
| 199 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 200 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 201 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 202 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START2 ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 203 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 204 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 205 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 206 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 207 | ||
| 208 | PORT_START("SERIAL1_DATA2_L") | |
| 209 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 210 | PORT_START("SERIAL1_DATA2_H") | |
| 211 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 212 | ||
| 213 | PORT_START("SERIAL2_DATA2_L") | |
| 214 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 215 | PORT_START("SERIAL2_DATA2_H") | |
| 216 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 217 | INPUT_PORTS_END | |
| 218 | ||
| 219 | static INPUT_PORTS_START( snes_mouse ) | |
| 220 | PORT_START("MOUSE1") | |
| 221 | /* bits 0,3 = mouse signature (must be 1) */ | |
| 222 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 223 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 224 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 225 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 226 | /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */ | |
| 227 | PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_mouse_speed_input, (void *)0) | |
| 228 | /* bits 6,7 = mouse buttons */ | |
| 229 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Mouse Button Left") PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 230 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Mouse Button Right") PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 231 | ||
| 232 | PORT_START("MOUSE1_X") | |
| 233 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 234 | ||
| 235 | PORT_START("MOUSE1_Y") | |
| 236 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 237 | ||
| 238 | PORT_START("MOUSE2") | |
| 239 | /* bits 0,3 = mouse signature (must be 1) */ | |
| 240 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 241 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 242 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 243 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 244 | /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */ | |
| 245 | PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_mouse_speed_input, (void *)1) | |
| 246 | /* bits 6,7 = mouse buttons */ | |
| 247 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Mouse Button Left") PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 248 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Mouse Button Right") PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 249 | ||
| 250 | PORT_START("MOUSE2_X") | |
| 251 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 252 | ||
| 253 | PORT_START("MOUSE2_Y") | |
| 254 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 255 | INPUT_PORTS_END | |
| 256 | ||
| 257 | static INPUT_PORTS_START( snes_superscope ) | |
| 258 | PORT_START("SUPERSCOPE1") | |
| 259 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise | |
| 260 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_superscope_offscreen_input, (void *)0) | |
| 261 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 262 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 263 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port1 Superscope Pause") PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 264 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port1 Superscope Turbo") PORT_TOGGLE PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 265 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port1 Superscope Cursor") PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 266 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port1 Superscope Fire") PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 267 | ||
| 268 | PORT_START("SUPERSCOPE1_X") | |
| 269 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port1 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 270 | ||
| 271 | PORT_START("SUPERSCOPE1_Y") | |
| 272 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port1 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 273 | ||
| 274 | PORT_START("SUPERSCOPE2") | |
| 275 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise | |
| 276 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_superscope_offscreen_input, (void *)1) | |
| 277 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 278 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 279 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port2 Superscope Pause") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 280 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port2 Superscope Turbo") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 281 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port2 Superscope Cursor") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 282 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port2 Superscope Fire") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 283 | ||
| 284 | PORT_START("SUPERSCOPE2_X") | |
| 285 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port2 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 286 | ||
| 287 | PORT_START("SUPERSCOPE2_Y") | |
| 288 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port2 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 289 | INPUT_PORTS_END | |
| 290 | ||
| 291 | static INPUT_PORTS_START( snes ) | |
| 292 | PORT_START("CTRLSEL") /* Select Controller Type */ | |
| 293 | PORT_CATEGORY_CLASS( 0x0f, 0x01, "P1 Controller") | |
| 294 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 10 ) | |
| 295 | PORT_CATEGORY_ITEM( 0x01, "Gamepad", 11 ) | |
| 296 | PORT_CATEGORY_ITEM( 0x02, "Mouse", 12 ) | |
| 297 | PORT_CATEGORY_ITEM( 0x03, "Superscope", 13 ) | |
| 298 | // PORT_CATEGORY_ITEM( 0x04, "Justfier", 14 ) | |
| 299 | // PORT_CATEGORY_ITEM( 0x05, "Multitap", 15 ) | |
| 300 | PORT_CATEGORY_CLASS( 0xf0, 0x10, "P2 Controller") | |
| 301 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 20 ) | |
| 302 | PORT_CATEGORY_ITEM( 0x10, "Gamepad", 21 ) | |
| 303 | PORT_CATEGORY_ITEM( 0x20, "Mouse", 22 ) | |
| 304 | PORT_CATEGORY_ITEM( 0x30, "Superscope", 23 ) | |
| 305 | // PORT_CATEGORY_ITEM( 0x40, "Justfier", 24 ) | |
| 306 | // PORT_CATEGORY_ITEM( 0x50, "Multitap", 25 ) | |
| 307 | ||
| 308 | PORT_INCLUDE(snes_joypads) | |
| 309 | PORT_INCLUDE(snes_mouse) | |
| 310 | PORT_INCLUDE(snes_superscope) | |
| 311 | ||
| 312 | PORT_START("OPTIONS") | |
| 313 | PORT_CONFNAME( 0x01, 0x00, "Hi-Res pixels blurring (TV effect)") | |
| 314 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 315 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) | |
| 316 | ||
| 317 | #if SNES_LAYER_DEBUG | |
| 318 | PORT_START("DEBUG1") | |
| 319 | PORT_CONFNAME( 0x03, 0x00, "Select BG1 priority" ) | |
| 320 | PORT_CONFSETTING( 0x00, "All" ) | |
| 321 | PORT_CONFSETTING( 0x01, "BG1B (lower) only" ) | |
| 322 | PORT_CONFSETTING( 0x02, "BG1A (higher) only" ) | |
| 323 | PORT_CONFNAME( 0x0c, 0x00, "Select BG2 priority" ) | |
| 324 | PORT_CONFSETTING( 0x00, "All" ) | |
| 325 | PORT_CONFSETTING( 0x04, "BG2B (lower) only" ) | |
| 326 | PORT_CONFSETTING( 0x08, "BG2A (higher) only" ) | |
| 327 | PORT_CONFNAME( 0x30, 0x00, "Select BG3 priority" ) | |
| 328 | PORT_CONFSETTING( 0x00, "All" ) | |
| 329 | PORT_CONFSETTING( 0x10, "BG3B (lower) only" ) | |
| 330 | PORT_CONFSETTING( 0x20, "BG3A (higher) only" ) | |
| 331 | PORT_CONFNAME( 0xc0, 0x00, "Select BG4 priority" ) | |
| 332 | PORT_CONFSETTING( 0x00, "All" ) | |
| 333 | PORT_CONFSETTING( 0x40, "BG4B (lower) only" ) | |
| 334 | PORT_CONFSETTING( 0x80, "BG4A (higher) only" ) | |
| 335 | ||
| 336 | PORT_START("DEBUG2") | |
| 337 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 1") PORT_CODE(KEYCODE_1_PAD) PORT_TOGGLE | |
| 338 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 2") PORT_CODE(KEYCODE_2_PAD) PORT_TOGGLE | |
| 339 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 3") PORT_CODE(KEYCODE_3_PAD) PORT_TOGGLE | |
| 340 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 4") PORT_CODE(KEYCODE_4_PAD) PORT_TOGGLE | |
| 341 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Objects") PORT_CODE(KEYCODE_5_PAD) PORT_TOGGLE | |
| 342 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Main/Sub") PORT_CODE(KEYCODE_6_PAD) PORT_TOGGLE | |
| 343 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Color Math") PORT_CODE(KEYCODE_7_PAD) PORT_TOGGLE | |
| 344 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Windows") PORT_CODE(KEYCODE_8_PAD) PORT_TOGGLE | |
| 345 | ||
| 346 | PORT_START("DEBUG3") | |
| 347 | PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mosaic") PORT_CODE(KEYCODE_9_PAD) PORT_TOGGLE | |
| 348 | PORT_CONFNAME( 0x70, 0x00, "Select OAM priority" ) | |
| 349 | PORT_CONFSETTING( 0x00, "All" ) | |
| 350 | PORT_CONFSETTING( 0x10, "OAM0 only" ) | |
| 351 | PORT_CONFSETTING( 0x20, "OAM1 only" ) | |
| 352 | PORT_CONFSETTING( 0x30, "OAM2 only" ) | |
| 353 | PORT_CONFSETTING( 0x40, "OAM3 only" ) | |
| 354 | PORT_CONFNAME( 0x80, 0x00, "Draw sprite in reverse order" ) | |
| 355 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 356 | PORT_CONFSETTING( 0x80, DEF_STR( On ) ) | |
| 357 | ||
| 358 | PORT_START("DEBUG4") | |
| 359 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 0 draw") PORT_TOGGLE | |
| 360 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 1 draw") PORT_TOGGLE | |
| 361 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 2 draw") PORT_TOGGLE | |
| 362 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 3 draw") PORT_TOGGLE | |
| 363 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 4 draw") PORT_TOGGLE | |
| 364 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 5 draw") PORT_TOGGLE | |
| 365 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 6 draw") PORT_TOGGLE | |
| 366 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 7 draw") PORT_TOGGLE | |
| 367 | #endif | |
| 368 | INPUT_PORTS_END | |
| 369 | ||
| 370 | ||
| 371 | /************************************* | |
| 372 | * | |
| 373 | * Input callbacks | |
| 374 | * | |
| 375 | *************************************/ | |
| 376 | ||
| 377 | static void snes_gun_latch( running_machine &machine, INT16 x, INT16 y ) | |
| 378 | { | |
| 379 | /* these are the theoretical boundaries */ | |
| 380 | if (x < 0) | |
| 381 | x = 0; | |
| 382 | if (x > (SNES_SCR_WIDTH - 1)) | |
| 383 | x = SNES_SCR_WIDTH - 1; | |
| 384 | ||
| 385 | if (y < 0) | |
| 386 | y = 0; | |
| 387 | if (y > (snes_ppu.beam.last_visible_line - 1)) | |
| 388 | y = snes_ppu.beam.last_visible_line - 1; | |
| 389 | ||
| 390 | snes_ppu.beam.latch_horz = x; | |
| 391 | snes_ppu.beam.latch_vert = y; | |
| 392 | snes_ram[STAT78] |= 0x40; | |
| 393 | } | |
| 394 | ||
| 395 | static void snes_input_read_joy( running_machine &machine, int port ) | |
| 396 | { | |
| 397 | snes_state *state = machine.driver_data<snes_state>(); | |
| 398 | static const char *const portnames[2][4] = | |
| 399 | { | |
| 400 | { "SERIAL1_DATA1_L", "SERIAL1_DATA1_H", "SERIAL1_DATA2_L", "SERIAL1_DATA2_H" }, | |
| 401 | { "SERIAL2_DATA1_L", "SERIAL2_DATA1_H", "SERIAL2_DATA2_L", "SERIAL2_DATA2_H" }, | |
| 402 | }; | |
| 403 | ||
| 404 | state->m_data1[port] = input_port_read(machine, portnames[port][0]) | (input_port_read(machine, portnames[port][1]) << 8); | |
| 405 | state->m_data2[port] = input_port_read(machine, portnames[port][2]) | (input_port_read(machine, portnames[port][3]) << 8); | |
| 406 | ||
| 407 | // avoid sending signals that could crash games | |
| 408 | // if left, no right | |
| 409 | if (state->m_data1[port] & 0x200) | |
| 410 | state->m_data1[port] &= ~0x100; | |
| 411 | // if up, no down | |
| 412 | if (state->m_data1[port] & 0x800) | |
| 413 | state->m_data1[port] &= ~0x400; | |
| 414 | ||
| 415 | state->m_joypad[port].buttons = state->m_data1[port]; | |
| 416 | } | |
| 417 | ||
| 418 | static void snes_input_read_mouse( running_machine &machine, int port ) | |
| 419 | { | |
| 420 | snes_state *state = machine.driver_data<snes_state>(); | |
| 421 | INT16 var; | |
| 422 | static const char *const portnames[2][3] = | |
| 423 | { | |
| 424 | { "MOUSE1", "MOUSE1_X", "MOUSE1_Y" }, | |
| 425 | { "MOUSE2", "MOUSE2_X", "MOUSE2_Y" }, | |
| 426 | }; | |
| 427 | ||
| 428 | state->m_mouse[port].buttons = input_port_read(machine, portnames[port][0]); | |
| 429 | state->m_mouse[port].x = input_port_read(machine, portnames[port][1]); | |
| 430 | state->m_mouse[port].y = input_port_read(machine, portnames[port][2]); | |
| 431 | var = state->m_mouse[port].x - state->m_mouse[port].oldx; | |
| 432 | ||
| 433 | if (var < -127) | |
| 434 | { | |
| 435 | state->m_mouse[port].deltax = 0xff; | |
| 436 | state->m_mouse[port].oldx -= 127; | |
| 437 | } | |
| 438 | else if (var < 0) | |
| 439 | { | |
| 440 | state->m_mouse[port].deltax = 0x80 | (-var); | |
| 441 | state->m_mouse[port].oldx = state->m_mouse[port].x; | |
| 442 | } | |
| 443 | else if (var > 127) | |
| 444 | { | |
| 445 | state->m_mouse[port].deltax = 0x7f; | |
| 446 | state->m_mouse[port].oldx += 127; | |
| 447 | } | |
| 448 | else | |
| 449 | { | |
| 450 | state->m_mouse[port].deltax = var & 0xff; | |
| 451 | state->m_mouse[port].oldx = state->m_mouse[port].x; | |
| 452 | } | |
| 453 | ||
| 454 | var = state->m_mouse[port].y - state->m_mouse[port].oldy; | |
| 455 | ||
| 456 | if (var < -127) | |
| 457 | { | |
| 458 | state->m_mouse[port].deltay = 0xff; | |
| 459 | state->m_mouse[port].oldy -= 127; | |
| 460 | } | |
| 461 | else if (var < 0) | |
| 462 | { | |
| 463 | state->m_mouse[port].deltay = 0x80 | (-var); | |
| 464 | state->m_mouse[port].oldy = state->m_mouse[port].y; | |
| 465 | } | |
| 466 | else if (var > 127) | |
| 467 | { | |
| 468 | state->m_mouse[port].deltay = 0x7f; | |
| 469 | state->m_mouse[port].oldy += 127; | |
| 470 | } | |
| 471 | else | |
| 472 | { | |
| 473 | state->m_mouse[port].deltay = var & 0xff; | |
| 474 | state->m_mouse[port].oldy = state->m_mouse[port].y; | |
| 475 | } | |
| 476 | ||
| 477 | state->m_data1[port] = state->m_mouse[port].buttons | (0x00 << 8); | |
| 478 | state->m_data2[port] = 0; | |
| 479 | } | |
| 480 | ||
| 481 | static void snes_input_read_superscope( running_machine &machine, int port ) | |
| 482 | { | |
| 483 | snes_state *state = machine.driver_data<snes_state>(); | |
| 484 | static const char *const portnames[2][3] = | |
| 485 | { | |
| 486 | { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, | |
| 487 | { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" }, | |
| 488 | }; | |
| 489 | UINT8 input; | |
| 490 | ||
| 491 | /* first read input bits */ | |
| 492 | state->m_scope[port].x = input_port_read(machine, portnames[port][1]); | |
| 493 | state->m_scope[port].y = input_port_read(machine, portnames[port][2]); | |
| 494 | input = input_port_read(machine, portnames[port][0]); | |
| 495 | ||
| 496 | /* then start elaborating input bits: only keep old turbo value */ | |
| 497 | state->m_scope[port].buttons &= 0x20; | |
| 498 | ||
| 499 | /* set onscreen/offscreen */ | |
| 500 | state->m_scope[port].buttons |= BIT(input, 1); | |
| 501 | ||
| 502 | /* turbo is a switch; toggle is edge sensitive */ | |
| 503 | if (BIT(input, 5) && !state->m_scope[port].turbo_lock) | |
| 504 | { | |
| 505 | state->m_scope[port].buttons ^= 0x20; | |
| 506 | state->m_scope[port].turbo_lock = 1; | |
| 507 | } | |
| 508 | else if (!BIT(input, 5)) | |
| 509 | state->m_scope[port].turbo_lock = 0; | |
| 510 | ||
| 511 | /* fire is a button; if turbo is active, trigger is level sensitive; otherwise it is edge sensitive */ | |
| 512 | if (BIT(input, 7) && (BIT(state->m_scope[port].buttons, 5) || !state->m_scope[port].fire_lock)) | |
| 513 | { | |
| 514 | state->m_scope[port].buttons |= 0x80; | |
| 515 | state->m_scope[port].fire_lock = 1; | |
| 516 | } | |
| 517 | else if (!BIT(input, 7)) | |
| 518 | state->m_scope[port].fire_lock = 0; | |
| 519 | ||
| 520 | /* cursor is a button; it is always level sensitive */ | |
| 521 | state->m_scope[port].buttons |= BIT(input, 6); | |
| 522 | ||
| 523 | /* pause is a button; it is always edge sensitive */ | |
| 524 | if (BIT(input, 4) && !state->m_scope[port].pause_lock) | |
| 525 | { | |
| 526 | state->m_scope[port].buttons |= 0x10; | |
| 527 | state->m_scope[port].pause_lock = 1; | |
| 528 | } | |
| 529 | else if (!BIT(input, 4)) | |
| 530 | state->m_scope[port].pause_lock = 0; | |
| 531 | ||
| 532 | /* If we have pressed fire or cursor and we are on-screen and SuperScope is in Port2, then latch video signal. | |
| 533 | Notice that we only latch Port2 because its IOBit pin is connected to bit7 of the IO Port, while Port1 has | |
| 534 | IOBit pin connected to bit6 of the IO Port, and the latter is not detected by the H/V Counters. In other | |
| 535 | words, you can connect SuperScope to Port1, but there is no way SNES could detect its on-screen position */ | |
| 536 | if ((state->m_scope[port].buttons & 0xc0) && !(state->m_scope[port].buttons & 0x02) && port == 1) | |
| 537 | snes_gun_latch(machine, state->m_scope[port].x, state->m_scope[port].y); | |
| 538 | ||
| 539 | state->m_data1[port] = 0xff | (state->m_scope[port].buttons << 8); | |
| 540 | state->m_data2[port] = 0; | |
| 541 | } | |
| 542 | ||
| 543 | static void snes_input_read( running_machine &machine ) | |
| 544 | { | |
| 545 | snes_state *state = machine.driver_data<snes_state>(); | |
| 546 | UINT8 ctrl1 = input_port_read(machine, "CTRLSEL") & 0x0f; | |
| 547 | UINT8 ctrl2 = (input_port_read(machine, "CTRLSEL") & 0xf0) >> 4; | |
| 548 | ||
| 549 | /* Check if lightgun has been chosen as input: if so, enable crosshair */ | |
| 550 | machine.scheduler().timer_set(attotime::zero, FUNC(lightgun_tick)); | |
| 551 | ||
| 552 | switch (ctrl1) | |
| 553 | { | |
| 554 | case 1: /* SNES joypad */ | |
| 555 | snes_input_read_joy(machine, 0); | |
| 556 | break; | |
| 557 | case 2: /* SNES Mouse */ | |
| 558 | snes_input_read_mouse(machine, 0); | |
| 559 | break; | |
| 560 | case 3: /* SNES Superscope */ | |
| 561 | snes_input_read_superscope(machine, 0); | |
| 562 | break; | |
| 563 | case 0: /* no controller in port1 */ | |
| 564 | default: | |
| 565 | state->m_data1[0] = 0; | |
| 566 | state->m_data2[0] = 0; | |
| 567 | break; | |
| 568 | } | |
| 569 | ||
| 570 | switch (ctrl2) | |
| 571 | { | |
| 572 | case 1: /* SNES joypad */ | |
| 573 | snes_input_read_joy(machine, 1); | |
| 574 | break; | |
| 575 | case 2: /* SNES Mouse */ | |
| 576 | snes_input_read_mouse(machine, 1); | |
| 577 | break; | |
| 578 | case 3: /* SNES Superscope */ | |
| 579 | snes_input_read_superscope(machine, 1); | |
| 580 | break; | |
| 581 | case 0: /* no controller in port2 */ | |
| 582 | default: | |
| 583 | state->m_data1[1] = 0; | |
| 584 | state->m_data2[1] = 0; | |
| 585 | break; | |
| 586 | } | |
| 587 | ||
| 588 | // is automatic reading on? if so, copy port data1/data2 to joy1l->joy4h | |
| 589 | // this actually works like reading the first 16bits from oldjoy1/2 in reverse order | |
| 590 | if (snes_ram[NMITIMEN] & 1) | |
| 591 | { | |
| 592 | state->m_joy1l = (state->m_data1[0] & 0x00ff) >> 0; | |
| 593 | state->m_joy1h = (state->m_data1[0] & 0xff00) >> 8; | |
| 594 | state->m_joy2l = (state->m_data1[1] & 0x00ff) >> 0; | |
| 595 | state->m_joy2h = (state->m_data1[1] & 0xff00) >> 8; | |
| 596 | state->m_joy3l = (state->m_data2[0] & 0x00ff) >> 0; | |
| 597 | state->m_joy3h = (state->m_data2[0] & 0xff00) >> 8; | |
| 598 | state->m_joy4l = (state->m_data2[1] & 0x00ff) >> 0; | |
| 599 | state->m_joy4h = (state->m_data2[1] & 0xff00) >> 8; | |
| 600 | ||
| 601 | // make sure read_idx starts returning all 1s because the auto-read reads it :-) | |
| 602 | state->m_read_idx[0] = 16; | |
| 603 | state->m_read_idx[1] = 16; | |
| 604 | } | |
| 605 | ||
| 606 | } | |
| 607 | ||
| 608 | static UINT8 snes_oldjoy1_read( running_machine &machine ) | |
| 609 | { | |
| 610 | snes_state *state = machine.driver_data<snes_state>(); | |
| 611 | UINT8 ctrl1 = input_port_read(machine, "CTRLSEL") & 0x0f; | |
| 612 | UINT8 res = 0; | |
| 613 | ||
| 614 | switch (ctrl1) | |
| 615 | { | |
| 616 | case 1: /* SNES joypad */ | |
| 617 | if (state->m_read_idx[0] >= 16) | |
| 618 | res = 0x01; | |
| 619 | else | |
| 620 | res = (state->m_joypad[0].buttons >> (15 - state->m_read_idx[0]++)) & 0x01; | |
| 621 | break; | |
| 622 | case 2: /* SNES Mouse */ | |
| 623 | if (state->m_read_idx[0] >= 32) | |
| 624 | res = 0x01; | |
| 625 | else if (state->m_read_idx[0] >= 24) | |
| 626 | res = (state->m_mouse[0].deltax >> (31 - state->m_read_idx[0]++)) & 0x01; | |
| 627 | else if (state->m_read_idx[0] >= 16) | |
| 628 | res = (state->m_mouse[0].deltay >> (23 - state->m_read_idx[0]++)) & 0x01; | |
| 629 | else if (state->m_read_idx[0] >= 8) | |
| 630 | res = (state->m_mouse[0].buttons >> (15 - state->m_read_idx[0]++)) & 0x01; | |
| 631 | else | |
| 632 | res = 0; | |
| 633 | break; | |
| 634 | case 3: /* SNES Superscope */ | |
| 635 | if (state->m_read_idx[0] >= 8) | |
| 636 | res = 0x01; | |
| 637 | else | |
| 638 | res = (state->m_scope[0].buttons >> (7 - state->m_read_idx[0]++)) & 0x01; | |
| 639 | break; | |
| 640 | case 0: /* no controller in port2 */ | |
| 641 | default: | |
| 642 | break; | |
| 643 | } | |
| 644 | ||
| 645 | return res; | |
| 646 | } | |
| 647 | ||
| 648 | static UINT8 snes_oldjoy2_read( running_machine &machine ) | |
| 649 | { | |
| 650 | snes_state *state = machine.driver_data<snes_state>(); | |
| 651 | UINT8 ctrl2 = (input_port_read(machine, "CTRLSEL") & 0xf0) >> 4; | |
| 652 | UINT8 res = 0; | |
| 653 | ||
| 654 | switch (ctrl2) | |
| 655 | { | |
| 656 | case 1: /* SNES joypad */ | |
| 657 | if (state->m_read_idx[1] >= 16) | |
| 658 | res = 0x01; | |
| 659 | else | |
| 660 | res = (state->m_joypad[1].buttons >> (15 - state->m_read_idx[1]++)) & 0x01; | |
| 661 | break; | |
| 662 | case 2: /* SNES Mouse */ | |
| 663 | if (state->m_read_idx[1] >= 32) | |
| 664 | res = 0x01; | |
| 665 | else if (state->m_read_idx[1] >= 24) | |
| 666 | res = (state->m_mouse[1].deltax >> (31 - state->m_read_idx[1]++)) & 0x01; | |
| 667 | else if (state->m_read_idx[1] >= 16) | |
| 668 | res = (state->m_mouse[1].deltay >> (23 - state->m_read_idx[1]++)) & 0x01; | |
| 669 | else if (state->m_read_idx[1] >= 8) | |
| 670 | res = (state->m_mouse[1].buttons >> (15 - state->m_read_idx[1]++)) & 0x01; | |
| 671 | else | |
| 672 | res = 0; | |
| 673 | break; | |
| 674 | case 3: /* SNES Superscope */ | |
| 675 | if (state->m_read_idx[1] >= 8) | |
| 676 | res = 0x01; | |
| 677 | else | |
| 678 | res = (state->m_scope[1].buttons >> (7 - state->m_read_idx[1]++)) & 0x01; | |
| 679 | break; | |
| 680 | case 0: /* no controller in port2 */ | |
| 681 | default: | |
| 682 | break; | |
| 683 | } | |
| 684 | ||
| 685 | return res; | |
| 686 | } | |
| 687 | ||
| 688 | /************************************* | |
| 689 | * | |
| 690 | * Machine driver | |
| 691 | * | |
| 692 | *************************************/ | |
| 693 | ||
| 694 | static MACHINE_RESET( snes_mess ) | |
| 695 | { | |
| 696 | snes_state *state = machine.driver_data<snes_state>(); | |
| 697 | ||
| 698 | MACHINE_RESET_CALL(snes); | |
| 699 | ||
| 700 | state->m_io_read = snes_input_read; | |
| 701 | state->m_oldjoy1_read = snes_oldjoy1_read; | |
| 702 | state->m_oldjoy2_read = snes_oldjoy2_read; | |
| 703 | } | |
| 704 | ||
| 705 | static MACHINE_CONFIG_START( snes_base, snes_state ) | |
| 706 | ||
| 707 | /* basic machine hardware */ | |
| 708 | MCFG_CPU_ADD("maincpu", _5A22, MCLK_NTSC) /* 2.68 MHz, also 3.58 MHz */ | |
| 709 | MCFG_CPU_PROGRAM_MAP(snes_map) | |
| 710 | ||
| 711 | MCFG_CPU_ADD("soundcpu", SPC700, 1024000) /* 1.024 MHz */ | |
| 712 | MCFG_CPU_PROGRAM_MAP(spc_map) | |
| 713 | ||
| 714 | //MCFG_QUANTUM_TIME(attotime::from_hz(48000)) | |
| 715 | MCFG_QUANTUM_PERFECT_CPU("maincpu") | |
| 716 | ||
| 717 | MCFG_MACHINE_START(snes_mess) | |
| 718 | MCFG_MACHINE_RESET(snes_mess) | |
| 719 | ||
| 720 | /* video hardware */ | |
| 721 | MCFG_VIDEO_START(snes) | |
| 722 | ||
| 723 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 724 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 725 | MCFG_SCREEN_RAW_PARAMS(DOTCLK_NTSC, SNES_HTOTAL, 0, SNES_SCR_WIDTH, SNES_VTOTAL_NTSC, 0, SNES_SCR_HEIGHT_NTSC) | |
| 726 | MCFG_SCREEN_UPDATE(snes) | |
| 727 | ||
| 728 | /* sound hardware */ | |
| 729 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 730 | MCFG_SOUND_ADD("spc700", SNES, 0) | |
| 731 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) | |
| 732 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) | |
| 733 | MACHINE_CONFIG_END | |
| 734 | ||
| 735 | static MACHINE_CONFIG_DERIVED( snes, snes_base ) | |
| 736 | ||
| 737 | MCFG_FRAGMENT_ADD(snes_cartslot) | |
| 738 | MACHINE_CONFIG_END | |
| 739 | ||
| 740 | static SUPERFX_CONFIG( snes_superfx_config ) | |
| 741 | { | |
| 742 | DEVCB_LINE(snes_extern_irq_w) /* IRQ line from cart */ | |
| 743 | }; | |
| 744 | ||
| 745 | static MACHINE_CONFIG_DERIVED( snessfx, snes ) | |
| 746 | ||
| 747 | MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */ | |
| 748 | MCFG_CPU_PROGRAM_MAP(superfx_map) | |
| 749 | MCFG_CPU_CONFIG(snes_superfx_config) | |
| 750 | MACHINE_CONFIG_END | |
| 751 | ||
| 752 | static MACHINE_CONFIG_DERIVED( snesdsp, snes ) | |
| 753 | ||
| 754 | MCFG_CPU_ADD("dsp", UPD7725, 8000000) | |
| 755 | MCFG_CPU_PROGRAM_MAP(dsp_prg_map) | |
| 756 | MCFG_CPU_DATA_MAP(dsp_data_map) | |
| 757 | MACHINE_CONFIG_END | |
| 758 | ||
| 759 | static MACHINE_CONFIG_DERIVED( snesst10, snes ) | |
| 760 | ||
| 761 | MCFG_CPU_ADD("setadsp", UPD96050, 10000000) | |
| 762 | MCFG_CPU_PROGRAM_MAP(setadsp_prg_map) | |
| 763 | MCFG_CPU_DATA_MAP(setadsp_data_map) | |
| 764 | MACHINE_CONFIG_END | |
| 765 | ||
| 766 | static MACHINE_CONFIG_DERIVED( snesst11, snes ) | |
| 767 | ||
| 768 | MCFG_CPU_ADD("setadsp", UPD96050, 15000000) | |
| 769 | MCFG_CPU_PROGRAM_MAP(setadsp_prg_map) | |
| 770 | MCFG_CPU_DATA_MAP(setadsp_data_map) | |
| 771 | MACHINE_CONFIG_END | |
| 772 | ||
| 773 | static MACHINE_CONFIG_DERIVED( snespal, snes ) | |
| 774 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 775 | MCFG_CPU_CLOCK( MCLK_PAL ) | |
| 776 | ||
| 777 | MCFG_SCREEN_MODIFY("screen") | |
| 778 | MCFG_SCREEN_RAW_PARAMS(DOTCLK_PAL, SNES_HTOTAL, 0, SNES_SCR_WIDTH, SNES_VTOTAL_PAL, 0, SNES_SCR_HEIGHT_PAL) | |
| 779 | MACHINE_CONFIG_END | |
| 780 | ||
| 781 | static MACHINE_CONFIG_DERIVED( snespsfx, snespal ) | |
| 782 | ||
| 783 | MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */ | |
| 784 | MCFG_CPU_PROGRAM_MAP(superfx_map) | |
| 785 | MCFG_CPU_CONFIG(snes_superfx_config) | |
| 786 | MACHINE_CONFIG_END | |
| 787 | ||
| 788 | static MACHINE_CONFIG_DERIVED( snespdsp, snespal ) | |
| 789 | ||
| 790 | MCFG_CPU_ADD("dsp", UPD7725, 8000000) | |
| 791 | MCFG_CPU_PROGRAM_MAP(dsp_prg_map) | |
| 792 | MCFG_CPU_DATA_MAP(dsp_data_map) | |
| 793 | MACHINE_CONFIG_END | |
| 794 | ||
| 795 | static MACHINE_CONFIG_DERIVED( snesst, snes_base ) | |
| 796 | ||
| 797 | MCFG_MACHINE_START(snesst) | |
| 798 | ||
| 799 | MCFG_FRAGMENT_ADD(sufami_cartslot) | |
| 800 | MACHINE_CONFIG_END | |
| 801 | ||
| 802 | static MACHINE_CONFIG_DERIVED( snesbsx, snes_base ) | |
| 803 | ||
| 804 | MCFG_FRAGMENT_ADD(bsx_cartslot) | |
| 805 | MACHINE_CONFIG_END | |
| 806 | ||
| 807 | ||
| 808 | /************************************* | |
| 809 | * | |
| 810 | * ROM definition(s) | |
| 811 | * | |
| 812 | *************************************/ | |
| 813 | ||
| 814 | ROM_START( snes ) | |
| 815 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 816 | ||
| 817 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 818 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 819 | ||
| 820 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 821 | ||
| 822 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 823 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 824 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 825 | ROM_END | |
| 826 | ||
| 827 | ROM_START( snesdsp ) | |
| 828 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 829 | ||
| 830 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 831 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 832 | ||
| 833 | ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 834 | ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) | |
| 835 | ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) | |
| 836 | ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) | |
| 837 | ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) | |
| 838 | ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) | |
| 839 | ||
| 840 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 841 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 842 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 843 | ROM_END | |
| 844 | ||
| 845 | ROM_START( snesst10 ) | |
| 846 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 847 | ||
| 848 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 849 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 850 | ||
| 851 | ROM_REGION( 0x11000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 852 | ROM_LOAD( "st010.bin", 0x000000, 0x011000, CRC(aa11ee2d) SHA1(cc1984e989cb94e3dcbb5f99e085b5414e18a017) ) | |
| 853 | ||
| 854 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 855 | ROM_REGION( 0x10000, "dspprg", ROMREGION_ERASEFF) | |
| 856 | ROM_REGION( 0x1000, "dspdata", ROMREGION_ERASEFF) | |
| 857 | ROM_END | |
| 858 | ||
| 859 | ROM_START( snesst11 ) | |
| 860 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 861 | ||
| 862 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 863 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 864 | ||
| 865 | ROM_REGION( 0x11000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 866 | ROM_LOAD( "st011.bin", 0x000000, 0x011000, CRC(34d2952c) SHA1(1375b8c1efc8cae4962b57dfe22f6b78e1ddacc8) ) | |
| 867 | ||
| 868 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 869 | ROM_REGION( 0x10000, "dspprg", ROMREGION_ERASEFF) | |
| 870 | ROM_REGION( 0x1000, "dspdata", ROMREGION_ERASEFF) | |
| 871 | ROM_END | |
| 872 | ||
| 873 | ROM_START( snessfx ) | |
| 874 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 875 | ||
| 876 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 877 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 878 | ||
| 879 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 880 | ||
| 881 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 882 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 883 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 884 | ROM_END | |
| 885 | ||
| 886 | ROM_START( snespal ) | |
| 887 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 888 | ||
| 889 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 890 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 891 | ||
| 892 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 893 | ||
| 894 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 895 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 896 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 897 | ROM_END | |
| 898 | ||
| 899 | ROM_START( snespdsp ) | |
| 900 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 901 | ||
| 902 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 903 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 904 | ||
| 905 | ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 906 | ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) | |
| 907 | ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) | |
| 908 | ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) | |
| 909 | ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) | |
| 910 | ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) | |
| 911 | ||
| 912 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 913 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 914 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 915 | ROM_END | |
| 916 | ||
| 917 | ROM_START( snespsfx ) | |
| 918 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 919 | ||
| 920 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 921 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 922 | ||
| 923 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 924 | ||
| 925 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 926 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 927 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 928 | ROM_END | |
| 929 | ||
| 930 | ROM_START( snesst ) | |
| 931 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 932 | ||
| 933 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 934 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 935 | ||
| 936 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 937 | ||
| 938 | ROM_REGION( 0x40000, "sufami", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 939 | ROM_LOAD( "shvc-qh-0.bin", 0, 0x40000, CRC(9b4ca911) SHA1(ef86ea192eed03d5c413fdbbfd46043be1d7a127) ) | |
| 940 | ||
| 941 | ROM_REGION( MAX_SNES_CART_SIZE, "slot_a", ROMREGION_ERASE00 ) | |
| 942 | ROM_REGION( MAX_SNES_CART_SIZE, "slot_b", ROMREGION_ERASE00 ) | |
| 943 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 944 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 945 | ROM_END | |
| 946 | ||
| 947 | ROM_START( snesbsx ) | |
| 948 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 949 | ||
| 950 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 951 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 952 | ||
| 953 | ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 954 | ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) | |
| 955 | ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) | |
| 956 | ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) | |
| 957 | ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) | |
| 958 | ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) | |
| 959 | ||
| 960 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 961 | ROM_REGION( MAX_SNES_CART_SIZE, "flash", ROMREGION_ERASE00 ) | |
| 962 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 963 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 964 | ROM_END | |
| 965 | ||
| 966 | ||
| 967 | ||
| 968 | /************************************* | |
| 969 | * | |
| 970 | * Game driver(s) | |
| 971 | * | |
| 972 | *************************************/ | |
| 973 | ||
| 974 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 975 | CONS( 1989, snes, 0, 0, snes, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 976 | CONS( 1991, snespal, snes, 0, snespal, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 977 | ||
| 978 | // FIXME: the "hacked" drivers below, currently needed due to limitations in the core device design, should eventually be removed | |
| 979 | ||
| 980 | // These would require CPU to be added/removed depending on the cart which is loaded | |
| 981 | CONS( 1989, snesdsp, snes, 0, snesdsp, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/DSP-x)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 982 | CONS( 1991, snespdsp, snes, 0, snespdsp, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/DSP-x)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 983 | CONS( 1989, snessfx, snes, 0, snessfx, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/SuperFX)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 984 | CONS( 1991, snespsfx, snes, 0, snespsfx, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/SuperFX)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 985 | CONS( 1989, snesst10, snes, 0, snesst10, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/ST-010)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 986 | CONS( 1989, snesst11, snes, 0, snesst11, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/ST-011)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 987 | //CONS( 1989, snessa1, snes, 0, snessa1, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/SA-1)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 988 | //CONS( 1991, snespsa1, snes, 0, snespsa1, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/SA-1)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 989 | ||
| 990 | // These would require cartslot to be added/removed depending on the cart which is loaded | |
| 991 | CONS( 1989, snesst, snes, 0, snesst, snes, snesst, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/Sufami Turbo)", GAME_NOT_WORKING ) | |
| 992 | CONS( 1989, snesbsx, snes, 0, snesbsx, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/BS-X Satellaview slotted cart)", GAME_NOT_WORKING ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Commodore Amiga 3000 | |
| 4 | ||
| 5 | Skeleton driver | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "cpu/m68000/m68000.h" | |
| 11 | ||
| 12 | ||
| 13 | class a3000_state : public driver_device | |
| 14 | { | |
| 15 | public: | |
| 16 | a3000_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 17 | : driver_device(mconfig, type, tag) { } | |
| 18 | ||
| 19 | }; | |
| 20 | ||
| 21 | ||
| 22 | ||
| 23 | /*************************************************************************** | |
| 24 | CONSTANTS | |
| 25 | ***************************************************************************/ | |
| 26 | ||
| 27 | #define XTAL_U104 XTAL_32MHz | |
| 28 | ||
| 29 | ||
| 30 | /*************************************************************************** | |
| 31 | ADDRESS MAPS | |
| 32 | ***************************************************************************/ | |
| 33 | ||
| 34 | static ADDRESS_MAP_START( a3000_mem, AS_PROGRAM, 32 ) | |
| 35 | ADDRESS_MAP_UNMAP_HIGH | |
| 36 | AM_RANGE(0x000000, 0x1fffff) AM_RAMBANK("chipram") | |
| 37 | AM_RANGE(0xf80000, 0xffffff) AM_ROM AM_REGION("kickstart", 0) | |
| 38 | ADDRESS_MAP_END | |
| 39 | ||
| 40 | ||
| 41 | /*************************************************************************** | |
| 42 | INPUT PORTS | |
| 43 | ***************************************************************************/ | |
| 44 | ||
| 45 | static INPUT_PORTS_START( a3000 ) | |
| 46 | INPUT_PORTS_END | |
| 47 | ||
| 48 | ||
| 49 | /*************************************************************************** | |
| 50 | MACHINE DRIVERS | |
| 51 | ***************************************************************************/ | |
| 52 | ||
| 53 | static MACHINE_CONFIG_START( a3000, a3000_state ) | |
| 54 | MCFG_CPU_ADD("maincpu", M68030, XTAL_U104 / 2) | |
| 55 | MCFG_CPU_PROGRAM_MAP(a3000_mem) | |
| 56 | ||
| 57 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 58 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 59 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 60 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 61 | MCFG_SCREEN_SIZE(512*2, 312) | |
| 62 | MCFG_SCREEN_VISIBLE_AREA((129-8-8)*2, (449+8-1+8)*2, 44-8, 300+8-1) | |
| 63 | MACHINE_CONFIG_END | |
| 64 | ||
| 65 | ||
| 66 | /*************************************************************************** | |
| 67 | ROM DEFINITIONS | |
| 68 | ***************************************************************************/ | |
| 69 | ||
| 70 | /* Note: I think those ROMs are correct, but they should be verified */ | |
| 71 | ROM_START( a3000 ) | |
| 72 | ROM_REGION32_BE(0x80000, "kickstart", 0) | |
| 73 | ROM_DEFAULT_BIOS("kick14") | |
| 74 | ROM_SYSTEM_BIOS(0, "kick14", "Kickstart 1.4 (36.16)") | |
| 75 | /* COPYRIGHT 1990 CAI // ALL RIGHTS RESERVED // ALPHA 5 ROM 0 CS=9713 */ | |
| 76 | ROMX_LOAD("390629-02.u182", 0x00000, 0x40000, CRC(58327536) SHA1(d1713d7f31474a5948e6d488e33686061cf3d1e2), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 77 | /* COPYRIGHT 1990 CAI // ALL RIGHTS RESERVED // ALPHA 5 ROM 1 CS=9B21 */ | |
| 78 | ROMX_LOAD("390630-02.u183", 0x00002, 0x40000, CRC(fe2f7fb9) SHA1(c05c9c52d014c66f9019152b3f2a2adc2c678794), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 79 | ROM_SYSTEM_BIOS(1, "kick204", "Kickstart 2.04 (37.175)") | |
| 80 | ROMX_LOAD("390629-03.u182", 0x00000, 0x40000, CRC(a245dbdf) SHA1(83bab8e95d378b55b0c6ae6561385a96f638598f), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) | |
| 81 | ROMX_LOAD("390630-03.u183", 0x00002, 0x40000, CRC(7db1332b) SHA1(48f14b31279da6757848df6feb5318818f8f576c), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) | |
| 82 | ROM_SYSTEM_BIOS(2, "kick31", "Kickstart 3.1 (40.68)") | |
| 83 | ROMX_LOAD("kick31.u182", 0x00000, 0x40000, CRC(286b9a0d) SHA1(6763a2258ec493f7408cf663110dae9a17803ad1), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(3)) | |
| 84 | ROMX_LOAD("kick31.u183", 0x00002, 0x40000, CRC(0b8cde6a) SHA1(5f02e97b48ebbba87d516a56b0400c6fc3434d8d), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(3)) | |
| 85 | ROM_END | |
| 86 | ||
| 87 | ||
| 88 | /*************************************************************************** | |
| 89 | GAME DRIVERS | |
| 90 | ***************************************************************************/ | |
| 91 | ||
| 92 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 93 | COMP( 1990, a3000, 0, 0, a3000, a3000, 0, "Commodore Business Machines", "Amiga 3000", GAME_NOT_WORKING | GAME_NO_SOUND ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /****************************************************************************** | |
| 2 | Atari 400/800 | |
| 3 | ||
| 4 | MESS Driver | |
| 5 | ||
| 6 | Juergen Buchmueller, June 1998 | |
| 7 | ||
| 8 | 2009-05 FP changes: | |
| 9 | Factored out MESS specific code from MAME | |
| 10 | Added skeleton support for other XL/XE machines (VERY preliminary): | |
| 11 | - a600xl based on maxaflex emulation in MAME | |
| 12 | - a1200xl sharing a800xl code without BASIC | |
| 13 | - a65xe, a65xea, a130xe, a800xe, xegs sharing a800xl code (and this is wrong | |
| 14 | at least for xegs) | |
| 15 | Added proper dumps and labels, thanks to Freddy Offenga researches (a few | |
| 16 | are still marked BAD_DUMP while waiting for crc confirmation, since they | |
| 17 | have been obtained by splitting whole dumps) | |
| 18 | ||
| 19 | To Do: | |
| 20 | - Find out why a600xl and a800xl don't work (xe machines should then follow) | |
| 21 | - Investigate supported RAM sizes and OS versions in different models | |
| 22 | - Implement differences between various models (currently most of the | |
| 23 | XL/XE are exactly an a800xl, but this will change as soon as emulation | |
| 24 | starts to work) | |
| 25 | - Fix various keyboard differences | |
| 26 | - Freddy emulation for 800XLF? | |
| 27 | - Add support for proto boards and expansions (a1400xl, C/PM board, etc.) | |
| 28 | - Clean up the whole driver + cart + floppy structure | |
| 29 | ||
| 30 | ******************************************************************************/ | |
| 31 | ||
| 32 | #include "emu.h" | |
| 33 | #include "deprecat.h" | |
| 34 | #include "cpu/m6502/m6502.h" | |
| 35 | #include "includes/atari.h" | |
| 36 | #include "machine/ataridev.h" | |
| 37 | #include "imagedev/cartslot.h" | |
| 38 | #include "sound/pokey.h" | |
| 39 | #include "machine/6821pia.h" | |
| 40 | #include "video/gtia.h" | |
| 41 | #include "sound/dac.h" | |
| 42 | #include "machine/ram.h" | |
| 43 | ||
| 44 | /****************************************************************************** | |
| 45 | Atari 800 memory map (preliminary) | |
| 46 | ||
| 47 | ***************** read access ******************* | |
| 48 | range short description | |
| 49 | 0000-9FFF RAM main memory | |
| 50 | A000-BFFF RAM/ROM RAM or (banked) ROM cartridges | |
| 51 | C000-CFFF ROM unused or monitor ROM | |
| 52 | ||
| 53 | ********* GTIA ******************************** | |
| 54 | ||
| 55 | D000 m0pf missile 0 playfield collisions | |
| 56 | D001 m1pf missile 1 playfield collisions | |
| 57 | D002 m2pf missile 2 playfield collisions | |
| 58 | D003 m3pf missile 3 playfield collisions | |
| 59 | D004 p0pf player 0 playfield collisions | |
| 60 | D005 p1pf player 1 playfield collisions | |
| 61 | D006 p2pf player 2 playfield collisions | |
| 62 | D007 p3pf player 3 playfield collisions | |
| 63 | D008 m0pl missile 0 player collisions | |
| 64 | D009 m1pl missile 1 player collisions | |
| 65 | D00A m2pl missile 2 player collisions | |
| 66 | D00B m3pl missile 3 player collisions | |
| 67 | D00C p0pl player 0 player collisions | |
| 68 | D00D p1pl player 1 player collisions | |
| 69 | D00E p2pl player 2 player collisions | |
| 70 | D00F p3pl player 3 player collisions | |
| 71 | D010 but0 button stick 0 | |
| 72 | D011 but1 button stick 1 | |
| 73 | D012 but2 button stick 2 | |
| 74 | D013 but3 button stick 3 | |
| 75 | D014 xff unused | |
| 76 | D015 xff unused | |
| 77 | D016 xff unused | |
| 78 | D017 xff unused | |
| 79 | D018 xff unused | |
| 80 | D019 xff unused | |
| 81 | D01A xff unused | |
| 82 | D01B xff unused | |
| 83 | D01C xff unused | |
| 84 | D01D xff unused | |
| 85 | D01E xff unused | |
| 86 | D01F cons console keys | |
| 87 | D020-D0FF repeated 7 times | |
| 88 | ||
| 89 | D100-D1FF xff | |
| 90 | ||
| 91 | ********* POKEY ******************************** | |
| 92 | D200 pot0 paddle 0 | |
| 93 | D201 pot1 paddle 1 | |
| 94 | D202 pot2 paddle 2 | |
| 95 | D203 pot3 paddle 3 | |
| 96 | D204 pot4 paddle 4 | |
| 97 | D205 pot5 paddle 5 | |
| 98 | D206 pot6 paddle 6 | |
| 99 | D207 pot7 paddle 7 | |
| 100 | D208 potb all paddles | |
| 101 | D209 kbcode keyboard scan code | |
| 102 | D20A random random number generator | |
| 103 | D20B xff unused | |
| 104 | D20C xff unused | |
| 105 | D20D serin serial input | |
| 106 | D20E irqst IRQ status | |
| 107 | D20F skstat sk status | |
| 108 | D210-D2FF repeated 15 times | |
| 109 | ||
| 110 | ********* PIO ******************************** | |
| 111 | D300 porta read pio port A | |
| 112 | D301 portb read pio port B | |
| 113 | D302 pactl read pio port A control | |
| 114 | D303 pbctl read pio port B control | |
| 115 | D304-D3FF repeated 63 times | |
| 116 | ||
| 117 | ********* ANTIC ******************************** | |
| 118 | D400 xff unused | |
| 119 | D401 xff unused | |
| 120 | D402 xff unused | |
| 121 | D403 xff unused | |
| 122 | D404 xff unused | |
| 123 | D405 xff unused | |
| 124 | D406 xff unused | |
| 125 | D407 xff unused | |
| 126 | D408 xff unused | |
| 127 | D409 xff unused | |
| 128 | D40A xff unused | |
| 129 | D40B vcount vertical (scanline) counter | |
| 130 | D40C penh light pen horizontal pos | |
| 131 | D40D penv light pen vertical pos | |
| 132 | D40E xff unused | |
| 133 | D40F nmist NMI status | |
| 134 | ||
| 135 | D500-D7FF xff unused memory | |
| 136 | ||
| 137 | D800-DFFF ROM floating point ROM | |
| 138 | E000-FFFF ROM bios ROM | |
| 139 | ||
| 140 | ***************** write access ******************* | |
| 141 | range short description | |
| 142 | 0000-9FFF RAM main memory | |
| 143 | A000-BFFF RAM/ROM RAM or (banked) ROM | |
| 144 | C000-CFFF ROM unused or monitor ROM | |
| 145 | ||
| 146 | ********* GTIA ******************************** | |
| 147 | D000 hposp0 player 0 horz position | |
| 148 | D001 hposp1 player 1 horz position | |
| 149 | D002 hposp2 player 2 horz position | |
| 150 | D003 hposp3 player 3 horz position | |
| 151 | D004 hposm0 missile 0 horz position | |
| 152 | D005 hposm1 missile 0 horz position | |
| 153 | D006 hposm2 missile 0 horz position | |
| 154 | D007 hposm3 missile 0 horz position | |
| 155 | D008 sizep0 size player 0 | |
| 156 | D009 sizep1 size player 0 | |
| 157 | D00A sizep2 size player 0 | |
| 158 | D00B sizep3 size player 0 | |
| 159 | D00C sizem size missiles | |
| 160 | D00D grafp0 graphics data for player 0 | |
| 161 | D00E grafp1 graphics data for player 1 | |
| 162 | D00F grafp2 graphics data for player 2 | |
| 163 | D010 grafp3 graphics data for player 3 | |
| 164 | D011 grafm graphics data for missiles | |
| 165 | D012 colpm0 color for player/missile 0 | |
| 166 | D013 colpm1 color for player/missile 1 | |
| 167 | D014 colpm2 color for player/missile 2 | |
| 168 | D015 colpm3 color for player/missile 3 | |
| 169 | D016 colpf0 color 0 playfield | |
| 170 | D017 colpf1 color 1 playfield | |
| 171 | D018 colpf2 color 2 playfield | |
| 172 | D019 colpf3 color 3 playfield | |
| 173 | D01A colbk background playfield | |
| 174 | D01B prior priority select | |
| 175 | D01C vdelay delay until vertical retrace | |
| 176 | D01D gractl graphics control | |
| 177 | D01E hitclr clear collisions | |
| 178 | D01F wcons write console (speaker) | |
| 179 | D020-D0FF repeated 7 times | |
| 180 | ||
| 181 | D100-D1FF xff unused | |
| 182 | ||
| 183 | ********* POKEY ******************************** | |
| 184 | D200 audf1 frequency audio chan #1 | |
| 185 | D201 audc1 control audio chan #1 | |
| 186 | D202 audf2 frequency audio chan #2 | |
| 187 | D203 audc2 control audio chan #2 | |
| 188 | D204 audf3 frequency audio chan #3 | |
| 189 | D205 audc3 control audio chan #3 | |
| 190 | D206 audf4 frequency audio chan #4 | |
| 191 | D207 audc4 control audio chan #4 | |
| 192 | D208 audctl audio control | |
| 193 | D209 stimer start timer | |
| 194 | D20A skres sk reset | |
| 195 | D20B potgo start pot AD conversion | |
| 196 | D20C xff unused | |
| 197 | D20D serout serial output | |
| 198 | D20E irqen IRQ enable | |
| 199 | D20F skctl sk control | |
| 200 | D210-D2FF repeated 15 times | |
| 201 | ||
| 202 | ********* PIO ******************************** | |
| 203 | D300 porta write pio port A (output or mask) | |
| 204 | D301 portb write pio port B (output or mask) | |
| 205 | D302 pactl write pio port A control | |
| 206 | D303 pbctl write pio port B control | |
| 207 | D304-D3FF repeated | |
| 208 | ||
| 209 | ********* ANTIC ******************************** | |
| 210 | D400 dmactl write DMA control | |
| 211 | D401 chactl write character control | |
| 212 | D402 dlistl write display list lo | |
| 213 | D403 dlisth write display list hi | |
| 214 | D404 hscrol write horz scroll | |
| 215 | D405 vscrol write vert scroll | |
| 216 | D406 xff unused | |
| 217 | D407 pmbash player/missile base addr hi | |
| 218 | D408 xff unused | |
| 219 | D409 chbash character generator base addr hi | |
| 220 | D40A wsync wait for hsync | |
| 221 | D40B xff unused | |
| 222 | D40C xff unused | |
| 223 | D40D xff unused | |
| 224 | D40E nmien NMI enable | |
| 225 | D40F nmires NMI reset | |
| 226 | ||
| 227 | D500-D7FF xff unused memory | |
| 228 | ||
| 229 | D800-DFFF ROM floating point ROM | |
| 230 | E000-FFFF ROM BIOS ROM | |
| 231 | ******************************************************************************/ | |
| 232 | ||
| 233 | /************************************************************** | |
| 234 | * | |
| 235 | * Memory maps | |
| 236 | * | |
| 237 | **************************************************************/ | |
| 238 | ||
| 239 | ||
| 240 | static ADDRESS_MAP_START(a400_mem, AS_PROGRAM, 8) | |
| 241 | AM_RANGE(0x0000, 0x9fff) AM_NOP /* RAM installed at runtime */ | |
| 242 | AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("a000") | |
| 243 | AM_RANGE(0xc000, 0xcfff) AM_ROM | |
| 244 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 245 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 246 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 247 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 248 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 249 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 250 | AM_RANGE(0xd800, 0xffff) AM_ROM | |
| 251 | ADDRESS_MAP_END | |
| 252 | ||
| 253 | ||
| 254 | static ADDRESS_MAP_START(a800_mem, AS_PROGRAM, 8) | |
| 255 | AM_RANGE(0x0000, 0x7fff) AM_RAMBANK("0000") | |
| 256 | AM_RANGE(0x8000, 0x9fff) AM_RAMBANK("8000") | |
| 257 | AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("a000") | |
| 258 | AM_RANGE(0xc000, 0xcfff) AM_ROM | |
| 259 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 260 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 261 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 262 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 263 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 264 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 265 | AM_RANGE(0xd800, 0xffff) AM_ROM | |
| 266 | ADDRESS_MAP_END | |
| 267 | ||
| 268 | ||
| 269 | static ADDRESS_MAP_START(a600xl_mem, AS_PROGRAM, 8) | |
| 270 | AM_RANGE(0x0000, 0x3fff) AM_RAM | |
| 271 | AM_RANGE(0x5000, 0x57ff) AM_ROM AM_REGION("maincpu", 0x5000) /* self test */ | |
| 272 | AM_RANGE(0xa000, 0xbfff) AM_ROM /* BASIC */ | |
| 273 | AM_RANGE(0xc000, 0xcfff) AM_ROM /* OS */ | |
| 274 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 275 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 276 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 277 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 278 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 279 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 280 | AM_RANGE(0xd800, 0xffff) AM_ROM /* OS */ | |
| 281 | ADDRESS_MAP_END | |
| 282 | ||
| 283 | ||
| 284 | static ADDRESS_MAP_START(a800xl_mem, AS_PROGRAM, 8) | |
| 285 | AM_RANGE(0x0000, 0x4fff) AM_RAM | |
| 286 | AM_RANGE(0x5000, 0x57ff) AM_RAMBANK("bank2") | |
| 287 | AM_RANGE(0x5800, 0x9fff) AM_RAM | |
| 288 | AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("bank1") | |
| 289 | AM_RANGE(0xc000, 0xcfff) AM_RAMBANK("bank3") | |
| 290 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 291 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 292 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 293 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 294 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 295 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 296 | AM_RANGE(0xd800, 0xffff) AM_RAMBANK("bank4") | |
| 297 | ADDRESS_MAP_END | |
| 298 | ||
| 299 | static ADDRESS_MAP_START(xegs_mem, AS_PROGRAM, 8) | |
| 300 | AM_RANGE(0x0000, 0x4fff) AM_RAM | |
| 301 | AM_RANGE(0x5000, 0x57ff) AM_RAMBANK("bank2") | |
| 302 | AM_RANGE(0x5800, 0x7fff) AM_RAM | |
| 303 | AM_RANGE(0x8000, 0x9fff) AM_ROMBANK("bank0") | |
| 304 | AM_RANGE(0xa000, 0xbfff) AM_ROMBANK("bank1") | |
| 305 | AM_RANGE(0xc000, 0xcfff) AM_RAMBANK("bank3") | |
| 306 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 307 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 308 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 309 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 310 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 311 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 312 | AM_RANGE(0xd800, 0xffff) AM_RAMBANK("bank4") | |
| 313 | ADDRESS_MAP_END | |
| 314 | ||
| 315 | ||
| 316 | static ADDRESS_MAP_START(a5200_mem, AS_PROGRAM, 8) | |
| 317 | AM_RANGE(0x0000, 0x3fff) AM_RAM | |
| 318 | AM_RANGE(0x4000, 0xbfff) AM_ROM | |
| 319 | AM_RANGE(0xc000, 0xc0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 320 | AM_RANGE(0xd400, 0xd5ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 321 | AM_RANGE(0xe800, 0xe8ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 322 | AM_RANGE(0xf800, 0xffff) AM_ROM | |
| 323 | ADDRESS_MAP_END | |
| 324 | ||
| 325 | ||
| 326 | #ifdef MESS | |
| 327 | int atari_input_disabled(running_machine &machine) | |
| 328 | { | |
| 329 | return 0; | |
| 330 | } | |
| 331 | #endif | |
| 332 | ||
| 333 | /************************************************************** | |
| 334 | * | |
| 335 | * Input ports | |
| 336 | * | |
| 337 | **************************************************************/ | |
| 338 | ||
| 339 | ||
| 340 | #define JOYSTICK_DELTA 10 | |
| 341 | #define JOYSTICK_SENSITIVITY 200 | |
| 342 | ||
| 343 | static INPUT_PORTS_START( atari_artifacting ) | |
| 344 | PORT_START("artifacts") | |
| 345 | PORT_CONFNAME(0x40, 0x00, "Television Artifacts" ) | |
| 346 | PORT_CONFSETTING(0x00, DEF_STR( Off ) ) | |
| 347 | PORT_CONFSETTING(0x40, DEF_STR( On ) ) | |
| 348 | INPUT_PORTS_END | |
| 349 | ||
| 350 | ||
| 351 | ||
| 352 | static INPUT_PORTS_START( atari_console ) | |
| 353 | PORT_START("console") | |
| 354 | PORT_BIT(0x04, 0x04, IPT_KEYBOARD) PORT_NAME("CONS.2: Option") PORT_CODE(KEYCODE_F3) | |
| 355 | PORT_BIT(0x02, 0x02, IPT_KEYBOARD) PORT_NAME("CONS.1: Select") PORT_CODE(KEYCODE_F2) | |
| 356 | PORT_BIT(0x01, 0x01, IPT_KEYBOARD) PORT_NAME("CONS.0: Start") PORT_CODE(KEYCODE_F1) | |
| 357 | INPUT_PORTS_END | |
| 358 | ||
| 359 | ||
| 360 | ||
| 361 | static INPUT_PORTS_START( atari_digital_joystick2 ) | |
| 362 | PORT_START("djoy_0_1") /* IN1 digital joystick #1 + #2 (PIA port A) */ | |
| 363 | PORT_BIT(0x01, 0x01, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(1) | |
| 364 | PORT_BIT(0x02, 0x02, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(1) | |
| 365 | PORT_BIT(0x04, 0x04, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(1) | |
| 366 | PORT_BIT(0x08, 0x08, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(1) | |
| 367 | PORT_BIT(0x10, 0x10, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(2) | |
| 368 | PORT_BIT(0x20, 0x20, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) | |
| 369 | PORT_BIT(0x40, 0x40, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(2) | |
| 370 | PORT_BIT(0x80, 0x80, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) | |
| 371 | ||
| 372 | PORT_START("djoy_2_3") /* IN2 digital joystick #3 + #4 (PIA port B) */ | |
| 373 | PORT_BIT(0x01, 0x01, IPT_UNUSED) | |
| 374 | PORT_BIT(0x02, 0x02, IPT_UNUSED) | |
| 375 | PORT_BIT(0x04, 0x04, IPT_UNUSED) | |
| 376 | PORT_BIT(0x08, 0x08, IPT_UNUSED) | |
| 377 | PORT_BIT(0x10, 0x10, IPT_UNUSED) | |
| 378 | PORT_BIT(0x20, 0x20, IPT_UNUSED) | |
| 379 | PORT_BIT(0x40, 0x40, IPT_UNUSED) | |
| 380 | PORT_BIT(0x80, 0x80, IPT_UNUSED) | |
| 381 | ||
| 382 | PORT_START("djoy_b") /* IN3 digital joystick buttons (GTIA button bits) */ | |
| 383 | PORT_BIT(0x01, 0x01, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 384 | PORT_BIT(0x02, 0x02, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 385 | PORT_BIT(0x04, 0x04, IPT_UNUSED) | |
| 386 | PORT_BIT(0x08, 0x08, IPT_UNUSED) | |
| 387 | PORT_BIT(0x10, 0x10, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 388 | PORT_BIT(0x20, 0x20, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 389 | PORT_BIT(0x40, 0x40, IPT_UNUSED) | |
| 390 | PORT_BIT(0x80, 0x80, IPT_UNUSED) | |
| 391 | INPUT_PORTS_END | |
| 392 | ||
| 393 | ||
| 394 | ||
| 395 | static INPUT_PORTS_START( atari_digital_joystick4 ) | |
| 396 | PORT_START("djoy_0_1") /* digital joystick #1 + #2 (PIA port A) */ | |
| 397 | PORT_BIT(0x01, 0x01, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(1) | |
| 398 | PORT_BIT(0x02, 0x02, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(1) | |
| 399 | PORT_BIT(0x04, 0x04, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(1) | |
| 400 | PORT_BIT(0x08, 0x08, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(1) | |
| 401 | PORT_BIT(0x10, 0x10, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(2) | |
| 402 | PORT_BIT(0x20, 0x20, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) | |
| 403 | PORT_BIT(0x40, 0x40, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(2) | |
| 404 | PORT_BIT(0x80, 0x80, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) | |
| 405 | ||
| 406 | PORT_START("djoy_2_3") /* digital joystick #3 + #4 (PIA port B) */ | |
| 407 | PORT_BIT(0x01, 0x01, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(3) | |
| 408 | PORT_BIT(0x02, 0x02, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(3) | |
| 409 | PORT_BIT(0x04, 0x04, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(3) | |
| 410 | PORT_BIT(0x08, 0x08, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(3) | |
| 411 | PORT_BIT(0x10, 0x10, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(4) | |
| 412 | PORT_BIT(0x20, 0x20, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(4) | |
| 413 | PORT_BIT(0x40, 0x40, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(4) | |
| 414 | PORT_BIT(0x80, 0x80, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(4) | |
| 415 | ||
| 416 | PORT_START("djoy_b") /* digital joystick buttons (GTIA button bits) */ | |
| 417 | PORT_BIT(0x01, 0x01, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 418 | PORT_BIT(0x02, 0x02, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 419 | PORT_BIT(0x04, 0x04, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON3) PORT_PLAYER(3) | |
| 420 | PORT_BIT(0x08, 0x08, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON4) PORT_PLAYER(4) | |
| 421 | PORT_BIT(0x10, 0x10, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 422 | PORT_BIT(0x20, 0x20, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 423 | PORT_BIT(0x40, 0x40, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON3) PORT_PLAYER(3) | |
| 424 | PORT_BIT(0x80, 0x80, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON4) PORT_PLAYER(4) | |
| 425 | INPUT_PORTS_END | |
| 426 | ||
| 427 | ||
| 428 | ||
| 429 | /* 2009-04 FP: | |
| 430 | Small note about natural keyboard support: currently, | |
| 431 | - "Break" is mapped to 'F1' | |
| 432 | - "Clear" is mapped to 'F2' | |
| 433 | - "Atari" is mapped to 'F3' */ | |
| 434 | ||
| 435 | static INPUT_PORTS_START( atari_keyboard ) | |
| 436 | PORT_START("keyboard_0") | |
| 437 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') | |
| 438 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') | |
| 439 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') | |
| 440 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(F1)) | |
| 441 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 442 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') | |
| 443 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('+') PORT_CHAR('\\') | |
| 444 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*') PORT_CHAR('^') | |
| 445 | ||
| 446 | PORT_START("keyboard_1") | |
| 447 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') | |
| 448 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) // None! | |
| 449 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') | |
| 450 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') | |
| 451 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) | |
| 452 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') | |
| 453 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('-') PORT_CHAR('_') | |
| 454 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('=') PORT_CHAR('|') | |
| 455 | ||
| 456 | PORT_START("keyboard_2") | |
| 457 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') | |
| 458 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 459 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') | |
| 460 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 461 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 462 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') | |
| 463 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') | |
| 464 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') | |
| 465 | ||
| 466 | PORT_START("keyboard_3") | |
| 467 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') | |
| 468 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 469 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') | |
| 470 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') | |
| 471 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Escape") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) | |
| 472 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') | |
| 473 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('\"') | |
| 474 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') | |
| 475 | ||
| 476 | PORT_START("keyboard_4") | |
| 477 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('[') | |
| 478 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') | |
| 479 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(']') | |
| 480 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') | |
| 481 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 482 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') | |
| 483 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') | |
| 484 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Atari") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(F3)) | |
| 485 | ||
| 486 | PORT_START("keyboard_5") | |
| 487 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') | |
| 488 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 489 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') | |
| 490 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') | |
| 491 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) | |
| 492 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') | |
| 493 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') | |
| 494 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') | |
| 495 | ||
| 496 | PORT_START("keyboard_6") | |
| 497 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') | |
| 498 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 499 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') | |
| 500 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') | |
| 501 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("BackS Delete") PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(DEL)) | |
| 502 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('@') | |
| 503 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("< Clear") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('<') PORT_CHAR(UCHAR_MAMEKEY(F2)) | |
| 504 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("> Insert") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('>') PORT_CHAR(UCHAR_MAMEKEY(INSERT)) | |
| 505 | ||
| 506 | PORT_START("keyboard_7") | |
| 507 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') | |
| 508 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') | |
| 509 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') | |
| 510 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 511 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) | |
| 512 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') | |
| 513 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') | |
| 514 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') | |
| 515 | ||
| 516 | PORT_START("fake") | |
| 517 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) | |
| 518 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) | |
| 519 | INPUT_PORTS_END | |
| 520 | ||
| 521 | ||
| 522 | static INPUT_PORTS_START( atari_analog_paddles ) | |
| 523 | PORT_START("analog_0") /* IN8 analog in #1 */ | |
| 524 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) PORT_REVERSE | |
| 525 | ||
| 526 | PORT_START("analog_1") /* IN9 analog in #2 */ | |
| 527 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) PORT_REVERSE | |
| 528 | ||
| 529 | PORT_START("analog_2") /* IN10 analog in #3 */ | |
| 530 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(3) PORT_REVERSE | |
| 531 | ||
| 532 | PORT_START("analog_3") /* IN11 analog in #4 */ | |
| 533 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(4) PORT_REVERSE | |
| 534 | ||
| 535 | PORT_START("analog_4") /* IN12 analog in #5 */ | |
| 536 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(5) */ | |
| 537 | ||
| 538 | PORT_START("analog_5") /* IN13 analog in #6 */ | |
| 539 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(6) */ | |
| 540 | ||
| 541 | PORT_START("analog_6") /* IN14 analog in #7 */ | |
| 542 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(7) */ | |
| 543 | ||
| 544 | PORT_START("analog_7") /* IN15 analog in #8 */ | |
| 545 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(8) */ | |
| 546 | INPUT_PORTS_END | |
| 547 | ||
| 548 | ||
| 549 | ||
| 550 | static INPUT_PORTS_START( a800 ) | |
| 551 | PORT_INCLUDE( atari_artifacting ) | |
| 552 | PORT_INCLUDE( atari_console ) | |
| 553 | PORT_INCLUDE( atari_digital_joystick4 ) | |
| 554 | PORT_INCLUDE( atari_keyboard ) | |
| 555 | PORT_INCLUDE( atari_analog_paddles ) | |
| 556 | INPUT_PORTS_END | |
| 557 | ||
| 558 | ||
| 559 | ||
| 560 | static INPUT_PORTS_START( a800xl ) | |
| 561 | PORT_INCLUDE( atari_artifacting ) | |
| 562 | PORT_INCLUDE( atari_console ) | |
| 563 | PORT_INCLUDE( atari_digital_joystick2 ) | |
| 564 | PORT_INCLUDE( atari_keyboard ) | |
| 565 | PORT_INCLUDE( atari_analog_paddles ) | |
| 566 | INPUT_PORTS_END | |
| 567 | ||
| 568 | ||
| 569 | ||
| 570 | static INPUT_PORTS_START( a5200 ) | |
| 571 | PORT_INCLUDE( atari_artifacting ) | |
| 572 | ||
| 573 | PORT_START("djoy_b") /* lower/upper buttons */ | |
| 574 | PORT_BIT(0x01, 0x01, IPT_BUTTON1) PORT_PLAYER(1) | |
| 575 | PORT_BIT(0x02, 0x02, IPT_BUTTON1) PORT_PLAYER(2) | |
| 576 | PORT_BIT(0x04, 0x04, IPT_BUTTON1) PORT_PLAYER(3) | |
| 577 | PORT_BIT(0x08, 0x08, IPT_BUTTON1) PORT_PLAYER(4) | |
| 578 | PORT_BIT(0x10, 0x10, IPT_BUTTON2) PORT_PLAYER(1) | |
| 579 | PORT_BIT(0x20, 0x20, IPT_BUTTON2) PORT_PLAYER(2) | |
| 580 | PORT_BIT(0x40, 0x40, IPT_BUTTON2) PORT_PLAYER(3) | |
| 581 | PORT_BIT(0x80, 0x80, IPT_BUTTON2) PORT_PLAYER(4) | |
| 582 | ||
| 583 | PORT_START("keypad_0") | |
| 584 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("(Break)") PORT_CODE(KEYCODE_PAUSE) // is this correct? | |
| 585 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[#]") PORT_CODE(KEYCODE_ENTER_PAD) | |
| 586 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[0]") PORT_CODE(KEYCODE_0_PAD) | |
| 587 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[*]") PORT_CODE(KEYCODE_PLUS_PAD) | |
| 588 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 589 | ||
| 590 | PORT_START("keypad_1") | |
| 591 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F3) | |
| 592 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[9]") PORT_CODE(KEYCODE_9_PAD) | |
| 593 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[8]") PORT_CODE(KEYCODE_8_PAD) | |
| 594 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[7]") PORT_CODE(KEYCODE_7_PAD) | |
| 595 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 596 | ||
| 597 | PORT_START("keypad_2") | |
| 598 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(DEF_STR(Pause)) PORT_CODE(KEYCODE_F2) | |
| 599 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[6]") PORT_CODE(KEYCODE_6_PAD) | |
| 600 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[5]") PORT_CODE(KEYCODE_5_PAD) | |
| 601 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[4]") PORT_CODE(KEYCODE_4_PAD) | |
| 602 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 603 | ||
| 604 | PORT_START("keypad_3") | |
| 605 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_START) PORT_NAME("Start") | |
| 606 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[3]") PORT_CODE(KEYCODE_3_PAD) | |
| 607 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[2]") PORT_CODE(KEYCODE_2_PAD) | |
| 608 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[1]") PORT_CODE(KEYCODE_1_PAD) | |
| 609 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 610 | ||
| 611 | PORT_START("analog_0") | |
| 612 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) | |
| 613 | ||
| 614 | PORT_START("analog_1") | |
| 615 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) | |
| 616 | ||
| 617 | PORT_START("analog_2") | |
| 618 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) | |
| 619 | ||
| 620 | PORT_START("analog_3") | |
| 621 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) | |
| 622 | ||
| 623 | PORT_START("analog_4") | |
| 624 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(3) | |
| 625 | ||
| 626 | PORT_START("analog_5") | |
| 627 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(3) | |
| 628 | ||
| 629 | PORT_START("analog_6") | |
| 630 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(4) | |
| 631 | ||
| 632 | PORT_START("analog_7") | |
| 633 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(4) | |
| 634 | ||
| 635 | INPUT_PORTS_END | |
| 636 | ||
| 637 | ||
| 638 | /************************************************************** | |
| 639 | * | |
| 640 | * Palette | |
| 641 | * | |
| 642 | **************************************************************/ | |
| 643 | ||
| 644 | static const UINT8 atari_palette[256*3] = | |
| 645 | { | |
| 646 | /* Grey */ | |
| 647 | 0x00,0x00,0x00, 0x25,0x25,0x25, 0x34,0x34,0x34, 0x4e,0x4e,0x4e, | |
| 648 | 0x68,0x68,0x68, 0x75,0x75,0x75, 0x8e,0x8e,0x8e, 0xa4,0xa4,0xa4, | |
| 649 | 0xb8,0xb8,0xb8, 0xc5,0xc5,0xc5, 0xd0,0xd0,0xd0, 0xd7,0xd7,0xd7, | |
| 650 | 0xe1,0xe1,0xe1, 0xea,0xea,0xea, 0xf4,0xf4,0xf4, 0xff,0xff,0xff, | |
| 651 | /* Gold */ | |
| 652 | 0x41,0x20,0x00, 0x54,0x28,0x00, 0x76,0x37,0x00, 0x9a,0x50,0x00, | |
| 653 | 0xc3,0x68,0x06, 0xe4,0x7b,0x07, 0xff,0x91,0x1a, 0xff,0xab,0x1d, | |
| 654 | 0xff,0xc5,0x1f, 0xff,0xd0,0x3b, 0xff,0xd8,0x4c, 0xff,0xe6,0x51, | |
| 655 | 0xff,0xf4,0x56, 0xff,0xf9,0x70, 0xff,0xff,0x90, 0xff,0xff,0xaa, | |
| 656 | /* Orange */ | |
| 657 | 0x45,0x19,0x04, 0x72,0x1e,0x11, 0x9f,0x24,0x1e, 0xb3,0x3a,0x20, | |
| 658 | 0xc8,0x51,0x20, 0xe3,0x69,0x20, 0xfc,0x81,0x20, 0xfd,0x8c,0x25, | |
| 659 | 0xfe,0x98,0x2c, 0xff,0xae,0x38, 0xff,0xb9,0x46, 0xff,0xbf,0x51, | |
| 660 | 0xff,0xc6,0x6d, 0xff,0xd5,0x87, 0xff,0xe4,0x98, 0xff,0xe6,0xab, | |
| 661 | /* Red-Orange */ | |
| 662 | 0x5d,0x1f,0x0c, 0x7a,0x24,0x0d, 0x98,0x2c,0x0e, 0xb0,0x2f,0x0f, | |
| 663 | 0xbf,0x36,0x24, 0xd3,0x4e,0x2a, 0xe7,0x62,0x3e, 0xf3,0x6e,0x4a, | |
| 664 | 0xfd,0x78,0x54, 0xff,0x8a,0x6a, 0xff,0x98,0x7c, 0xff,0xa4,0x8b, | |
| 665 | 0xff,0xb3,0x9e, 0xff,0xc2,0xb2, 0xff,0xd0,0xc3, 0xff,0xda,0xd0, | |
| 666 | /* Pink */ | |
| 667 | 0x4a,0x17,0x00, 0x72,0x1f,0x00, 0xa8,0x13,0x00, 0xc8,0x21,0x0a, | |
| 668 | 0xdf,0x25,0x12, 0xec,0x3b,0x24, 0xfa,0x52,0x36, 0xfc,0x61,0x48, | |
| 669 | 0xff,0x70,0x5f, 0xff,0x7e,0x7e, 0xff,0x8f,0x8f, 0xff,0x9d,0x9e, | |
| 670 | 0xff,0xab,0xad, 0xff,0xb9,0xbd, 0xff,0xc7,0xce, 0xff,0xca,0xde, | |
| 671 | /* Purple */ | |
| 672 | 0x49,0x00,0x36, 0x66,0x00,0x4b, 0x80,0x03,0x5f, 0x95,0x0f,0x74, | |
| 673 | 0xaa,0x22,0x88, 0xba,0x3d,0x99, 0xca,0x4d,0xa9, 0xd7,0x5a,0xb6, | |
| 674 | 0xe4,0x67,0xc3, 0xef,0x72,0xce, 0xfb,0x7e,0xda, 0xff,0x8d,0xe1, | |
| 675 | 0xff,0x9d,0xe5, 0xff,0xa5,0xe7, 0xff,0xaf,0xea, 0xff,0xb8,0xec, | |
| 676 | /* Purple-Blue */ | |
| 677 | 0x48,0x03,0x6c, 0x5c,0x04,0x88, 0x65,0x0d,0x90, 0x7b,0x23,0xa7, | |
| 678 | 0x93,0x3b,0xbf, 0x9d,0x45,0xc9, 0xa7,0x4f,0xd3, 0xb2,0x5a,0xde, | |
| 679 | 0xbd,0x65,0xe9, 0xc5,0x6d,0xf1, 0xce,0x76,0xfa, 0xd5,0x83,0xff, | |
| 680 | 0xda,0x90,0xff, 0xde,0x9c,0xff, 0xe2,0xa9,0xff, 0xe6,0xb6,0xff, | |
| 681 | /* Blue 1 */ | |
| 682 | 0x05,0x1e,0x81, 0x06,0x26,0xa5, 0x08,0x2f,0xca, 0x26,0x3d,0xd4, | |
| 683 | 0x44,0x4c,0xde, 0x4f,0x5a,0xec, 0x5a,0x68,0xff, 0x65,0x75,0xff, | |
| 684 | 0x71,0x83,0xff, 0x80,0x91,0xff, 0x90,0xa0,0xff, 0x97,0xa9,0xff, | |
| 685 | 0x9f,0xb2,0xff, 0xaf,0xbe,0xff, 0xc0,0xcb,0xff, 0xcd,0xd3,0xff, | |
| 686 | /* Blue 2 */ | |
| 687 | 0x0b,0x07,0x79, 0x20,0x1c,0x8e, 0x35,0x31,0xa3, 0x46,0x42,0xb4, | |
| 688 | 0x57,0x53,0xc5, 0x61,0x5d,0xcf, 0x6d,0x69,0xdb, 0x7b,0x77,0xe9, | |
| 689 | 0x89,0x85,0xf7, 0x91,0x8d,0xff, 0x9c,0x98,0xff, 0xa7,0xa4,0xff, | |
| 690 | 0xb2,0xaf,0xff, 0xbb,0xb8,0xff, 0xc3,0xc1,0xff, 0xd3,0xd1,0xff, | |
| 691 | /* Light-Blue */ | |
| 692 | 0x1d,0x29,0x5a, 0x1d,0x38,0x76, 0x1d,0x48,0x92, 0x1d,0x5c,0xac, | |
| 693 | 0x1d,0x71,0xc6, 0x32,0x86,0xcf, 0x48,0x9b,0xd9, 0x4e,0xa8,0xec, | |
| 694 | 0x55,0xb6,0xff, 0x69,0xca,0xff, 0x74,0xcb,0xff, 0x82,0xd3,0xff, | |
| 695 | 0x8d,0xda,0xff, 0x9f,0xd4,0xff, 0xb4,0xe2,0xff, 0xc0,0xeb,0xff, | |
| 696 | /* Turquoise */ | |
| 697 | 0x00,0x4b,0x59, 0x00,0x5d,0x6e, 0x00,0x6f,0x84, 0x00,0x84,0x9c, | |
| 698 | 0x00,0x99,0xbf, 0x00,0xab,0xca, 0x00,0xbc,0xde, 0x00,0xd0,0xf5, | |
| 699 | 0x10,0xdc,0xff, 0x3e,0xe1,0xff, 0x64,0xe7,0xff, 0x76,0xea,0xff, | |
| 700 | 0x8b,0xed,0xff, 0x9a,0xef,0xff, 0xb1,0xf3,0xff, 0xc7,0xf6,0xff, | |
| 701 | /* Green-Blue */ | |
| 702 | 0x00,0x48,0x00, 0x00,0x54,0x00, 0x03,0x6b,0x03, 0x0e,0x76,0x0e, | |
| 703 | 0x18,0x80,0x18, 0x27,0x92,0x27, 0x36,0xa4,0x36, 0x4e,0xb9,0x4e, | |
| 704 | 0x51,0xcd,0x51, 0x72,0xda,0x72, 0x7c,0xe4,0x7c, 0x85,0xed,0x85, | |
| 705 | 0x99,0xf2,0x99, 0xb3,0xf7,0xb3, 0xc3,0xf9,0xc3, 0xcd,0xfc,0xcd, | |
| 706 | /* Green */ | |
| 707 | 0x16,0x40,0x00, 0x1c,0x53,0x00, 0x23,0x66,0x00, 0x28,0x78,0x00, | |
| 708 | 0x2e,0x8c,0x00, 0x3a,0x98,0x0c, 0x47,0xa5,0x19, 0x51,0xaf,0x23, | |
| 709 | 0x5c,0xba,0x2e, 0x71,0xcf,0x43, 0x85,0xe3,0x57, 0x8d,0xeb,0x5f, | |
| 710 | 0x97,0xf5,0x69, 0xa0,0xfe,0x72, 0xb1,0xff,0x8a, 0xbc,0xff,0x9a, | |
| 711 | /* Yellow-Green */ | |
| 712 | 0x2c,0x35,0x00, 0x38,0x44,0x00, 0x44,0x52,0x00, 0x49,0x56,0x00, | |
| 713 | 0x60,0x71,0x00, 0x6c,0x7f,0x00, 0x79,0x8d,0x0a, 0x8b,0x9f,0x1c, | |
| 714 | 0x9e,0xb2,0x2f, 0xab,0xbf,0x3c, 0xb8,0xcc,0x49, 0xc2,0xd6,0x53, | |
| 715 | 0xcd,0xe1,0x53, 0xdb,0xef,0x6c, 0xe8,0xfc,0x79, 0xf2,0xff,0xab, | |
| 716 | /* Orange-Green */ | |
| 717 | 0x46,0x3a,0x09, 0x4d,0x3f,0x09, 0x54,0x45,0x09, 0x6c,0x58,0x09, | |
| 718 | 0x90,0x76,0x09, 0xab,0x8b,0x0a, 0xc1,0xa1,0x20, 0xd0,0xb0,0x2f, | |
| 719 | 0xde,0xbe,0x3d, 0xe6,0xc6,0x45, 0xed,0xcd,0x4c, 0xf5,0xd8,0x62, | |
| 720 | 0xfb,0xe2,0x76, 0xfc,0xee,0x98, 0xfd,0xf3,0xa9, 0xfd,0xf3,0xbe, | |
| 721 | /* Light-Orange */ | |
| 722 | 0x40,0x1a,0x02, 0x58,0x1f,0x05, 0x70,0x24,0x08, 0x8d,0x3a,0x13, | |
| 723 | 0xab,0x51,0x1f, 0xb5,0x64,0x27, 0xbf,0x77,0x30, 0xd0,0x85,0x3a, | |
| 724 | 0xe1,0x93,0x44, 0xed,0xa0,0x4e, 0xf9,0xad,0x58, 0xfc,0xb7,0x5c, | |
| 725 | 0xff,0xc1,0x60, 0xff,0xca,0x69, 0xff,0xcf,0x7e, 0xff,0xda,0x96 | |
| 726 | }; | |
| 727 | ||
| 728 | ||
| 729 | /* Initialise the palette */ | |
| 730 | static PALETTE_INIT( mess_atari ) | |
| 731 | { | |
| 732 | int i; | |
| 733 | ||
| 734 | for ( i = 0; i < sizeof(atari_palette) / 3; i++ ) | |
| 735 | { | |
| 736 | palette_set_color_rgb(machine, i, atari_palette[i*3], atari_palette[i*3+1], atari_palette[i*3+2]); | |
| 737 | } | |
| 738 | } | |
| 739 | ||
| 740 | /************************************************************** | |
| 741 | * | |
| 742 | * Memory banking | |
| 743 | * | |
| 744 | **************************************************************/ | |
| 745 | ||
| 746 | static void a800xl_mmu(running_machine &machine, UINT8 new_mmu) | |
| 747 | { | |
| 748 | UINT8 *base = machine.region("maincpu")->base(); | |
| 749 | UINT8 *base1, *base2, *base3, *base4; | |
| 750 | ||
| 751 | /* check if memory C000-FFFF changed */ | |
| 752 | if( new_mmu & 0x01 ) | |
| 753 | { | |
| 754 | logerror("%s MMU BIOS ROM\n", machine.system().name); | |
| 755 | base3 = base + 0x14000; /* 8K lo BIOS */ | |
| 756 | base4 = base + 0x15800; /* 4K FP ROM + 8K hi BIOS */ | |
| 757 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xc000, 0xcfff, "bank3"); | |
| 758 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xc000, 0xcfff); | |
| 759 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xd800, 0xffff, "bank4"); | |
| 760 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xd800, 0xffff); | |
| 761 | } | |
| 762 | else | |
| 763 | { | |
| 764 | logerror("%s MMU BIOS RAM\n", machine.system().name); | |
| 765 | base3 = base + 0x0c000; /* 8K RAM */ | |
| 766 | base4 = base + 0x0d800; /* 4K RAM + 8K RAM */ | |
| 767 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xc000, 0xcfff, "bank3"); | |
| 768 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xd800, 0xffff, "bank4"); | |
| 769 | } | |
| 770 | memory_set_bankptr(machine, "bank3", base3); | |
| 771 | memory_set_bankptr(machine, "bank4", base4); | |
| 772 | ||
| 773 | /* check if BASIC changed */ | |
| 774 | if( new_mmu & 0x02 ) | |
| 775 | { | |
| 776 | logerror("%s MMU BASIC RAM\n", machine.system().name); | |
| 777 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xa000, 0xbfff, "bank1"); | |
| 778 | base1 = base + 0x0a000; /* 8K RAM */ | |
| 779 | } | |
| 780 | else | |
| 781 | { | |
| 782 | logerror("%s MMU BASIC ROM\n", machine.system().name); | |
| 783 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xbfff, "bank1"); | |
| 784 | machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0xa000, 0xbfff); | |
| 785 | base1 = base + 0x10000; /* 8K BASIC */ | |
| 786 | } | |
| 787 | ||
| 788 | memory_set_bankptr(machine, "bank1", base1); | |
| 789 | ||
| 790 | /* check if self-test ROM changed */ | |
| 791 | if( new_mmu & 0x80 ) | |
| 792 | { | |
| 793 | logerror("%s MMU SELFTEST RAM\n", machine.system().name); | |
| 794 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x5000, 0x57ff, "bank2"); | |
| 795 | base2 = base + 0x05000; /* 0x0800 bytes */ | |
| 796 | } | |
| 797 | else | |
| 798 | { | |
| 799 | logerror("%s MMU SELFTEST ROM\n", machine.system().name); | |
| 800 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x5000, 0x57ff, "bank2"); | |
| 801 | machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0x5000, 0x57ff); | |
| 802 | base2 = base + 0x15000; /* 0x0800 bytes */ | |
| 803 | } | |
| 804 | memory_set_bankptr(machine, "bank2", base2); | |
| 805 | } | |
| 806 | ||
| 807 | /* BASIC was available in a separate cart, so we don't test it */ | |
| 808 | static void a1200xl_mmu(running_machine &machine, UINT8 new_mmu) | |
| 809 | { | |
| 810 | UINT8 *base = machine.region("maincpu")->base(); | |
| 811 | UINT8 *base2, *base3, *base4; | |
| 812 | ||
| 813 | /* check if memory C000-FFFF changed */ | |
| 814 | if( new_mmu & 0x01 ) | |
| 815 | { | |
| 816 | logerror("%s MMU BIOS ROM\n", machine.system().name); | |
| 817 | base3 = base + 0x14000; /* 8K lo BIOS */ | |
| 818 | base4 = base + 0x15800; /* 4K FP ROM + 8K hi BIOS */ | |
| 819 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xc000, 0xcfff, "bank3"); | |
| 820 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xc000, 0xcfff); | |
| 821 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xd800, 0xffff, "bank4"); | |
| 822 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xd800, 0xffff); | |
| 823 | } | |
| 824 | else | |
| 825 | { | |
| 826 | logerror("%s MMU BIOS RAM\n", machine.system().name); | |
| 827 | base3 = base + 0x0c000; /* 8K RAM */ | |
| 828 | base4 = base + 0x0d800; /* 4K RAM + 8K RAM */ | |
| 829 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xc000, 0xcfff, "bank3"); | |
| 830 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xd800, 0xffff, "bank4"); | |
| 831 | } | |
| 832 | memory_set_bankptr(machine, "bank3", base3); | |
| 833 | memory_set_bankptr(machine, "bank4", base4); | |
| 834 | ||
| 835 | /* check if self-test ROM changed */ | |
| 836 | if( new_mmu & 0x80 ) | |
| 837 | { | |
| 838 | logerror("%s MMU SELFTEST RAM\n", machine.system().name); | |
| 839 | base2 = base + 0x05000; /* 0x0800 bytes */ | |
| 840 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x5000, 0x57ff, "bank2"); | |
| 841 | } | |
| 842 | else | |
| 843 | { | |
| 844 | logerror("%s MMU SELFTEST ROM\n", machine.system().name); | |
| 845 | base2 = base + 0x15000; /* 0x0800 bytes */ | |
| 846 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x5000, 0x57ff, "bank2"); | |
| 847 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x5000, 0x57ff); | |
| 848 | } | |
| 849 | memory_set_bankptr(machine, "bank2", base2); | |
| 850 | } | |
| 851 | ||
| 852 | static void xegs_mmu(running_machine &machine, UINT8 new_mmu) | |
| 853 | { | |
| 854 | UINT8 *base = machine.region("maincpu")->base(); | |
| 855 | UINT8 *base2, *base3, *base4; | |
| 856 | ||
| 857 | /* check if memory C000-FFFF changed */ | |
| 858 | if( new_mmu & 0x01 ) | |
| 859 | { | |
| 860 | logerror("%s MMU BIOS ROM\n", machine.system().name); | |
| 861 | base3 = base + 0x14000; /* 8K lo BIOS */ | |
| 862 | base4 = base + 0x15800; /* 4K FP ROM + 8K hi BIOS */ | |
| 863 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xc000, 0xcfff, "bank3"); | |
| 864 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xc000, 0xcfff); | |
| 865 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xd800, 0xffff, "bank4"); | |
| 866 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xd800, 0xffff); | |
| 867 | } | |
| 868 | else | |
| 869 | { | |
| 870 | logerror("%s MMU BIOS RAM\n", machine.system().name); | |
| 871 | base3 = base + 0x0c000; /* 8K RAM */ | |
| 872 | base4 = base + 0x0d800; /* 4K RAM + 8K RAM */ | |
| 873 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xc000, 0xcfff, "bank3"); | |
| 874 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xd800, 0xffff, "bank4"); | |
| 875 | } | |
| 876 | memory_set_bankptr(machine, "bank3", base3); | |
| 877 | memory_set_bankptr(machine, "bank4", base4); | |
| 878 | ||
| 879 | ||
| 880 | /* check if self-test ROM changed */ | |
| 881 | if( new_mmu & 0x80 ) | |
| 882 | { | |
| 883 | logerror("%s MMU SELFTEST RAM\n", machine.system().name); | |
| 884 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x5000, 0x57ff, "bank2"); | |
| 885 | base2 = base + 0x05000; /* 0x0800 bytes */ | |
| 886 | } | |
| 887 | else | |
| 888 | { | |
| 889 | logerror("%s MMU SELFTEST ROM\n", machine.system().name); | |
| 890 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x5000, 0x57ff, "bank2"); | |
| 891 | machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0x5000, 0x57ff); | |
| 892 | base2 = base + 0x15000; /* 0x0800 bytes */ | |
| 893 | } | |
| 894 | memory_set_bankptr(machine, "bank2", base2); | |
| 895 | } | |
| 896 | ||
| 897 | /************************************************************** | |
| 898 | * | |
| 899 | * PIA interface | |
| 900 | * | |
| 901 | **************************************************************/ | |
| 902 | ||
| 903 | static WRITE8_DEVICE_HANDLER(a1200xl_pia_pb_w) { a1200xl_mmu(device->machine(), data); } | |
| 904 | static WRITE8_DEVICE_HANDLER(a800xl_pia_pb_w) | |
| 905 | { | |
| 906 | if (downcast<pia6821_device *>(device)->port_b_z_mask() != 0xff) | |
| 907 | a800xl_mmu(device->machine(), data); | |
| 908 | } | |
| 909 | ||
| 910 | static WRITE8_DEVICE_HANDLER(xegs_pia_pb_w) | |
| 911 | { | |
| 912 | if (downcast<pia6821_device *>(device)->port_b_z_mask() != 0xff) | |
| 913 | xegs_mmu(device->machine(), data); | |
| 914 | } | |
| 915 | ||
| 916 | static const pokey_interface atari_pokey_interface = | |
| 917 | { | |
| 918 | { | |
| 919 | DEVCB_INPUT_PORT("analog_0"), | |
| 920 | DEVCB_INPUT_PORT("analog_1"), | |
| 921 | DEVCB_INPUT_PORT("analog_2"), | |
| 922 | DEVCB_INPUT_PORT("analog_3"), | |
| 923 | DEVCB_INPUT_PORT("analog_4"), | |
| 924 | DEVCB_INPUT_PORT("analog_5"), | |
| 925 | DEVCB_INPUT_PORT("analog_6"), | |
| 926 | DEVCB_INPUT_PORT("analog_7") | |
| 927 | }, | |
| 928 | DEVCB_NULL, | |
| 929 | DEVCB_DEVICE_HANDLER("fdc", atari_serin_r), | |
| 930 | DEVCB_DEVICE_HANDLER("fdc", atari_serout_w), | |
| 931 | atari_interrupt_cb, | |
| 932 | }; | |
| 933 | ||
| 934 | ||
| 935 | static const pia6821_interface atari_pia_interface = | |
| 936 | { | |
| 937 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 938 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 939 | DEVCB_NULL, /* line CA1 in */ | |
| 940 | DEVCB_NULL, /* line CB1 in */ | |
| 941 | DEVCB_NULL, /* line CA2 in */ | |
| 942 | DEVCB_NULL, /* line CB2 in */ | |
| 943 | DEVCB_NULL, /* port A out */ | |
| 944 | DEVCB_NULL, /* port B out */ | |
| 945 | DEVCB_NULL, /* line CA2 out */ | |
| 946 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 947 | DEVCB_NULL, /* IRQA */ | |
| 948 | DEVCB_NULL /* IRQB */ | |
| 949 | }; | |
| 950 | ||
| 951 | static const pia6821_interface a600xl_pia_interface = | |
| 952 | { | |
| 953 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 954 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 955 | DEVCB_NULL, /* line CA1 in */ | |
| 956 | DEVCB_NULL, /* line CB1 in */ | |
| 957 | DEVCB_NULL, /* line CA2 in */ | |
| 958 | DEVCB_NULL, /* line CB2 in */ | |
| 959 | DEVCB_NULL, /* port A out */ | |
| 960 | DEVCB_HANDLER(a600xl_pia_pb_w), /* port B out */ | |
| 961 | DEVCB_NULL, /* line CA2 out */ | |
| 962 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 963 | DEVCB_NULL, /* IRQA */ | |
| 964 | DEVCB_NULL /* IRQB */ | |
| 965 | }; | |
| 966 | ||
| 967 | static const pia6821_interface a1200xl_pia_interface = | |
| 968 | { | |
| 969 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 970 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 971 | DEVCB_NULL, /* line CA1 in */ | |
| 972 | DEVCB_NULL, /* line CB1 in */ | |
| 973 | DEVCB_NULL, /* line CA2 in */ | |
| 974 | DEVCB_NULL, /* line CB2 in */ | |
| 975 | DEVCB_NULL, /* port A out */ | |
| 976 | DEVCB_HANDLER(a1200xl_pia_pb_w), /* port B out */ | |
| 977 | DEVCB_NULL, /* line CA2 out */ | |
| 978 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 979 | DEVCB_NULL, /* IRQA */ | |
| 980 | DEVCB_NULL /* IRQB */ | |
| 981 | }; | |
| 982 | ||
| 983 | static const pia6821_interface a800xl_pia_interface = | |
| 984 | { | |
| 985 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 986 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 987 | DEVCB_NULL, /* line CA1 in */ | |
| 988 | DEVCB_NULL, /* line CB1 in */ | |
| 989 | DEVCB_NULL, /* line CA2 in */ | |
| 990 | DEVCB_NULL, /* line CB2 in */ | |
| 991 | DEVCB_NULL, /* port A out */ | |
| 992 | DEVCB_HANDLER(a800xl_pia_pb_w), /* port B out */ | |
| 993 | DEVCB_NULL, /* line CA2 out */ | |
| 994 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 995 | DEVCB_NULL, /* IRQA */ | |
| 996 | DEVCB_NULL /* IRQB */ | |
| 997 | }; | |
| 998 | ||
| 999 | static const pia6821_interface xegs_pia_interface = | |
| 1000 | { | |
| 1001 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 1002 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 1003 | DEVCB_NULL, /* line CA1 in */ | |
| 1004 | DEVCB_NULL, /* line CB1 in */ | |
| 1005 | DEVCB_NULL, /* line CA2 in */ | |
| 1006 | DEVCB_NULL, /* line CB2 in */ | |
| 1007 | DEVCB_NULL, /* port A out */ | |
| 1008 | DEVCB_HANDLER(xegs_pia_pb_w), /* port B out */ | |
| 1009 | DEVCB_NULL, /* line CA2 out */ | |
| 1010 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 1011 | DEVCB_NULL, /* IRQA */ | |
| 1012 | DEVCB_NULL /* IRQB */ | |
| 1013 | }; | |
| 1014 | ||
| 1015 | // FIXME: should there be anything connected where other system have the fdc? | |
| 1016 | static const pokey_interface a5200_pokey_interface = | |
| 1017 | { | |
| 1018 | { | |
| 1019 | DEVCB_INPUT_PORT("analog_0"), | |
| 1020 | DEVCB_INPUT_PORT("analog_1"), | |
| 1021 | DEVCB_INPUT_PORT("analog_2"), | |
| 1022 | DEVCB_INPUT_PORT("analog_3"), | |
| 1023 | DEVCB_INPUT_PORT("analog_4"), | |
| 1024 | DEVCB_INPUT_PORT("analog_5"), | |
| 1025 | DEVCB_INPUT_PORT("analog_6"), | |
| 1026 | DEVCB_INPUT_PORT("analog_7") | |
| 1027 | }, | |
| 1028 | DEVCB_NULL, | |
| 1029 | DEVCB_NULL, // FIXME: is there anything connected here? | |
| 1030 | DEVCB_NULL, // FIXME: is there anything connected here? | |
| 1031 | atari_interrupt_cb, | |
| 1032 | }; | |
| 1033 | ||
| 1034 | static const pia6821_interface a5200_pia_interface = | |
| 1035 | { | |
| 1036 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 1037 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 1038 | DEVCB_NULL, /* line CA1 in */ | |
| 1039 | DEVCB_NULL, /* line CB1 in */ | |
| 1040 | DEVCB_NULL, /* line CA2 in */ | |
| 1041 | DEVCB_NULL, /* line CB2 in */ | |
| 1042 | DEVCB_NULL, /* port A out */ | |
| 1043 | DEVCB_NULL, /* port B out */ | |
| 1044 | DEVCB_NULL, /* line CA2 out */ | |
| 1045 | DEVCB_NULL, /* port CB2 out */ // FIXME: is there anything connected here | |
| 1046 | DEVCB_NULL, /* IRQA */ | |
| 1047 | DEVCB_NULL /* IRQB */ | |
| 1048 | }; | |
| 1049 | ||
| 1050 | ||
| 1051 | /************************************************************** | |
| 1052 | * | |
| 1053 | * Machine drivers | |
| 1054 | * | |
| 1055 | **************************************************************/ | |
| 1056 | ||
| 1057 | static MACHINE_CONFIG_FRAGMENT( a400_cartslot ) | |
| 1058 | MCFG_CARTSLOT_ADD("cart1") | |
| 1059 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1060 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1061 | MCFG_CARTSLOT_LOAD(a800_cart) | |
| 1062 | MCFG_CARTSLOT_UNLOAD(a800_cart) | |
| 1063 | MCFG_CARTSLOT_INTERFACE("a800_cart") | |
| 1064 | MACHINE_CONFIG_END | |
| 1065 | ||
| 1066 | static MACHINE_CONFIG_FRAGMENT( a800_cartslot ) | |
| 1067 | MCFG_CARTSLOT_ADD("cart1") | |
| 1068 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1069 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1070 | MCFG_CARTSLOT_LOAD(a800_cart) | |
| 1071 | MCFG_CARTSLOT_UNLOAD(a800_cart) | |
| 1072 | MCFG_CARTSLOT_INTERFACE("a800_cart") | |
| 1073 | ||
| 1074 | MCFG_CARTSLOT_ADD("cart2") | |
| 1075 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1076 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1077 | MCFG_CARTSLOT_LOAD(a800_cart_right) | |
| 1078 | MCFG_CARTSLOT_UNLOAD(a800_cart_right) | |
| 1079 | MCFG_CARTSLOT_INTERFACE("a800_cart") | |
| 1080 | MACHINE_CONFIG_END | |
| 1081 | ||
| 1082 | static MACHINE_CONFIG_START( atari_common_nodac, driver_device ) | |
| 1083 | /* basic machine hardware */ | |
| 1084 | MCFG_CPU_ADD("maincpu", M6502, FREQ_17_EXACT) | |
| 1085 | ||
| 1086 | /* video hardware */ | |
| 1087 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 1088 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1)) | |
| 1089 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 1090 | MCFG_SCREEN_VISIBLE_AREA(MIN_X, MAX_X, MIN_Y, MAX_Y) | |
| 1091 | MCFG_PALETTE_LENGTH(sizeof(atari_palette) / 3) | |
| 1092 | MCFG_PALETTE_INIT(mess_atari) | |
| 1093 | MCFG_SCREEN_UPDATE(atari) | |
| 1094 | ||
| 1095 | MCFG_VIDEO_START(atari) | |
| 1096 | ||
| 1097 | MCFG_PIA6821_ADD( "pia", atari_pia_interface ) | |
| 1098 | ||
| 1099 | /* sound hardware */ | |
| 1100 | MCFG_SPEAKER_STANDARD_MONO("mono") | |
| 1101 | MCFG_SOUND_ADD("pokey", POKEY, FREQ_17_EXACT) | |
| 1102 | MCFG_SOUND_CONFIG(atari_pokey_interface) | |
| 1103 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) | |
| 1104 | ||
| 1105 | /* internal ram */ | |
| 1106 | MCFG_RAM_ADD(RAM_TAG) | |
| 1107 | MCFG_RAM_DEFAULT_SIZE("40K") | |
| 1108 | MACHINE_CONFIG_END | |
| 1109 | ||
| 1110 | ||
| 1111 | static MACHINE_CONFIG_DERIVED( atari_common, atari_common_nodac ) | |
| 1112 | MCFG_SOUND_ADD("dac", DAC, 0) | |
| 1113 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) | |
| 1114 | ||
| 1115 | MCFG_ATARI_FDC_ADD("fdc") | |
| 1116 | MACHINE_CONFIG_END | |
| 1117 | ||
| 1118 | ||
| 1119 | static MACHINE_CONFIG_DERIVED( a400, atari_common ) | |
| 1120 | ||
| 1121 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1122 | MCFG_CPU_PROGRAM_MAP(a400_mem) | |
| 1123 | MCFG_CPU_VBLANK_INT_HACK(a400_interrupt, TOTAL_LINES_60HZ) | |
| 1124 | ||
| 1125 | MCFG_MACHINE_START( a400 ) | |
| 1126 | ||
| 1127 | MCFG_SCREEN_MODIFY("screen") | |
| 1128 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1129 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1130 | ||
| 1131 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1132 | ||
| 1133 | /* software lists */ | |
| 1134 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1135 | MACHINE_CONFIG_END | |
| 1136 | ||
| 1137 | ||
| 1138 | static MACHINE_CONFIG_DERIVED( a400pal, atari_common ) | |
| 1139 | ||
| 1140 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1141 | MCFG_CPU_PROGRAM_MAP(a400_mem) | |
| 1142 | MCFG_CPU_VBLANK_INT_HACK(a400_interrupt, TOTAL_LINES_50HZ) | |
| 1143 | ||
| 1144 | MCFG_MACHINE_START( a400 ) | |
| 1145 | ||
| 1146 | MCFG_SCREEN_MODIFY("screen") | |
| 1147 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_50HZ) | |
| 1148 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_50HZ) | |
| 1149 | ||
| 1150 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1151 | ||
| 1152 | /* software lists */ | |
| 1153 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1154 | MACHINE_CONFIG_END | |
| 1155 | ||
| 1156 | ||
| 1157 | static MACHINE_CONFIG_DERIVED( a800, atari_common ) | |
| 1158 | ||
| 1159 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1160 | MCFG_CPU_PROGRAM_MAP(a800_mem) | |
| 1161 | MCFG_CPU_VBLANK_INT_HACK(a800_interrupt, TOTAL_LINES_60HZ) | |
| 1162 | ||
| 1163 | MCFG_MACHINE_START( a800 ) | |
| 1164 | ||
| 1165 | MCFG_SCREEN_MODIFY("screen") | |
| 1166 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1167 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1168 | ||
| 1169 | MCFG_FRAGMENT_ADD(a800_cartslot) | |
| 1170 | ||
| 1171 | /* software lists */ | |
| 1172 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1173 | MACHINE_CONFIG_END | |
| 1174 | ||
| 1175 | ||
| 1176 | static MACHINE_CONFIG_DERIVED( a800pal, atari_common ) | |
| 1177 | ||
| 1178 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1179 | MCFG_CPU_PROGRAM_MAP(a800_mem) | |
| 1180 | MCFG_CPU_VBLANK_INT_HACK(a800_interrupt, TOTAL_LINES_50HZ) | |
| 1181 | ||
| 1182 | MCFG_MACHINE_START( a800 ) | |
| 1183 | ||
| 1184 | MCFG_SCREEN_MODIFY("screen") | |
| 1185 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_50HZ) | |
| 1186 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_50HZ) | |
| 1187 | ||
| 1188 | MCFG_FRAGMENT_ADD(a800_cartslot) | |
| 1189 | ||
| 1190 | /* software lists */ | |
| 1191 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1192 | MACHINE_CONFIG_END | |
| 1193 | ||
| 1194 | ||
| 1195 | static MACHINE_CONFIG_DERIVED( a600xl, atari_common ) | |
| 1196 | ||
| 1197 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1198 | MCFG_CPU_PROGRAM_MAP(a600xl_mem) // FIXME? | |
| 1199 | MCFG_CPU_VBLANK_INT_HACK(a800xl_interrupt, TOTAL_LINES_60HZ) | |
| 1200 | ||
| 1201 | MCFG_PIA6821_MODIFY( "pia", a600xl_pia_interface ) | |
| 1202 | ||
| 1203 | MCFG_MACHINE_START( a800xl ) // FIXME? | |
| 1204 | ||
| 1205 | MCFG_SCREEN_MODIFY("screen") | |
| 1206 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1207 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1208 | ||
| 1209 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1210 | ||
| 1211 | /* software lists */ | |
| 1212 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1213 | ||
| 1214 | /* internal ram */ | |
| 1215 | MCFG_RAM_MODIFY(RAM_TAG) | |
| 1216 | MCFG_RAM_DEFAULT_SIZE("16K") | |
| 1217 | MACHINE_CONFIG_END | |
| 1218 | ||
| 1219 | ||
| 1220 | static MACHINE_CONFIG_DERIVED( a800xl, atari_common ) | |
| 1221 | ||
| 1222 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1223 | MCFG_CPU_PROGRAM_MAP(a800xl_mem) | |
| 1224 | MCFG_CPU_VBLANK_INT_HACK(a800xl_interrupt, TOTAL_LINES_60HZ) | |
| 1225 | ||
| 1226 | MCFG_PIA6821_MODIFY( "pia", a800xl_pia_interface ) | |
| 1227 | ||
| 1228 | MCFG_MACHINE_START( a800xl ) | |
| 1229 | ||
| 1230 | MCFG_SCREEN_MODIFY("screen") | |
| 1231 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1232 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1233 | ||
| 1234 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1235 | ||
| 1236 | /* software lists */ | |
| 1237 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1238 | MACHINE_CONFIG_END | |
| 1239 | ||
| 1240 | static MACHINE_CONFIG_DERIVED( a800xlpal, a800xl ) | |
| 1241 | ||
| 1242 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1243 | MCFG_CPU_CLOCK( 1773000 ) | |
| 1244 | MCFG_CPU_VBLANK_INT_HACK(a800xl_interrupt, TOTAL_LINES_50HZ) | |
| 1245 | MCFG_SCREEN_MODIFY("screen") | |
| 1246 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_50HZ) | |
| 1247 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_50HZ) | |
| 1248 | ||
| 1249 | MCFG_SOUND_MODIFY("pokey") | |
| 1250 | MCFG_SOUND_CLOCK(1773000) | |
| 1251 | MACHINE_CONFIG_END | |
| 1252 | ||
| 1253 | static MACHINE_CONFIG_DERIVED( a1200xl, a800xl ) | |
| 1254 | ||
| 1255 | MCFG_PIA6821_MODIFY( "pia", a1200xl_pia_interface ) | |
| 1256 | MACHINE_CONFIG_END | |
| 1257 | ||
| 1258 | static MACHINE_CONFIG_DERIVED( xegs, a800xl ) | |
| 1259 | ||
| 1260 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1261 | MCFG_CPU_PROGRAM_MAP(xegs_mem) | |
| 1262 | ||
| 1263 | MCFG_MACHINE_START( xegs ) | |
| 1264 | ||
| 1265 | MCFG_PIA6821_MODIFY( "pia", xegs_pia_interface ) | |
| 1266 | ||
| 1267 | MCFG_DEVICE_REMOVE("cart1") | |
| 1268 | MCFG_DEVICE_REMOVE("cart_list") | |
| 1269 | ||
| 1270 | MCFG_CARTSLOT_ADD("cart1") | |
| 1271 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1272 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1273 | MCFG_CARTSLOT_LOAD(xegs_cart) | |
| 1274 | MCFG_CARTSLOT_UNLOAD(xegs_cart) | |
| 1275 | MCFG_CARTSLOT_INTERFACE("xegs_cart") | |
| 1276 | ||
| 1277 | /* software lists */ | |
| 1278 | MCFG_SOFTWARE_LIST_ADD("cart_list","xegs") | |
| 1279 | MACHINE_CONFIG_END | |
| 1280 | ||
| 1281 | ||
| 1282 | static MACHINE_CONFIG_DERIVED( a5200, atari_common_nodac ) | |
| 1283 | ||
| 1284 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1285 | MCFG_CPU_PROGRAM_MAP(a5200_mem) | |
| 1286 | MCFG_CPU_VBLANK_INT_HACK(a5200_interrupt, TOTAL_LINES_60HZ) | |
| 1287 | ||
| 1288 | MCFG_DEVICE_REMOVE("pokey") | |
| 1289 | MCFG_SOUND_ADD("pokey", POKEY, FREQ_17_EXACT) | |
| 1290 | MCFG_SOUND_CONFIG(a5200_pokey_interface) | |
| 1291 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) | |
| 1292 | ||
| 1293 | MCFG_PIA6821_MODIFY( "pia", a5200_pia_interface ) | |
| 1294 | ||
| 1295 | MCFG_MACHINE_START( a5200 ) | |
| 1296 | ||
| 1297 | MCFG_SCREEN_MODIFY( "screen" ) | |
| 1298 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1299 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1300 | ||
| 1301 | MCFG_CARTSLOT_ADD("cart") | |
| 1302 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin,a52") | |
| 1303 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1304 | MCFG_CARTSLOT_LOAD(a5200_cart) | |
| 1305 | MCFG_CARTSLOT_UNLOAD(a5200_cart) | |
| 1306 | MCFG_CARTSLOT_INTERFACE("a5200_cart") | |
| 1307 | ||
| 1308 | /* Software lists */ | |
| 1309 | MCFG_SOFTWARE_LIST_ADD("cart_list","a5200") | |
| 1310 | ||
| 1311 | /* internal ram */ | |
| 1312 | MCFG_RAM_MODIFY(RAM_TAG) | |
| 1313 | MCFG_RAM_DEFAULT_SIZE("16K") | |
| 1314 | MACHINE_CONFIG_END | |
| 1315 | ||
| 1316 | ||
| 1317 | /************************************************************** | |
| 1318 | * | |
| 1319 | * ROM loading | |
| 1320 | * | |
| 1321 | **************************************************************/ | |
| 1322 | ||
| 1323 | ROM_START(a400) | |
| 1324 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1325 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1326 | ROM_SYSTEM_BIOS(0, "default", "OS Rev. B") | |
| 1327 | ROMX_LOAD( "co12499b.rom", 0xe000, 0x1000, BAD_DUMP CRC(d818f3e8) SHA1(bcdec2188f6a6a5bfc1df4e383bd828d34b5c4ac), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1328 | ROMX_LOAD( "co14599b.rom", 0xf000, 0x1000, BAD_DUMP CRC(c1690a9b) SHA1(c5248e8565574fd39ae1c3f4f356aa4cac07df95), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1329 | ROM_SYSTEM_BIOS(1, "reva", "OS Rev. A") | |
| 1330 | ROMX_LOAD( "co12499a.rom", 0xe000, 0x1000, BAD_DUMP CRC(29f64e17) SHA1(abf7ec488c6b600f1b7f30bdc7f8a2bf6a727675), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1331 | ROMX_LOAD( "co14599a.rom", 0xf000, 0x1000, BAD_DUMP CRC(bc533f0c) SHA1(e217148495fa747fe5488132d8d22533e68c7e58), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1332 | ||
| 1333 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1334 | ROM_END | |
| 1335 | ||
| 1336 | ROM_START(a400pal) | |
| 1337 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1338 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1339 | ROM_LOAD( "co15199.rom", 0xe000, 0x1000, BAD_DUMP CRC(8e547f56) SHA1(1bd746ea798b723bfb18495a7facca113183d713) ) // Rev. A - CRC and label waiting for confirmation | |
| 1340 | ROM_LOAD( "co15299.rom", 0xf000, 0x1000, BAD_DUMP CRC(be55b413) SHA1(d88afae49b08e75943d0258cb580e5d34756414a) ) // Rev. A - CRC and label waiting for confirmation | |
| 1341 | ||
| 1342 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1343 | ROM_END | |
| 1344 | ||
| 1345 | ROM_START(a800) | |
| 1346 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1347 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1348 | ROM_SYSTEM_BIOS(0, "default", "OS Rev. B") | |
| 1349 | ROMX_LOAD( "co12499b.rom", 0xe000, 0x1000, BAD_DUMP CRC(d818f3e8) SHA1(bcdec2188f6a6a5bfc1df4e383bd828d34b5c4ac), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1350 | ROMX_LOAD( "co14599b.rom", 0xf000, 0x1000, BAD_DUMP CRC(c1690a9b) SHA1(c5248e8565574fd39ae1c3f4f356aa4cac07df95), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1351 | ROM_SYSTEM_BIOS(1, "reva", "OS Rev. A") | |
| 1352 | ROMX_LOAD( "co12499a.rom", 0xe000, 0x1000, BAD_DUMP CRC(29f64e17) SHA1(abf7ec488c6b600f1b7f30bdc7f8a2bf6a727675), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1353 | ROMX_LOAD( "co14599a.rom", 0xf000, 0x1000, BAD_DUMP CRC(bc533f0c) SHA1(e217148495fa747fe5488132d8d22533e68c7e58), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1354 | ||
| 1355 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1356 | ||
| 1357 | ROM_REGION(0x2000, "rslot", ROMREGION_ERASEFF) | |
| 1358 | ROM_END | |
| 1359 | ||
| 1360 | ROM_START(a800pal) | |
| 1361 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1362 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1363 | ROM_LOAD( "co15199.rom", 0xe000, 0x1000, BAD_DUMP CRC(8e547f56) SHA1(1bd746ea798b723bfb18495a7facca113183d713) ) // Rev. A - CRC and label waiting for confirmation | |
| 1364 | ROM_LOAD( "co15299.rom", 0xf000, 0x1000, BAD_DUMP CRC(be55b413) SHA1(d88afae49b08e75943d0258cb580e5d34756414a) ) // Rev. A - CRC and label waiting for confirmation | |
| 1365 | ||
| 1366 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1367 | ||
| 1368 | ROM_REGION(0x2000, "rslot", ROMREGION_ERASEFF) | |
| 1369 | ROM_END | |
| 1370 | ||
| 1371 | ROM_START(a1200xl) | |
| 1372 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1373 | ROM_SYSTEM_BIOS(0, "default", "OS Rev. 11") | |
| 1374 | ROMX_LOAD( "co60616b.rom", 0x14000, 0x2000, BAD_DUMP CRC(6e29ec8d) SHA1(3f9c06d6b4d261f3d5bf4354e3cff0c17b9347b9), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1375 | ROMX_LOAD( "co60617b.rom", 0x16000, 0x2000, BAD_DUMP CRC(d73ce29a) SHA1(64790242d902643fe0c40dd842749f1fe461831b), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1376 | ROM_SYSTEM_BIOS(1, "rev10", "OS Rev. 10") | |
| 1377 | ROMX_LOAD( "co60616a.rom", 0x14000, 0x2000, BAD_DUMP CRC(0391386b) SHA1(7c176657c88b89b8a69bf021fa8e0939efc0dff2), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1378 | ROMX_LOAD( "co60617a.rom", 0x16000, 0x2000, BAD_DUMP CRC(b502f1e7) SHA1(6688db57d97fa570aef5c15cef3e5fb2688879c2), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1379 | ||
| 1380 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1381 | ROM_END | |
| 1382 | ||
| 1383 | ROM_START(a600xl) | |
| 1384 | ROM_REGION(0x10000, "maincpu", 0) | |
| 1385 | ROM_LOAD( "co60302a.rom", 0xa000, 0x2000, CRC(f0202fb3) SHA1(7ad88dd99ff4a6ee66f6d162074db6f8bef7a9b6) ) // Rev. B | |
| 1386 | ROM_LOAD( "co62024.rom", 0xc000, 0x4000, CRC(643bcc98) SHA1(881d030656b40bbe48f15a696b28f22c0b752ab0) ) // Rev. 1 | |
| 1387 | ||
| 1388 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1389 | ROM_END | |
| 1390 | ||
| 1391 | ROM_START(a800xl) | |
| 1392 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1393 | ROM_FILL( 0, 0x10000, 0x00 ) | |
| 1394 | ROM_LOAD( "co60302a.rom", 0x10000, 0x2000, CRC(f0202fb3) SHA1(7ad88dd99ff4a6ee66f6d162074db6f8bef7a9b6) ) // Rev. B | |
| 1395 | ROM_LOAD( "co61598b.rom", 0x14000, 0x4000, CRC(1f9cd270) SHA1(ae4f523ba08b6fd59f3cae515a2b2410bbd98f55) ) // Rev. 2 | |
| 1396 | ||
| 1397 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1398 | ROM_END | |
| 1399 | ||
| 1400 | #define rom_a800xlp rom_a800xl | |
| 1401 | ||
| 1402 | ROM_START(a65xe) | |
| 1403 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1404 | ROM_LOAD( "co24947a.rom", 0x10000, 0x2000, CRC(7d684184) SHA1(3693c9cb9bf3b41bae1150f7a8264992468fc8c0) ) // Rev. C | |
| 1405 | ROM_LOAD( "co61598b.rom", 0x14000, 0x4000, CRC(1f9cd270) SHA1(ae4f523ba08b6fd59f3cae515a2b2410bbd98f55) ) // Rev. 2 | |
| 1406 | ||
| 1407 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1408 | ROM_END | |
| 1409 | ||
| 1410 | ROM_START(a65xea) | |
| 1411 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1412 | ROM_LOAD( "basic_ar.rom", 0x10000, 0x2000, CRC(c899f4d6) SHA1(043df191d1fe402e792266a108e147ffcda35130) ) // is this correct? or shall we use Rev. C? | |
| 1413 | // ROM_LOAD( "c101700.rom", 0x14000, 0x4000, CRC(7f9a76c8) SHA1(57eb6d87850a763f11767f53d4eaede186f831a2) ) // this was from Savetz and has wrong bits! | |
| 1414 | ROM_LOAD( "c101700.rom", 0x14000, 0x4000, CRC(45f47988) SHA1(a36b8b20f657580f172749bb0625c08706ed824c) ) // Rev. 3B ? | |
| 1415 | ||
| 1416 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1417 | ROM_END | |
| 1418 | ||
| 1419 | ROM_START(a130xe) | |
| 1420 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1421 | ROM_LOAD( "co24947a.rom", 0x10000, 0x2000, CRC(7d684184) SHA1(3693c9cb9bf3b41bae1150f7a8264992468fc8c0) ) // Rev. C | |
| 1422 | ROM_LOAD( "co61598b.rom", 0x14000, 0x4000, CRC(1f9cd270) SHA1(ae4f523ba08b6fd59f3cae515a2b2410bbd98f55) ) // Rev. 2 | |
| 1423 | ||
| 1424 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1425 | ROM_END | |
| 1426 | ||
| 1427 | ROM_START(a800xe) | |
| 1428 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1429 | ROM_LOAD( "co24947a.rom", 0x10000, 0x2000, CRC(7d684184) SHA1(3693c9cb9bf3b41bae1150f7a8264992468fc8c0) ) // Rev. C | |
| 1430 | ROM_LOAD( "c300717.rom", 0x14000, 0x4000, CRC(29f133f7) SHA1(f03b9b93000ee84abb9cf8d6367241006f172182) ) // Rev. 3 | |
| 1431 | ||
| 1432 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1433 | ROM_END | |
| 1434 | ||
| 1435 | ROM_START(xegs) | |
| 1436 | ROM_REGION(0x1a000, "maincpu", 0) | |
| 1437 | ROM_LOAD( "c101687.rom", 0x10000, 0x8000, CRC(d50260d1) SHA1(0e0625ab2473f8431640df3ac8af61925760b9b9) ) // Rev. C + Rev. 4 + Missile Command | |
| 1438 | ||
| 1439 | ROM_REGION(0x20000, "user1", ROMREGION_ERASE00) | |
| 1440 | ROM_END | |
| 1441 | ||
| 1442 | ||
| 1443 | ROM_START(a5200) | |
| 1444 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 16K for cartridges */ | |
| 1445 | ROM_SYSTEM_BIOS(0, "default", "a5200") | |
| 1446 | ROMX_LOAD( "5200.rom", 0xf800, 0x0800, CRC(4248d3e3) SHA1(6ad7a1e8c9fad486fbec9498cb48bf5bc3adc530), ROM_BIOS(1) ) | |
| 1447 | ROM_SYSTEM_BIOS(1, "alt", "a5200 (alt)") | |
| 1448 | ROMX_LOAD( "5200a.rom", 0xf800, 0x0800, CRC(c2ba2613) SHA1(1d2a3f00109d75d2d79fecb565775eb95b7d04d5), ROM_BIOS(2) ) | |
| 1449 | ROM_END | |
| 1450 | ||
| 1451 | /************************************************************** | |
| 1452 | * | |
| 1453 | * Driver initializations | |
| 1454 | * | |
| 1455 | **************************************************************/ | |
| 1456 | ||
| 1457 | static DRIVER_INIT( a800xl ) | |
| 1458 | { | |
| 1459 | a800xl_mmu(machine, 0xff); | |
| 1460 | } | |
| 1461 | ||
| 1462 | static DRIVER_INIT( xegs ) | |
| 1463 | { | |
| 1464 | xegs_mmu(machine, 0xff); | |
| 1465 | } | |
| 1466 | ||
| 1467 | static DRIVER_INIT( a600xl ) | |
| 1468 | { | |
| 1469 | UINT8 *rom = machine.region("maincpu")->base(); | |
| 1470 | memcpy( rom + 0x5000, rom + 0xd000, 0x800 ); | |
| 1471 | } | |
| 1472 | ||
| 1473 | /************************************************************** | |
| 1474 | * | |
| 1475 | * Game driver(s) | |
| 1476 | * | |
| 1477 | **************************************************************/ | |
| 1478 | ||
| 1479 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 1480 | COMP ( 1979, a400, 0, 0, a400, a800, 0, "Atari", "Atari 400 (NTSC)", 0) | |
| 1481 | COMP ( 1979, a400pal, a400, 0, a400pal, a800, 0, "Atari", "Atari 400 (PAL)", 0) | |
| 1482 | COMP ( 1979, a800, 0, 0, a800, a800, 0, "Atari", "Atari 800 (NTSC)", 0) | |
| 1483 | COMP ( 1979, a800pal, a800, 0, a800pal, a800, 0, "Atari", "Atari 800 (PAL)", 0) | |
| 1484 | COMP ( 1982, a1200xl, a800, 0, a1200xl, a800xl, a800xl, "Atari", "Atari 1200XL", GAME_NOT_WORKING ) // 64k RAM | |
| 1485 | COMP ( 1983, a600xl, a800xl, 0, a600xl, a800xl, a600xl, "Atari", "Atari 600XL", GAME_NOT_WORKING ) // 16k RAM | |
| 1486 | COMP ( 1983, a800xl, 0, 0, a800xl, a800xl, a800xl, "Atari", "Atari 800XL (NTSC)",GAME_IMPERFECT_GRAPHICS ) // 64k RAM | |
| 1487 | COMP ( 1983, a800xlp, a800xl, 0, a800xlpal, a800xl, a800xl, "Atari", "Atari 800XL (PAL)", GAME_IMPERFECT_GRAPHICS ) // 64k RAM | |
| 1488 | COMP ( 1986, a65xe, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 65XE", GAME_NOT_WORKING ) // 64k RAM | |
| 1489 | COMP ( 1986, a65xea, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 65XE (Arabic)", GAME_NOT_WORKING ) | |
| 1490 | COMP ( 1986, a130xe, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 130XE", GAME_NOT_WORKING ) // 128k RAM | |
| 1491 | COMP ( 1986, a800xe, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 800XE", GAME_NOT_WORKING ) // 64k RAM | |
| 1492 | COMP ( 1987, xegs, 0, 0, xegs, a800xl, xegs, "Atari", "Atari XE Game System", GAME_NOT_WORKING ) // 64k RAM | |
| 1493 | ||
| 1494 | CONS ( 1982, a5200, 0, 0, a5200, a5200, 0, "Atari", "Atari 5200", 0) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | Commodore Amiga - (c) 1985, Commodore Business Machines Co. | |
| 3 | ||
| 4 | Preliminary driver by: | |
| 5 | ||
| 6 | Ernesto Corvi | |
| 7 | ||
| 8 | Note 1: The 'fast-mem' memory detector in Kickstart 1.2 expects to | |
| 9 | see the custom chips at the end of any present fast memory (mapped | |
| 10 | from $C00000 onwards). I assume this is a bug, given that the routine | |
| 11 | was entirely rewritten for Kickstart 1.3. So the strategy is, for | |
| 12 | any machine that can run Kickstart 1.2 (a500,a1000 and a2000), we | |
| 13 | map a mirror of the custom chips right after any fast-mem we mapped. | |
| 14 | If we didn't map any, then we still put a mirror, but where fast-mem | |
| 15 | would commence ($C00000). | |
| 16 | ||
| 17 | ***************************************************************************/ | |
| 18 | ||
| 19 | /* Core includes */ | |
| 20 | #include "emu.h" | |
| 21 | #include "includes/amiga.h" | |
| 22 | ||
| 23 | /* Components */ | |
| 24 | #include "cpu/m68000/m68000.h" | |
| 25 | #include "cpu/m6502/m6502.h" | |
| 26 | #include "machine/6525tpi.h" | |
| 27 | #include "machine/6526cia.h" | |
| 28 | #include "machine/amigafdc.h" | |
| 29 | #include "machine/amigakbd.h" | |
| 30 | #include "machine/amigacd.h" | |
| 31 | #include "machine/amigacrt.h" | |
| 32 | #include "machine/msm6242.h" | |
| 33 | #include "machine/ctronics.h" | |
| 34 | #include "machine/nvram.h" | |
| 35 | #include "sound/cdda.h" | |
| 36 | ||
| 37 | /* Devices */ | |
| 38 | #include "imagedev/chd_cd.h" | |
| 39 | #include "imagedev/cartslot.h" | |
| 40 | ||
| 41 | ||
| 42 | static READ8_DEVICE_HANDLER( amiga_cia_0_portA_r ); | |
| 43 | static READ8_DEVICE_HANDLER( amiga_cia_0_cdtv_portA_r ); | |
| 44 | static WRITE8_DEVICE_HANDLER( amiga_cia_0_portA_w ); | |
| 45 | ||
| 46 | /*************************************************************************** | |
| 47 | Battery Backed-Up Clock (MSM6264) | |
| 48 | ***************************************************************************/ | |
| 49 | ||
| 50 | static READ16_HANDLER( amiga_clock_r ) | |
| 51 | { | |
| 52 | device_t *rtc = space->machine().device("rtc"); | |
| 53 | return msm6242_r(rtc, offset / 2); | |
| 54 | } | |
| 55 | ||
| 56 | ||
| 57 | static WRITE16_HANDLER( amiga_clock_w ) | |
| 58 | { | |
| 59 | device_t *rtc = space->machine().device("rtc"); | |
| 60 | msm6242_w(rtc, offset / 2, data); | |
| 61 | } | |
| 62 | ||
| 63 | ||
| 64 | /*************************************************************************** | |
| 65 | CENTRONICS PORT | |
| 66 | ***************************************************************************/ | |
| 67 | ||
| 68 | static READ8_DEVICE_HANDLER( amiga_cia_1_porta_r ) | |
| 69 | { | |
| 70 | UINT8 result = 0; | |
| 71 | ||
| 72 | /* centronics status is stored in PA0 to PA2 */ | |
| 73 | result |= centronics_busy_r(device) << 0; | |
| 74 | result |= !centronics_pe_r(device) << 1; | |
| 75 | result |= centronics_vcc_r(device) << 2; | |
| 76 | ||
| 77 | /* PA3 to PA7 store the serial line status (not emulated) */ | |
| 78 | ||
| 79 | return result; | |
| 80 | } | |
| 81 | ||
| 82 | static const centronics_interface amiga_centronics_config = | |
| 83 | { | |
| 84 | FALSE, | |
| 85 | DEVCB_DEVICE_LINE("cia_0", mos6526_flag_w), | |
| 86 | DEVCB_NULL, | |
| 87 | DEVCB_NULL | |
| 88 | }; | |
| 89 | ||
| 90 | ||
| 91 | /*************************************************************************** | |
| 92 | Address maps | |
| 93 | ***************************************************************************/ | |
| 94 | ||
| 95 | static ADDRESS_MAP_START(amiga_mem, AS_PROGRAM, 16) | |
| 96 | ADDRESS_MAP_UNMAP_HIGH | |
| 97 | AM_RANGE(0x000000, 0x07ffff) AM_MIRROR(0x80000) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(amiga_state, m_chip_ram, m_chip_ram_size) | |
| 98 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) | |
| 99 | AM_RANGE(0xc00000, 0xc7ffff) AM_RAM /* slow-mem */ | |
| 100 | AM_RANGE(0xc80000, 0xcfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) /* see Note 1 above */ | |
| 101 | AM_RANGE(0xdf0000, 0xdfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) AM_BASE_MEMBER(amiga_state, m_custom_regs) /* Custom Chips */ | |
| 102 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE(amiga_autoconfig_r, amiga_autoconfig_w) | |
| 103 | AM_RANGE(0xf80000, 0xffffff) AM_ROM AM_REGION("user1", 0) /* System ROM - mirror */ | |
| 104 | ADDRESS_MAP_END | |
| 105 | ||
| 106 | static ADDRESS_MAP_START(keyboard_mem, AS_PROGRAM, 8) | |
| 107 | AM_RANGE(0x0000, 0x003f) AM_RAM /* internal user ram */ | |
| 108 | AM_RANGE(0x0040, 0x007f) AM_NOP /* unassigned */ | |
| 109 | AM_RANGE(0x0080, 0x0080) AM_NOP /* port a */ | |
| 110 | AM_RANGE(0x0081, 0x0081) AM_NOP /* port b */ | |
| 111 | AM_RANGE(0x0082, 0x0082) AM_NOP /* port c */ | |
| 112 | AM_RANGE(0x0083, 0x0083) AM_NOP /* port d */ | |
| 113 | AM_RANGE(0x0084, 0x0085) AM_NOP /* latch */ | |
| 114 | AM_RANGE(0x0086, 0x0087) AM_NOP /* count */ | |
| 115 | AM_RANGE(0x0088, 0x0088) AM_NOP /* upper latch & transfer latch to counter */ | |
| 116 | AM_RANGE(0x0089, 0x0089) AM_NOP /* clear pa0 pos edge detected */ | |
| 117 | AM_RANGE(0x008a, 0x008a) AM_NOP /* clear pa1 neg edge detected */ | |
| 118 | AM_RANGE(0x008b, 0x008e) AM_NOP /* unassigned */ | |
| 119 | AM_RANGE(0x008f, 0x008f) AM_NOP /* control register */ | |
| 120 | AM_RANGE(0x0090, 0x07ff) AM_NOP /* unassigned */ | |
| 121 | AM_RANGE(0x0800, 0x0fff) AM_ROM AM_REGION("keyboard", 0) /* internal mask rom */ | |
| 122 | ADDRESS_MAP_END | |
| 123 | ||
| 124 | ||
| 125 | /* | |
| 126 | * CDTV memory map (source: http://www.l8r.net/technical/cdtv-technical.html) | |
| 127 | * | |
| 128 | * 000000-0FFFFF Chip memory | |
| 129 | * 100000-1FFFFF Space for extra chip memory (Megachip) | |
| 130 | * 200000-9FFFFF Space for AutoConfig memory | |
| 131 | * A00000-BFFFFF CIA chips | |
| 132 | * C00000-C7FFFF Space for slow-fast memory | |
| 133 | * C80000-DBFFFF Space | |
| 134 | * DC0000-DC7FFF Power backed-up real time clock | |
| 135 | * DC8000-DC87FF Non-volatile RAM | |
| 136 | * DC8800-DCFFFF Space in non-volatile RAM decoded area | |
| 137 | * DD0000-DEFFFF Space | |
| 138 | * DF0000-DFFFFF Custom chips | |
| 139 | * E00000-E7FFFF Memory card address space for front panel memory card | |
| 140 | * E80000-E8FFFF AutoConfig configuration space | |
| 141 | * E90000-E9FFFF First AutoConfig device, used by DMAC | |
| 142 | * EA0000-EFFFFF Space for other AutoConfig devices | |
| 143 | * F00000-F3FFFF CDTV ROM | |
| 144 | * F40000-F7FFFF Space in CDTV ROM decoded area | |
| 145 | * F80000-FBFFFF Space in Kickstart ROM decoded area (used by Kickstart 2) | |
| 146 | * FC0000-FFFFFF Kickstart ROM | |
| 147 | * | |
| 148 | */ | |
| 149 | ||
| 150 | static ADDRESS_MAP_START(cdtv_mem, AS_PROGRAM, 16) | |
| 151 | AM_RANGE(0x000000, 0x0fffff) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(amiga_state, m_chip_ram, m_chip_ram_size) | |
| 152 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) | |
| 153 | AM_RANGE(0xdc0000, 0xdc003f) AM_READWRITE(amiga_clock_r, amiga_clock_w) | |
| 154 | AM_RANGE(0xdc8000, 0xdc87ff) AM_RAM AM_SHARE("nvram") | |
| 155 | AM_RANGE(0xdf0000, 0xdfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) AM_BASE_MEMBER(amiga_state, m_custom_regs) /* Custom Chips */ | |
| 156 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE(amiga_autoconfig_r, amiga_autoconfig_w) | |
| 157 | AM_RANGE(0xf00000, 0xffffff) AM_ROM AM_REGION("user1", 0) /* CDTV & System ROM */ | |
| 158 | ADDRESS_MAP_END | |
| 159 | ||
| 160 | static ADDRESS_MAP_START(cdtv_rcmcu_mem, AS_PROGRAM, 8) | |
| 161 | AM_RANGE(0x0000, 0x003f) AM_RAM /* internal user ram */ | |
| 162 | AM_RANGE(0x0040, 0x007f) AM_NOP /* unassigned */ | |
| 163 | AM_RANGE(0x0080, 0x0080) AM_NOP /* port a */ | |
| 164 | AM_RANGE(0x0081, 0x0081) AM_NOP /* port b */ | |
| 165 | AM_RANGE(0x0082, 0x0082) AM_NOP /* port c */ | |
| 166 | AM_RANGE(0x0083, 0x0083) AM_NOP /* port d */ | |
| 167 | AM_RANGE(0x0084, 0x0085) AM_NOP /* latch */ | |
| 168 | AM_RANGE(0x0086, 0x0087) AM_NOP /* count */ | |
| 169 | AM_RANGE(0x0088, 0x0088) AM_NOP /* upper latch & transfer latch to counter */ | |
| 170 | AM_RANGE(0x0089, 0x0089) AM_NOP /* clear pa0 pos edge detected */ | |
| 171 | AM_RANGE(0x008a, 0x008a) AM_NOP /* clear pa1 neg edge detected */ | |
| 172 | AM_RANGE(0x008b, 0x008e) AM_NOP /* unassigned */ | |
| 173 | AM_RANGE(0x008f, 0x008f) AM_NOP /* control register */ | |
| 174 | AM_RANGE(0x0090, 0x07ff) AM_NOP /* unassigned */ | |
| 175 | AM_RANGE(0x0800, 0x0fff) AM_ROM AM_REGION("rcmcu", 0) /* internal mask rom */ | |
| 176 | ADDRESS_MAP_END | |
| 177 | ||
| 178 | static ADDRESS_MAP_START(a1000_mem, AS_PROGRAM, 16) | |
| 179 | AM_RANGE(0x000000, 0x03ffff) AM_MIRROR(0xc0000) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(amiga_state, m_chip_ram, m_chip_ram_size) | |
| 180 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) | |
| 181 | AM_RANGE(0xc00000, 0xc3ffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) /* See Note 1 above */ | |
| 182 | AM_RANGE(0xdf0000, 0xdfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) AM_BASE_MEMBER(amiga_state, m_custom_regs) /* Custom Chips */ | |
| 183 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE(amiga_autoconfig_r, amiga_autoconfig_w) | |
| 184 | AM_RANGE(0xf80000, 0xfbffff) AM_ROM AM_REGION("user1", 0) /* Bootstrap ROM */ | |
| 185 | AM_RANGE(0xfc0000, 0xffffff) AM_RAMBANK("bank2") /* Writable Control Store RAM */ | |
| 186 | ADDRESS_MAP_END | |
| 187 | ||
| 188 | ||
| 189 | /*************************************************************************** | |
| 190 | Inputs | |
| 191 | ***************************************************************************/ | |
| 192 | ||
| 193 | static INPUT_PORTS_START( amiga_common ) | |
| 194 | PORT_START("input") | |
| 195 | PORT_CONFNAME( 0x20, 0x00, "Input Port 0 Device") | |
| 196 | PORT_CONFSETTING( 0x00, "Mouse" ) | |
| 197 | PORT_CONFSETTING( 0x20, DEF_STR(Joystick) ) | |
| 198 | PORT_CONFNAME( 0x10, 0x10, "Input Port 1 Device") | |
| 199 | PORT_CONFSETTING( 0x00, "Mouse" ) | |
| 200 | PORT_CONFSETTING( 0x10, DEF_STR(Joystick) ) | |
| 201 | ||
| 202 | PORT_START("CIA0PORTA") | |
| 203 | PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_SPECIAL ) | |
| 204 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) | |
| 205 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) | |
| 206 | ||
| 207 | PORT_START("JOY0DAT") | |
| 208 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P1JOY") | |
| 209 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 210 | ||
| 211 | PORT_START("JOY1DAT") | |
| 212 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P2JOY") | |
| 213 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 214 | ||
| 215 | PORT_START("POTGO") | |
| 216 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 217 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) | |
| 218 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 219 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) | |
| 220 | PORT_BIT( 0xaaff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 221 | ||
| 222 | PORT_START("P1JOY") | |
| 223 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) | |
| 224 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) | |
| 225 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) | |
| 226 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) | |
| 227 | ||
| 228 | PORT_START("P2JOY") | |
| 229 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) | |
| 230 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) | |
| 231 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) | |
| 232 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) | |
| 233 | ||
| 234 | PORT_START("P0MOUSEX") | |
| 235 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 236 | ||
| 237 | PORT_START("P0MOUSEY") | |
| 238 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 239 | ||
| 240 | PORT_START("P1MOUSEX") | |
| 241 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 242 | ||
| 243 | PORT_START("P1MOUSEY") | |
| 244 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 245 | ||
| 246 | PORT_INCLUDE( amiga_us_keyboard ) | |
| 247 | ||
| 248 | INPUT_PORTS_END | |
| 249 | ||
| 250 | ||
| 251 | static INPUT_PORTS_START( amiga ) | |
| 252 | PORT_START("hardware") | |
| 253 | PORT_CONFNAME( 0x08, 0x08, "Battery backed-up RTC") | |
| 254 | PORT_CONFSETTING( 0x00, "Not Installed" ) | |
| 255 | PORT_CONFSETTING( 0x08, "Installed" ) | |
| 256 | ||
| 257 | PORT_INCLUDE( amiga_common ) | |
| 258 | INPUT_PORTS_END | |
| 259 | ||
| 260 | ||
| 261 | /* TODO: Support for the CDTV remote control */ | |
| 262 | static INPUT_PORTS_START( cdtv ) | |
| 263 | PORT_INCLUDE( amiga_common ) | |
| 264 | INPUT_PORTS_END | |
| 265 | ||
| 266 | /*************************************************************************** | |
| 267 | Machine drivers | |
| 268 | ***************************************************************************/ | |
| 269 | ||
| 270 | static MACHINE_START( cdtv ) | |
| 271 | { | |
| 272 | MACHINE_START_CALL( amigacd ); | |
| 273 | } | |
| 274 | ||
| 275 | ||
| 276 | static MACHINE_RESET( cdtv ) | |
| 277 | { | |
| 278 | MACHINE_RESET_CALL( amiga ); | |
| 279 | ||
| 280 | /* initialize the cdrom controller */ | |
| 281 | MACHINE_RESET_CALL( amigacd ); | |
| 282 | } | |
| 283 | ||
| 284 | static const mos6526_interface cia_0_ntsc_intf = | |
| 285 | { | |
| 286 | 60, /* tod_clock */ | |
| 287 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 288 | DEVCB_DEVICE_LINE("centronics", centronics_strobe_w), /* pc_func */ | |
| 289 | DEVCB_NULL, | |
| 290 | DEVCB_NULL, | |
| 291 | DEVCB_HANDLER(amiga_cia_0_portA_r), | |
| 292 | DEVCB_HANDLER(amiga_cia_0_portA_w), /* port A */ | |
| 293 | DEVCB_NULL, | |
| 294 | DEVCB_DEVICE_HANDLER("centronics", centronics_data_w) /* port B */ | |
| 295 | }; | |
| 296 | ||
| 297 | static const mos6526_interface cia_0_pal_intf = | |
| 298 | { | |
| 299 | 50, /* tod_clock */ | |
| 300 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 301 | DEVCB_DEVICE_LINE("centronics", centronics_strobe_w), /* pc_func */ | |
| 302 | DEVCB_NULL, | |
| 303 | DEVCB_NULL, | |
| 304 | DEVCB_HANDLER(amiga_cia_0_portA_r), | |
| 305 | DEVCB_HANDLER(amiga_cia_0_portA_w), /* port A */ | |
| 306 | DEVCB_NULL, | |
| 307 | DEVCB_DEVICE_HANDLER("centronics", centronics_data_w) /* port B */ | |
| 308 | }; | |
| 309 | ||
| 310 | static const mos6526_interface cia_1_intf = | |
| 311 | { | |
| 312 | 0, /* tod_clock */ | |
| 313 | DEVCB_LINE(amiga_cia_1_irq), /* irq_func */ | |
| 314 | DEVCB_NULL, /* pc_func */ | |
| 315 | DEVCB_NULL, | |
| 316 | DEVCB_NULL, | |
| 317 | DEVCB_DEVICE_HANDLER("centronics", amiga_cia_1_porta_r), | |
| 318 | DEVCB_NULL, /* port A */ | |
| 319 | DEVCB_NULL, | |
| 320 | DEVCB_DEVICE_HANDLER("fdc", amiga_fdc_control_w) /* port B */ | |
| 321 | }; | |
| 322 | ||
| 323 | static const mos6526_interface cia_0_cdtv_intf = | |
| 324 | { | |
| 325 | 0, /* tod_clock */ | |
| 326 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 327 | DEVCB_DEVICE_LINE("centronics", centronics_strobe_w), /* pc_func */ | |
| 328 | DEVCB_NULL, | |
| 329 | DEVCB_NULL, | |
| 330 | DEVCB_HANDLER(amiga_cia_0_cdtv_portA_r), | |
| 331 | DEVCB_HANDLER(amiga_cia_0_portA_w), /* port A */ | |
| 332 | DEVCB_NULL, | |
| 333 | DEVCB_DEVICE_HANDLER("centronics", centronics_data_w) /* port B */ | |
| 334 | }; | |
| 335 | ||
| 336 | static const mos6526_interface cia_1_cdtv_intf = | |
| 337 | { | |
| 338 | 0, /* tod_clock */ | |
| 339 | DEVCB_LINE(amiga_cia_1_irq), /* irq_func */ | |
| 340 | DEVCB_NULL, /* pc_func */ | |
| 341 | DEVCB_NULL, | |
| 342 | DEVCB_NULL, | |
| 343 | DEVCB_DEVICE_HANDLER("centronics", amiga_cia_1_porta_r), | |
| 344 | DEVCB_NULL, /* port A */ | |
| 345 | DEVCB_NULL, | |
| 346 | DEVCB_NULL /* port B */ | |
| 347 | }; | |
| 348 | ||
| 349 | static const tpi6525_interface cdtv_tpi_intf = | |
| 350 | { | |
| 351 | DEVCB_LINE(amigacd_tpi6525_irq), | |
| 352 | DEVCB_NULL, | |
| 353 | DEVCB_NULL, | |
| 354 | DEVCB_NULL, | |
| 355 | DEVCB_HANDLER(amigacd_tpi6525_portb_w), | |
| 356 | DEVCB_HANDLER(amigacd_tpi6525_portc_r), | |
| 357 | DEVCB_NULL, | |
| 358 | DEVCB_NULL, | |
| 359 | DEVCB_NULL | |
| 360 | }; | |
| 361 | ||
| 362 | ||
| 363 | static MACHINE_CONFIG_FRAGMENT( amiga_cartslot ) | |
| 364 | MCFG_CARTSLOT_ADD("cart") | |
| 365 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 366 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 367 | MACHINE_CONFIG_END | |
| 368 | ||
| 369 | static MACHINE_CONFIG_START( ntsc, amiga_state ) | |
| 370 | /* basic machine hardware */ | |
| 371 | MCFG_CPU_ADD("maincpu", M68000, AMIGA_68000_NTSC_CLOCK) | |
| 372 | MCFG_CPU_PROGRAM_MAP(amiga_mem) | |
| 373 | ||
| 374 | MCFG_CPU_ADD("keyboard", M6502, XTAL_1MHz) /* 1 MHz? */ | |
| 375 | MCFG_CPU_PROGRAM_MAP(keyboard_mem) | |
| 376 | ||
| 377 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 378 | MCFG_SCREEN_REFRESH_RATE(59.997) | |
| 379 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 380 | ||
| 381 | MCFG_MACHINE_RESET( amiga ) | |
| 382 | ||
| 383 | /* video hardware */ | |
| 384 | MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) | |
| 385 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 386 | MCFG_SCREEN_SIZE(228*4, 262) | |
| 387 | MCFG_SCREEN_VISIBLE_AREA(214, (228*4)-1, 34, 262-1) | |
| 388 | MCFG_SCREEN_UPDATE(amiga) | |
| 389 | ||
| 390 | MCFG_PALETTE_LENGTH(4096) | |
| 391 | MCFG_PALETTE_INIT( amiga ) | |
| 392 | ||
| 393 | MCFG_VIDEO_START(amiga) | |
| 394 | ||
| 395 | /* devices */ | |
| 396 | MCFG_MSM6242_ADD("rtc") | |
| 397 | MCFG_CENTRONICS_ADD("centronics", amiga_centronics_config) | |
| 398 | ||
| 399 | /* sound hardware */ | |
| 400 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 401 | ||
| 402 | MCFG_SOUND_ADD("amiga", AMIGA, 3579545) | |
| 403 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.50) | |
| 404 | MCFG_SOUND_ROUTE(1, "rspeaker", 0.50) | |
| 405 | MCFG_SOUND_ROUTE(2, "rspeaker", 0.50) | |
| 406 | MCFG_SOUND_ROUTE(3, "lspeaker", 0.50) | |
| 407 | ||
| 408 | /* cia */ | |
| 409 | MCFG_MOS8520_ADD("cia_0", AMIGA_68000_NTSC_CLOCK / 10, cia_0_ntsc_intf) | |
| 410 | MCFG_MOS8520_ADD("cia_1", AMIGA_68000_NTSC_CLOCK, cia_1_intf) | |
| 411 | ||
| 412 | MCFG_AMIGA_FDC_ADD("fdc") | |
| 413 | MACHINE_CONFIG_END | |
| 414 | ||
| 415 | static MACHINE_CONFIG_DERIVED( a1000n, ntsc ) | |
| 416 | MCFG_CPU_MODIFY("maincpu") | |
| 417 | MCFG_CPU_PROGRAM_MAP(a1000_mem) | |
| 418 | MACHINE_CONFIG_END | |
| 419 | ||
| 420 | static MACHINE_CONFIG_DERIVED( a500n, ntsc ) | |
| 421 | MCFG_FRAGMENT_ADD(amiga_cartslot) | |
| 422 | MACHINE_CONFIG_END | |
| 423 | ||
| 424 | ||
| 425 | static MACHINE_CONFIG_DERIVED( cdtv, ntsc ) | |
| 426 | MCFG_CPU_REPLACE("maincpu", M68000, CDTV_CLOCK_X1 / 4) | |
| 427 | MCFG_CPU_PROGRAM_MAP(cdtv_mem) | |
| 428 | ||
| 429 | MCFG_DEVICE_REMOVE("keyboard") | |
| 430 | ||
| 431 | MCFG_CPU_ADD("rcmcu", M6502, XTAL_1MHz) /* 1 MHz? */ | |
| 432 | MCFG_CPU_PROGRAM_MAP(cdtv_rcmcu_mem) | |
| 433 | MCFG_DEVICE_DISABLE() | |
| 434 | ||
| 435 | // MCFG_CPU_ADD("lcd", LC6554, XTAL_4MHz) /* 4 MHz? */ | |
| 436 | // MCFG_CPU_PROGRAM_MAP(cdtv_lcd_mem) | |
| 437 | ||
| 438 | MCFG_MACHINE_START( cdtv ) | |
| 439 | MCFG_MACHINE_RESET( cdtv ) | |
| 440 | ||
| 441 | MCFG_NVRAM_ADD_0FILL("nvram") | |
| 442 | ||
| 443 | MCFG_SOUND_ADD( "cdda", CDDA, 0 ) | |
| 444 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.0 ) | |
| 445 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.0 ) | |
| 446 | ||
| 447 | /* cdrom */ | |
| 448 | MCFG_CDROM_ADD( "cdrom" ) | |
| 449 | MCFG_CDROM_INTERFACE("cdrom") | |
| 450 | MCFG_SOFTWARE_LIST_ADD("cd_list", "cdtv") | |
| 451 | ||
| 452 | MCFG_TPI6525_ADD("tpi6525", cdtv_tpi_intf) | |
| 453 | ||
| 454 | /* cia */ | |
| 455 | MCFG_DEVICE_REMOVE("cia_0") | |
| 456 | MCFG_DEVICE_REMOVE("cia_1") | |
| 457 | MCFG_MOS8520_ADD("cia_0", CDTV_CLOCK_X1 / 40, cia_0_cdtv_intf) | |
| 458 | MCFG_MOS8520_ADD("cia_1", CDTV_CLOCK_X1 / 4, cia_1_cdtv_intf) | |
| 459 | MACHINE_CONFIG_END | |
| 460 | ||
| 461 | ||
| 462 | static MACHINE_CONFIG_DERIVED( pal, ntsc ) | |
| 463 | ||
| 464 | /* adjust for PAL specs */ | |
| 465 | MCFG_CPU_MODIFY("maincpu") | |
| 466 | MCFG_CPU_CLOCK( AMIGA_68000_PAL_CLOCK) | |
| 467 | ||
| 468 | MCFG_SCREEN_MODIFY("screen") | |
| 469 | MCFG_SCREEN_REFRESH_RATE(50) | |
| 470 | MCFG_SCREEN_SIZE(228*4, 312) | |
| 471 | MCFG_SCREEN_VISIBLE_AREA(214, (228*4)-1, 34, 312-1) | |
| 472 | ||
| 473 | /* cia */ | |
| 474 | MCFG_DEVICE_REMOVE("cia_0") | |
| 475 | MCFG_MOS8520_ADD("cia_0", AMIGA_68000_PAL_CLOCK / 10, cia_0_pal_intf) | |
| 476 | MACHINE_CONFIG_END | |
| 477 | ||
| 478 | static MACHINE_CONFIG_DERIVED( a500p, pal ) | |
| 479 | MCFG_FRAGMENT_ADD(amiga_cartslot) | |
| 480 | MACHINE_CONFIG_END | |
| 481 | ||
| 482 | static MACHINE_CONFIG_DERIVED( a1000p, pal ) | |
| 483 | MCFG_CPU_MODIFY("maincpu") | |
| 484 | MCFG_CPU_PROGRAM_MAP(a1000_mem) | |
| 485 | MACHINE_CONFIG_END | |
| 486 | ||
| 487 | /*************************************************************************** | |
| 488 | ||
| 489 | Amiga specific stuff | |
| 490 | ||
| 491 | ***************************************************************************/ | |
| 492 | ||
| 493 | ||
| 494 | static READ8_DEVICE_HANDLER( amiga_cia_0_portA_r ) | |
| 495 | { | |
| 496 | UINT8 ret = input_port_read(device->machine(), "CIA0PORTA") & 0xc0; /* Gameport 1 and 0 buttons */ | |
| 497 | ret |= amiga_fdc_status_r(device->machine().device("fdc")); | |
| 498 | return ret; | |
| 499 | } | |
| 500 | ||
| 501 | ||
| 502 | static READ8_DEVICE_HANDLER( amiga_cia_0_cdtv_portA_r ) | |
| 503 | { | |
| 504 | return input_port_read(device->machine(), "CIA0PORTA") & 0xc0; /* Gameport 1 and 0 buttons */ | |
| 505 | } | |
| 506 | ||
| 507 | ||
| 508 | static WRITE8_DEVICE_HANDLER( amiga_cia_0_portA_w ) | |
| 509 | { | |
| 510 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 511 | /* switch banks as appropriate */ | |
| 512 | memory_set_bank(device->machine(), "bank1", data & 1); | |
| 513 | ||
| 514 | /* swap the write handlers between ROM and bank 1 based on the bit */ | |
| 515 | if ((data & 1) == 0) { | |
| 516 | UINT32 mirror_mask = state->m_chip_ram_size; | |
| 517 | ||
| 518 | while( (mirror_mask<<1) < 0x100000 ) { | |
| 519 | mirror_mask |= ( mirror_mask << 1 ); | |
| 520 | } | |
| 521 | ||
| 522 | /* overlay disabled, map RAM on 0x000000 */ | |
| 523 | device->machine().device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x000000, state->m_chip_ram_size - 1, 0, mirror_mask, "bank1"); | |
| 524 | ||
| 525 | /* if there is a cart region, check for cart overlay */ | |
| 526 | if (device->machine().region("user2")->base() != NULL) | |
| 527 | amiga_cart_check_overlay(device->machine()); | |
| 528 | } | |
| 529 | else | |
| 530 | /* overlay enabled, map Amiga system ROM on 0x000000 */ | |
| 531 | device->machine().device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x000000, state->m_chip_ram_size - 1); | |
| 532 | ||
| 533 | set_led_status( device->machine(), 0, ( data & 2 ) ? 0 : 1 ); /* bit 2 = Power Led on Amiga */ | |
| 534 | output_set_value("power_led", ( data & 2 ) ? 0 : 1); | |
| 535 | } | |
| 536 | ||
| 537 | static UINT16 amiga_read_joy0dat(running_machine &machine) | |
| 538 | { | |
| 539 | if ( input_port_read(machine, "input") & 0x20 ) { | |
| 540 | /* Joystick */ | |
| 541 | return input_port_read_safe(machine, "JOY0DAT", 0xffff); | |
| 542 | } else { | |
| 543 | /* Mouse */ | |
| 544 | int input; | |
| 545 | input = ( input_port_read(machine, "P0MOUSEX") & 0xff ); | |
| 546 | input |= ( input_port_read(machine, "P0MOUSEY") & 0xff ) << 8; | |
| 547 | return input; | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | static UINT16 amiga_read_joy1dat(running_machine &machine) | |
| 552 | { | |
| 553 | if ( input_port_read(machine, "input") & 0x10 ) { | |
| 554 | /* Joystick */ | |
| 555 | return input_port_read_safe(machine, "JOY1DAT", 0xffff); | |
| 556 | } else { | |
| 557 | /* Mouse */ | |
| 558 | int input; | |
| 559 | input = ( input_port_read(machine, "P1MOUSEX") & 0xff ); | |
| 560 | input |= ( input_port_read(machine, "P1MOUSEY") & 0xff ) << 8; | |
| 561 | return input; | |
| 562 | } | |
| 563 | } | |
| 564 | ||
| 565 | static UINT16 amiga_read_dskbytr(running_machine &machine) | |
| 566 | { | |
| 567 | return amiga_fdc_get_byte(machine.device("fdc")); | |
| 568 | } | |
| 569 | ||
| 570 | static void amiga_write_dsklen(running_machine &machine, UINT16 data) | |
| 571 | { | |
| 572 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 573 | if ( data & 0x8000 ) { | |
| 574 | if ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) | |
| 575 | amiga_fdc_setup_dma(machine.device("fdc")); | |
| 576 | } | |
| 577 | } | |
| 578 | ||
| 579 | ||
| 580 | static void amiga_reset(running_machine &machine) | |
| 581 | { | |
| 582 | if (input_port_read(machine, "hardware") & 0x08) | |
| 583 | { | |
| 584 | /* Install RTC */ | |
| 585 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0xdc0000, 0xdc003f, FUNC(amiga_clock_r), FUNC(amiga_clock_w)); | |
| 586 | } | |
| 587 | else | |
| 588 | { | |
| 589 | /* No RTC support */ | |
| 590 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_readwrite(0xdc0000, 0xdc003f); | |
| 591 | } | |
| 592 | } | |
| 593 | ||
| 594 | static DRIVER_INIT( amiga ) | |
| 595 | { | |
| 596 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 597 | static const amiga_machine_interface amiga_intf = | |
| 598 | { | |
| 599 | ANGUS_CHIP_RAM_MASK, | |
| 600 | amiga_read_joy0dat, amiga_read_joy1dat, /* joy0dat_r & joy1dat_r */ | |
| 601 | NULL, /* potgo_w */ | |
| 602 | amiga_read_dskbytr, amiga_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 603 | NULL, /* serdat_w */ | |
| 604 | NULL, /* scanline0_callback */ | |
| 605 | amiga_reset, /* reset_callback */ | |
| 606 | amiga_cart_nmi, /* nmi_callback */ | |
| 607 | 0 /* flags */ | |
| 608 | }; | |
| 609 | ||
| 610 | amiga_machine_config(machine, &amiga_intf); | |
| 611 | ||
| 612 | /* set up memory */ | |
| 613 | memory_configure_bank(machine, "bank1", 0, 1, state->m_chip_ram, 0); | |
| 614 | memory_configure_bank(machine, "bank1", 1, 1, machine.region("user1")->base(), 0); | |
| 615 | ||
| 616 | /* initialize cartridge (if present) */ | |
| 617 | amiga_cart_init(machine); | |
| 618 | ||
| 619 | /* initialize keyboard */ | |
| 620 | amigakbd_init(machine); | |
| 621 | } | |
| 622 | ||
| 623 | #ifdef UNUSED_FUNCTION | |
| 624 | static DRIVER_INIT( amiga_ecs ) | |
| 625 | { | |
| 626 | static const amiga_machine_interface amiga_intf = | |
| 627 | { | |
| 628 | ECS_CHIP_RAM_MASK, | |
| 629 | amiga_cia_0_portA_r, NULL, /* CIA0 port A & B read */ | |
| 630 | amiga_cia_0_portA_w, NULL, /* CIA0 port A & B write */ | |
| 631 | NULL, NULL, /* CIA1 port A & B read */ | |
| 632 | NULL, amiga_fdc_control_w, /* CIA1 port A & B write */ | |
| 633 | amiga_read_joy0dat, amiga_read_joy1dat, /* joy0dat_r & joy1dat_r */ | |
| 634 | NULL, /* potgo_w */ | |
| 635 | amiga_read_dskbytr, amiga_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 636 | NULL, /* serdat_w */ | |
| 637 | NULL, /* scanline0_callback */ | |
| 638 | amiga_reset, /* reset_callback */ | |
| 639 | amiga_cart_nmi, /* nmi_callback */ | |
| 640 | 0 /* flags */ | |
| 641 | }; | |
| 642 | ||
| 643 | amiga_machine_config(machine, &amiga_intf); | |
| 644 | ||
| 645 | /* set up memory */ | |
| 646 | memory_configure_bank(1, 0, 1, state->m_chip_ram, 0); | |
| 647 | memory_configure_bank(1, 1, 1, machine.region("user1")->base(), 0); | |
| 648 | ||
| 649 | /* initialize Action Replay (if present) */ | |
| 650 | amiga_cart_init(machine); | |
| 651 | ||
| 652 | /* initialize keyboard */ | |
| 653 | amigakbd_init(machine); | |
| 654 | } | |
| 655 | #endif | |
| 656 | ||
| 657 | static DRIVER_INIT( cdtv ) | |
| 658 | { | |
| 659 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 660 | static const amiga_machine_interface amiga_intf = | |
| 661 | { | |
| 662 | ECS_CHIP_RAM_MASK, | |
| 663 | amiga_read_joy0dat, amiga_read_joy1dat, /* joy0dat_r & joy1dat_r */ | |
| 664 | NULL, /* potgo_w */ | |
| 665 | amiga_read_dskbytr, amiga_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 666 | NULL, /* serdat_w */ | |
| 667 | NULL, /* scanline0_callback */ | |
| 668 | NULL, /* reset_callback */ | |
| 669 | NULL, /* nmi_callback */ | |
| 670 | 0 /* flags */ | |
| 671 | }; | |
| 672 | ||
| 673 | amiga_machine_config(machine, &amiga_intf); | |
| 674 | ||
| 675 | /* set up memory */ | |
| 676 | memory_configure_bank(machine, "bank1", 0, 1, state->m_chip_ram, 0); | |
| 677 | memory_configure_bank(machine, "bank1", 1, 1, machine.region("user1")->base(), 0); | |
| 678 | ||
| 679 | /* initialize keyboard - in cdtv we can use a standard Amiga keyboard*/ | |
| 680 | amigakbd_init(machine); | |
| 681 | } | |
| 682 | ||
| 683 | ||
| 684 | /*************************************************************************** | |
| 685 | ROM DEFINITIONS | |
| 686 | ***************************************************************************/ | |
| 687 | ||
| 688 | ROM_START( a500n ) | |
| 689 | ROM_REGION16_BE(0x080000, "user1", 0) | |
| 690 | ROM_DEFAULT_BIOS("kick13") | |
| 691 | ROM_SYSTEM_BIOS(0, "kick12", "Kickstart 1.2 (33.180)") | |
| 692 | ROMX_LOAD("315093-01.u6", 0x000000, 0x040000, CRC(a6ce1636) SHA1(11f9e62cf299f72184835b7b2a70a16333fc0d88), ROM_GROUPWORD | ROM_BIOS(1)) | |
| 693 | ROM_SYSTEM_BIOS(1, "kick13", "Kickstart 1.3 (34.5)") | |
| 694 | ROMX_LOAD("315093-02.u6", 0x000000, 0x040000, CRC(c4f0f55f) SHA1(891e9a547772fe0c6c19b610baf8bc4ea7fcb785), ROM_GROUPWORD | ROM_BIOS(2)) | |
| 695 | ROM_COPY("user1", 0x000000, 0x040000, 0x040000) | |
| 696 | ROM_SYSTEM_BIOS(2, "kick204", "Kickstart 2.04 (37.175)") | |
| 697 | ROMX_LOAD("390979-01.u6", 0x000000, 0x080000, CRC(c3bdb240) SHA1(c5839f5cb98a7a8947065c3ed2f14f5f42e334a1), ROM_GROUPWORD | ROM_BIOS(3)) /* identical to 363968.01 */ | |
| 698 | ROM_SYSTEM_BIOS(3, "kick31", "Kickstart 3.1 (40.63)") | |
| 699 | ROMX_LOAD("kick40063.u6", 0x000000, 0x080000, CRC(fc24ae0d) SHA1(3b7f1493b27e212830f989f26ca76c02049f09ca), ROM_GROUPWORD | ROM_BIOS(4)) /* part number? */ | |
| 700 | ||
| 701 | /* action replay cartridge */ | |
| 702 | ROM_REGION16_BE(0x080000, "user2", ROMREGION_ERASEFF ) | |
| 703 | ROM_CART_LOAD("cart", 0x0000, 0x080000, ROM_NOMIRROR | ROM_OPTIONAL) | |
| 704 | ||
| 705 | /* keyboard controller, mos 6500/1 mcu */ | |
| 706 | ROM_REGION(0x800, "keyboard", 0) | |
| 707 | ROM_LOAD("328191-02.ic1", 0x000, 0x800, NO_DUMP) | |
| 708 | ROM_END | |
| 709 | ||
| 710 | #define rom_a500p rom_a500n | |
| 711 | ||
| 712 | ||
| 713 | ROM_START( a1000n ) | |
| 714 | ROM_REGION16_BE(0x080000, "user1", 0) | |
| 715 | ROM_LOAD16_BYTE("252179-01.u5n", 0x000000, 0x001000, CRC(42553bc4) SHA1(8855a97f7a44e3f62d1c88d938fee1f4c606af5b)) | |
| 716 | ROM_LOAD16_BYTE("252180-01.u5p", 0x000001, 0x001000, CRC(8e5b9a37) SHA1(d10f1564b99f5ffe108fa042362e877f569de2c3)) | |
| 717 | ||
| 718 | /* keyboard controller, mos 6500/1 mcu */ | |
| 719 | ROM_REGION(0x800, "keyboard", 0) | |
| 720 | ROM_LOAD("328191-01.bin", 0x000, 0x800, NO_DUMP) | |
| 721 | ROM_END | |
| 722 | ||
| 723 | #define rom_a1000p rom_a1000n | |
| 724 | ||
| 725 | ||
| 726 | ROM_START( cdtv ) | |
| 727 | ROM_REGION16_BE(0x100000, "user1", 0) | |
| 728 | ROM_LOAD16_BYTE("391008-01.u34", 0x000000, 0x020000, CRC(791cb14b) SHA1(277a1778924496353ffe56be68063d2a334360e4)) | |
| 729 | ROM_LOAD16_BYTE("391009-01.u35", 0x000001, 0x020000, CRC(accbbc2e) SHA1(41b06d1679c6e6933c3378b7626025f7641ebc5c)) | |
| 730 | ROM_COPY("user1", 0x000000, 0x040000, 0x040000) | |
| 731 | ROMX_LOAD( "315093-02.u13", 0x080000, 0x040000, CRC(c4f0f55f) SHA1(891e9a547772fe0c6c19b610baf8bc4ea7fcb785), ROM_GROUPWORD) | |
| 732 | ROM_COPY("user1", 0x080000, 0x0c0000, 0x040000) | |
| 733 | ||
| 734 | /* remote control input converter, mos 6500/1 mcu */ | |
| 735 | ROM_REGION(0x800, "rcmcu", 0) | |
| 736 | ROM_LOAD("252609-02.u75", 0x000, 0x800, NO_DUMP) | |
| 737 | ||
| 738 | /* lcd controller, sanyo lc6554h */ | |
| 739 | ROM_REGION(0x1000, "lcd", 0) | |
| 740 | ROM_LOAD("252608-01.u62", 0x000, 0x1000, NO_DUMP) | |
| 741 | ROM_END | |
| 742 | ||
| 743 | /*************************************************************************** | |
| 744 | GAME DRIVERS | |
| 745 | ***************************************************************************/ | |
| 746 | ||
| 747 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 748 | COMP( 1985, a1000n, 0, 0, a1000n, amiga, amiga, "Commodore Business Machines", "Amiga 1000 (NTSC)", GAME_IMPERFECT_GRAPHICS ) | |
| 749 | COMP( 1985, a1000p, a1000n, 0, a1000p, amiga, amiga, "Commodore Business Machines", "Amiga 1000 (PAL)", GAME_IMPERFECT_GRAPHICS ) | |
| 750 | COMP( 1987, a500n, 0, 0, a500n, amiga, amiga, "Commodore Business Machines", "Amiga 500 (NTSC, OCS)", GAME_IMPERFECT_GRAPHICS ) | |
| 751 | COMP( 1987, a500p, a500n, 0, a500p, amiga, amiga, "Commodore Business Machines", "Amiga 500 (PAL, OCS)", GAME_IMPERFECT_GRAPHICS ) | |
| 752 | COMP( 1991, cdtv, 0, 0, cdtv, cdtv, cdtv, "Commodore Business Machines", "CDTV (NTSC)", GAME_IMPERFECT_GRAPHICS ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Acorn Archimedes 7000/7000+ | |
| 4 | ||
| 5 | preliminary driver by Angelo Salese, | |
| 6 | based on work by Tomasz Slanina and Tom Walker | |
| 7 | ||
| 8 | ??? | |
| 9 | bp (0382827C) (second trigger) | |
| 10 | do R13 = SR13 | |
| 11 | ||
| 12 | ****************************************************************************/ | |
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | #include "cpu/arm7/arm7.h" | |
| 16 | #include "cpu/arm7/arm7core.h" | |
| 17 | ||
| 18 | ||
| 19 | class a7000_state : public driver_device | |
| 20 | { | |
| 21 | public: | |
| 22 | a7000_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 23 | : driver_device(mconfig, type, tag) { } | |
| 24 | ||
| 25 | UINT8 m_vidc20_pal_index; | |
| 26 | UINT16 m_vidc20_horz_reg[0x10]; | |
| 27 | UINT16 m_vidc20_vert_reg[0x10]; | |
| 28 | UINT8 m_vidc20_bpp_mode; | |
| 29 | emu_timer *m_flyback_timer; | |
| 30 | UINT16 m_timer_in[2]; | |
| 31 | UINT16 m_timer_out[2]; | |
| 32 | int m_timer_counter[2]; | |
| 33 | emu_timer *m_IOMD_timer[2]; | |
| 34 | UINT8 m_IRQ_status_A; | |
| 35 | UINT8 m_IRQ_mask_A; | |
| 36 | UINT8 m_IOMD_IO_ctrl; | |
| 37 | UINT8 m_IOMD_keyb_ctrl; | |
| 38 | UINT16 m_io_id; | |
| 39 | UINT8 m_viddma_status; | |
| 40 | UINT32 m_viddma_addr_start; | |
| 41 | UINT32 m_viddma_addr_end; | |
| 42 | UINT8 m_t0readinc; | |
| 43 | UINT8 m_t1readinc; | |
| 44 | }; | |
| 45 | ||
| 46 | ||
| 47 | /* | |
| 48 | * | |
| 49 | * VIDC20 chip emulation | |
| 50 | * | |
| 51 | */ | |
| 52 | ||
| 53 | ||
| 54 | static const char *const vidc20_regnames[] = | |
| 55 | { | |
| 56 | "Video Palette", // 0 | |
| 57 | "Video Palette Address", // 1 | |
| 58 | "RESERVED", // 2 | |
| 59 | "LCD offset", // 3 | |
| 60 | "Border Colour", // 4 | |
| 61 | "Cursor Palette Logical Colour 1", // 5 | |
| 62 | "Cursor Palette Logical Colour 2", // 6 | |
| 63 | "Cursor Palette Logical Colour 3", // 7 | |
| 64 | "Horizontal", // 8 | |
| 65 | "Vertical", // 9 | |
| 66 | "Stereo Image", // A | |
| 67 | "Sound", // B | |
| 68 | "External", // C | |
| 69 | "Frequency Synthesis", // D | |
| 70 | "Control", // E | |
| 71 | "Data Control" // F | |
| 72 | }; | |
| 73 | ||
| 74 | static const char *const vidc20_horz_regnames[] = | |
| 75 | { | |
| 76 | "Horizontal Cycle", // 0x80 HCR | |
| 77 | "Horizontal Sync Width", // 0x81 HSWR | |
| 78 | "Horizontal Border Start", // 0x82 HBSR | |
| 79 | "Horizontal Display Start", // 0x83 HDSR | |
| 80 | "Horizontal Display End", // 0x84 HDER | |
| 81 | "Horizontal Border End", // 0x85 HBER | |
| 82 | "Horizontal Cursor Start", // 0x86 HCSR | |
| 83 | "Horizontal Interlace", // 0x87 HIR | |
| 84 | "Horizontal Counter TEST", // 0x88 | |
| 85 | "Horizontal <UNDEFINED>", // 0x89 | |
| 86 | "Horizontal <UNDEFINED>", // 0x8a | |
| 87 | "Horizontal <UNDEFINED>", // 0x8b | |
| 88 | "Horizontal All TEST", // 0x8c | |
| 89 | "Horizontal <UNDEFINED>", // 0x8d | |
| 90 | "Horizontal <UNDEFINED>", // 0x8e | |
| 91 | "Horizontal <UNDEFINED>" // 0x8f | |
| 92 | }; | |
| 93 | ||
| 94 | #define HCR 0 | |
| 95 | #define HSWR 1 | |
| 96 | #define HBSR 2 | |
| 97 | #define HDSR 3 | |
| 98 | #define HDER 4 | |
| 99 | #define HBER 5 | |
| 100 | #define HCSR 6 | |
| 101 | #define HIR 7 | |
| 102 | ||
| 103 | static const char *const vidc20_vert_regnames[] = | |
| 104 | { | |
| 105 | "Vertical Cycle", // 0x90 VCR | |
| 106 | "Vertical Sync Width", // 0x91 VSWR | |
| 107 | "Vertical Border Start", // 0x92 VBSR | |
| 108 | "Vertical Display Start", // 0x93 VDSR | |
| 109 | "Vertical Display End", // 0x94 VDER | |
| 110 | "Vertical Border End", // 0x95 VBER | |
| 111 | "Vertical Cursor Start", // 0x96 VCSR | |
| 112 | "Vertical Cursor End", // 0x97 VCER | |
| 113 | "Vertical Counter TEST", // 0x98 | |
| 114 | "Horizontal <UNDEFINED>", // 0x99 | |
| 115 | "Vertical Counter Increment TEST", // 0x9a | |
| 116 | "Horizontal <UNDEFINED>", // 0x9b | |
| 117 | "Vertical All TEST", // 0x9c | |
| 118 | "Horizontal <UNDEFINED>", // 0x9d | |
| 119 | "Horizontal <UNDEFINED>", // 0x9e | |
| 120 | "Horizontal <UNDEFINED>" // 0x9f | |
| 121 | }; | |
| 122 | ||
| 123 | #define VCR 0 | |
| 124 | #define VSWR 1 | |
| 125 | #define VBSR 2 | |
| 126 | #define VDSR 3 | |
| 127 | #define VDER 4 | |
| 128 | #define VBER 5 | |
| 129 | #define VCSR 6 | |
| 130 | #define VCER 7 | |
| 131 | ||
| 132 | static void vidc20_dynamic_screen_change(running_machine &machine) | |
| 133 | { | |
| 134 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 135 | /* sanity checks - first pass */ | |
| 136 | /* | |
| 137 | total cycles + border start/end | |
| 138 | */ | |
| 139 | if(state->m_vidc20_horz_reg[HCR] && state->m_vidc20_horz_reg[HBSR] && state->m_vidc20_horz_reg[HBER] && | |
| 140 | state->m_vidc20_vert_reg[VCR] && state->m_vidc20_vert_reg[VBSR] && state->m_vidc20_vert_reg[VBER]) | |
| 141 | { | |
| 142 | /* sanity checks - second pass */ | |
| 143 | /* | |
| 144 | total cycles > border end > border start | |
| 145 | */ | |
| 146 | if((state->m_vidc20_horz_reg[HCR] > state->m_vidc20_horz_reg[HBER]) && | |
| 147 | (state->m_vidc20_horz_reg[HBER] > state->m_vidc20_horz_reg[HBSR]) && | |
| 148 | (state->m_vidc20_vert_reg[VCR] > state->m_vidc20_vert_reg[VBER]) && | |
| 149 | (state->m_vidc20_vert_reg[VBER] > state->m_vidc20_vert_reg[VBSR])) | |
| 150 | { | |
| 151 | /* finally ready to change the resolution */ | |
| 152 | int hblank_period,vblank_period; | |
| 153 | rectangle visarea = machine.primary_screen->visible_area(); | |
| 154 | hblank_period = (state->m_vidc20_horz_reg[HCR] & 0x3ffc); | |
| 155 | vblank_period = (state->m_vidc20_vert_reg[VCR] & 0x3fff); | |
| 156 | /* note that we use the border registers as the visible area */ | |
| 157 | visarea.min_x = (state->m_vidc20_horz_reg[HBSR] & 0x3ffe); | |
| 158 | visarea.max_x = (state->m_vidc20_horz_reg[HBER] & 0x3ffe)-1; | |
| 159 | visarea.min_y = (state->m_vidc20_vert_reg[VBSR] & 0x1fff); | |
| 160 | visarea.max_y = (state->m_vidc20_vert_reg[VBER] & 0x1fff)-1; | |
| 161 | ||
| 162 | machine.primary_screen->configure(hblank_period, vblank_period, visarea, machine.primary_screen->frame_period().attoseconds ); | |
| 163 | logerror("VIDC20: successfully changed the screen to:\n Display Size = %d x %d\n Border Size %d x %d\n Cycle Period %d x %d\n", | |
| 164 | (state->m_vidc20_horz_reg[HDER]-state->m_vidc20_horz_reg[HDSR]),(state->m_vidc20_vert_reg[VDER]-state->m_vidc20_vert_reg[VDSR]), | |
| 165 | (state->m_vidc20_horz_reg[HBER]-state->m_vidc20_horz_reg[HBSR]),(state->m_vidc20_vert_reg[VBER]-state->m_vidc20_vert_reg[VBSR]), | |
| 166 | hblank_period,vblank_period); | |
| 167 | } | |
| 168 | } | |
| 169 | } | |
| 170 | ||
| 171 | static WRITE32_HANDLER( a7000_vidc20_w ) | |
| 172 | { | |
| 173 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 174 | int reg = data >> 28; | |
| 175 | ||
| 176 | switch(reg) | |
| 177 | { | |
| 178 | case 0: // Video Palette | |
| 179 | { | |
| 180 | int r,g,b; | |
| 181 | ||
| 182 | r = (data & 0x0000ff) >> 0; | |
| 183 | g = (data & 0x00ff00) >> 8; | |
| 184 | b = (data & 0xff0000) >> 16; | |
| 185 | ||
| 186 | palette_set_color_rgb(space->machine(),state->m_vidc20_pal_index & 0xff,r,g,b); | |
| 187 | ||
| 188 | /* auto-increment & wrap-around */ | |
| 189 | state->m_vidc20_pal_index++; | |
| 190 | state->m_vidc20_pal_index &= 0xff; | |
| 191 | } | |
| 192 | break; | |
| 193 | case 1: // Video Palette Address | |
| 194 | { | |
| 195 | // according to RPCEmu, these mustn't be set | |
| 196 | if (data & 0x0fffff00) | |
| 197 | return; | |
| 198 | ||
| 199 | state->m_vidc20_pal_index = data & 0xff; | |
| 200 | } | |
| 201 | break; | |
| 202 | ||
| 203 | case 4: // Border Color | |
| 204 | { | |
| 205 | int r,g,b; | |
| 206 | ||
| 207 | r = (data & 0x0000ff) >> 0; | |
| 208 | g = (data & 0x00ff00) >> 8; | |
| 209 | b = (data & 0xff0000) >> 16; | |
| 210 | ||
| 211 | palette_set_color_rgb(space->machine(),0x100,r,g,b); | |
| 212 | } | |
| 213 | break; | |
| 214 | case 5: // Cursor Palette Logical Colour n | |
| 215 | case 6: | |
| 216 | case 7: | |
| 217 | { | |
| 218 | int r,g,b; | |
| 219 | int cursor_index = 0x100 + reg - 4; // 0x101,0x102 and 0x103 (plus 0x100 of above, 2bpp) | |
| 220 | ||
| 221 | r = (data & 0x0000ff) >> 0; | |
| 222 | g = (data & 0x00ff00) >> 8; | |
| 223 | b = (data & 0xff0000) >> 16; | |
| 224 | ||
| 225 | palette_set_color_rgb(space->machine(),cursor_index,r,g,b); | |
| 226 | } | |
| 227 | break; | |
| 228 | case 8: // Horizontal | |
| 229 | { | |
| 230 | int horz_reg; | |
| 231 | ||
| 232 | horz_reg = (data >> 24) & 0xf; | |
| 233 | state->m_vidc20_horz_reg[horz_reg] = data & 0x3fff; | |
| 234 | if(horz_reg == 0 || horz_reg == 2 || horz_reg == 5) | |
| 235 | vidc20_dynamic_screen_change(space->machine()); | |
| 236 | ||
| 237 | // logerror("VIDC20: %s Register write = %08x (%d)\n",vidc20_horz_regnames[horz_reg],val,val); | |
| 238 | } | |
| 239 | break; | |
| 240 | case 9: // Vertical | |
| 241 | { | |
| 242 | int vert_reg; | |
| 243 | ||
| 244 | vert_reg = (data >> 24) & 0xf; | |
| 245 | state->m_vidc20_vert_reg[vert_reg] = data & 0x1fff; | |
| 246 | if(vert_reg == 0 || vert_reg == 2 || vert_reg == 5) | |
| 247 | vidc20_dynamic_screen_change(space->machine()); | |
| 248 | ||
| 249 | if(vert_reg == 4) | |
| 250 | { | |
| 251 | if(state->m_vidc20_vert_reg[VDER] != 0) | |
| 252 | state->m_flyback_timer->adjust(space->machine().primary_screen->time_until_pos(state->m_vidc20_vert_reg[VDER])); | |
| 253 | else | |
| 254 | state->m_flyback_timer->adjust(attotime::never); | |
| 255 | } | |
| 256 | ||
| 257 | // logerror("VIDC20: %s Register write = %08x (%d)\n",vidc20_vert_regnames[vert_reg],val,val); | |
| 258 | ||
| 259 | } | |
| 260 | break; | |
| 261 | case 0x0e: // Control | |
| 262 | { | |
| 263 | state->m_vidc20_bpp_mode = (data & 0xe0) >> 5; | |
| 264 | } | |
| 265 | break; | |
| 266 | default: logerror("VIDC20: %s Register write = %08x\n",vidc20_regnames[reg],data & 0xfffffff); | |
| 267 | } | |
| 268 | } | |
| 269 | ||
| 270 | static VIDEO_START( a7000 ) | |
| 271 | { | |
| 272 | } | |
| 273 | ||
| 274 | static SCREEN_UPDATE( a7000 ) | |
| 275 | { | |
| 276 | a7000_state *state = screen->machine().driver_data<a7000_state>(); | |
| 277 | int x_size,y_size,x_start,y_start; | |
| 278 | int x,y,xi; | |
| 279 | UINT32 count; | |
| 280 | UINT8 *vram = screen->machine().region("vram")->base(); | |
| 281 | ||
| 282 | bitmap_fill(bitmap, cliprect, screen->machine().pens[0x100]); | |
| 283 | ||
| 284 | x_size = (state->m_vidc20_horz_reg[HDER]-state->m_vidc20_horz_reg[HDSR]); | |
| 285 | y_size = (state->m_vidc20_vert_reg[VDER]-state->m_vidc20_vert_reg[VDSR]); | |
| 286 | x_start = state->m_vidc20_horz_reg[HDSR]; | |
| 287 | y_start = state->m_vidc20_vert_reg[VDSR]; | |
| 288 | ||
| 289 | /* check if display is enabled */ | |
| 290 | if(x_size <= 0 || y_size <= 0) | |
| 291 | return 0; | |
| 292 | ||
| 293 | // popmessage("%d",state->m_vidc20_bpp_mode); | |
| 294 | ||
| 295 | count = 0; | |
| 296 | ||
| 297 | switch(state->m_vidc20_bpp_mode) | |
| 298 | { | |
| 299 | case 0: /* 1 bpp */ | |
| 300 | { | |
| 301 | for(y=0;y<y_size;y++) | |
| 302 | { | |
| 303 | for(x=0;x<x_size;x+=8) | |
| 304 | { | |
| 305 | for(xi=0;xi<8;xi++) | |
| 306 | *BITMAP_ADDR32(bitmap, y+y_start, x+xi+x_start) = screen->machine().pens[(vram[count]>>(xi))&1]; | |
| 307 | ||
| 308 | count++; | |
| 309 | } | |
| 310 | } | |
| 311 | } | |
| 312 | break; | |
| 313 | case 1: /* 2 bpp */ | |
| 314 | { | |
| 315 | for(y=0;y<y_size;y++) | |
| 316 | { | |
| 317 | for(x=0;x<x_size;x+=4) | |
| 318 | { | |
| 319 | for(xi=0;xi<4;xi++) | |
| 320 | *BITMAP_ADDR32(bitmap, y+y_start, x+xi+x_start) = screen->machine().pens[(vram[count]>>(xi*2))&3]; | |
| 321 | ||
| 322 | count++; | |
| 323 | } | |
| 324 | } | |
| 325 | } | |
| 326 | break; | |
| 327 | case 2: /* 4 bpp */ | |
| 328 | { | |
| 329 | for(y=0;y<y_size;y++) | |
| 330 | { | |
| 331 | for(x=0;x<x_size;x+=2) | |
| 332 | { | |
| 333 | for(xi=0;xi<2;xi++) | |
| 334 | *BITMAP_ADDR32(bitmap, y+y_start, x+xi+x_start) = screen->machine().pens[(vram[count]>>(xi*4))&0xf]; | |
| 335 | ||
| 336 | count++; | |
| 337 | } | |
| 338 | } | |
| 339 | } | |
| 340 | break; | |
| 341 | case 3: /* 8 bpp */ | |
| 342 | { | |
| 343 | for(y=0;y<y_size;y++) | |
| 344 | { | |
| 345 | for(x=0;x<x_size;x++) | |
| 346 | { | |
| 347 | *BITMAP_ADDR32(bitmap, y+y_start, x+x_start) = screen->machine().pens[(vram[count])&0xff]; | |
| 348 | ||
| 349 | count++; | |
| 350 | } | |
| 351 | } | |
| 352 | } | |
| 353 | break; | |
| 354 | case 4: /* 16 bpp */ | |
| 355 | { | |
| 356 | for(y=0;y<y_size;y++) | |
| 357 | { | |
| 358 | for(x=0;x<x_size;x++) | |
| 359 | { | |
| 360 | int r,g,b,pen; | |
| 361 | ||
| 362 | pen = ((vram[count]<<8)|(vram[count+1]))&0xffff; | |
| 363 | r = (pen & 0x000f); | |
| 364 | g = (pen & 0x00f0) >> 4; | |
| 365 | b = (pen & 0x0f00) >> 8; | |
| 366 | r = (r << 4) | (r & 0xf); | |
| 367 | g = (g << 4) | (g & 0xf); | |
| 368 | b = (b << 4) | (b & 0xf); | |
| 369 | ||
| 370 | *BITMAP_ADDR32(bitmap, y+y_start, x+x_start) = b | g << 8 | r << 16; | |
| 371 | ||
| 372 | count+=2; | |
| 373 | } | |
| 374 | } | |
| 375 | } | |
| 376 | break; | |
| 377 | case 6: /* 32 bpp */ | |
| 378 | { | |
| 379 | for(y=0;y<y_size;y++) | |
| 380 | { | |
| 381 | for(x=0;x<x_size;x++) | |
| 382 | { | |
| 383 | int r,g,b,pen; | |
| 384 | ||
| 385 | pen = ((vram[count]<<24)|(vram[count+1]<<16)|(vram[count+2]<<8)|(vram[count+3]<<0)); | |
| 386 | r = (pen & 0x0000ff); | |
| 387 | g = (pen & 0x00ff00) >> 8; | |
| 388 | b = (pen & 0xff0000) >> 16; | |
| 389 | ||
| 390 | *BITMAP_ADDR32(bitmap, y+y_start, x+x_start) = b | g << 8 | r << 16; | |
| 391 | ||
| 392 | count+=4; | |
| 393 | } | |
| 394 | } | |
| 395 | } | |
| 396 | break; | |
| 397 | default: | |
| 398 | //fatalerror("VIDC20 %08x BPP mode not supported\n",state->m_vidc20_bpp_mode); | |
| 399 | break; | |
| 400 | } | |
| 401 | ||
| 402 | return 0; | |
| 403 | } | |
| 404 | ||
| 405 | /* | |
| 406 | * | |
| 407 | * IOMD / ARM7500 / ARM7500FE chip emulation | |
| 408 | * | |
| 409 | */ | |
| 410 | ||
| 411 | /* TODO: some of these registers are actually ARM7500 specific */ | |
| 412 | static const char *const iomd_regnames[] = | |
| 413 | { | |
| 414 | "I/O Control", // 0x000 IOCR | |
| 415 | "Keyboard Data", // 0x004 KBDDAT | |
| 416 | "Keyboard Control", // 0x008 KBDCR | |
| 417 | "General Purpose I/O Lines", // 0x00c IOLINES | |
| 418 | "IRQA Status", // 0x010 IRQSTA | |
| 419 | "IRQA Request/clear", // 0x014 IRQRQA | |
| 420 | "IRQA Mask", // 0x018 IRQMSKA | |
| 421 | "Enter SUSPEND Mode", // 0x01c SUSMODE | |
| 422 | "IRQB Status", // 0x020 IRQSTB | |
| 423 | "IRQB Request/clear", // 0x024 IRQRQB | |
| 424 | "IRQB Mask", // 0x028 IRQMSKB | |
| 425 | "Enter STOP Mode", // 0x02c STOPMODE | |
| 426 | "FIQ Status", // 0x030 FIQST | |
| 427 | "FIQ Request/clear", // 0x034 FIQRQ | |
| 428 | "FIQ Mask", // 0x038 FIQMSK | |
| 429 | "Clock divider control", // 0x03c CLKCTL | |
| 430 | "Timer 0 Low Bits", // 0x040 T0LOW | |
| 431 | "Timer 0 High Bits", // 0x044 T0HIGH | |
| 432 | "Timer 0 Go Command", // 0x048 T0GO | |
| 433 | "Timer 0 Latch Command", // 0x04c T0LATCH | |
| 434 | "Timer 1 Low Bits", // 0x050 T1LOW | |
| 435 | "Timer 1 High Bits", // 0x054 T1HIGH | |
| 436 | "Timer 1 Go Command", // 0x058 T1GO | |
| 437 | "Timer 1 Latch Command", // 0x05c T1LATCH | |
| 438 | "IRQC Status", // 0x060 IRQSTC | |
| 439 | "IRQC Request/clear", // 0x064 IRQRQC | |
| 440 | "IRQC Mask", // 0x068 IRQMSKC | |
| 441 | "LCD and IIS Control Bits", // 0x06c VIDIMUX | |
| 442 | "IRQD Status", // 0x070 IRQSTD | |
| 443 | "IRQD Request/clear", // 0x074 IRQRQD | |
| 444 | "IRQD Mask", // 0x078 IRQMSKD | |
| 445 | "<RESERVED>", // 0x07c | |
| 446 | "ROM Control Bank 0", // 0x080 ROMCR0 | |
| 447 | "ROM Control Bank 1", // 0x084 ROMCR1 | |
| 448 | "DRAM Control (IOMD)", // 0x088 DRAMCR | |
| 449 | "VRAM and Refresh Control", // 0x08c VREFCR | |
| 450 | "Flyback Line Size", // 0x090 FSIZE | |
| 451 | "Chip ID no. Low Byte", // 0x094 ID0 | |
| 452 | "Chip ID no. High Byte", // 0x098 ID1 | |
| 453 | "Chip Version Number", // 0x09c VERSION | |
| 454 | "Mouse X Position", // 0x0a0 MOUSEX | |
| 455 | "Mouse Y Position", // 0x0a4 MOUSEY | |
| 456 | "Mouse Data", // 0x0a8 MSEDAT | |
| 457 | "Mouse Control", // 0x0ac MSECR | |
| 458 | "<RESERVED>", // 0x0b0 | |
| 459 | "<RESERVED>", // 0x0b4 | |
| 460 | "<RESERVED>", // 0x0b8 | |
| 461 | "<RESERVED>", // 0x0bc | |
| 462 | "DACK Timing Control", // 0x0c0 DMATCR | |
| 463 | "I/O Timing Control", // 0x0c4 IOTCR | |
| 464 | "Expansion Card Timing", // 0x0c8 ECTCR | |
| 465 | "DMA External Control", // 0x0cc DMAEXT (IOMD) / ASTCR (ARM7500) | |
| 466 | "DRAM Width Control", // 0x0d0 DRAMWID | |
| 467 | "Force CAS/RAS Lines Low", // 0x0d4 SELFREF | |
| 468 | "<RESERVED>", // 0x0d8 | |
| 469 | "<RESERVED>", // 0x0dc | |
| 470 | "A to D IRQ Control", // 0x0e0 ATODICR | |
| 471 | "A to D IRQ Status", // 0x0e4 ATODCC | |
| 472 | "A to D IRQ Converter Control", // 0x0e8 ATODICR | |
| 473 | "A to D IRQ Counter 1", // 0x0ec ATODCNT1 | |
| 474 | "A to D IRQ Counter 2", // 0x0f0 ATODCNT2 | |
| 475 | "A to D IRQ Counter 3", // 0x0f4 ATODCNT3 | |
| 476 | "A to D IRQ Counter 4", // 0x0f8 ATODCNT4 | |
| 477 | "<RESERVED>", // 0x0fc | |
| 478 | "I/O DMA 0 CurA", // 0x100 IO0CURA | |
| 479 | "I/O DMA 0 EndA", // 0x104 IO0ENDA | |
| 480 | "I/O DMA 0 CurB", // 0x108 IO0CURB | |
| 481 | "I/O DMA 0 EndB", // 0x10c IO0ENDB | |
| 482 | "I/O DMA 0 Control", // 0x110 IO0CR | |
| 483 | "I/O DMA 0 Status", // 0x114 IO0ST | |
| 484 | "<RESERVED>", // 0x118 | |
| 485 | "<RESERVED>", // 0x11c | |
| 486 | "I/O DMA 1 CurA", // 0x120 IO1CURA | |
| 487 | "I/O DMA 1 EndA", // 0x124 IO1ENDA | |
| 488 | "I/O DMA 1 CurB", // 0x128 IO1CURB | |
| 489 | "I/O DMA 1 EndB", // 0x12c IO1ENDB | |
| 490 | "I/O DMA 1 Control", // 0x130 IO1CR | |
| 491 | "I/O DMA 1 Status", // 0x134 IO1ST | |
| 492 | "<RESERVED>", // 0x138 | |
| 493 | "<RESERVED>", // 0x13c | |
| 494 | "I/O DMA 2 CurA", // 0x140 IO2CURA | |
| 495 | "I/O DMA 2 EndA", // 0x144 IO2ENDA | |
| 496 | "I/O DMA 2 CurB", // 0x148 IO2CURB | |
| 497 | "I/O DMA 2 EndB", // 0x14c IO2ENDB | |
| 498 | "I/O DMA 2 Control", // 0x150 IO2CR | |
| 499 | "I/O DMA 2 Status", // 0x154 IO2ST | |
| 500 | "<RESERVED>", // 0x158 | |
| 501 | "<RESERVED>", // 0x15c | |
| 502 | "I/O DMA 3 CurA", // 0x160 IO3CURA | |
| 503 | "I/O DMA 3 EndA", // 0x164 IO3ENDA | |
| 504 | "I/O DMA 3 CurB", // 0x168 IO3CURB | |
| 505 | "I/O DMA 3 EndB", // 0x16c IO3ENDB | |
| 506 | "I/O DMA 3 Control", // 0x170 IO3CR | |
| 507 | "I/O DMA 3 Status", // 0x174 IO3ST | |
| 508 | "<RESERVED>", // 0x178 | |
| 509 | "<RESERVED>", // 0x17c | |
| 510 | "Sound DMA 0 CurA", // 0x180 SD0CURA | |
| 511 | "Sound DMA 0 EndA", // 0x184 SD0ENDA | |
| 512 | "Sound DMA 0 CurB", // 0x188 SD0CURB | |
| 513 | "Sound DMA 0 EndB", // 0x18c SD0ENDB | |
| 514 | "Sound DMA 0 Control", // 0x190 SD0CR | |
| 515 | "Sound DMA 0 Status", // 0x194 SD0ST | |
| 516 | "<RESERVED>", // 0x198 | |
| 517 | "<RESERVED>", // 0x19c | |
| 518 | "Sound DMA 1 CurA", // 0x1a0 SD1CURA | |
| 519 | "Sound DMA 1 EndA", // 0x1a4 SD1ENDA | |
| 520 | "Sound DMA 1 CurB", // 0x1a8 SD1CURB | |
| 521 | "Sound DMA 1 EndB", // 0x1ac SD1ENDB | |
| 522 | "Sound DMA 1 Control", // 0x1b0 SD1CR | |
| 523 | "Sound DMA 1 Status", // 0x1b4 SD1ST | |
| 524 | "<RESERVED>", // 0x1b8 | |
| 525 | "<RESERVED>", // 0x1bc | |
| 526 | "Cursor DMA Current", // 0x1c0 CURSCUR | |
| 527 | "Cursor DMA Init", // 0x1c4 CURSINIT | |
| 528 | "Duplex LCD Current B", // 0x1c8 VIDCURB | |
| 529 | "<RESERVED>", // 0x1cc | |
| 530 | "Video DMA Current", // 0x1d0 VIDCUR | |
| 531 | "Video DMA End", // 0x1d4 VIDEND | |
| 532 | "Video DMA Start", // 0x1d8 VIDSTART | |
| 533 | "Video DMA Init", // 0x1dc VIDINIT | |
| 534 | "Video DMA Control", // 0x1e0 VIDCR | |
| 535 | "<RESERVED>", // 0x1e4 | |
| 536 | "Duplex LCD Init B", // 0x1e8 VIDINITB | |
| 537 | "<RESERVED>", // 0x1ec | |
| 538 | "DMA IRQ Status", // 0x1f0 DMAST | |
| 539 | "DMA IRQ Request", // 0x1f4 DMARQ | |
| 540 | "DMA IRQ Mask", // 0x1f8 DMAMSK | |
| 541 | "<RESERVED>" // 0x1fc | |
| 542 | }; | |
| 543 | ||
| 544 | #define IOMD_IOCR 0x000/4 | |
| 545 | #define IOMD_KBDDAT 0x004/4 | |
| 546 | #define IOMD_KBDCR 0x008/4 | |
| 547 | ||
| 548 | #define IOMD_IRQSTA 0x010/4 | |
| 549 | #define IOMD_IRQRQA 0x014/4 | |
| 550 | #define IOMD_IRQMSKA 0x018/4 | |
| 551 | ||
| 552 | #define IOMD_T0LOW 0x040/4 | |
| 553 | #define IOMD_T0HIGH 0x044/4 | |
| 554 | #define IOMD_T0GO 0x048/4 | |
| 555 | #define IOMD_T0LATCH 0x04c/4 | |
| 556 | ||
| 557 | #define IOMD_T1LOW 0x050/4 | |
| 558 | #define IOMD_T1HIGH 0x054/4 | |
| 559 | #define IOMD_T1GO 0x058/4 | |
| 560 | #define IOMD_T1LATCH 0x05c/4 | |
| 561 | ||
| 562 | #define IOMD_ID0 0x094/4 | |
| 563 | #define IOMD_ID1 0x098/4 | |
| 564 | #define IOMD_VERSION 0x09c/4 | |
| 565 | ||
| 566 | #define IOMD_VIDCUR 0x1d0/4 | |
| 567 | #define IOMD_VIDEND 0x1d4/4 | |
| 568 | #define IOMD_VIDSTART 0x1d8/4 | |
| 569 | #define IOMD_VIDINIT 0x1dc/4 | |
| 570 | #define IOMD_VIDCR 0x1e0/4 | |
| 571 | ||
| 572 | ||
| 573 | ||
| 574 | static void fire_iomd_timer(a7000_state *state, int timer) | |
| 575 | { | |
| 576 | int timer_count = state->m_timer_counter[timer]; | |
| 577 | int val = timer_count / 2; // correct? | |
| 578 | ||
| 579 | if(val==0) | |
| 580 | state->m_IOMD_timer[timer]->adjust(attotime::never); | |
| 581 | else | |
| 582 | state->m_IOMD_timer[timer]->adjust(attotime::from_usec(val), 0, attotime::from_usec(val)); | |
| 583 | } | |
| 584 | ||
| 585 | static TIMER_CALLBACK( IOMD_timer0_callback ) | |
| 586 | { | |
| 587 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 588 | state->m_IRQ_status_A|=0x20; | |
| 589 | if(state->m_IRQ_mask_A&0x20) | |
| 590 | { | |
| 591 | generic_pulse_irq_line(machine.device("maincpu"), ARM7_IRQ_LINE); | |
| 592 | } | |
| 593 | } | |
| 594 | ||
| 595 | static TIMER_CALLBACK( IOMD_timer1_callback ) | |
| 596 | { | |
| 597 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 598 | state->m_IRQ_status_A|=0x40; | |
| 599 | if(state->m_IRQ_mask_A&0x40) | |
| 600 | { | |
| 601 | generic_pulse_irq_line(machine.device("maincpu"), ARM7_IRQ_LINE); | |
| 602 | } | |
| 603 | } | |
| 604 | ||
| 605 | static TIMER_CALLBACK( flyback_timer_callback ) | |
| 606 | { | |
| 607 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 608 | state->m_IRQ_status_A|=0x08; | |
| 609 | if(state->m_IRQ_mask_A&0x08) | |
| 610 | { | |
| 611 | generic_pulse_irq_line(machine.device("maincpu"), ARM7_IRQ_LINE); | |
| 612 | } | |
| 613 | ||
| 614 | state->m_flyback_timer->adjust(machine.primary_screen->time_until_pos(state->m_vidc20_vert_reg[VDER])); | |
| 615 | } | |
| 616 | ||
| 617 | static void viddma_transfer_start(address_space *space) | |
| 618 | { | |
| 619 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 620 | UINT32 src = state->m_viddma_addr_start; | |
| 621 | UINT32 dst = 0; | |
| 622 | UINT32 size = state->m_viddma_addr_end; | |
| 623 | UINT32 dma_index; | |
| 624 | UINT8 *vram = space->machine().region("vram")->base(); | |
| 625 | ||
| 626 | /* TODO: this should actually be a qword transfer */ | |
| 627 | for(dma_index = 0;dma_index < size;dma_index++) | |
| 628 | { | |
| 629 | vram[dst] = space->read_byte(src); | |
| 630 | ||
| 631 | src++; | |
| 632 | dst++; | |
| 633 | } | |
| 634 | } | |
| 635 | ||
| 636 | static READ32_HANDLER( a7000_iomd_r ) | |
| 637 | { | |
| 638 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 639 | // if(offset != IOMD_KBDCR) | |
| 640 | // logerror("IOMD: %s Register (%04x) read\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4); | |
| 641 | ||
| 642 | ||
| 643 | switch(offset) | |
| 644 | { | |
| 645 | case IOMD_IOCR: | |
| 646 | { | |
| 647 | UINT8 flyback; | |
| 648 | int vert_pos; | |
| 649 | ||
| 650 | vert_pos = space->machine().primary_screen->vpos(); | |
| 651 | flyback = (vert_pos <= state->m_vidc20_vert_reg[VDSR] || vert_pos >= state->m_vidc20_vert_reg[VDER]) ? 0x80 : 0x00; | |
| 652 | ||
| 653 | return state->m_IOMD_IO_ctrl | 0x34 | flyback; | |
| 654 | } | |
| 655 | case IOMD_KBDCR: return state->m_IOMD_keyb_ctrl | 0x80; //IOMD Keyb status | |
| 656 | ||
| 657 | /* | |
| 658 | 1--- ---- always high | |
| 659 | -x-- ---- Timer 1 | |
| 660 | --x- ---- Timer 0 | |
| 661 | ---x ---- Power On Reset | |
| 662 | ---- x--- Flyback | |
| 663 | ---- -x-- nINT1 | |
| 664 | ---- --0- always low | |
| 665 | ---- ---x INT2 | |
| 666 | */ | |
| 667 | case IOMD_IRQSTA: return (state->m_IRQ_status_A & ~2) | 0x80; | |
| 668 | case IOMD_IRQRQA: return (state->m_IRQ_status_A & state->m_IRQ_mask_A) | 0x80; | |
| 669 | case IOMD_IRQMSKA: return (state->m_IRQ_mask_A); | |
| 670 | ||
| 671 | case IOMD_T0LOW: return state->m_timer_out[0] & 0xff; | |
| 672 | case IOMD_T0HIGH: return (state->m_timer_out[0] >> 8) & 0xff; | |
| 673 | ||
| 674 | case IOMD_T1LOW: return state->m_timer_out[1] & 0xff; | |
| 675 | case IOMD_T1HIGH: return (state->m_timer_out[1] >> 8) & 0xff; | |
| 676 | ||
| 677 | case IOMD_ID0: return state->m_io_id & 0xff; // IOMD ID low | |
| 678 | case IOMD_ID1: return (state->m_io_id >> 8) & 0xff; // IOMD ID high | |
| 679 | case IOMD_VERSION: return 0; | |
| 680 | ||
| 681 | case IOMD_VIDEND: return (state->m_viddma_addr_end & 0x00fffff8); //bits 31:24 undefined | |
| 682 | case IOMD_VIDSTART: return (state->m_viddma_addr_start & 0x1ffffff8); //bits 31, 30, 29 undefined | |
| 683 | case IOMD_VIDCR: return (state->m_viddma_status & 0xa0) | 0x50; //bit 6 = DRAM mode, bit 4 = QWORD transfer | |
| 684 | ||
| 685 | default: logerror("IOMD: %s Register (%04x) read\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4); break; | |
| 686 | } | |
| 687 | ||
| 688 | return 0; | |
| 689 | } | |
| 690 | ||
| 691 | static WRITE32_HANDLER( a7000_iomd_w ) | |
| 692 | { | |
| 693 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 694 | // logerror("IOMD: %s Register (%04x) write = %08x\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4,data); | |
| 695 | ||
| 696 | switch(offset) | |
| 697 | { | |
| 698 | case IOMD_IOCR: state->m_IOMD_IO_ctrl = data & ~0xf4; break; | |
| 699 | ||
| 700 | case IOMD_KBDCR: | |
| 701 | state->m_IOMD_keyb_ctrl = data & ~0xf4; | |
| 702 | //keyboard_ctrl_write(data & 0x08); | |
| 703 | break; | |
| 704 | ||
| 705 | case IOMD_IRQRQA: state->m_IRQ_status_A &= ~data; break; | |
| 706 | case IOMD_IRQMSKA: state->m_IRQ_mask_A = (data & ~2) | 0x80; break; | |
| 707 | ||
| 708 | case IOMD_T0LOW: state->m_timer_in[0] = (state->m_timer_in[0] & 0xff00) | (data & 0xff); break; | |
| 709 | case IOMD_T0HIGH: state->m_timer_in[0] = (state->m_timer_in[0] & 0x00ff) | ((data & 0xff) << 8); break; | |
| 710 | case IOMD_T0GO: | |
| 711 | state->m_timer_counter[0] = state->m_timer_in[0]; | |
| 712 | fire_iomd_timer(state,0); | |
| 713 | break; | |
| 714 | case IOMD_T0LATCH: | |
| 715 | { | |
| 716 | state->m_t0readinc^=1; | |
| 717 | state->m_timer_out[0] = state->m_timer_counter[0]; | |
| 718 | if(state->m_t0readinc) | |
| 719 | { | |
| 720 | state->m_timer_counter[0]--; | |
| 721 | if(state->m_timer_counter[0] < 0) | |
| 722 | state->m_timer_counter[0]+= state->m_timer_in[0]; | |
| 723 | } | |
| 724 | } | |
| 725 | break; | |
| 726 | ||
| 727 | case IOMD_T1LOW: state->m_timer_in[1] = (state->m_timer_in[1] & 0xff00) | (data & 0xff); break; | |
| 728 | case IOMD_T1HIGH: state->m_timer_in[1] = (state->m_timer_in[1] & 0x00ff) | ((data & 0xff) << 8); break; | |
| 729 | case IOMD_T1GO: | |
| 730 | state->m_timer_counter[1] = state->m_timer_in[1]; | |
| 731 | fire_iomd_timer(state,1); | |
| 732 | break; | |
| 733 | case IOMD_T1LATCH: | |
| 734 | { | |
| 735 | state->m_t1readinc^=1; | |
| 736 | state->m_timer_out[1] = state->m_timer_counter[1]; | |
| 737 | if(state->m_t1readinc) | |
| 738 | { | |
| 739 | state->m_timer_counter[1]--; | |
| 740 | if(state->m_timer_counter[1] < 0) | |
| 741 | state->m_timer_counter[1]+= state->m_timer_in[1]; | |
| 742 | } | |
| 743 | } | |
| 744 | break; | |
| 745 | ||
| 746 | case IOMD_VIDEND: state->m_viddma_addr_end = data & 0x00fffff8; //bits 31:24 unused | |
| 747 | case IOMD_VIDSTART: state->m_viddma_addr_start = data & 0x1ffffff8; //bits 31, 30, 29 unused | |
| 748 | case IOMD_VIDCR: | |
| 749 | state->m_viddma_status = data & 0xa0; if(data & 0x20) { viddma_transfer_start(space); } | |
| 750 | break; | |
| 751 | ||
| 752 | ||
| 753 | default: logerror("IOMD: %s Register (%04x) write = %08x\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4,data); | |
| 754 | } | |
| 755 | } | |
| 756 | ||
| 757 | static ADDRESS_MAP_START( a7000_mem, AS_PROGRAM, 32) | |
| 758 | AM_RANGE(0x00000000, 0x003fffff) AM_MIRROR(0x00800000) AM_ROM AM_REGION("user1", 0x0) | |
| 759 | // AM_RANGE(0x01000000, 0x01ffffff) AM_NOP //expansion ROM | |
| 760 | // AM_RANGE(0x02000000, 0x02ffffff) AM_RAM //VRAM | |
| 761 | // I/O 03000000 - 033fffff | |
| 762 | // AM_RANGE(0x03010000, 0x03011fff) //Super IO | |
| 763 | // AM_RANGE(0x03012000, 0x03029fff) //FDC | |
| 764 | // AM_RANGE(0x0302b000, 0x0302bfff) //Network podule | |
| 765 | // AM_RANGE(0x03040000, 0x0304ffff) //podule space 0,1,2,3 | |
| 766 | // AM_RANGE(0x03070000, 0x0307ffff) //podule space 4,5,6,7 | |
| 767 | AM_RANGE(0x03200000, 0x032001ff) AM_READWRITE(a7000_iomd_r,a7000_iomd_w) //IOMD Registers //mirrored at 0x03000000-0x1ff? | |
| 768 | // AM_RANGE(0x03310000, 0x03310003) //Mouse Buttons | |
| 769 | ||
| 770 | AM_RANGE(0x03400000, 0x037fffff) AM_WRITE(a7000_vidc20_w) | |
| 771 | // AM_RANGE(0x08000000, 0x08ffffff) AM_MIRROR(0x07000000) //EASI space | |
| 772 | AM_RANGE(0x10000000, 0x13ffffff) AM_RAM //SIMM 0 bank 0 | |
| 773 | AM_RANGE(0x14000000, 0x17ffffff) AM_RAM //SIMM 0 bank 1 | |
| 774 | // AM_RANGE(0x18000000, 0x18ffffff) AM_MIRROR(0x03000000) AM_RAM //SIMM 1 bank 0 | |
| 775 | // AM_RANGE(0x1c000000, 0x1cffffff) AM_MIRROR(0x03000000) AM_RAM //SIMM 1 bank 1 | |
| 776 | ADDRESS_MAP_END | |
| 777 | ||
| 778 | ||
| 779 | /* Input ports */ | |
| 780 | static INPUT_PORTS_START( a7000 ) | |
| 781 | INPUT_PORTS_END | |
| 782 | ||
| 783 | static MACHINE_START(a7000) | |
| 784 | { | |
| 785 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 786 | state->m_IOMD_timer[0] = machine.scheduler().timer_alloc(FUNC(IOMD_timer0_callback)); | |
| 787 | state->m_IOMD_timer[1] = machine.scheduler().timer_alloc(FUNC(IOMD_timer1_callback)); | |
| 788 | state->m_flyback_timer = machine.scheduler().timer_alloc(FUNC(flyback_timer_callback)); | |
| 789 | ||
| 790 | state->m_io_id = 0xd4e7; | |
| 791 | } | |
| 792 | ||
| 793 | static MACHINE_RESET(a7000) | |
| 794 | { | |
| 795 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 796 | state->m_IOMD_IO_ctrl = 0x0b | 0x34; //bit 0,1 and 3 set high on reset plus 2,4,5 always high | |
| 797 | // state->m_IRQ_status_A = 0x10; // set POR bit ON | |
| 798 | state->m_IRQ_mask_A = 0x00; | |
| 799 | ||
| 800 | state->m_IOMD_keyb_ctrl = 0x00; | |
| 801 | ||
| 802 | state->m_IOMD_timer[0]->adjust( attotime::never); | |
| 803 | state->m_IOMD_timer[1]->adjust( attotime::never); | |
| 804 | state->m_flyback_timer->adjust( attotime::never); | |
| 805 | } | |
| 806 | ||
| 807 | static MACHINE_CONFIG_START( a7000, a7000_state ) | |
| 808 | ||
| 809 | /* Basic machine hardware */ | |
| 810 | MCFG_CPU_ADD( "maincpu", ARM7, XTAL_32MHz ) | |
| 811 | MCFG_CPU_PROGRAM_MAP(a7000_mem) | |
| 812 | ||
| 813 | MCFG_MACHINE_START( a7000 ) | |
| 814 | MCFG_MACHINE_RESET( a7000 ) | |
| 815 | ||
| 816 | /* video hardware */ | |
| 817 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 818 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 819 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 820 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 821 | MCFG_SCREEN_SIZE(1900, 1080) //max available size | |
| 822 | MCFG_SCREEN_VISIBLE_AREA(0, 1900-1, 0, 1080-1) | |
| 823 | MCFG_SCREEN_UPDATE(a7000) | |
| 824 | MCFG_PALETTE_LENGTH(0x200) | |
| 825 | // MCFG_PALETTE_INIT(black_and_white) | |
| 826 | ||
| 827 | MCFG_VIDEO_START(a7000) | |
| 828 | MACHINE_CONFIG_END | |
| 829 | ||
| 830 | static MACHINE_CONFIG_DERIVED( a7000p, a7000 ) | |
| 831 | ||
| 832 | MCFG_CPU_MODIFY("maincpu") | |
| 833 | MCFG_CPU_CLOCK(XTAL_48MHz) | |
| 834 | MACHINE_CONFIG_END | |
| 835 | ||
| 836 | ROM_START(a7000) | |
| 837 | ROM_REGION( 0x800000, "user1", ROMREGION_ERASEFF ) | |
| 838 | ROM_LOAD( "rom1.bin", 0x000000, 0x100000, CRC(ff0e3d12) SHA1(fa489bebede3d13dc43cddec5b5c9b6829a28914) ) | |
| 839 | ROM_LOAD( "rom2.bin", 0x100000, 0x100000, CRC(4ae4fd8b) SHA1(1b30d5905d5364dfa48bad69257b0ef8190e9bf6) ) | |
| 840 | ROM_LOAD( "rom3.bin", 0x200000, 0x100000, CRC(3108fb2b) SHA1(865b01583f3fb5f4ed5e9201676db327cdeb40b3) ) | |
| 841 | ROM_LOAD( "rom4.bin", 0x300000, 0x100000, CRC(55a51980) SHA1(a7191727edd5babf679ebbdea6585833a1fb34e6) ) | |
| 842 | ||
| 843 | ROM_REGION( 0x800000, "vram", ROMREGION_ERASE00 ) | |
| 844 | ROM_END | |
| 845 | ||
| 846 | ROM_START(a7000p) | |
| 847 | ROM_REGION( 0x800000, "user1", ROMREGION_ERASEFF ) | |
| 848 | ROM_LOAD( "riscos-3.71.rom", 0x000000, 0x400000, CRC(211cf888) SHA1(c5fe0645e48894fb4b245abeefdc9a65d659af59)) | |
| 849 | ||
| 850 | ROM_REGION( 0x800000, "vram", ROMREGION_ERASE00 ) | |
| 851 | ROM_END | |
| 852 | ||
| 853 | /*************************************************************************** | |
| 854 | ||
| 855 | Game driver(s) | |
| 856 | ||
| 857 | ***************************************************************************/ | |
| 858 | ||
| 859 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 860 | COMP( 1995, a7000, 0, 0, a7000, a7000, 0, "Acorn", "Archimedes A7000", GAME_NOT_WORKING | GAME_NO_SOUND ) | |
| 861 | COMP( 1997, a7000p, a7000, 0, a7000p, a7000, 0, "Acorn", "Archimedes A7000+", GAME_NOT_WORKING | GAME_NO_SOUND ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | Amiga 1200 | |
| 3 | ||
| 4 | Preliminary MAME driver by Mariusz Wojcieszek | |
| 5 | CD-ROM controller by Ernesto Corvi | |
| 6 | Borrowed by incog for MESS | |
| 7 | ||
| 8 | 2009-05 Fabio Priuli: | |
| 9 | Amiga 1200 support is just sketched (I basically took cd32 and removed Akiko). I connected | |
| 10 | the floppy drive in the same way as in amiga.c but it seems to be not working, since I | |
| 11 | tried to load WB3.1 with no success. However, this problem may be due to anything: maybe | |
| 12 | the floppy code must be connected elsewhere, or the .adf image is broken, or I made some | |
| 13 | stupid mistake in the CIA interfaces. | |
| 14 | Later, it could be wise to re-factor this source and merge the non-AGA code with | |
| 15 | mess/drivers/amiga.c | |
| 16 | */ | |
| 17 | ||
| 18 | #include "emu.h" | |
| 19 | #include "cpu/m68000/m68000.h" | |
| 20 | #include "machine/6526cia.h" | |
| 21 | #include "machine/i2cmem.h" | |
| 22 | #include "machine/amigafdc.h" | |
| 23 | #include "machine/amigakbd.h" | |
| 24 | ||
| 25 | #include "includes/amiga.h" | |
| 26 | #include "includes/cd32.h" | |
| 27 | ||
| 28 | ||
| 29 | ||
| 30 | class ami1200_state : public cd32_state | |
| 31 | { | |
| 32 | public: | |
| 33 | ami1200_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 34 | : cd32_state(mconfig, type, tag) { } | |
| 35 | ||
| 36 | UINT16 potgo_value; | |
| 37 | int cd32_shifter[2]; | |
| 38 | int oldstate[2]; | |
| 39 | }; | |
| 40 | ||
| 41 | ||
| 42 | ||
| 43 | #define A1200PAL_XTAL_X1 XTAL_28_37516MHz | |
| 44 | #define A1200PAL_XTAL_X2 XTAL_4_433619MHz | |
| 45 | ||
| 46 | ||
| 47 | ||
| 48 | static void handle_cd32_joystick_cia(ami1200_state *state, UINT8 pra, UINT8 dra); | |
| 49 | ||
| 50 | static WRITE32_HANDLER( aga_overlay_w ) | |
| 51 | { | |
| 52 | if (ACCESSING_BITS_16_23) | |
| 53 | { | |
| 54 | data = (data >> 16) & 1; | |
| 55 | ||
| 56 | /* switch banks as appropriate */ | |
| 57 | memory_set_bank(space->machine(), "bank1", data & 1); | |
| 58 | ||
| 59 | /* swap the write handlers between ROM and bank 1 based on the bit */ | |
| 60 | if ((data & 1) == 0) | |
| 61 | /* overlay disabled, map RAM on 0x000000 */ | |
| 62 | space->install_write_bank(0x000000, 0x1fffff, "bank1"); | |
| 63 | else | |
| 64 | /* overlay enabled, map Amiga system ROM on 0x000000 */ | |
| 65 | space->unmap_write(0x000000, 0x1fffff); | |
| 66 | } | |
| 67 | } | |
| 68 | ||
| 69 | /************************************* | |
| 70 | * | |
| 71 | * CIA-A port A access: | |
| 72 | * | |
| 73 | * PA7 = game port 1, pin 6 (fire) | |
| 74 | * PA6 = game port 0, pin 6 (fire) | |
| 75 | * PA5 = /RDY (disk ready) | |
| 76 | * PA4 = /TK0 (disk track 00) | |
| 77 | * PA3 = /WPRO (disk write protect) | |
| 78 | * PA2 = /CHNG (disk change) | |
| 79 | * PA1 = /LED (LED, 0=bright / audio filter control) | |
| 80 | * PA0 = MUTE | |
| 81 | * | |
| 82 | *************************************/ | |
| 83 | ||
| 84 | static WRITE8_DEVICE_HANDLER( ami1200_cia_0_porta_w ) | |
| 85 | { | |
| 86 | ami1200_state *state = device->machine().driver_data<ami1200_state>(); | |
| 87 | ||
| 88 | /* bit 2 = Power Led on Amiga */ | |
| 89 | set_led_status(device->machine(), 0, !BIT(data, 1)); | |
| 90 | ||
| 91 | handle_cd32_joystick_cia(state, data, mos6526_r(device, 2)); | |
| 92 | } | |
| 93 | ||
| 94 | /************************************* | |
| 95 | * | |
| 96 | * CIA-A port B access: | |
| 97 | * | |
| 98 | * PB7 = parallel data 7 | |
| 99 | * PB6 = parallel data 6 | |
| 100 | * PB5 = parallel data 5 | |
| 101 | * PB4 = parallel data 4 | |
| 102 | * PB3 = parallel data 3 | |
| 103 | * PB2 = parallel data 2 | |
| 104 | * PB1 = parallel data 1 | |
| 105 | * PB0 = parallel data 0 | |
| 106 | * | |
| 107 | *************************************/ | |
| 108 | ||
| 109 | static READ8_DEVICE_HANDLER( ami1200_cia_0_portb_r ) | |
| 110 | { | |
| 111 | /* parallel port */ | |
| 112 | logerror("%s:CIA0_portb_r\n", device->machine().describe_context()); | |
| 113 | return 0xff; | |
| 114 | } | |
| 115 | ||
| 116 | static WRITE8_DEVICE_HANDLER( ami1200_cia_0_portb_w ) | |
| 117 | { | |
| 118 | /* parallel port */ | |
| 119 | logerror("%s:CIA0_portb_w(%02x)\n", device->machine().describe_context(), data); | |
| 120 | } | |
| 121 | ||
| 122 | static ADDRESS_MAP_START( a1200_map, AS_PROGRAM, 32 ) | |
| 123 | ADDRESS_MAP_UNMAP_HIGH | |
| 124 | AM_RANGE(0x000000, 0x1fffff) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(cd32_state, m_chip_ram, m_chip_ram_size) | |
| 125 | AM_RANGE(0xbfa000, 0xbfa003) AM_WRITE(aga_overlay_w) | |
| 126 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE16(amiga_cia_r, amiga_cia_w, 0xffffffff) | |
| 127 | AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE16(amiga_custom_r, amiga_custom_w, 0xffffffff) AM_BASE_MEMBER(cd32_state, m_custom_regs) | |
| 128 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE16(amiga_autoconfig_r, amiga_autoconfig_w, 0xffffffff) | |
| 129 | AM_RANGE(0xf80000, 0xffffff) AM_ROM AM_REGION("user1", 0) /* Kickstart */ | |
| 130 | ADDRESS_MAP_END | |
| 131 | ||
| 132 | ||
| 133 | //int cd32_input_port_val = 0; | |
| 134 | //int cd32_input_select = 0; | |
| 135 | ||
| 136 | static void cd32_potgo_w(running_machine &machine, UINT16 data) | |
| 137 | { | |
| 138 | ami1200_state *state = machine.driver_data<ami1200_state>(); | |
| 139 | int i; | |
| 140 | ||
| 141 | state->m_potgo_value = state->m_potgo_value & 0x5500; | |
| 142 | state->m_potgo_value |= data & 0xaa00; | |
| 143 | ||
| 144 | for (i = 0; i < 8; i += 2) | |
| 145 | { | |
| 146 | UINT16 dir = 0x0200 << i; | |
| 147 | if (data & dir) | |
| 148 | { | |
| 149 | UINT16 d = 0x0100 << i; | |
| 150 | state->m_potgo_value &= ~d; | |
| 151 | state->m_potgo_value |= data & d; | |
| 152 | } | |
| 153 | } | |
| 154 | for (i = 0; i < 2; i++) | |
| 155 | { | |
| 156 | UINT16 p5dir = 0x0200 << (i * 4); /* output enable P5 */ | |
| 157 | UINT16 p5dat = 0x0100 << (i * 4); /* data P5 */ | |
| 158 | if ((state->m_potgo_value & p5dir) && (state->m_potgo_value & p5dat)) | |
| 159 | state->m_cd32_shifter[i] = 8; | |
| 160 | } | |
| 161 | } | |
| 162 | ||
| 163 | static void handle_cd32_joystick_cia(ami1200_state *state, UINT8 pra, UINT8 dra) | |
| 164 | { | |
| 165 | int i; | |
| 166 | ||
| 167 | for (i = 0; i < 2; i++) | |
| 168 | { | |
| 169 | UINT8 but = 0x40 << i; | |
| 170 | UINT16 p5dir = 0x0200 << (i * 4); /* output enable P5 */ | |
| 171 | UINT16 p5dat = 0x0100 << (i * 4); /* data P5 */ | |
| 172 | if (!(state->m_potgo_value & p5dir) || !(state->m_potgo_value & p5dat)) | |
| 173 | { | |
| 174 | if ((dra & but) && (pra & but) != state->m_oldstate[i]) | |
| 175 | { | |
| 176 | if (!(pra & but)) | |
| 177 | { | |
| 178 | state->m_cd32_shifter[i]--; | |
| 179 | if (state->m_cd32_shifter[i] < 0) | |
| 180 | state->m_cd32_shifter[i] = 0; | |
| 181 | } | |
| 182 | } | |
| 183 | } | |
| 184 | state->m_oldstate[i] = pra & but; | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | ||
| 189 | static INPUT_PORTS_START( a1200 ) | |
| 190 | PORT_START("CIA0PORTA") | |
| 191 | PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_SPECIAL ) | |
| 192 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) | |
| 193 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) | |
| 194 | ||
| 195 | PORT_START("CIA0PORTB") | |
| 196 | PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 197 | ||
| 198 | PORT_START("JOY0DAT") | |
| 199 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P1JOY") | |
| 200 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 201 | ||
| 202 | PORT_START("JOY1DAT") | |
| 203 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P2JOY") | |
| 204 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 205 | ||
| 206 | PORT_START("POTGO") | |
| 207 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 208 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) | |
| 209 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 210 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) | |
| 211 | PORT_BIT( 0xaaff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 212 | ||
| 213 | PORT_START("P1JOY") | |
| 214 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) | |
| 215 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) | |
| 216 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) | |
| 217 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) | |
| 218 | ||
| 219 | PORT_START("P2JOY") | |
| 220 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) | |
| 221 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) | |
| 222 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) | |
| 223 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) | |
| 224 | ||
| 225 | PORT_START("P0MOUSEX") | |
| 226 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 227 | ||
| 228 | PORT_START("P0MOUSEY") | |
| 229 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 230 | ||
| 231 | PORT_START("P1MOUSEX") | |
| 232 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 233 | ||
| 234 | PORT_START("P1MOUSEY") | |
| 235 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 236 | ||
| 237 | PORT_INCLUDE( amiga_us_keyboard ) | |
| 238 | INPUT_PORTS_END | |
| 239 | ||
| 240 | ||
| 241 | /************************************* | |
| 242 | * | |
| 243 | * Sound definitions | |
| 244 | * | |
| 245 | *************************************/ | |
| 246 | ||
| 247 | static READ8_DEVICE_HANDLER( a1200_cia_0_portA_r ) | |
| 248 | { | |
| 249 | UINT8 ret = input_port_read(device->machine(), "CIA0PORTA") & 0xc0; /* Gameport 1 and 0 buttons */ | |
| 250 | ret |= amiga_fdc_status_r(device->machine().device("fdc")); | |
| 251 | return ret; | |
| 252 | } | |
| 253 | ||
| 254 | ||
| 255 | static const mos6526_interface a1200_cia_0_intf = | |
| 256 | { | |
| 257 | 0, /* tod_clock */ | |
| 258 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 259 | DEVCB_NULL, /* pc_func */ | |
| 260 | DEVCB_NULL, | |
| 261 | DEVCB_NULL, | |
| 262 | DEVCB_HANDLER(a1200_cia_0_portA_r), | |
| 263 | DEVCB_HANDLER(ami1200_cia_0_porta_w), /* port A */ | |
| 264 | DEVCB_HANDLER(ami1200_cia_0_portb_r), | |
| 265 | DEVCB_HANDLER(ami1200_cia_0_portb_w) /* port B */ | |
| 266 | }; | |
| 267 | ||
| 268 | static const mos6526_interface a1200_cia_1_intf = | |
| 269 | { | |
| 270 | 0, /* tod_clock */ | |
| 271 | DEVCB_LINE(amiga_cia_1_irq), /* irq_func */ | |
| 272 | DEVCB_NULL, /* pc_func */ | |
| 273 | DEVCB_NULL, | |
| 274 | DEVCB_NULL, | |
| 275 | DEVCB_NULL, | |
| 276 | DEVCB_NULL, /* port A */ | |
| 277 | DEVCB_NULL, | |
| 278 | DEVCB_DEVICE_HANDLER("fdc", amiga_fdc_control_w) /* port B */ | |
| 279 | }; | |
| 280 | ||
| 281 | ||
| 282 | static MACHINE_CONFIG_START( a1200n, ami1200_state ) | |
| 283 | ||
| 284 | /* basic machine hardware */ | |
| 285 | MCFG_CPU_ADD("maincpu", M68EC020, AMIGA_68EC020_NTSC_CLOCK) /* 14.3 Mhz */ | |
| 286 | MCFG_CPU_PROGRAM_MAP(a1200_map) | |
| 287 | ||
| 288 | // MCFG_CPU_ADD("keyboard_mpu", MC68HC05) | |
| 289 | ||
| 290 | MCFG_MACHINE_RESET(amiga) | |
| 291 | ||
| 292 | /* video hardware */ | |
| 293 | MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) | |
| 294 | ||
| 295 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 296 | MCFG_SCREEN_REFRESH_RATE(59.997) | |
| 297 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 298 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 299 | MCFG_SCREEN_SIZE(512*2, 312) | |
| 300 | MCFG_SCREEN_VISIBLE_AREA((129-8-8)*2, (449+8-1+8)*2, 44-8, 300+8-1) | |
| 301 | MCFG_SCREEN_UPDATE(amiga_aga) | |
| 302 | ||
| 303 | MCFG_VIDEO_START(amiga_aga) | |
| 304 | ||
| 305 | /* sound hardware */ | |
| 306 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 307 | ||
| 308 | MCFG_SOUND_ADD("amiga", AMIGA, XTAL_28_63636MHz/8) | |
| 309 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.25) | |
| 310 | MCFG_SOUND_ROUTE(1, "rspeaker", 0.25) | |
| 311 | MCFG_SOUND_ROUTE(2, "rspeaker", 0.25) | |
| 312 | MCFG_SOUND_ROUTE(3, "lspeaker", 0.25) | |
| 313 | ||
| 314 | /* cia */ | |
| 315 | MCFG_MOS8520_ADD("cia_0", AMIGA_68EC020_NTSC_CLOCK / 10, a1200_cia_0_intf) | |
| 316 | MCFG_MOS8520_ADD("cia_1", AMIGA_68EC020_NTSC_CLOCK / 10, a1200_cia_1_intf) | |
| 317 | ||
| 318 | MCFG_AMIGA_FDC_ADD("fdc") | |
| 319 | MACHINE_CONFIG_END | |
| 320 | ||
| 321 | static MACHINE_CONFIG_DERIVED( a1200p, a1200n ) | |
| 322 | ||
| 323 | /* adjust for PAL specs */ | |
| 324 | MCFG_CPU_MODIFY("maincpu") | |
| 325 | MCFG_CPU_CLOCK(A1200PAL_XTAL_X1/2) /* 14.18758 MHz */ | |
| 326 | ||
| 327 | /* video hardware */ | |
| 328 | MCFG_SCREEN_MODIFY("screen") | |
| 329 | MCFG_SCREEN_REFRESH_RATE(50) | |
| 330 | ||
| 331 | /* sound hardware */ | |
| 332 | MCFG_SOUND_MODIFY("amiga") | |
| 333 | MCFG_SOUND_CLOCK(A1200PAL_XTAL_X1/8) /* 3.546895 MHz */ | |
| 334 | ||
| 335 | /* cia */ | |
| 336 | MCFG_DEVICE_MODIFY("cia_0") | |
| 337 | MCFG_DEVICE_CLOCK(A1200PAL_XTAL_X1/20) | |
| 338 | MCFG_DEVICE_MODIFY("cia_1") | |
| 339 | MCFG_DEVICE_CLOCK(A1200PAL_XTAL_X1/20) | |
| 340 | MACHINE_CONFIG_END | |
| 341 | ||
| 342 | ||
| 343 | /*************************************************************************** | |
| 344 | ROM DEFINITIONS | |
| 345 | ***************************************************************************/ | |
| 346 | ||
| 347 | ROM_START( a1200n ) | |
| 348 | ROM_REGION32_BE(0x080000, "user1", 0) | |
| 349 | ROM_DEFAULT_BIOS("kick31") | |
| 350 | ROM_SYSTEM_BIOS(0, "kick30", "Kickstart 3.0 (39.106)") | |
| 351 | ROMX_LOAD("391523-01.u6a", 0x000000, 0x040000, CRC(c742a412) SHA1(999eb81c65dfd07a71ee19315d99c7eb858ab186), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 352 | ROMX_LOAD("391524-01.u6b", 0x000002, 0x040000, CRC(d55c6ec6) SHA1(3341108d3a402882b5ef9d3b242cbf3c8ab1a3e9), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 353 | ROM_SYSTEM_BIOS(1, "kick31", "Kickstart 3.1 (40.068)") | |
| 354 | ROMX_LOAD("391773-01.u6a", 0x000000, 0x040000, CRC(08dbf275) SHA1(b8800f5f909298109ea69690b1b8523fa22ddb37), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) // ROM_LOAD32_WORD_SWAP! | |
| 355 | ROMX_LOAD("391774-01.u6b", 0x000002, 0x040000, CRC(16c07bf8) SHA1(90e331be1970b0e53f53a9b0390b51b59b3869c2), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) | |
| 356 | ||
| 357 | // COMMODORE | 391508-01 REV0 | KEYBOARD MPU | |
| 358 | ROM_REGION(0x1040, "keyboard_rev0", 0) | |
| 359 | ROM_LOAD("391508-01.u13", 0x0000, 0x1040, NO_DUMP) | |
| 360 | ||
| 361 | // Amiga Tech REV1 Keyboard MPU | |
| 362 | ROM_REGION(0x2f40, "keyboard_rev1", 0) | |
| 363 | ROM_LOAD("391508-02.u13", 0x0000, 0x2f40, NO_DUMP) | |
| 364 | ROM_END | |
| 365 | ||
| 366 | #define rom_a1200p rom_a1200n | |
| 367 | ||
| 368 | ||
| 369 | /***************************************************************************************************/ | |
| 370 | ||
| 371 | // these come directly from amiga.c | |
| 372 | ||
| 373 | static UINT16 a1200_read_dskbytr(running_machine &machine) | |
| 374 | { | |
| 375 | return amiga_fdc_get_byte(machine.device("fdc")); | |
| 376 | } | |
| 377 | ||
| 378 | static void a1200_write_dsklen(running_machine &machine, UINT16 data) | |
| 379 | { | |
| 380 | cd32_state *state = machine.driver_data<cd32_state>(); | |
| 381 | if ( data & 0x8000 ) | |
| 382 | { | |
| 383 | if ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) | |
| 384 | amiga_fdc_setup_dma(machine.device("fdc")); | |
| 385 | } | |
| 386 | } | |
| 387 | ||
| 388 | ||
| 389 | static DRIVER_INIT( a1200 ) | |
| 390 | { | |
| 391 | cd32_state *state = machine.driver_data<cd32_state>(); | |
| 392 | static const amiga_machine_interface cd32_intf = | |
| 393 | { | |
| 394 | AGA_CHIP_RAM_MASK, | |
| 395 | NULL, NULL, /* joy0dat_r & joy1dat_r */ | |
| 396 | cd32_potgo_w, /* potgo_w */ | |
| 397 | a1200_read_dskbytr, a1200_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 398 | NULL, /* serdat_w */ | |
| 399 | NULL, /* scanline0_callback */ | |
| 400 | NULL, /* reset_callback */ | |
| 401 | NULL, /* nmi_callback */ | |
| 402 | FLAGS_AGA_CHIPSET /* flags */ | |
| 403 | }; | |
| 404 | ||
| 405 | /* configure our Amiga setup */ | |
| 406 | amiga_machine_config(machine, &cd32_intf); | |
| 407 | ||
| 408 | /* set up memory */ | |
| 409 | memory_configure_bank(machine, "bank1", 0, 1, state->m_chip_ram, 0); | |
| 410 | memory_configure_bank(machine, "bank1", 1, 1, machine.region("user1")->base(), 0); | |
| 411 | ||
| 412 | /* initialize keyboard */ | |
| 413 | amigakbd_init(machine); | |
| 414 | } | |
| 415 | ||
| 416 | ||
| 417 | /***************************************************************************************************/ | |
| 418 | ||
| 419 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 420 | COMP( 1992, a1200n, 0, 0, a1200n, a1200, a1200, "Commodore Business Machines", "Amiga 1200 (NTSC)" , GAME_NOT_WORKING ) | |
| 421 | COMP( 1992, a1200p, a1200n, 0, a1200p, a1200, a1200, "Commodore Business Machines", "Amiga 1200 (PAL)" , GAME_NOT_WORKING ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /**************************************************************************** | |
| 2 | ||
| 3 | PC-Engine / Turbo Grafx 16 driver | |
| 4 | by Charles Mac Donald | |
| 5 | E-Mail: cgfm2@hooked.net | |
| 6 | ||
| 7 | Thanks to David Shadoff and Brian McPhail for help with the driver. | |
| 8 | ||
| 9 | ****************************************************************************/ | |
| 10 | ||
| 11 | /********************************************************************** | |
| 12 | To-Do List: | |
| 13 | - convert h6280-based drivers to internal memory map for the I/O region | |
| 14 | - test sprite collision and overflow interrupts | |
| 15 | - sprite precaching | |
| 16 | - rewrite the base renderer loop | |
| 17 | - Add CD support | |
| 18 | - Add 6 button joystick support | |
| 19 | - Add 263 line mode | |
| 20 | - Sprite DMA should use vdc VRAM functions | |
| 21 | - properly implement the pixel clocks instead of the simple scaling we do now | |
| 22 | ||
| 23 | Banking | |
| 24 | ======= | |
| 25 | ||
| 26 | Normally address spacebanks 00-F6 are assigned to regular HuCard ROM space. There | |
| 27 | are a couple of special situations: | |
| 28 | ||
| 29 | Street Fighter II: | |
| 30 | - address space banks 40-7F switchable by writing to 1FF0-1FF3 | |
| 31 | 1FF0 - select rom banks 40-7F | |
| 32 | 1FF1 - select rom banks 80-BF | |
| 33 | 1FF2 - select rom banks C0-FF | |
| 34 | 1FF3 - select rom banks 100-13F | |
| 35 | ||
| 36 | Populous: | |
| 37 | - address space banks 40-43 contains 32KB RAM | |
| 38 | ||
| 39 | CDRom units: | |
| 40 | - address space banks 80-87 contains 64KB RAM | |
| 41 | ||
| 42 | Super System Card: | |
| 43 | - address space banks 68-7F contains 192KB RAM | |
| 44 | ||
| 45 | **********************************************************************/ | |
| 46 | ||
| 47 | /********************************************************************** | |
| 48 | Known Bugs | |
| 49 | *********************************************************************** | |
| 50 | - Benkei Gaiden: hangs after a few Sunsoft logo spins. | |
| 51 | - Busou Keiji Cyber Cross: hangs on attract mode | |
| 52 | - Cadash: After choosing character and name, the game starts and the display 'jiggles' like tracking if off a VCR | |
| 53 | - Fighting Run: has color and sprite issues during gameplay; | |
| 54 | - Hisou Kihei - Xserd: black screen; | |
| 55 | **********************************************************************/ | |
| 56 | ||
| 57 | #include "emu.h" | |
| 58 | #include "deprecat.h" | |
| 59 | #include "video/vdc.h" | |
| 60 | #include "cpu/h6280/h6280.h" | |
| 61 | #include "includes/pce.h" | |
| 62 | #include "imagedev/cartslot.h" | |
| 63 | #include "imagedev/chd_cd.h" | |
| 64 | #include "sound/c6280.h" | |
| 65 | #include "sound/cdda.h" | |
| 66 | #include "sound/msm5205.h" | |
| 67 | #include "hash.h" | |
| 68 | ||
| 69 | ||
| 70 | static ADDRESS_MAP_START( pce_mem , AS_PROGRAM, 8) | |
| 71 | AM_RANGE( 0x000000, 0x07FFFF) AM_ROMBANK("bank1") | |
| 72 | AM_RANGE( 0x080000, 0x087FFF) AM_ROMBANK("bank2") | |
| 73 | AM_RANGE( 0x088000, 0x0CFFFF) AM_ROMBANK("bank3") | |
| 74 | AM_RANGE( 0x0D0000, 0x0FFFFF) AM_ROMBANK("bank4") | |
| 75 | AM_RANGE( 0x100000, 0x10FFFF) AM_RAM AM_BASE_MEMBER( pce_state, m_cd_ram ) | |
| 76 | AM_RANGE( 0x110000, 0x1EDFFF) AM_NOP | |
| 77 | AM_RANGE( 0x1EE000, 0x1EE7FF) AM_ROMBANK("bank10") AM_WRITE( pce_cd_bram_w ) | |
| 78 | AM_RANGE( 0x1EE800, 0x1EFFFF) AM_NOP | |
| 79 | AM_RANGE( 0x1F0000, 0x1F1FFF) AM_RAM AM_MIRROR(0x6000) AM_BASE_MEMBER( pce_state, m_user_ram ) | |
| 80 | AM_RANGE( 0x1FE000, 0x1FE3FF) AM_READWRITE( vdc_0_r, vdc_0_w ) | |
| 81 | AM_RANGE( 0x1FE400, 0x1FE7FF) AM_READWRITE( vce_r, vce_w ) | |
| 82 | AM_RANGE( 0x1FE800, 0x1FEBFF) AM_DEVREADWRITE(C6280_TAG, c6280_r, c6280_w ) | |
| 83 | AM_RANGE( 0x1FEC00, 0x1FEFFF) AM_READWRITE( h6280_timer_r, h6280_timer_w ) | |
| 84 | AM_RANGE( 0x1FF000, 0x1FF3FF) AM_READWRITE( pce_joystick_r, pce_joystick_w ) | |
| 85 | AM_RANGE( 0x1FF400, 0x1FF7FF) AM_READWRITE( h6280_irq_status_r, h6280_irq_status_w ) | |
| 86 | AM_RANGE( 0x1FF800, 0x1FFBFF) AM_READWRITE( pce_cd_intf_r, pce_cd_intf_w ) | |
| 87 | ADDRESS_MAP_END | |
| 88 | ||
| 89 | static ADDRESS_MAP_START( pce_io , AS_IO, 8) | |
| 90 | AM_RANGE( 0x00, 0x03) AM_READWRITE( vdc_0_r, vdc_0_w ) | |
| 91 | ADDRESS_MAP_END | |
| 92 | ||
| 93 | static ADDRESS_MAP_START( sgx_mem , AS_PROGRAM, 8) | |
| 94 | AM_RANGE( 0x000000, 0x07FFFF) AM_ROMBANK("bank1") | |
| 95 | AM_RANGE( 0x080000, 0x087FFF) AM_ROMBANK("bank2") | |
| 96 | AM_RANGE( 0x088000, 0x0CFFFF) AM_ROMBANK("bank3") | |
| 97 | AM_RANGE( 0x0D0000, 0x0FFFFF) AM_ROMBANK("bank4") | |
| 98 | AM_RANGE( 0x100000, 0x10FFFF) AM_RAM AM_BASE_MEMBER( pce_state, m_cd_ram ) | |
| 99 | AM_RANGE( 0x110000, 0x1EDFFF) AM_NOP | |
| 100 | AM_RANGE( 0x1EE000, 0x1EE7FF) AM_ROMBANK("bank10") AM_WRITE( pce_cd_bram_w ) | |
| 101 | AM_RANGE( 0x1EE800, 0x1EFFFF) AM_NOP | |
| 102 | AM_RANGE( 0x1F0000, 0x1F7FFF) AM_RAM AM_BASE_MEMBER( pce_state, m_user_ram ) | |
| 103 | AM_RANGE( 0x1FE000, 0x1FE007) AM_READWRITE( vdc_0_r, vdc_0_w ) AM_MIRROR(0x03E0) | |
| 104 | AM_RANGE( 0x1FE008, 0x1FE00F) AM_READWRITE( vpc_r, vpc_w ) AM_MIRROR(0x03E0) | |
| 105 | AM_RANGE( 0x1FE010, 0x1FE017) AM_READWRITE( vdc_1_r, vdc_1_w ) AM_MIRROR(0x03E0) | |
| 106 | AM_RANGE( 0x1FE400, 0x1FE7FF) AM_READWRITE( vce_r, vce_w ) | |
| 107 | AM_RANGE( 0x1FE800, 0x1FEBFF) AM_DEVREADWRITE(C6280_TAG, c6280_r, c6280_w ) | |
| 108 | AM_RANGE( 0x1FEC00, 0x1FEFFF) AM_READWRITE( h6280_timer_r, h6280_timer_w ) | |
| 109 | AM_RANGE( 0x1FF000, 0x1FF3FF) AM_READWRITE( pce_joystick_r, pce_joystick_w ) | |
| 110 | AM_RANGE( 0x1FF400, 0x1FF7FF) AM_READWRITE( h6280_irq_status_r, h6280_irq_status_w ) | |
| 111 | AM_RANGE( 0x1FF800, 0x1FFBFF) AM_READWRITE( pce_cd_intf_r, pce_cd_intf_w ) | |
| 112 | ADDRESS_MAP_END | |
| 113 | ||
| 114 | static ADDRESS_MAP_START( sgx_io , AS_IO, 8) | |
| 115 | AM_RANGE( 0x00, 0x03) AM_READWRITE( sgx_vdc_r, sgx_vdc_w ) | |
| 116 | ADDRESS_MAP_END | |
| 117 | ||
| 118 | /* todo: alternate forms of input (multitap, mouse, etc.) */ | |
| 119 | static INPUT_PORTS_START( pce ) | |
| 120 | ||
| 121 | PORT_START("JOY_P1") | |
| 122 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 123 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button I") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 124 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button II") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 125 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 126 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P1 Run") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 127 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 128 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 129 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 130 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 131 | ||
| 132 | PORT_START("JOY_P2") | |
| 133 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 134 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Button I") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 135 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Button II") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 136 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 137 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P2 Run") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 138 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 139 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 140 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 141 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 142 | ||
| 143 | PORT_START("JOY_P3") | |
| 144 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 145 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P3 Button I") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 146 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P3 Button II") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 147 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P3 Select") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 148 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P3 Run") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 149 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 150 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 151 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 152 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 153 | ||
| 154 | PORT_START("JOY_P4") | |
| 155 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 156 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P4 Button I") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 157 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P4 Button II") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 158 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P4 Select") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 159 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P4 Run") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 160 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 161 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 162 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 163 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 164 | ||
| 165 | PORT_START("JOY_P5") | |
| 166 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 167 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P5 Button I") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 168 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P5 Button II") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 169 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P5 Select") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 170 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P5 Run") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 171 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 172 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 173 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 174 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 175 | ||
| 176 | PORT_START("JOY6B_P1") | |
| 177 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 178 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button I") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 179 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button II") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 180 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 181 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P1 Run") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 182 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 183 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 184 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 185 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 186 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button III") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 187 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button IV") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 188 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Button V") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 189 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Button VI") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 190 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 191 | ||
| 192 | PORT_START("JOY6B_P2") /* Player 2 controls */ | |
| 193 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 194 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Button I") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 195 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Button II") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 196 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 197 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P2 Run") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 198 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 199 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 200 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 201 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 202 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P2 Button III") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 203 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P2 Button IV") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 204 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button V") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 205 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button VI") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 206 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 207 | ||
| 208 | PORT_START("JOY6B_P3") /* Player 3 controls */ | |
| 209 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 210 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P3 Button I") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 211 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P3 Button II") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 212 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P3 Select") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 213 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P3 Run") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 214 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 215 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 216 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 217 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 218 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P3 Button III") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 219 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P3 Button IV") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 220 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P3 Button V") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 221 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P3 Button VI") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 222 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 223 | ||
| 224 | PORT_START("JOY6B_P4") /* Player 4 controls */ | |
| 225 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 226 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P4 Button I") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 227 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P4 Button II") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 228 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P4 Select") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 229 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P4 Run") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 230 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 231 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 232 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 233 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 234 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P3 Button III") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 235 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P3 Button IV") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 236 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P3 Button V") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 237 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P3 Button VI") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 238 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 239 | ||
| 240 | PORT_START("JOY6B_P5") /* Player 5 controls */ | |
| 241 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 242 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P5 Button I") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 243 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P5 Button II") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 244 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P5 Select") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 245 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P5 Run") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 246 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 247 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 248 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 249 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 250 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P5 Button III") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 251 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P5 Button IV") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 252 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P5 Button V") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 253 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P5 Button VI") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 254 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 255 | ||
| 256 | PORT_START("JOY_TYPE") | |
| 257 | PORT_CATEGORY_CLASS(0x0003,0x0000,"Joystick Type Player 1") | |
| 258 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 10) | |
| 259 | // PORT_CATEGORY_ITEM( 0x0001,"3-buttons", xx) | |
| 260 | PORT_CATEGORY_ITEM( 0x0002,"6-buttons", 11) | |
| 261 | // PORT_CATEGORY_ITEM( 0x0003,"Mouse", xx) | |
| 262 | PORT_CATEGORY_CLASS(0x000c,0x0000,"Joystick Type Player 2") | |
| 263 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 20) | |
| 264 | // PORT_CATEGORY_ITEM( 0x0004,"3-buttons", xx) | |
| 265 | PORT_CATEGORY_ITEM( 0x0008,"6-buttons", 21) | |
| 266 | // PORT_CATEGORY_ITEM( 0x000c,"Mouse", xx) | |
| 267 | PORT_CATEGORY_CLASS(0x0030,0x0000,"Joystick Type Player 3") | |
| 268 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 30) | |
| 269 | // PORT_CATEGORY_ITEM( 0x0010,"3-buttons", xx) | |
| 270 | PORT_CATEGORY_ITEM( 0x0020,"6-buttons", 31) | |
| 271 | // PORT_CATEGORY_ITEM( 0x0030,"Mouse", xx) | |
| 272 | PORT_CATEGORY_CLASS(0x00c0,0x0000,"Joystick Type Player 4") | |
| 273 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 40) | |
| 274 | // PORT_CATEGORY_ITEM( 0x0040,"3-buttons", xx) | |
| 275 | PORT_CATEGORY_ITEM( 0x0080,"6-buttons", 41) | |
| 276 | // PORT_CATEGORY_ITEM( 0x00c0,"Mouse", xx) | |
| 277 | PORT_CATEGORY_CLASS(0x0300,0x0000,"Joystick Type Player 5") | |
| 278 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 50) | |
| 279 | // PORT_CATEGORY_ITEM( 0x0100,"3-buttons", xx) | |
| 280 | PORT_CATEGORY_ITEM( 0x0200,"6-buttons", 51) | |
| 281 | // PORT_CATEGORY_ITEM( 0x0300,"Mouse", xx) | |
| 282 | ||
| 283 | PORT_START("A_CARD") | |
| 284 | PORT_CONFNAME( 0x01, 0x01, "Arcade Card" ) | |
| 285 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 286 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) | |
| 287 | INPUT_PORTS_END | |
| 288 | ||
| 289 | ||
| 290 | static void pce_partialhash(hash_collection &dest, const unsigned char *data, | |
| 291 | unsigned long length, const char *functions) | |
| 292 | { | |
| 293 | if ( ( length <= PCE_HEADER_SIZE ) || ( length & PCE_HEADER_SIZE ) ) { | |
| 294 | dest.compute(&data[PCE_HEADER_SIZE], length - PCE_HEADER_SIZE, functions); | |
| 295 | } else { | |
| 296 | dest.compute(data, length, functions); | |
| 297 | } | |
| 298 | } | |
| 299 | ||
| 300 | static const c6280_interface c6280_config = | |
| 301 | { | |
| 302 | "maincpu" | |
| 303 | }; | |
| 304 | static MACHINE_CONFIG_FRAGMENT( pce_cdslot ) | |
| 305 | MCFG_CDROM_ADD( "cdrom" ) | |
| 306 | MCFG_CDROM_INTERFACE("pce_cdrom") | |
| 307 | ||
| 308 | MCFG_SOFTWARE_LIST_ADD("cd_list","pcecd") | |
| 309 | MACHINE_CONFIG_END | |
| 310 | ||
| 311 | static MACHINE_CONFIG_FRAGMENT( pce_cartslot ) | |
| 312 | MCFG_CARTSLOT_ADD("cart") | |
| 313 | MCFG_CARTSLOT_EXTENSION_LIST("pce,bin") | |
| 314 | MCFG_CARTSLOT_MANDATORY | |
| 315 | MCFG_CARTSLOT_INTERFACE("pce_cart") | |
| 316 | MCFG_CARTSLOT_LOAD(pce_cart) | |
| 317 | MCFG_CARTSLOT_PARTIALHASH(pce_partialhash) | |
| 318 | MCFG_SOFTWARE_LIST_ADD("cart_list","pce") | |
| 319 | MACHINE_CONFIG_END | |
| 320 | ||
| 321 | static MACHINE_CONFIG_FRAGMENT( tg16_cartslot ) | |
| 322 | MCFG_CARTSLOT_ADD("cart") | |
| 323 | MCFG_CARTSLOT_EXTENSION_LIST("pce,bin") | |
| 324 | MCFG_CARTSLOT_MANDATORY | |
| 325 | MCFG_CARTSLOT_INTERFACE("tg16_cart") | |
| 326 | MCFG_CARTSLOT_LOAD(pce_cart) | |
| 327 | MCFG_CARTSLOT_PARTIALHASH(pce_partialhash) | |
| 328 | MCFG_SOFTWARE_LIST_ADD("cart_list","tg16") | |
| 329 | MACHINE_CONFIG_END | |
| 330 | ||
| 331 | static MACHINE_CONFIG_FRAGMENT( sgx_cartslot ) | |
| 332 | MCFG_CARTSLOT_ADD("cart") | |
| 333 | MCFG_CARTSLOT_EXTENSION_LIST("pce,bin") | |
| 334 | MCFG_CARTSLOT_MANDATORY | |
| 335 | MCFG_CARTSLOT_INTERFACE("pce_cart") | |
| 336 | MCFG_CARTSLOT_LOAD(pce_cart) | |
| 337 | MCFG_CARTSLOT_PARTIALHASH(pce_partialhash) | |
| 338 | MCFG_SOFTWARE_LIST_ADD("cart_list","sgx") | |
| 339 | MACHINE_CONFIG_END | |
| 340 | ||
| 341 | static MACHINE_CONFIG_START( pce_common, pce_state ) | |
| 342 | /* basic machine hardware */ | |
| 343 | MCFG_CPU_ADD("maincpu", H6280, MAIN_CLOCK/3) | |
| 344 | MCFG_CPU_PROGRAM_MAP(pce_mem) | |
| 345 | MCFG_CPU_IO_MAP(pce_io) | |
| 346 | MCFG_CPU_VBLANK_INT_HACK(pce_interrupt, VDC_LPF) | |
| 347 | MCFG_QUANTUM_TIME(attotime::from_hz(60)) | |
| 348 | ||
| 349 | MCFG_MACHINE_START( pce ) | |
| 350 | MCFG_MACHINE_RESET( pce ) | |
| 351 | ||
| 352 | /* video hardware */ | |
| 353 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 354 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 355 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 356 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 357 | MCFG_SCREEN_RAW_PARAMS(MAIN_CLOCK/2, VDC_WPF, 70, 70 + 512 + 32, VDC_LPF, 14, 14+242) | |
| 358 | MCFG_SCREEN_UPDATE( pce ) | |
| 359 | ||
| 360 | /* MCFG_GFXDECODE( pce ) */ | |
| 361 | MCFG_PALETTE_LENGTH(1024) | |
| 362 | MCFG_PALETTE_INIT( vce ) | |
| 363 | ||
| 364 | MCFG_VIDEO_START( pce ) | |
| 365 | ||
| 366 | MCFG_NVRAM_HANDLER( pce ) | |
| 367 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 368 | MCFG_SOUND_ADD(C6280_TAG, C6280, MAIN_CLOCK/6) | |
| 369 | MCFG_SOUND_CONFIG(c6280_config) | |
| 370 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) | |
| 371 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) | |
| 372 | ||
| 373 | MCFG_SOUND_ADD( "msm5205", MSM5205, PCE_CD_CLOCK / 6 ) | |
| 374 | MCFG_SOUND_CONFIG( pce_cd_msm5205_interface ) | |
| 375 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "lspeaker", 0.50 ) | |
| 376 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "rspeaker", 0.50 ) | |
| 377 | ||
| 378 | MCFG_SOUND_ADD( "cdda", CDDA, 0 ) | |
| 379 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) | |
| 380 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) | |
| 381 | MACHINE_CONFIG_END | |
| 382 | ||
| 383 | static MACHINE_CONFIG_DERIVED( pce, pce_common ) | |
| 384 | MCFG_FRAGMENT_ADD( pce_cartslot ) | |
| 385 | MCFG_FRAGMENT_ADD( pce_cdslot ) | |
| 386 | MACHINE_CONFIG_END | |
| 387 | ||
| 388 | static MACHINE_CONFIG_DERIVED( tg16, pce_common ) | |
| 389 | MCFG_FRAGMENT_ADD( tg16_cartslot ) | |
| 390 | MCFG_FRAGMENT_ADD( pce_cdslot ) | |
| 391 | MACHINE_CONFIG_END | |
| 392 | ||
| 393 | static MACHINE_CONFIG_START( sgx, pce_state ) | |
| 394 | /* basic machine hardware */ | |
| 395 | MCFG_CPU_ADD("maincpu", H6280, MAIN_CLOCK/3) | |
| 396 | MCFG_CPU_PROGRAM_MAP(sgx_mem) | |
| 397 | MCFG_CPU_IO_MAP(sgx_io) | |
| 398 | MCFG_CPU_VBLANK_INT_HACK(sgx_interrupt, VDC_LPF) | |
| 399 | MCFG_QUANTUM_TIME(attotime::from_hz(60)) | |
| 400 | ||
| 401 | MCFG_MACHINE_START( pce ) | |
| 402 | MCFG_MACHINE_RESET( pce ) | |
| 403 | ||
| 404 | /* video hardware */ | |
| 405 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 406 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 407 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 408 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 409 | MCFG_SCREEN_RAW_PARAMS(MAIN_CLOCK/2, VDC_WPF, 70, 70 + 512 + 32, VDC_LPF, 14, 14+242) | |
| 410 | MCFG_SCREEN_UPDATE( pce ) | |
| 411 | ||
| 412 | MCFG_PALETTE_LENGTH(1024) | |
| 413 | MCFG_PALETTE_INIT( vce ) | |
| 414 | ||
| 415 | MCFG_VIDEO_START( pce ) | |
| 416 | ||
| 417 | MCFG_NVRAM_HANDLER( pce ) | |
| 418 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 419 | MCFG_SOUND_ADD(C6280_TAG, C6280, MAIN_CLOCK/6) | |
| 420 | MCFG_SOUND_CONFIG(c6280_config) | |
| 421 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) | |
| 422 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) | |
| 423 | ||
| 424 | MCFG_SOUND_ADD( "msm5205", MSM5205, PCE_CD_CLOCK / 6 ) | |
| 425 | MCFG_SOUND_CONFIG( pce_cd_msm5205_interface ) | |
| 426 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "lspeaker", 0.00 ) | |
| 427 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "rspeaker", 0.00 ) | |
| 428 | ||
| 429 | MCFG_SOUND_ADD( "cdda", CDDA, 0 ) | |
| 430 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) | |
| 431 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) | |
| 432 | ||
| 433 | MCFG_FRAGMENT_ADD( sgx_cartslot ) | |
| 434 | MCFG_FRAGMENT_ADD( pce_cdslot ) | |
| 435 | MACHINE_CONFIG_END | |
| 436 | ||
| 437 | /*************************************************************************** | |
| 438 | ||
| 439 | Game driver(s) | |
| 440 | ||
| 441 | ***************************************************************************/ | |
| 442 | ||
| 443 | ROM_START( pce ) | |
| 444 | ROM_REGION( PCE_ROM_MAXSIZE, "user1", 0 ) /* Cartridge ROM area */ | |
| 445 | ROM_FILL( 0, PCE_ROM_MAXSIZE, 0xFF ) | |
| 446 | ROM_END | |
| 447 | ||
| 448 | #define rom_tg16 rom_pce | |
| 449 | #define rom_sgx rom_pce | |
| 450 | ||
| 451 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 452 | CONS( 1987, pce, 0, 0, pce, pce, pce, "Nippon Electronic Company", "PC Engine", GAME_IMPERFECT_SOUND) | |
| 453 | CONS( 1989, tg16, pce, 0, tg16, pce, tg16, "Nippon Electronic Company", "TurboGrafx 16", GAME_IMPERFECT_SOUND) | |
| 454 | CONS( 1989, sgx, pce, 0, sgx, pce, sgx, "Nippon Electronic Company", "SuperGrafx", GAME_IMPERFECT_SOUND) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | Nintendo 64 | |
| 3 | ||
| 4 | Driver by Ville Linde | |
| 5 | Reformatted to share hardware by R. Belmont | |
| 6 | Additional work by Ryan Holtz | |
| 7 | Porting from Mupen64 by Harmony | |
| 8 | */ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "cpu/rsp/rsp.h" | |
| 12 | #include "cpu/mips/mips3.h" | |
| 13 | #include "sound/dmadac.h" | |
| 14 | #include "imagedev/cartslot.h" | |
| 15 | #include "includes/n64.h" | |
| 16 | ||
| 17 | ||
| 18 | static ADDRESS_MAP_START( n64_map, AS_PROGRAM, 32 ) | |
| 19 | AM_RANGE(0x00000000, 0x007fffff) AM_RAM AM_BASE(&rdram) // RDRAM | |
| 20 | AM_RANGE(0x03f00000, 0x03f00027) AM_READWRITE(n64_rdram_reg_r, n64_rdram_reg_w) | |
| 21 | AM_RANGE(0x04000000, 0x04000fff) AM_RAM AM_SHARE("dmem") // RSP DMEM | |
| 22 | AM_RANGE(0x04001000, 0x04001fff) AM_RAM AM_SHARE("imem") // RSP IMEM | |
| 23 | AM_RANGE(0x04040000, 0x040fffff) AM_DEVREADWRITE("rsp", n64_sp_reg_r, n64_sp_reg_w) // RSP | |
| 24 | AM_RANGE(0x04100000, 0x041fffff) AM_DEVREADWRITE("rsp", n64_dp_reg_r, n64_dp_reg_w) // RDP | |
| 25 | AM_RANGE(0x04300000, 0x043fffff) AM_READWRITE(n64_mi_reg_r, n64_mi_reg_w) // MIPS Interface | |
| 26 | AM_RANGE(0x04400000, 0x044fffff) AM_READWRITE(n64_vi_reg_r, n64_vi_reg_w) // Video Interface | |
| 27 | AM_RANGE(0x04500000, 0x045fffff) AM_READWRITE(n64_ai_reg_r, n64_ai_reg_w) // Audio Interface | |
| 28 | AM_RANGE(0x04600000, 0x046fffff) AM_READWRITE(n64_pi_reg_r, n64_pi_reg_w) // Peripheral Interface | |
| 29 | AM_RANGE(0x04700000, 0x047fffff) AM_READWRITE(n64_ri_reg_r, n64_ri_reg_w) // RDRAM Interface | |
| 30 | AM_RANGE(0x04800000, 0x048fffff) AM_READWRITE(n64_si_reg_r, n64_si_reg_w) // Serial Interface | |
| 31 | //AM_RANGE(0x08000000, 0x08007fff) AM_RAM // Cartridge SRAM | |
| 32 | AM_RANGE(0x10000000, 0x13ffffff) AM_ROM AM_REGION("user2", 0) // Cartridge | |
| 33 | AM_RANGE(0x1fc00000, 0x1fc007bf) AM_ROM AM_REGION("user1", 0) // PIF ROM | |
| 34 | AM_RANGE(0x1fc007c0, 0x1fc007ff) AM_READWRITE(n64_pif_ram_r, n64_pif_ram_w) | |
| 35 | ADDRESS_MAP_END | |
| 36 | ||
| 37 | static ADDRESS_MAP_START( rsp_map, AS_PROGRAM, 32 ) | |
| 38 | AM_RANGE(0x00000000, 0x00000fff) AM_RAM AM_SHARE("dmem") | |
| 39 | AM_RANGE(0x00001000, 0x00001fff) AM_RAM AM_SHARE("imem") | |
| 40 | AM_RANGE(0x04000000, 0x04000fff) AM_RAM AM_BASE(&rsp_dmem) AM_SHARE("dmem") | |
| 41 | AM_RANGE(0x04001000, 0x04001fff) AM_RAM AM_BASE(&rsp_imem) AM_SHARE("imem") | |
| 42 | ADDRESS_MAP_END | |
| 43 | ||
| 44 | static INPUT_PORTS_START( n64 ) | |
| 45 | PORT_START("P1") | |
| 46 | PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 Button A") | |
| 47 | PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 Button B") | |
| 48 | PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 Button Z") | |
| 49 | PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(1) PORT_NAME("P1 Start") | |
| 50 | PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x91") /* Up */ | |
| 51 | PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x93") /* Down */ | |
| 52 | PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x90") /* Left */ | |
| 53 | PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x92") /* Right */ | |
| 54 | PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 55 | PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("P1 Button L") | |
| 56 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("P1 Button R") | |
| 57 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x91") /* Up */ | |
| 58 | PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x93") /* Down */ | |
| 59 | PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x90") /* Left */ | |
| 60 | PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x92") /* Right */ | |
| 61 | ||
| 62 | PORT_START("P1_ANALOG_X") | |
| 63 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(1) | |
| 64 | ||
| 65 | PORT_START("P1_ANALOG_Y") | |
| 66 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(1) PORT_REVERSE | |
| 67 | ||
| 68 | PORT_START("P2") | |
| 69 | PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 Button A") | |
| 70 | PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("P2 Button B") | |
| 71 | PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 Button Z") | |
| 72 | PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(2) PORT_NAME("P2 Start") | |
| 73 | PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x91") /* Up */ | |
| 74 | PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x93") /* Down */ | |
| 75 | PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x90") /* Left */ | |
| 76 | PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x92") /* Right */ | |
| 77 | PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 78 | PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("P2 Button L") | |
| 79 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("P2 Button R") | |
| 80 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x91") /* Up */ | |
| 81 | PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x93") /* Down */ | |
| 82 | PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x90") /* Left */ | |
| 83 | PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x92") /* Right */ | |
| 84 | ||
| 85 | PORT_START("P2_ANALOG_X") | |
| 86 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(2) | |
| 87 | ||
| 88 | PORT_START("P2_ANALOG_Y") | |
| 89 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(2) PORT_REVERSE | |
| 90 | ||
| 91 | INPUT_PORTS_END | |
| 92 | ||
| 93 | /* ?? */ | |
| 94 | static const mips3_config config = | |
| 95 | { | |
| 96 | 16384, /* code cache size */ | |
| 97 | 8192, /* data cache size */ | |
| 98 | 62500000 /* system clock */ | |
| 99 | }; | |
| 100 | ||
| 101 | static INTERRUPT_GEN( n64_vblank ) | |
| 102 | { | |
| 103 | signal_rcp_interrupt(device->machine(), VI_INTERRUPT); | |
| 104 | } | |
| 105 | ||
| 106 | static DEVICE_IMAGE_LOAD(n64_cart) | |
| 107 | { | |
| 108 | int i, length; | |
| 109 | UINT8 *cart = image.device().machine().region("user2")->base(); | |
| 110 | ||
| 111 | if (image.software_entry() == NULL) | |
| 112 | { | |
| 113 | length = image.fread( cart, 0x4000000); | |
| 114 | } | |
| 115 | else | |
| 116 | { | |
| 117 | length = image.get_software_region_length("rom"); | |
| 118 | memcpy(cart, image.get_software_region("rom"), length); | |
| 119 | } | |
| 120 | ||
| 121 | if (cart[0] == 0x37 && cart[1] == 0x80) | |
| 122 | { | |
| 123 | for (i = 0; i < length; i += 4) | |
| 124 | { | |
| 125 | UINT8 b1 = cart[i + 0]; | |
| 126 | UINT8 b2 = cart[i + 1]; | |
| 127 | UINT8 b3 = cart[i + 2]; | |
| 128 | UINT8 b4 = cart[i + 3]; | |
| 129 | cart[i + 0] = b3; | |
| 130 | cart[i + 1] = b4; | |
| 131 | cart[i + 2] = b1; | |
| 132 | cart[i + 3] = b2; | |
| 133 | } | |
| 134 | } | |
| 135 | else | |
| 136 | { | |
| 137 | for (i = 0; i < length; i += 4) | |
| 138 | { | |
| 139 | UINT8 b1 = cart[i + 0]; | |
| 140 | UINT8 b2 = cart[i + 1]; | |
| 141 | UINT8 b3 = cart[i + 2]; | |
| 142 | UINT8 b4 = cart[i + 3]; | |
| 143 | cart[i + 0] = b4; | |
| 144 | cart[i + 1] = b3; | |
| 145 | cart[i + 2] = b2; | |
| 146 | cart[i + 3] = b1; | |
| 147 | } | |
| 148 | } | |
| 149 | ||
| 150 | logerror("cart length = %d\n", length); | |
| 151 | return IMAGE_INIT_PASS; | |
| 152 | } | |
| 153 | ||
| 154 | static MACHINE_CONFIG_START( n64, _n64_state ) | |
| 155 | ||
| 156 | /* basic machine hardware */ | |
| 157 | MCFG_CPU_ADD("maincpu", VR4300BE, 93750000) | |
| 158 | MCFG_CPU_CONFIG(config) | |
| 159 | MCFG_CPU_PROGRAM_MAP(n64_map) | |
| 160 | MCFG_CPU_VBLANK_INT("screen", n64_vblank) | |
| 161 | ||
| 162 | MCFG_CPU_ADD("rsp", RSP, 62500000) | |
| 163 | MCFG_CPU_CONFIG(n64_rsp_config) | |
| 164 | MCFG_CPU_PROGRAM_MAP(rsp_map) | |
| 165 | ||
| 166 | MCFG_MACHINE_START( n64 ) | |
| 167 | MCFG_MACHINE_RESET( n64 ) | |
| 168 | MCFG_QUANTUM_TIME(attotime::from_hz(600)) | |
| 169 | ||
| 170 | /* video hardware */ | |
| 171 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 172 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 173 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 174 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 175 | MCFG_SCREEN_SIZE(640, 525) | |
| 176 | MCFG_SCREEN_VISIBLE_AREA(0, 639, 0, 239) | |
| 177 | MCFG_SCREEN_UPDATE(n64) | |
| 178 | ||
| 179 | MCFG_PALETTE_LENGTH(0x1000) | |
| 180 | ||
| 181 | MCFG_VIDEO_START(n64) | |
| 182 | ||
| 183 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 184 | ||
| 185 | MCFG_SOUND_ADD("dac2", DMADAC, 0) | |
| 186 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) | |
| 187 | MCFG_SOUND_ADD("dac1", DMADAC, 0) | |
| 188 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) | |
| 189 | ||
| 190 | /* cartridge */ | |
| 191 | MCFG_CARTSLOT_ADD("cart") | |
| 192 | MCFG_CARTSLOT_EXTENSION_LIST("v64,z64,rom,n64,bin") | |
| 193 | MCFG_CARTSLOT_MANDATORY | |
| 194 | MCFG_CARTSLOT_INTERFACE("n64_cart") | |
| 195 | MCFG_CARTSLOT_LOAD(n64_cart) | |
| 196 | ||
| 197 | /* software lists */ | |
| 198 | MCFG_SOFTWARE_LIST_ADD("cart_list","n64") | |
| 199 | MACHINE_CONFIG_END | |
| 200 | ||
| 201 | ROM_START( n64 ) | |
| 202 | ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF ) /* dummy region for R4300 */ | |
| 203 | ||
| 204 | ROM_REGION32_BE( 0x800, "user1", 0 ) | |
| 205 | ROM_LOAD( "pifdata.bin", 0x0000, 0x0800, CRC(5ec82be9) SHA1(9174eadc0f0ea2654c95fd941406ab46b9dc9bdd) ) | |
| 206 | ||
| 207 | ROM_REGION32_BE( 0x4000000, "user2", ROMREGION_ERASEFF) | |
| 208 | ||
| 209 | ROM_REGION16_BE( 0x80, "normpoint", 0 ) | |
| 210 | ROM_LOAD( "normpnt.rom", 0x00, 0x80, CRC(e7f2a005) SHA1(c27b4a364a24daeee6e99fd286753fd6216362b4) ) | |
| 211 | ||
| 212 | ROM_REGION16_BE( 0x80, "normslope", 0 ) | |
| 213 | ROM_LOAD( "normslp.rom", 0x00, 0x80, CRC(4f2ae525) SHA1(eab43f8cc52c8551d9cff6fced18ef80eaba6f05) ) | |
| 214 | ROM_END | |
| 215 | ||
| 216 | CONS(1996, n64, 0, 0, n64, n64, 0, "Nintendo", "Nintendo 64", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| r11531 | r11532 | |
|---|---|---|
| 1 | /****************************************************************************** | |
| 2 | * | |
| 3 | * Acorn Archimedes 310 | |
| 4 | * | |
| 5 | * Skeleton: Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000 | |
| 6 | * Enhanced: R. Belmont, June 2007 | |
| 7 | * Angelo Salese, August 2010 | |
| 8 | * | |
| 9 | * TODO: | |
| 10 | * - try to understand why bios 2 was working at some point and now isn't | |
| 11 | * - fix RISC OS / Arthur booting, possible causes: | |
| 12 | * \- missing reset page size hook-up | |
| 13 | * \- some subtle memory paging fault | |
| 14 | * \- missing RAM max size | |
| 15 | * \- ARM bug? | |
| 16 | * | |
| 17 | * | |
| 18 | ======================================================================================= | |
| 19 | * | |
| 20 | * Memory map (from http://b-em.bbcmicro.com/arculator/archdocs.txt) | |
| 21 | * | |
| 22 | * 0000000 - 1FFFFFF - logical RAM (32 meg) | |
| 23 | * 2000000 - 2FFFFFF - physical RAM (supervisor only - max 16MB - requires quad MEMCs) | |
| 24 | * 3000000 - 33FFFFF - IOC (IO controllers - supervisor only) | |
| 25 | * 3310000 - FDC - WD1772 | |
| 26 | * 33A0000 - Econet - 6854 | |
| 27 | * 33B0000 - Serial - 6551 | |
| 28 | * 3240000 - 33FFFFF - internal expansion cards | |
| 29 | * 32D0000 - hard disc controller (not IDE) - HD63463 | |
| 30 | * 3350010 - printer | |
| 31 | * 3350018 - latch A | |
| 32 | * 3350040 - latch B | |
| 33 | * 3270000 - external expansion cards | |
| 34 | * | |
| 35 | * 3400000 - 3FFFFFF - ROM (read - 12 meg - Arthur and RiscOS 2 512k, RiscOS 3 2MB) | |
| 36 | * 3400000 - 37FFFFF - Low ROM (4 meg, I think this is expansion ROMs) | |
| 37 | * 3800000 - 3FFFFFF - High ROM (main OS ROM) | |
| 38 | * | |
| 39 | * 3400000 - 35FFFFF - VICD10 (write - supervisor only) | |
| 40 | * 3600000 - 3FFFFFF - MEMC (write - supervisor only) | |
| 41 | * | |
| 42 | *****************************************************************************/ | |
| 43 | /* | |
| 44 | DASM of code (bios 2 / RISC OS 2) | |
| 45 | 0x380d4e0: MEMC: control to 0x10c (page size 32 kbytes, DRAM ram refresh only during flyback) | |
| 46 | 0x380d4f0: VIDC: params (screen + sound frequency) | |
| 47 | 0x380d51c: IOC: sets control to 0xff, clear IRQA and FIQ masks, sets IRQB mask to 0x80 (keyboard receive full irq) | |
| 48 | 0x380d530: IOC: sets timer 0 to 0x4e20, go command | |
| 49 | 0x380e0a8: work RAM physical check, max size etc. | |
| 50 | 0x380e1f8: IOC: Disables DRAM ram refresh, sets timer 1 to 0x7ffe, go command, then it tests the latch of this timer, enables DRAM refresh | |
| 51 | 0x380d00c: Set up default logical space | |
| 52 | 0x380d16c: Set up case by case logical space | |
| 53 | ||
| 54 | ||
| 55 | */ | |
| 56 | ||
| 57 | ||
| 58 | #include "emu.h" | |
| 59 | #include "machine/wd17xx.h" | |
| 60 | #include "imagedev/flopdrv.h" | |
| 61 | #include "cpu/arm/arm.h" | |
| 62 | #include "sound/dac.h" | |
| 63 | #include "includes/archimds.h" | |
| 64 | #include "machine/i2cmem.h" | |
| 65 | #include "machine/ram.h" | |
| 66 | ||
| 67 | ||
| 68 | class a310_state : public driver_device | |
| 69 | { | |
| 70 | public: | |
| 71 | a310_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 72 | : driver_device(mconfig, type, tag) { } | |
| 73 | ||
| 74 | }; | |
| 75 | ||
| 76 | ||
| 77 | static WRITE_LINE_DEVICE_HANDLER( a310_wd177x_intrq_w ) | |
| 78 | { | |
| 79 | if (state) | |
| 80 | archimedes_request_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY); | |
| 81 | else | |
| 82 | archimedes_clear_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY); | |
| 83 | } | |
| 84 | ||
| 85 | static WRITE_LINE_DEVICE_HANDLER( a310_wd177x_drq_w ) | |
| 86 | { | |
| 87 | if (state) | |
| 88 | archimedes_request_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY_DRQ); | |
| 89 | else | |
| 90 | archimedes_clear_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY_DRQ); | |
| 91 | } | |
| 92 | ||
| 93 | static READ32_HANDLER( a310_psy_wram_r ) | |
| 94 | { | |
| 95 | return archimedes_memc_physmem[offset]; | |
| 96 | } | |
| 97 | ||
| 98 | static WRITE32_HANDLER( a310_psy_wram_w ) | |
| 99 | { | |
| 100 | COMBINE_DATA(&archimedes_memc_physmem[offset]); | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | static DRIVER_INIT(a310) | |
| 105 | { | |
| 106 | UINT32 ram_size = ram_get_size(machine.device(RAM_TAG)); | |
| 107 | ||
| 108 | archimedes_memc_physmem = auto_alloc_array(machine, UINT32, 0x01000000); | |
| 109 | ||
| 110 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler( 0x02000000, 0x02000000+(ram_size-1), FUNC(a310_psy_wram_r), FUNC(a310_psy_wram_w) ); | |
| 111 | ||
| 112 | archimedes_driver_init(machine); | |
| 113 | } | |
| 114 | ||
| 115 | static MACHINE_START( a310 ) | |
| 116 | { | |
| 117 | archimedes_init(machine); | |
| 118 | ||
| 119 | // reset the DAC to centerline | |
| 120 | //dac_signed_data_w(machine.device("dac"), 0x80); | |
| 121 | } | |
| 122 | ||
| 123 | static MACHINE_RESET( a310 ) | |
| 124 | { | |
| 125 | archimedes_reset(machine); | |
| 126 | } | |
| 127 | ||
| 128 | static ADDRESS_MAP_START( a310_mem, AS_PROGRAM, 32 ) | |
| 129 | AM_RANGE(0x00000000, 0x01ffffff) AM_READWRITE(archimedes_memc_logical_r, archimedes_memc_logical_w) | |
| 130 | // AM_RANGE(0x02000000, 0x02ffffff) AM_RAM AM_BASE(&archimedes_memc_physmem) /* physical RAM - 16 MB for now, should be 512k for the A310 */ | |
| 131 | AM_RANGE(0x03000000, 0x033fffff) AM_READWRITE(archimedes_ioc_r, archimedes_ioc_w) | |
| 132 | AM_RANGE(0x03400000, 0x035fffff) AM_READWRITE(archimedes_vidc_r, archimedes_vidc_w) | |
| 133 | AM_RANGE(0x03600000, 0x037fffff) AM_READWRITE(archimedes_memc_r, archimedes_memc_w) | |
| 134 | AM_RANGE(0x03800000, 0x03ffffff) AM_ROM AM_REGION("maincpu", 0) AM_WRITE(archimedes_memc_page_w) | |
| 135 | ADDRESS_MAP_END | |
| 136 | ||
| 137 | ||
| 138 | static INPUT_PORTS_START( a310 ) | |
| 139 | PORT_START("dip") /* DIP switches */ | |
| 140 | PORT_BIT(0xfd, 0xfd, IPT_UNUSED) | |
| 141 | ||
| 142 | PORT_START("key0") /* KEY ROW 0 */ | |
| 143 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) | |
| 144 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) | |
| 145 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) | |
| 146 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) | |
| 147 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) | |
| 148 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) | |
| 149 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) | |
| 150 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("7 '") PORT_CODE(KEYCODE_7) | |
| 151 | ||
| 152 | PORT_START("key1") /* KEY ROW 1 */ | |
| 153 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) | |
| 154 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) | |
| 155 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) | |
| 156 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) | |
| 157 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) | |
| 158 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("` ~") PORT_CODE(KEYCODE_TILDE) | |
| 159 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("BACK SPACE") PORT_CODE(KEYCODE_BACKSPACE) | |
| 160 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) | |
| 161 | ||
| 162 | PORT_START("key2") /* KEY ROW 2 */ | |
| 163 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("q Q") PORT_CODE(KEYCODE_Q) | |
| 164 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("w W") PORT_CODE(KEYCODE_W) | |
| 165 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("e E") PORT_CODE(KEYCODE_E) | |
| 166 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("r R") PORT_CODE(KEYCODE_R) | |
| 167 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("t T") PORT_CODE(KEYCODE_T) | |
| 168 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("y Y") PORT_CODE(KEYCODE_Y) | |
| 169 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("u U") PORT_CODE(KEYCODE_U) | |
| 170 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("i I") PORT_CODE(KEYCODE_I) | |
| 171 | ||
| 172 | PORT_START("key3") /* KEY ROW 3 */ | |
| 173 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("o O") PORT_CODE(KEYCODE_O) | |
| 174 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("p P") PORT_CODE(KEYCODE_P) | |
| 175 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) | |
| 176 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) | |
| 177 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) | |
| 178 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) | |
| 179 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) | |
| 180 | PORT_BIT(0x80, 0x80, IPT_KEYBOARD) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE | |
| 181 | ||
| 182 | PORT_START("key4") /* KEY ROW 4 */ | |
| 183 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("a A") PORT_CODE(KEYCODE_A) | |
| 184 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("s S") PORT_CODE(KEYCODE_S) | |
| 185 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("d D") PORT_CODE(KEYCODE_D) | |
| 186 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("f F") PORT_CODE(KEYCODE_F) | |
| 187 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("g G") PORT_CODE(KEYCODE_G) | |
| 188 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("h H") PORT_CODE(KEYCODE_H) | |
| 189 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("j J") PORT_CODE(KEYCODE_J) | |
| 190 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("k K") PORT_CODE(KEYCODE_K) | |
| 191 | ||
| 192 | PORT_START("key5") /* KEY ROW 5 */ | |
| 193 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("l L") PORT_CODE(KEYCODE_L) | |
| 194 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) | |
| 195 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) | |
| 196 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_ASTERISK) | |
| 197 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("SHIFT (L)") PORT_CODE(KEYCODE_LSHIFT) | |
| 198 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("z Z") PORT_CODE(KEYCODE_Z) | |
| 199 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("x X") PORT_CODE(KEYCODE_X) | |
| 200 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("c C") PORT_CODE(KEYCODE_C) | |
| 201 | ||
| 202 | PORT_START("key6") /* KEY ROW 6 */ | |
| 203 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("v V") PORT_CODE(KEYCODE_V) | |
| 204 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("b B") PORT_CODE(KEYCODE_B) | |
| 205 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("n N") PORT_CODE(KEYCODE_N) | |
| 206 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("m M") PORT_CODE(KEYCODE_M) | |
| 207 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) | |
| 208 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) | |
| 209 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) | |
| 210 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("SHIFT (R)") PORT_CODE(KEYCODE_RSHIFT) | |
| 211 | ||
| 212 | PORT_START("key7") /* KEY ROW 7 */ | |
| 213 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("LINE FEED") | |
| 214 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) | |
| 215 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("- (KP)") PORT_CODE(KEYCODE_MINUS_PAD) | |
| 216 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME(", (KP)") PORT_CODE(KEYCODE_PLUS_PAD) | |
| 217 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("ENTER (KP)") PORT_CODE(KEYCODE_ENTER_PAD) | |
| 218 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME(". (KP)") PORT_CODE(KEYCODE_DEL_PAD) | |
| 219 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("0 (KP)") PORT_CODE(KEYCODE_0_PAD) | |
| 220 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("1 (KP)") PORT_CODE(KEYCODE_1_PAD) | |
| 221 | ||
| 222 | PORT_START("key8") /* KEY ROW 8 */ | |
| 223 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("2 (KP)") PORT_CODE(KEYCODE_2_PAD) | |
| 224 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("3 (KP)") PORT_CODE(KEYCODE_3_PAD) | |
| 225 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("4 (KP)") PORT_CODE(KEYCODE_4_PAD) | |
| 226 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("5 (KP)") PORT_CODE(KEYCODE_5_PAD) | |
| 227 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("6 (KP)") PORT_CODE(KEYCODE_6_PAD) | |
| 228 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("7 (KP)") PORT_CODE(KEYCODE_7_PAD) | |
| 229 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("8 (KP)") PORT_CODE(KEYCODE_8_PAD) | |
| 230 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("9 (KP)") PORT_CODE(KEYCODE_9_PAD) | |
| 231 | ||
| 232 | PORT_START("via1a") /* VIA #1 PORT A */ | |
| 233 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START) PORT_PLAYER(1) | |
| 234 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START) PORT_PLAYER(2) | |
| 235 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) | |
| 236 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) | |
| 237 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_4WAY | |
| 238 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_4WAY | |
| 239 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_4WAY | |
| 240 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_4WAY | |
| 241 | ||
| 242 | PORT_START("tape")/* tape control */ | |
| 243 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("TAPE STOP") PORT_CODE(KEYCODE_F5) | |
| 244 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("TAPE PLAY") PORT_CODE(KEYCODE_F6) | |
| 245 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("TAPE REW") PORT_CODE(KEYCODE_F7) | |
| 246 | PORT_BIT (0xf8, 0x80, IPT_UNUSED) | |
| 247 | INPUT_PORTS_END | |
| 248 | ||
| 249 | static const wd17xx_interface a310_wd17xx_interface = | |
| 250 | { | |
| 251 | DEVCB_NULL, | |
| 252 | DEVCB_LINE(a310_wd177x_intrq_w), | |
| 253 | DEVCB_LINE(a310_wd177x_drq_w), | |
| 254 | {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3} | |
| 255 | }; | |
| 256 | ||
| 257 | static const i2cmem_interface i2cmem_interface = | |
| 258 | { | |
| 259 | I2CMEM_SLAVE_ADDRESS, 0, 0x100 | |
| 260 | }; | |
| 261 | ||
| 262 | static MACHINE_CONFIG_START( a310, a310_state ) | |
| 263 | /* basic machine hardware */ | |
| 264 | MCFG_CPU_ADD("maincpu", ARM, 8000000) /* 8 MHz */ | |
| 265 | MCFG_CPU_PROGRAM_MAP(a310_mem) | |
| 266 | ||
| 267 | MCFG_MACHINE_START( a310 ) | |
| 268 | MCFG_MACHINE_RESET( a310 ) | |
| 269 | ||
| 270 | MCFG_I2CMEM_ADD("i2cmem",i2cmem_interface) | |
| 271 | ||
| 272 | /* video hardware */ | |
| 273 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 274 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 275 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 276 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 277 | MCFG_SCREEN_SIZE(1280, 1024) //TODO: default screen size | |
| 278 | MCFG_SCREEN_VISIBLE_AREA(0*8, 1280 - 1, 0*16, 1024 - 1) | |
| 279 | MCFG_SCREEN_UPDATE(archimds_vidc) | |
| 280 | ||
| 281 | MCFG_PALETTE_LENGTH(32768) | |
| 282 | ||
| 283 | MCFG_VIDEO_START(archimds_vidc) | |
| 284 | ||
| 285 | MCFG_RAM_ADD(RAM_TAG) | |
| 286 | MCFG_RAM_DEFAULT_SIZE("2M") | |
| 287 | MCFG_RAM_EXTRA_OPTIONS("512K, 1M, 4M, 8M, 16M") | |
| 288 | ||
| 289 | MCFG_WD1772_ADD("wd1772", a310_wd17xx_interface ) | |
| 290 | ||
| 291 | //MCFG_FLOPPY_4_DRIVES_ADD(a310_floppy_config) | |
| 292 | ||
| 293 | MCFG_SPEAKER_STANDARD_MONO("mono") | |
| 294 | MCFG_SOUND_ADD("dac0", DAC, 0) | |
| 295 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 296 | ||
| 297 | MCFG_SOUND_ADD("dac1", DAC, 0) | |
| 298 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 299 | ||
| 300 | MCFG_SOUND_ADD("dac2", DAC, 0) | |
| 301 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 302 | ||
| 303 | MCFG_SOUND_ADD("dac3", DAC, 0) | |
| 304 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 305 | ||
| 306 | MCFG_SOUND_ADD("dac4", DAC, 0) | |
| 307 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 308 | ||
| 309 | MCFG_SOUND_ADD("dac5", DAC, 0) | |
| 310 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 311 | ||
| 312 | MCFG_SOUND_ADD("dac6", DAC, 0) | |
| 313 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 314 | ||
| 315 | MCFG_SOUND_ADD("dac7", DAC, 0) | |
| 316 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 317 | MACHINE_CONFIG_END | |
| 318 | ||
| 319 | ROM_START(a310) | |
| 320 | ROM_REGION( 0x800000, "maincpu", 0 ) | |
| 321 | ROM_SYSTEM_BIOS( 0, "311", "RiscOS 3.11 (29 Sep 1992)" ) | |
| 322 | ROMX_LOAD( "ic24.rom", 0x000000, 0x80000, CRC(c1adde84) SHA1(12d060e0401dd0523d44453f947bdc55dd2c3240), ROM_BIOS(1) ) | |
| 323 | ROMX_LOAD( "ic25.rom", 0x080000, 0x80000, CRC(15d89664) SHA1(78f5d0e6f1e8ee603317807f53ff8fe65a3b3518), ROM_BIOS(1) ) | |
| 324 | ROMX_LOAD( "ic26.rom", 0x100000, 0x80000, CRC(a81ceb7c) SHA1(46b870876bc1f68f242726415f0c49fef7be0c72), ROM_BIOS(1) ) | |
| 325 | ROMX_LOAD( "ic27.rom", 0x180000, 0x80000, CRC(707b0c6c) SHA1(345199a33fed23996374b9db8170a52ab63f0380), ROM_BIOS(1) ) | |
| 326 | ROM_SYSTEM_BIOS( 1, "120", "Arthur/RiscOS 1.20 (25 Sep 1987)" ) | |
| 327 | ROMX_LOAD( "arthur.bin", 0x000000, 0x080000, CRC(eb3fda57) SHA1(1181ff9c2c2f3d6d414054ec33b2260404bafc81), ROM_BIOS(2) ) | |
| 328 | ROM_SYSTEM_BIOS( 2, "200", "RiscOS 2.0 (05 Oct 1988)" ) | |
| 329 | ROMX_LOAD( "riscos2.bin", 0x000000, 0x080000, CRC(89c4ad36) SHA1(b82a78830dac386f9b649b6d32a34f9c6910546d), ROM_BIOS(3) ) | |
| 330 | ||
| 331 | ROM_REGION( 0x200000, "vram", ROMREGION_ERASE00 ) | |
| 332 | ||
| 333 | ROM_REGION( 0x100, "i2cmem", ROMREGION_ERASE00 ) | |
| 334 | ROM_END | |
| 335 | ||
| 336 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 337 | COMP( 1988, a310, 0, 0, a310, a310, a310, "Acorn", "Archimedes 310", GAME_NOT_WORKING) |
| r0 | r11532 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | aescart.c | |
| 4 | ||
| 5 | Neo-Geo AES cartridge management | |
| 6 | R. Belmont, 2009 | |
| 7 | ||
| 8 | Based on ti99cart.c by Michael Zapf | |
| 9 | ||
| 10 | We leave the support in place for multiple slots in case MAME | |
| 11 | uses this at some future point for MVS multi-cart. | |
| 12 | ||
| 13 | *********************************************************************/ | |
| 14 | #include "emu.h" | |
| 15 | #include "aescart.h" | |
| 16 | #include "imagedev/cartslot.h" | |
| 17 | #include "imagedev/multcart.h" | |
| 18 | #include "includes/neogeo.h" | |
| 19 | ||
| 20 | typedef int assmfct(running_machine &machine, device_t *); | |
| 21 | ||
| 22 | enum | |
| 23 | { | |
| 24 | AESCART_FCT_ASSM = DEVINFO_FCT_DEVICE_SPECIFIC, | |
| 25 | AESCART_FCT_DISASSM | |
| 26 | }; | |
| 27 | ||
| 28 | struct _aes_multicart_t | |
| 29 | { | |
| 30 | /* Reserves space for all cartridges. This is also used in the legacy | |
| 31 | cartridge system, but only for slot 0. */ | |
| 32 | aescartridge_t cartridge[AES_NUMBER_OF_CARTRIDGE_SLOTS]; | |
| 33 | ||
| 34 | /* Determines which slot is currently active. This value is changed when there | |
| 35 | are accesses to other GROM base addresses. */ | |
| 36 | int active_slot; | |
| 37 | ||
| 38 | /* Used in order to enforce a special slot. This value is retrieved | |
| 39 | from the dipswitch setting. A value of -1 means automatic, that is, | |
| 40 | the grom base switch is used. Values 0 .. max refer to the | |
| 41 | respective slot. */ | |
| 42 | int fixed_slot; | |
| 43 | ||
| 44 | /* Holds the highest index of a cartridge being plugged in plus one. | |
| 45 | If we only have one cartridge inserted, we don't want to get a | |
| 46 | selection option, so we just mirror the memory contents. */ | |
| 47 | int next_free_slot; | |
| 48 | ||
| 49 | /* Counts the number of slots which currently contain legacy format | |
| 50 | cartridge images. */ | |
| 51 | int legacy_slots; | |
| 52 | ||
| 53 | /* Counts the number of slots which currently contain new format | |
| 54 | cartridge images. */ | |
| 55 | int multi_slots; | |
| 56 | }; | |
| 57 | typedef struct _aes_multicart_t aes_multicart_t; | |
| 58 | ||
| 59 | #define AUTO -1 | |
| 60 | ||
| 61 | /* Access to the pcb. Contained in the token of the pcb instance. */ | |
| 62 | struct _aes_pcb_t | |
| 63 | { | |
| 64 | /* Link up to the cartridge structure which contains this pcb. */ | |
| 65 | aescartridge_t *cartridge; | |
| 66 | ||
| 67 | /* Function to assemble this cartridge. */ | |
| 68 | assmfct *assemble; | |
| 69 | ||
| 70 | /* Function to disassemble this cartridge. */ | |
| 71 | assmfct *disassemble; | |
| 72 | }; | |
| 73 | typedef struct _aes_pcb_t aes_pcb_t; | |
| 74 | ||
| 75 | INLINE aes_multicart_t *get_safe_token(device_t *device) | |
| 76 | { | |
| 77 | assert(device != NULL); | |
| 78 | assert(device->type() == AES_MULTICART); | |
| 79 | ||
| 80 | return (aes_multicart_t *)downcast<legacy_device_base *>(device)->token(); | |
| 81 | } | |
| 82 | ||
| 83 | INLINE aes_pcb_t *get_safe_pcb_token(device_t *device) | |
| 84 | { | |
| 85 | assert(device != NULL); | |
| 86 | assert(device->type() == AES_CARTRIDGE_PCB_NONE || device->type() == AES_CARTRIDGE_PCB_STD); | |
| 87 | ||
| 88 | return (aes_pcb_t *)downcast<legacy_device_base *>(device)->token(); | |
| 89 | } | |
| 90 | ||
| 91 | INLINE cartslot_t *get_safe_cartslot_token(device_t *device) | |
| 92 | { | |
| 93 | assert(device != NULL); | |
| 94 | assert(device->type() == CARTSLOT); | |
| 95 | ||
| 96 | return (cartslot_t *)downcast<legacy_device_base *>(device)->token(); | |
| 97 | } | |
| 98 | ||
| 99 | /* | |
| 100 | Find the index of the cartridge name. We assume the format | |
| 101 | <name><number>, i.e. the number is the longest string from the right | |
| 102 | which can be interpreted as a number. | |
| 103 | */ | |
| 104 | static int get_index_from_tagname(device_t *image) | |
| 105 | { | |
| 106 | const char *tag = image->tag(); | |
| 107 | int maxlen = strlen(tag); | |
| 108 | int i; | |
| 109 | for (i=maxlen-1; i >=0; i--) | |
| 110 | if (tag[i] < 48 || tag[i] > 57) break; | |
| 111 | ||
| 112 | return atoi(tag+i+1); | |
| 113 | } | |
| 114 | ||
| 115 | /* | |
| 116 | Common routine to assemble cartridges from resources. | |
| 117 | */ | |
| 118 | static aescartridge_t *assemble_common(running_machine &machine, device_t *cartslot) | |
| 119 | { | |
| 120 | /* Pointer to the cartridge structure. */ | |
| 121 | aescartridge_t *cartridge; | |
| 122 | device_t *cartsys = cartslot->owner(); | |
| 123 | aes_multicart_t *cartslots = get_safe_token(cartsys); | |
| 124 | UINT8 *socketcont, *romrgn; | |
| 125 | int reslength, i, blockofs; | |
| 126 | char sprname1[16], sprname2[16]; | |
| 127 | ||
| 128 | int slotnumber = get_index_from_tagname(cartslot)-1; | |
| 129 | assert(slotnumber>=0 && slotnumber<AES_NUMBER_OF_CARTRIDGE_SLOTS); | |
| 130 | ||
| 131 | /* There is a cartridge in this slot, check the maximum slot number. */ | |
| 132 | if (cartslots->next_free_slot <= slotnumber) | |
| 133 | { | |
| 134 | cartslots->next_free_slot = slotnumber+1; | |
| 135 | } | |
| 136 | cartridge = &cartslots->cartridge[slotnumber]; | |
| 137 | ||
| 138 | // check for up to 4 program ROMs | |
| 139 | romrgn = (UINT8 *)machine.region("maincpu")->base(); | |
| 140 | blockofs = 0; | |
| 141 | for (i = 0; i < 4; i++) | |
| 142 | { | |
| 143 | sprintf(sprname1, "p%d", i+1); | |
| 144 | ||
| 145 | socketcont = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 146 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 147 | ||
| 148 | if (socketcont != NULL) | |
| 149 | { | |
| 150 | memcpy(romrgn+blockofs, socketcont, reslength); | |
| 151 | blockofs += reslength; | |
| 152 | } | |
| 153 | } | |
| 154 | ||
| 155 | // 1 m1 ROM | |
| 156 | socketcont = (UINT8*)cartslot_get_socket(cartslot, "m1"); | |
| 157 | reslength = cartslot_get_resource_length(cartslot, "m1"); | |
| 158 | if (socketcont != NULL) | |
| 159 | { | |
| 160 | romrgn = (UINT8 *)machine.region("audiocpu")->base(); | |
| 161 | ||
| 162 | memcpy(romrgn, socketcont, reslength); | |
| 163 | // mirror (how does this really work?) | |
| 164 | memcpy(romrgn+0x10000, socketcont, reslength); | |
| 165 | } | |
| 166 | ||
| 167 | // up to 8 YM sample ROMs | |
| 168 | romrgn = (UINT8 *)machine.region("ymsnd")->base(); | |
| 169 | blockofs = 0; | |
| 170 | for (i = 0; i < 8; i++) | |
| 171 | { | |
| 172 | sprintf(sprname1, "v1%d", i+1); | |
| 173 | ||
| 174 | socketcont = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 175 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 176 | ||
| 177 | if (socketcont != NULL) | |
| 178 | { | |
| 179 | memcpy(romrgn+blockofs, socketcont, reslength); | |
| 180 | blockofs += reslength; | |
| 181 | } | |
| 182 | } | |
| 183 | ||
| 184 | // up to 8 YM delta-T sample ROMs | |
| 185 | romrgn = (UINT8 *)machine.region("ymsnd.deltat")->base(); | |
| 186 | blockofs = 0; | |
| 187 | for (i = 0; i < 8; i++) | |
| 188 | { | |
| 189 | sprintf(sprname1, "v2%d", i+1); | |
| 190 | ||
| 191 | socketcont = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 192 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 193 | ||
| 194 | if (socketcont != NULL) | |
| 195 | { | |
| 196 | memcpy(romrgn+blockofs, socketcont, reslength); | |
| 197 | blockofs += reslength; | |
| 198 | } | |
| 199 | } | |
| 200 | ||
| 201 | // 1 s1 ROM | |
| 202 | socketcont = (UINT8*)cartslot_get_socket(cartslot, "s1"); | |
| 203 | reslength = cartslot_get_resource_length(cartslot, "s1"); | |
| 204 | if (socketcont != NULL) | |
| 205 | { | |
| 206 | romrgn = (UINT8 *)machine.region("fixed")->base(); | |
| 207 | ||
| 208 | memcpy(romrgn, socketcont, reslength); | |
| 209 | } | |
| 210 | ||
| 211 | // up to 8 sprite ROMs in byte-interleaved pairs | |
| 212 | romrgn = (UINT8 *)machine.region("sprites")->base(); | |
| 213 | blockofs = 0; | |
| 214 | for (i = 0; i < 8; i+=2) | |
| 215 | { | |
| 216 | UINT8 *spr1, *spr2; | |
| 217 | int j; | |
| 218 | ||
| 219 | sprintf(sprname1, "c%d", i+1); | |
| 220 | sprintf(sprname2, "c%d", i+2); | |
| 221 | ||
| 222 | spr1 = (UINT8*)cartslot_get_socket(cartslot, sprname1); | |
| 223 | spr2 = (UINT8*)cartslot_get_socket(cartslot, sprname2); | |
| 224 | reslength = cartslot_get_resource_length(cartslot, sprname1); | |
| 225 | ||
| 226 | if ((spr1) && (spr2)) | |
| 227 | { | |
| 228 | for (j = 0; j < reslength; j++) | |
| 229 | { | |
| 230 | romrgn[blockofs + (j*2)] = spr1[j]; | |
| 231 | romrgn[blockofs + (j*2) + 1] = spr2[j]; | |
| 232 | } | |
| 233 | ||
| 234 | blockofs += reslength*2; | |
| 235 | } | |
| 236 | } | |
| 237 | ||
| 238 | return cartridge; | |
| 239 | } | |
| 240 | ||
| 241 | static void set_pointers(device_t *pcb, int index) | |
| 242 | { | |
| 243 | device_t *cartsys = pcb->owner()->owner(); | |
| 244 | aes_multicart_t *cartslots = get_safe_token(cartsys); | |
| 245 | aes_pcb_t *pcb_def = get_safe_pcb_token(pcb); | |
| 246 | ||
| 247 | pcb_def->assemble = (assmfct *)downcast<const legacy_cart_slot_device_base *>(pcb)->get_legacy_fct(AESCART_FCT_ASSM); | |
| 248 | pcb_def->disassemble = (assmfct *)downcast<const legacy_cart_slot_device_base *>(pcb)->get_legacy_fct(AESCART_FCT_DISASSM); | |
| 249 | ||
| 250 | pcb_def->cartridge = &cartslots->cartridge[index]; | |
| 251 | pcb_def->cartridge->pcb = pcb; | |
| 252 | } | |
| 253 | ||
| 254 | /***************************************************************************** | |
| 255 | Cartridge type: None | |
| 256 | This PCB device is just a pseudo device; the legacy mode is handled | |
| 257 | by dedicated functions. | |
| 258 | ******************************************************************************/ | |
| 259 | static DEVICE_START(aes_pcb_none) | |
| 260 | { | |
| 261 | /* device is aes_cartslot:cartridge:pcb */ | |
| 262 | // printf("DEVICE_START(aes_pcb_none), tag of device=%s\n", device->tag()); | |
| 263 | set_pointers(device, get_index_from_tagname(device->owner())-1); | |
| 264 | } | |
| 265 | ||
| 266 | /***************************************************************************** | |
| 267 | Cartridge type: Standard | |
| 268 | Most cartridges are built in this type. This includes word-swapped program, | |
| 269 | z80 program, YM samples, delta-T samples, sprites, and sfix. | |
| 270 | ******************************************************************************/ | |
| 271 | ||
| 272 | static DEVICE_START(aes_pcb_std) | |
| 273 | { | |
| 274 | /* device is aes_cartslot:cartridge:pcb */ | |
| 275 | // printf("DEVICE_START(aes_pcb_std), tag of device=%s\n", device->tag()); | |
| 276 | set_pointers(device, get_index_from_tagname(device->owner())-1); | |
| 277 | } | |
| 278 | ||
| 279 | /* | |
| 280 | The standard cartridge assemble routine. We just call the common | |
| 281 | function here. | |
| 282 | */ | |
| 283 | static int assemble_std(running_machine &machine, device_t *image) | |
| 284 | { | |
| 285 | // aescartridge_t *cart; | |
| 286 | // printf("assemble_std, %s\n", image->tag); | |
| 287 | /*cart = */assemble_common(machine, image); | |
| 288 | ||
| 289 | return IMAGE_INIT_PASS; | |
| 290 | } | |
| 291 | ||
| 292 | /* | |
| 293 | Removes pointers and restores the state before plugging in the | |
| 294 | cartridge. | |
| 295 | The pointer to the location after the last cartridge is adjusted. | |
| 296 | As it seems, we can use the same function for the disassembling of all | |
| 297 | cartridge types. | |
| 298 | */ | |
| 299 | static int disassemble_std(device_t *image) | |
| 300 | { | |
| 301 | // int slotnumber; | |
| 302 | // int i; | |
| 303 | // aescartridge_t *cart; | |
| 304 | // device_t *cartsys = image->owner(); | |
| 305 | // aes_multicart_t *cartslots = (aes_multicart_t *)cartsys->token; | |
| 306 | ||
| 307 | // slotnumber = get_index_from_tagname(image)-1; | |
| 308 | // printf("Disassemble cartridge %d\n", slotnumber); | |
| 309 | #if 0 | |
| 310 | /* Search the highest remaining cartridge. */ | |
| 311 | cartslots->next_free_slot = 0; | |
| 312 | for (i=AES_NUMBER_OF_CARTRIDGE_SLOTS-1; i >= 0; i--) | |
| 313 | { | |
| 314 | if (i != slotnumber) | |
| 315 | { | |
| 316 | if (0) //!slot_is_empty(cartsys, i)) (for future use?) | |
| 317 | { | |
| 318 | cartslots->next_free_slot = i+1; | |
| 319 | // printf("Setting new next_free_slot to %d\n", cartslots->next_free_slot); | |
| 320 | break; | |
| 321 | } | |
| 322 | } | |
| 323 | } | |
| 324 | #endif | |
| 325 | /* Do we have RAM? If so, swap the bytes (undo the BIG_ENDIANIZE) */ | |
| 326 | // cart = &cartslots->cartridge[slotnumber]; | |
| 327 | ||
| 328 | // clear_slot(cartsys, slotnumber); | |
| 329 | ||
| 330 | return IMAGE_INIT_PASS; | |
| 331 | } | |
| 332 | ||
| 333 | /***************************************************************************** | |
| 334 | Device metadata | |
| 335 | ******************************************************************************/ | |
| 336 | ||
| 337 | static DEVICE_GET_INFO(aes_cart_common) | |
| 338 | { | |
| 339 | switch(state) | |
| 340 | { | |
| 341 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 342 | case DEVINFO_INT_TOKEN_BYTES: | |
| 343 | info->i = sizeof(aes_pcb_t); | |
| 344 | break; | |
| 345 | case DEVINFO_INT_INLINE_CONFIG_BYTES: | |
| 346 | info->i = 0; | |
| 347 | break; | |
| 348 | ||
| 349 | /* --- the following bits of info are returned as pointers to functions --- */ | |
| 350 | case DEVINFO_FCT_START: | |
| 351 | info->start = DEVICE_START_NAME(aes_pcb_std); | |
| 352 | break; | |
| 353 | case DEVINFO_FCT_STOP: | |
| 354 | /* Nothing */ | |
| 355 | break; | |
| 356 | case DEVINFO_FCT_RESET: | |
| 357 | /* Nothing */ | |
| 358 | break; | |
| 359 | ||
| 360 | case AESCART_FCT_ASSM: | |
| 361 | info->f = (genf *) assemble_std; | |
| 362 | break; | |
| 363 | ||
| 364 | case AESCART_FCT_DISASSM: | |
| 365 | info->f = (genf *) disassemble_std; | |
| 366 | break; | |
| 367 | ||
| 368 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 369 | case DEVINFO_STR_NAME: | |
| 370 | strcpy(info->s, "AES standard cartridge pcb"); | |
| 371 | break; | |
| 372 | case DEVINFO_STR_FAMILY: | |
| 373 | strcpy(info->s, "AES cartridge pcb"); | |
| 374 | break; | |
| 375 | case DEVINFO_STR_VERSION: | |
| 376 | strcpy(info->s, "1.0"); | |
| 377 | break; | |
| 378 | case DEVINFO_STR_SOURCE_FILE: | |
| 379 | strcpy(info->s, __FILE__); | |
| 380 | break; | |
| 381 | case DEVINFO_STR_CREDITS: | |
| 382 | /* Nothing */ | |
| 383 | break; | |
| 384 | } | |
| 385 | } | |
| 386 | ||
| 387 | DEVICE_GET_INFO(aes_cartridge_pcb_none) | |
| 388 | { | |
| 389 | switch(state) | |
| 390 | { | |
| 391 | case DEVINFO_FCT_START: | |
| 392 | info->start = DEVICE_START_NAME(aes_pcb_none); | |
| 393 | break; | |
| 394 | ||
| 395 | case DEVINFO_STR_NAME: | |
| 396 | strcpy(info->s, "AES empty cartridge"); | |
| 397 | break; | |
| 398 | ||
| 399 | default: | |
| 400 | DEVICE_GET_INFO_CALL(aes_cart_common); | |
| 401 | break; | |
| 402 | } | |
| 403 | } | |
| 404 | ||
| 405 | DEVICE_GET_INFO(aes_cartridge_pcb_std) | |
| 406 | { | |
| 407 | DEVICE_GET_INFO_CALL(aes_cart_common); | |
| 408 | } | |
| 409 | ||
| 410 | /***************************************************************************** | |
| 411 | The cartridge handling of the multi-cartridge system. | |
| 412 | Every cartridge contains a PCB device. The memory handlers delegate the calls | |
| 413 | to the respective handlers of the cartridges. | |
| 414 | ******************************************************************************/ | |
| 415 | /* | |
| 416 | Initialize a cartridge. Each cartridge contains a PCB device. | |
| 417 | */ | |
| 418 | static DEVICE_START( aes_cartridge ) | |
| 419 | { | |
| 420 | cartslot_t *cart = get_safe_cartslot_token(device); | |
| 421 | ||
| 422 | /* find the PCB device */ | |
| 423 | cart->pcb_device = device->subdevice(TAG_PCB); | |
| 424 | } | |
| 425 | ||
| 426 | // handle protected carts | |
| 427 | static void install_protection(device_image_interface& image) | |
| 428 | { | |
| 429 | neogeo_state *state = image.device().machine().driver_data<neogeo_state>(); | |
| 430 | const char *crypt_feature = image.get_feature( "crypt" ); | |
| 431 | ||
| 432 | if(crypt_feature == NULL) | |
| 433 | return; | |
| 434 | ||
| 435 | if(strcmp(crypt_feature,"fatfury2_prot") == 0) | |
| 436 | { | |
| 437 | fatfury2_install_protection(image.device().machine()); | |
| 438 | logerror("Installed Fatal Fury 2 protection\n"); | |
| 439 | } | |
| 440 | if(strcmp(crypt_feature,"kof99_crypt") == 0) | |
| 441 | { | |
| 442 | kof99_decrypt_68k(image.device().machine()); | |
| 443 | state->m_fixed_layer_bank_type = 1; | |
| 444 | kof99_neogeo_gfx_decrypt(image.device().machine(), 0x00); | |
| 445 | kof99_install_protection(image.device().machine()); | |
| 446 | logerror("Decrypted KOF99 code and graphics.\n"); | |
| 447 | } | |
| 448 | if(strcmp(crypt_feature,"mslug3_crypt") == 0) | |
| 449 | { | |
| 450 | state->m_fixed_layer_bank_type = 1; | |
| 451 | kof99_neogeo_gfx_decrypt(image.device().machine(), 0xad); | |
| 452 | logerror("Decrypted Metal Slug 3 graphics\n"); | |
| 453 | } | |
| 454 | if(strcmp(crypt_feature,"matrim_crypt") == 0) | |
| 455 | { | |
| 456 | matrim_decrypt_68k(image.device().machine()); | |
| 457 | neo_pcm2_swap(image.device().machine(), 1); | |
| 458 | state->m_fixed_layer_bank_type = 2; | |
| 459 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 460 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x6a); | |
| 461 | logerror("Decrypted Matrimelee code, sound and graphics\n"); | |
| 462 | } | |
| 463 | if(strcmp(crypt_feature,"svc_crypt") == 0) | |
| 464 | { | |
| 465 | svc_px_decrypt(image.device().machine()); | |
| 466 | neo_pcm2_swap(image.device().machine(), 3); | |
| 467 | state->m_fixed_layer_bank_type = 2; | |
| 468 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 469 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x57); | |
| 470 | install_pvc_protection(image.device().machine()); | |
| 471 | logerror("Decrypted SvC code, sound and graphics.\n"); | |
| 472 | } | |
| 473 | if(strcmp(crypt_feature,"samsho5_crypt") == 0) | |
| 474 | { | |
| 475 | samsho5_decrypt_68k(image.device().machine()); | |
| 476 | neo_pcm2_swap(image.device().machine(), 4); | |
| 477 | state->m_fixed_layer_bank_type = 1; | |
| 478 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 479 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x0f); | |
| 480 | logerror("Decrypted Samurai Shodown V code, sound and graphics.\n"); | |
| 481 | } | |
| 482 | if(strcmp(crypt_feature,"kof2000_crypt") == 0) | |
| 483 | { | |
| 484 | kof2000_decrypt_68k(image.device().machine()); | |
| 485 | state->m_fixed_layer_bank_type = 2; | |
| 486 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 487 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x00); | |
| 488 | kof2000_install_protection(image.device().machine()); | |
| 489 | logerror("Decrypted KOF2000 code, sound and graphics.\n"); | |
| 490 | } | |
| 491 | if(strcmp(crypt_feature,"kof2001_crypt") == 0) | |
| 492 | { | |
| 493 | state->m_fixed_layer_bank_type = 1; | |
| 494 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x1e); | |
| 495 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 496 | logerror("Decrypted KOF2001 code and graphics.\n"); | |
| 497 | } | |
| 498 | if(strcmp(crypt_feature,"kof2002_crypt") == 0) | |
| 499 | { | |
| 500 | kof2002_decrypt_68k(image.device().machine()); | |
| 501 | neo_pcm2_swap(image.device().machine(), 0); | |
| 502 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 503 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0xec); | |
| 504 | logerror("Decrypted KOF2002 code, sound and graphics.\n"); | |
| 505 | } | |
| 506 | if(strcmp(crypt_feature,"mslug4_crypt") == 0) | |
| 507 | { | |
| 508 | state->m_fixed_layer_bank_type = 1; /* USA violent content screen is wrong -- not a bug, confirmed on real hardware! */ | |
| 509 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 510 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x31); | |
| 511 | neo_pcm2_snk_1999(image.device().machine(), 8); | |
| 512 | logerror("Decrypted Metal Slug 4 code, sound and graphics.\n"); | |
| 513 | } | |
| 514 | if(strcmp(crypt_feature,"mslug5_crypt") == 0) | |
| 515 | { | |
| 516 | mslug5_decrypt_68k(image.device().machine()); | |
| 517 | neo_pcm2_swap(image.device().machine(), 2); | |
| 518 | state->m_fixed_layer_bank_type = 1; | |
| 519 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 520 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x19); | |
| 521 | install_pvc_protection(image.device().machine()); | |
| 522 | logerror("Decrypted Metal Slug 5 code and graphics, and installed protection routines.\n"); | |
| 523 | } | |
| 524 | if(strcmp(crypt_feature,"kof2003_crypt") == 0) | |
| 525 | { | |
| 526 | kof2003h_decrypt_68k(image.device().machine()); | |
| 527 | neo_pcm2_swap(image.device().machine(), 5); | |
| 528 | state->m_fixed_layer_bank_type = 2; | |
| 529 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 530 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x9d); | |
| 531 | install_pvc_protection(image.device().machine()); | |
| 532 | logerror("Decrypted KOF2003 code and graphicss, and installed protection routines.\n"); | |
| 533 | } | |
| 534 | if(strcmp(crypt_feature,"samsho5s_crypt") == 0) | |
| 535 | { | |
| 536 | samsh5sp_decrypt_68k(image.device().machine()); | |
| 537 | neo_pcm2_swap(image.device().machine(), 6); | |
| 538 | state->m_fixed_layer_bank_type = 1; | |
| 539 | neogeo_cmc50_m1_decrypt(image.device().machine()); | |
| 540 | kof2000_neogeo_gfx_decrypt(image.device().machine(), 0x0d); | |
| 541 | } | |
| 542 | } | |
| 543 | ||
| 544 | /* | |
| 545 | Load the cartridge image files. Apart from reading, we set pointers | |
| 546 | to the image files so that during runtime we do not need search | |
| 547 | operations. | |
| 548 | */ | |
| 549 | static DEVICE_IMAGE_LOAD( aes_cartridge ) | |
| 550 | { | |
| 551 | device_t *pcbdev = cartslot_get_pcb(image); | |
| 552 | aes_pcb_t *pcb; | |
| 553 | cartslot_t *cart; | |
| 554 | multicart_open_error me; | |
| 555 | UINT32 size; | |
| 556 | device_t* ym = image.device().machine().device("ymsnd"); | |
| 557 | ||
| 558 | // first check software list | |
| 559 | if(image.software_entry() != NULL) | |
| 560 | { | |
| 561 | // create memory regions | |
| 562 | size = image.get_software_region_length("maincpu"); | |
| 563 | image.device().machine().region_free("maincpu"); | |
| 564 | image.device().machine().region_alloc("maincpu",size,1, ENDIANNESS_LITTLE); | |
| 565 | memcpy(image.device().machine().region("maincpu")->base(),image.get_software_region("maincpu"),size); | |
| 566 | size = image.get_software_region_length("fixed"); | |
| 567 | image.device().machine().region_free("fixed"); | |
| 568 | image.device().machine().region_alloc("fixed",size,1, ENDIANNESS_LITTLE); | |
| 569 | memcpy(image.device().machine().region("fixed")->base(),image.get_software_region("fixed"),size); | |
| 570 | size = image.get_software_region_length("audiocpu"); | |
| 571 | image.device().machine().region_free("audiocpu"); | |
| 572 | image.device().machine().region_alloc("audiocpu",size,1, ENDIANNESS_LITTLE); | |
| 573 | memcpy(image.device().machine().region("audiocpu")->base(),image.get_software_region("audiocpu"),size); | |
| 574 | size = image.get_software_region_length("ymsnd"); | |
| 575 | image.device().machine().region_free("ymsnd"); | |
| 576 | image.device().machine().region_alloc("ymsnd",size,1, ENDIANNESS_LITTLE); | |
| 577 | memcpy(image.device().machine().region("ymsnd")->base(),image.get_software_region("ymsnd"),size); | |
| 578 | if(image.get_software_region("ymsnd.deltat") != NULL) | |
| 579 | { | |
| 580 | size = image.get_software_region_length("ymsnd.deltat"); | |
| 581 | image.device().machine().region_free("ymsnd.deltat"); | |
| 582 | image.device().machine().region_alloc("ymsnd.deltat",size,1, ENDIANNESS_LITTLE); | |
| 583 | memcpy(image.device().machine().region("ymsnd.deltat")->base(),image.get_software_region("ymsnd.deltat"),size); | |
| 584 | } | |
| 585 | else | |
| 586 | image.device().machine().region_free("ymsnd.deltat"); // removing the region will fix sound glitches in non-Delta-T games | |
| 587 | ym->reset(); | |
| 588 | size = image.get_software_region_length("sprites"); | |
| 589 | image.device().machine().region_free("sprites"); | |
| 590 | image.device().machine().region_alloc("sprites",size,1, ENDIANNESS_LITTLE); | |
| 591 | memcpy(image.device().machine().region("sprites")->base(),image.get_software_region("sprites"),size); | |
| 592 | if(image.get_software_region("audiocrypt") != NULL) // encrypted Z80 code | |
| 593 | { | |
| 594 | size = image.get_software_region_length("audiocrypt"); | |
| 595 | image.device().machine().region_alloc("audiocrypt",size,1, ENDIANNESS_LITTLE); | |
| 596 | memcpy(image.device().machine().region("audiocrypt")->base(),image.get_software_region("audiocrypt"),size); | |
| 597 | } | |
| 598 | ||
| 599 | // setup cartridge ROM area | |
| 600 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x000080,0x0fffff,"cart_rom"); | |
| 601 | memory_set_bankptr(image.device().machine(),"cart_rom",&image.device().machine().region("maincpu")->base()[0x80]); | |
| 602 | ||
| 603 | // handle possible protection | |
| 604 | install_protection(image); | |
| 605 | ||
| 606 | return IMAGE_INIT_PASS; | |
| 607 | } | |
| 608 | ||
| 609 | if (pcbdev == NULL) | |
| 610 | fatalerror("Error loading multicart: no pcb found."); | |
| 611 | ||
| 612 | /* If we are here, we have a multicart. */ | |
| 613 | pcb = get_safe_pcb_token(pcbdev); | |
| 614 | cart = get_safe_cartslot_token(&image.device()); | |
| 615 | ||
| 616 | /* try opening this as a multicart */ | |
| 617 | /* This line requires that cartslot_t be included in cartslot.h, | |
| 618 | otherwise one cannot make use of multicart handling within such a | |
| 619 | custom LOAD function. */ | |
| 620 | me = multicart_open(image.device().machine().options(), image.filename(), image.device().machine().system().name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc); | |
| 621 | ||
| 622 | /* Now that we have loaded the image files, let the PCB put them all | |
| 623 | together. This means we put the images in a structure which allows | |
| 624 | for a quick access by the memory handlers. Every PCB defines an | |
| 625 | own assembly method. */ | |
| 626 | if (me != MCERR_NONE) | |
| 627 | fatalerror("Error loading multicart: %s", multicart_error_text(me)); | |
| 628 | ||
| 629 | return pcb->assemble(pcbdev->machine(), image); | |
| 630 | } | |
| 631 | ||
| 632 | /* | |
| 633 | This is called when the cartridge is unplugged (or the emulator is | |
| 634 | stopped). | |
| 635 | */ | |
| 636 | static DEVICE_IMAGE_UNLOAD( aes_cartridge ) | |
| 637 | { | |
| 638 | device_t *pcbdev; | |
| 639 | ||
| 640 | if (downcast<legacy_device_base *>(&image.device())->token() == NULL) | |
| 641 | { | |
| 642 | /* This means something went wrong during the pcb | |
| 643 | identification (e.g. one of the cartridge files was not | |
| 644 | found). We do not need to (and cannot) unload | |
| 645 | the cartridge. */ | |
| 646 | return; | |
| 647 | } | |
| 648 | pcbdev = cartslot_get_pcb(image); | |
| 649 | ||
| 650 | if (pcbdev != NULL) | |
| 651 | { | |
| 652 | aes_pcb_t *pcb = get_safe_pcb_token(pcbdev); | |
| 653 | cartslot_t *cart = get_safe_cartslot_token(&image.device()); | |
| 654 | ||
| 655 | // printf("unload\n"); | |
| 656 | if (cart->mc != NULL) | |
| 657 | { | |
| 658 | /* Remove pointers and de-big-endianize RAM contents. */ | |
| 659 | pcb->disassemble(pcbdev->machine(), image); | |
| 660 | ||
| 661 | /* Close the multicart; all RAM resources will be | |
| 662 | written to disk */ | |
| 663 | multicart_close(pcbdev->machine().options(), cart->mc); | |
| 664 | cart->mc = NULL; | |
| 665 | } | |
| 666 | // else | |
| 667 | // fatalerror("Lost pointer to multicart in cartridge. Report bug."); | |
| 668 | } | |
| 669 | } | |
| 670 | ||
| 671 | /***************************************************************************** | |
| 672 | The overall multi-cartridge slot system. It contains instances of | |
| 673 | cartridges which contain PCB devices. The memory handlers delegate the calls | |
| 674 | to the respective handlers of the cartridges. | |
| 675 | ||
| 676 | Note that the term "multi-cartridge system" and "multicart" are not the same: | |
| 677 | A "multicart" may contain multiple resources, organized on a PCB. The multi- | |
| 678 | cart system may thus host multiple multicarts. | |
| 679 | ||
| 680 | Actually, the name of the device should be changed (however, the device name | |
| 681 | length is limited) | |
| 682 | ******************************************************************************/ | |
| 683 | /* | |
| 684 | Instantiation of a multicart system for the Neo Geo AES. | |
| 685 | */ | |
| 686 | static DEVICE_START(aes_multicart) | |
| 687 | { | |
| 688 | int i; | |
| 689 | // printf("DEVICE_START(aes_multicart)\n"); | |
| 690 | aes_multicart_t *cartslots = get_safe_token(device); | |
| 691 | ||
| 692 | /* Save this in the shortcut; we don't want to look for it each time | |
| 693 | that we have a memory access. And currently we do not plan for | |
| 694 | multiple multicart instances. */ | |
| 695 | cartslots->active_slot = 0; | |
| 696 | cartslots->next_free_slot = 0; | |
| 697 | ||
| 698 | for (i=0; i < AES_NUMBER_OF_CARTRIDGE_SLOTS; i++) | |
| 699 | { | |
| 700 | cartslots->cartridge[i].pcb = NULL; | |
| 701 | } | |
| 702 | ||
| 703 | cartslots->multi_slots = 0; | |
| 704 | ||
| 705 | /* The cartslot system is initialized now. The cartridges themselves | |
| 706 | need to check whether their parts are available. */ | |
| 707 | } | |
| 708 | ||
| 709 | static DEVICE_STOP(aes_multicart) | |
| 710 | { | |
| 711 | // printf("DEVICE_STOP(aes_multicart)\n"); | |
| 712 | } | |
| 713 | ||
| 714 | static MACHINE_CONFIG_FRAGMENT(aes_multicart) | |
| 715 | MCFG_CARTSLOT_ADD("cartridge1") | |
| 716 | MCFG_CARTSLOT_EXTENSION_LIST("rpk,bin") | |
| 717 | MCFG_CARTSLOT_PCBTYPE(0, "none", AES_CARTRIDGE_PCB_NONE) | |
| 718 | MCFG_CARTSLOT_PCBTYPE(1, "standard", AES_CARTRIDGE_PCB_STD) | |
| 719 | ||
| 720 | MCFG_CARTSLOT_START(aes_cartridge) | |
| 721 | MCFG_CARTSLOT_LOAD(aes_cartridge) | |
| 722 | MCFG_CARTSLOT_UNLOAD(aes_cartridge) | |
| 723 | MCFG_CARTSLOT_INTERFACE("aes_cart") | |
| 724 | MCFG_CARTSLOT_MANDATORY | |
| 725 | MACHINE_CONFIG_END | |
| 726 | ||
| 727 | ||
| 728 | DEVICE_GET_INFO(aes_multicart) | |
| 729 | { | |
| 730 | switch (state) | |
| 731 | { | |
| 732 | /* --- the following bits of info are returned as pointers to data --- */ | |
| 733 | case DEVINFO_PTR_MACHINE_CONFIG: | |
| 734 | info->machine_config = MACHINE_CONFIG_NAME(aes_multicart); break; | |
| 735 | ||
| 736 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 737 | case DEVINFO_STR_NAME: | |
| 738 | strcpy(info->s, "AES Cartridge handler"); | |
| 739 | break; | |
| 740 | ||
| 741 | case DEVINFO_INT_TOKEN_BYTES: /* private storage, automatically allocated */ | |
| 742 | info->i = sizeof(aes_multicart_t); | |
| 743 | break; | |
| 744 | ||
| 745 | case DEVINFO_STR_FAMILY: | |
| 746 | strcpy(info->s, "Cartridge slot"); | |
| 747 | break; | |
| 748 | case DEVINFO_STR_VERSION: | |
| 749 | strcpy(info->s, "1.0"); | |
| 750 | break; | |
| 751 | case DEVINFO_STR_SOURCE_FILE: | |
| 752 | strcpy(info->s, __FILE__); | |
| 753 | break; | |
| 754 | /* --- the following bits of info are returned as pointers to functions --- */ | |
| 755 | case DEVINFO_FCT_START: | |
| 756 | info->start = DEVICE_START_NAME(aes_multicart); | |
| 757 | break; | |
| 758 | case DEVINFO_FCT_STOP: | |
| 759 | info->stop = DEVICE_STOP_NAME(aes_multicart); | |
| 760 | break; | |
| 761 | case DEVINFO_FCT_RESET: | |
| 762 | /* Nothing */ | |
| 763 | break; | |
| 764 | } | |
| 765 | } | |
| 766 | ||
| 767 | DEFINE_LEGACY_CART_SLOT_DEVICE(AES_MULTICART, aes_multicart); | |
| 768 | DEFINE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_NONE, aes_cartridge_pcb_none); | |
| 769 | DEFINE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_STD, aes_cartridge_pcb_std); |
| r0 | r11532 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | aescart.h | |
| 4 | ||
| 5 | AES cartridge management | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #ifndef __AESCART_H__ | |
| 10 | #define __AESCART_H__ | |
| 11 | ||
| 12 | #include "image.h" | |
| 13 | #include "imagedev/cartslot.h" | |
| 14 | ||
| 15 | DECLARE_LEGACY_CART_SLOT_DEVICE(AES_MULTICART, aes_multicart); | |
| 16 | DECLARE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_NONE, aes_cartridge_pcb_none); | |
| 17 | DECLARE_LEGACY_CART_SLOT_DEVICE(AES_CARTRIDGE_PCB_STD, aes_cartridge_pcb_std); | |
| 18 | ||
| 19 | /* There's only 1 slot in an AES */ | |
| 20 | #define AES_NUMBER_OF_CARTRIDGE_SLOTS 1 | |
| 21 | ||
| 22 | /* Generic AES cartridge structure. */ | |
| 23 | struct _aescartridge_t | |
| 24 | { | |
| 25 | /* PCB device associated to this cartridge. If NULL, the slot is empty. */ | |
| 26 | device_t *pcb; | |
| 27 | }; | |
| 28 | typedef struct _aescartridge_t aescartridge_t; | |
| 29 | ||
| 30 | #define MCFG_AES_CARTRIDGE_ADD(_tag) \ | |
| 31 | MCFG_DEVICE_ADD(_tag, AES_MULTICART, 0) | |
| 32 | ||
| 33 | #endif /* __AESCART_H__ */ |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | MESS specific Atari init and Cartridge code for Atari 8 bit systems | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #include "emu.h" | |
| 8 | #include "emuopts.h" | |
| 9 | #include "includes/atari.h" | |
| 10 | #include "ataridev.h" | |
| 11 | #include "machine/ram.h" | |
| 12 | #include "hashfile.h" | |
| 13 | ||
| 14 | #define LEFT_CARTSLOT_MOUNTED 1 | |
| 15 | #define RIGHT_CARTSLOT_MOUNTED 2 | |
| 16 | ||
| 17 | /* PCB */ | |
| 18 | enum | |
| 19 | { | |
| 20 | A800_UNKNOWN = 0, | |
| 21 | A800_4K, A800_8K, A800_12K, A800_16K, | |
| 22 | A800_RIGHT_4K, A800_RIGHT_8K, | |
| 23 | OSS_034M, OSS_M091, PHOENIX_8K, XEGS_32K, | |
| 24 | BBSB, DIAMOND_64K, WILLIAMS_64K, EXPRESS_64, | |
| 25 | SPARTADOS_X | |
| 26 | }; | |
| 27 | ||
| 28 | static int a800_cart_loaded = 0; | |
| 29 | static int atari = 0; | |
| 30 | static int a800_cart_type = A800_UNKNOWN; | |
| 31 | ||
| 32 | /************************************* | |
| 33 | * | |
| 34 | * Generic code | |
| 35 | * | |
| 36 | *************************************/ | |
| 37 | ||
| 38 | ||
| 39 | // Currently, the drivers have fixed 40k RAM, however the function here is ready for different sizes too | |
| 40 | static void a800_setbank(running_machine &machine, int cart_mounted) | |
| 41 | { | |
| 42 | offs_t ram_top; | |
| 43 | ||
| 44 | // take care of 0x0000-0x7fff: RAM or NOP | |
| 45 | ram_top = MIN(ram_get_size(machine.device(RAM_TAG)), 0x8000) - 1; | |
| 46 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x0000, ram_top, "0000"); | |
| 47 | memory_set_bankptr(machine, "0000", ram_get_ptr(machine.device(RAM_TAG))); | |
| 48 | ||
| 49 | // take care of 0x8000-0x9fff: A800 -> either right slot or RAM or NOP, others -> RAM or NOP | |
| 50 | // is there anything in the right slot? | |
| 51 | if (cart_mounted & RIGHT_CARTSLOT_MOUNTED) | |
| 52 | { | |
| 53 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x9fff, "8000"); | |
| 54 | memory_set_bankptr(machine, "8000", machine.region("rslot")->base()); | |
| 55 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0x9fff); | |
| 56 | } | |
| 57 | else if (a800_cart_type != BBSB) | |
| 58 | { | |
| 59 | ram_top = MIN(ram_get_size(machine.device(RAM_TAG)), 0xa000) - 1; | |
| 60 | if (ram_top > 0x8000) | |
| 61 | { | |
| 62 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x8000, ram_top, "8000"); | |
| 63 | memory_set_bankptr(machine, "8000", ram_get_ptr(machine.device(RAM_TAG)) + 0x8000); | |
| 64 | } | |
| 65 | } | |
| 66 | ||
| 67 | // take care of 0xa000-0xbfff: is there anything in the left slot? | |
| 68 | if (cart_mounted & LEFT_CARTSLOT_MOUNTED) | |
| 69 | { | |
| 70 | // FIXME: this is an hack to keep XL working until we clean up its memory map as well! | |
| 71 | if (atari == ATARI_800XL) | |
| 72 | { | |
| 73 | if (a800_cart_type == A800_16K) | |
| 74 | { | |
| 75 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x9fff, "8000"); | |
| 76 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base()); | |
| 77 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0x9fff); | |
| 78 | ||
| 79 | memcpy(machine.region("maincpu")->base() + 0x10000, machine.region("lslot")->base() + 0x2000, 0x2000); | |
| 80 | } | |
| 81 | else if (a800_cart_type == A800_8K) | |
| 82 | memcpy(machine.region("maincpu")->base() + 0x10000, machine.region("lslot")->base(), 0x2000); | |
| 83 | else | |
| 84 | fatalerror("This type of cart is not supported yet in this driver. Please use a400 or a800.\n"); | |
| 85 | } | |
| 86 | else if (a800_cart_type == A800_16K) | |
| 87 | { | |
| 88 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base()); | |
| 89 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base() + 0x2000); | |
| 90 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0xbfff); | |
| 91 | } | |
| 92 | else if (a800_cart_type == BBSB) | |
| 93 | { | |
| 94 | // this requires separate banking in 0x8000 & 0x9000! | |
| 95 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x8fff, "8000"); | |
| 96 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x9000, 0x9fff, "9000"); | |
| 97 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base() + 0x0000); | |
| 98 | memory_set_bankptr(machine, "9000", machine.region("lslot")->base() + 0x4000); | |
| 99 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base() + 0x8000); | |
| 100 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 101 | } | |
| 102 | else if (a800_cart_type == OSS_034M) | |
| 103 | { | |
| 104 | // this requires separate banking in 0xa000 & 0xb000! | |
| 105 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xafff, "a000"); | |
| 106 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xb000, 0xbfff, "b000"); | |
| 107 | memory_set_bankptr(machine, "b000", machine.region("lslot")->base() + 0x3000); | |
| 108 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 109 | } | |
| 110 | else if (a800_cart_type == OSS_M091) | |
| 111 | { | |
| 112 | // this requires separate banking in 0xa000 & 0xb000! | |
| 113 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xafff, "a000"); | |
| 114 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xb000, 0xbfff, "b000"); | |
| 115 | memory_set_bankptr(machine, "b000", machine.region("lslot")->base()); | |
| 116 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 117 | } | |
| 118 | else if (a800_cart_type == XEGS_32K) | |
| 119 | { | |
| 120 | memory_set_bankptr(machine, "8000", machine.region("lslot")->base()); | |
| 121 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base() + 0x6000); | |
| 122 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0xbfff); | |
| 123 | } | |
| 124 | else | |
| 125 | { | |
| 126 | memory_set_bankptr(machine, "a000", machine.region("lslot")->base()); | |
| 127 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff); | |
| 128 | } | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | /* MESS specific parts that have to be started */ | |
| 133 | static void ms_atari_machine_start(running_machine &machine, int type, int has_cart) | |
| 134 | { | |
| 135 | /* set atari type (temporarily not used) */ | |
| 136 | atari = type; | |
| 137 | a800_setbank(machine, a800_cart_loaded); | |
| 138 | } | |
| 139 | ||
| 140 | static void ms_atari800xl_machine_start(running_machine &machine, int type, int has_cart) | |
| 141 | { | |
| 142 | /* set atari type (temporarily not used) */ | |
| 143 | atari = type; | |
| 144 | a800_setbank(machine, a800_cart_loaded); | |
| 145 | } | |
| 146 | ||
| 147 | /************************************* | |
| 148 | * | |
| 149 | * Atari 400 | |
| 150 | * | |
| 151 | *************************************/ | |
| 152 | ||
| 153 | MACHINE_START( a400 ) | |
| 154 | { | |
| 155 | atari_machine_start(machine); | |
| 156 | ms_atari_machine_start(machine, ATARI_400, TRUE); | |
| 157 | } | |
| 158 | ||
| 159 | ||
| 160 | /************************************* | |
| 161 | * | |
| 162 | * Atari 800 | |
| 163 | * | |
| 164 | *************************************/ | |
| 165 | ||
| 166 | MACHINE_START( a800 ) | |
| 167 | { | |
| 168 | atari_machine_start(machine); | |
| 169 | ms_atari_machine_start(machine, ATARI_800, TRUE); | |
| 170 | } | |
| 171 | ||
| 172 | static WRITE8_HANDLER( x32_bank_w ) | |
| 173 | { | |
| 174 | // printf("written %x\n", data); | |
| 175 | int bank = data & 0x03; | |
| 176 | memory_set_bankptr(space->machine(), "8000", space->machine().region("lslot")->base() + bank * 0x2000); | |
| 177 | } | |
| 178 | ||
| 179 | static WRITE8_HANDLER( w64_bank_w ) | |
| 180 | { | |
| 181 | // printf("write to %x\n", offset); | |
| 182 | ||
| 183 | if (offset < 8) | |
| 184 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + offset * 0x2000); | |
| 185 | else | |
| 186 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base()); | |
| 187 | // FIXME: writes to 0x8-0xf should disable the cart | |
| 188 | } | |
| 189 | ||
| 190 | // this covers Express 64, Diamond 64 and SpartaDOS (same bankswitch, but at different addresses) | |
| 191 | static WRITE8_HANDLER( ex64_bank_w ) | |
| 192 | { | |
| 193 | // printf("write to %x\n", offset); | |
| 194 | ||
| 195 | if (offset < 8) | |
| 196 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + (7 - offset) * 0x2000); | |
| 197 | else | |
| 198 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base()); | |
| 199 | // FIXME: writes to 0x8-0xf should disable the cart | |
| 200 | } | |
| 201 | ||
| 202 | static WRITE8_HANDLER( bbsb_bankl_w ) | |
| 203 | { | |
| 204 | // printf("write to %x\n", 0x8000 + offset); | |
| 205 | if (offset >= 0xff6 && offset <= 0xff9) | |
| 206 | memory_set_bankptr(space->machine(), "8000", space->machine().region("lslot")->base() + 0x0000 + (offset - 0xff6) * 0x1000); | |
| 207 | } | |
| 208 | ||
| 209 | static WRITE8_HANDLER( bbsb_bankh_w ) | |
| 210 | { | |
| 211 | // printf("write to %x\n", 0x9000 + offset); | |
| 212 | if (offset >= 0xff6 && offset <= 0xff9) | |
| 213 | memory_set_bankptr(space->machine(), "9000", space->machine().region("lslot")->base() + 0x4000 + (offset - 0xff6) * 0x1000); | |
| 214 | } | |
| 215 | ||
| 216 | static WRITE8_HANDLER( oss_034m_w ) | |
| 217 | { | |
| 218 | switch (offset & 0x0f) | |
| 219 | { | |
| 220 | case 0: | |
| 221 | case 1: | |
| 222 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base()); | |
| 223 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 224 | break; | |
| 225 | case 2: | |
| 226 | case 6: | |
| 227 | // docs says this should put 0xff in the 0xa000 bank -> let's point to the end of the cart | |
| 228 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x4000); | |
| 229 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 230 | break; | |
| 231 | case 3: | |
| 232 | case 7: | |
| 233 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x1000); | |
| 234 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 235 | break; | |
| 236 | case 4: | |
| 237 | case 5: | |
| 238 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x2000); | |
| 239 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base() + 0x3000); | |
| 240 | break; | |
| 241 | default: | |
| 242 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base() + 0xa000); | |
| 243 | memory_set_bankptr(space->machine(), "b000", space->machine().region("maincpu")->base() + 0xb000); | |
| 244 | break; | |
| 245 | } | |
| 246 | } | |
| 247 | ||
| 248 | static WRITE8_HANDLER( oss_m091_w ) | |
| 249 | { | |
| 250 | switch (offset & 0x09) | |
| 251 | { | |
| 252 | case 0: | |
| 253 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x1000); | |
| 254 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base()); | |
| 255 | break; | |
| 256 | case 1: | |
| 257 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x3000); | |
| 258 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base()); | |
| 259 | break; | |
| 260 | case 8: | |
| 261 | memory_set_bankptr(space->machine(), "a000", space->machine().region("maincpu")->base() + 0xa000); | |
| 262 | memory_set_bankptr(space->machine(), "b000", space->machine().region("maincpu")->base() + 0xb000); | |
| 263 | break; | |
| 264 | case 9: | |
| 265 | memory_set_bankptr(space->machine(), "a000", space->machine().region("lslot")->base() + 0x2000); | |
| 266 | memory_set_bankptr(space->machine(), "b000", space->machine().region("lslot")->base()); | |
| 267 | break; | |
| 268 | } | |
| 269 | } | |
| 270 | ||
| 271 | #if 0 | |
| 272 | static int bbsb_bankl = 0; | |
| 273 | static int bbsb_bankh = 0; | |
| 274 | ||
| 275 | static WRITE8_HANDLER( bbsb_bankl_w ) | |
| 276 | { | |
| 277 | bbsb_bankl = offset; // 0,1,2,3 | |
| 278 | } | |
| 279 | ||
| 280 | static WRITE8_HANDLER( bbsb_bankh_w ) | |
| 281 | { | |
| 282 | bbsb_bankh = offset; // 4,5,6,7 | |
| 283 | } | |
| 284 | ||
| 285 | static READ8_HANDLER( bbsb_bankl_r ) | |
| 286 | { | |
| 287 | // return data from the selected bank (0,1,2,3) | |
| 288 | UINT8 *mem = space->machine().region("lslot")->base(); | |
| 289 | return &mem[0x0000 + bbsb_bankl * 0x1000]; | |
| 290 | } | |
| 291 | ||
| 292 | static READ8_HANDLER( bbsb_bankh_r ) | |
| 293 | { | |
| 294 | // return data from the selected bank (4,5,6,7) | |
| 295 | UINT8 *mem = space->machine().region("lslot")->base(); | |
| 296 | return &mem[0x4000 + bbsb_bankh * 0x1000]; | |
| 297 | } | |
| 298 | #endif | |
| 299 | ||
| 300 | typedef struct _a800_pcb a800_pcb; | |
| 301 | struct _a800_pcb | |
| 302 | { | |
| 303 | const char *pcb_name; | |
| 304 | int pcb_id; | |
| 305 | }; | |
| 306 | ||
| 307 | // Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it | |
| 308 | // WARNING: most of these are still unsupported by the driver | |
| 309 | static const a800_pcb pcb_list[] = | |
| 310 | { | |
| 311 | {"standard 4k", A800_8K}, | |
| 312 | {"standard 8k", A800_8K}, | |
| 313 | {"standard 12k", A800_16K}, | |
| 314 | {"standard 16k", A800_16K}, | |
| 315 | {"right slot 4k", A800_RIGHT_4K}, | |
| 316 | {"right slot 8k", A800_RIGHT_8K}, | |
| 317 | ||
| 318 | {"oss 034m", OSS_034M}, | |
| 319 | {"oss m091", OSS_M091}, | |
| 320 | {"phoenix 8k", PHOENIX_8K}, | |
| 321 | {"xegs 32k", XEGS_32K}, | |
| 322 | {"bbsb", BBSB}, | |
| 323 | {"diamond 64k", DIAMOND_64K}, | |
| 324 | {"williams 64k", WILLIAMS_64K}, | |
| 325 | {"express 64", EXPRESS_64}, | |
| 326 | {"spartados x", SPARTADOS_X}, | |
| 327 | {"N/A", A800_UNKNOWN} | |
| 328 | }; | |
| 329 | ||
| 330 | static int a800_get_pcb_id(const char *pcb) | |
| 331 | { | |
| 332 | int i; | |
| 333 | ||
| 334 | for (i = 0; i < ARRAY_LENGTH(pcb_list); i++) | |
| 335 | { | |
| 336 | if (!mame_stricmp(pcb_list[i].pcb_name, pcb)) | |
| 337 | return pcb_list[i].pcb_id; | |
| 338 | } | |
| 339 | ||
| 340 | return A800_UNKNOWN; | |
| 341 | } | |
| 342 | ||
| 343 | // currently this does nothing, but it will eventually install the memory handlers required by the mappers | |
| 344 | static void a800_setup_mappers(running_machine &machine, int type) | |
| 345 | { | |
| 346 | switch (type) | |
| 347 | { | |
| 348 | case A800_4K: | |
| 349 | case A800_RIGHT_4K: | |
| 350 | case A800_12K: | |
| 351 | case A800_8K: | |
| 352 | case A800_16K: | |
| 353 | case A800_RIGHT_8K: | |
| 354 | case PHOENIX_8K: // as normal 8k cart, but it can be disabled by writing to 0xd500-0xdfff | |
| 355 | break; | |
| 356 | case XEGS_32K: | |
| 357 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(x32_bank_w)); | |
| 358 | break; | |
| 359 | case OSS_034M: | |
| 360 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(oss_034m_w)); | |
| 361 | break; | |
| 362 | case OSS_M091: | |
| 363 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(oss_m091_w)); | |
| 364 | break; | |
| 365 | case BBSB: | |
| 366 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x8000, 0x8fff, FUNC(bbsb_bankl_w)); | |
| 367 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x9000, 0x9fff, FUNC(bbsb_bankh_w)); | |
| 368 | break; | |
| 369 | case WILLIAMS_64K: | |
| 370 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd50f, FUNC(w64_bank_w)); | |
| 371 | break; | |
| 372 | case DIAMOND_64K: | |
| 373 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd5d0, 0xd5df, FUNC(ex64_bank_w)); | |
| 374 | break; | |
| 375 | case EXPRESS_64: | |
| 376 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd570, 0xd57f, FUNC(ex64_bank_w)); | |
| 377 | break; | |
| 378 | case SPARTADOS_X: | |
| 379 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd5e0, 0xd5ef, FUNC(ex64_bank_w)); | |
| 380 | break; | |
| 381 | default: | |
| 382 | break; | |
| 383 | } | |
| 384 | } | |
| 385 | ||
| 386 | static int a800_get_type(device_image_interface &image) | |
| 387 | { | |
| 388 | UINT8 header[16]; | |
| 389 | image.fread(header, 0x10); | |
| 390 | int hdr_type, cart_type = A800_UNKNOWN; | |
| 391 | ||
| 392 | // add check of CART format | |
| 393 | if (strncmp((const char *)header, "CART", 4)) | |
| 394 | fatalerror("Invalid header detected!\n"); | |
| 395 | ||
| 396 | hdr_type = (header[4] << 24) + (header[5] << 16) + (header[6] << 8) + (header[7] << 0); | |
| 397 | switch (hdr_type) | |
| 398 | { | |
| 399 | case 1: | |
| 400 | cart_type = A800_8K; | |
| 401 | break; | |
| 402 | case 2: | |
| 403 | cart_type = A800_16K; | |
| 404 | break; | |
| 405 | case 3: | |
| 406 | cart_type = OSS_034M; | |
| 407 | break; | |
| 408 | case 8: | |
| 409 | cart_type = WILLIAMS_64K; | |
| 410 | break; | |
| 411 | case 9: | |
| 412 | cart_type = DIAMOND_64K; | |
| 413 | break; | |
| 414 | case 10: | |
| 415 | cart_type = EXPRESS_64; | |
| 416 | break; | |
| 417 | case 11: | |
| 418 | cart_type = SPARTADOS_X; | |
| 419 | break; | |
| 420 | case 12: | |
| 421 | cart_type = XEGS_32K; | |
| 422 | break; | |
| 423 | case 15: | |
| 424 | cart_type = OSS_M091; | |
| 425 | break; | |
| 426 | case 18: | |
| 427 | cart_type = BBSB; | |
| 428 | break; | |
| 429 | case 21: | |
| 430 | cart_type = A800_RIGHT_8K; | |
| 431 | break; | |
| 432 | case 39: | |
| 433 | cart_type = PHOENIX_8K; | |
| 434 | break; | |
| 435 | case 4: | |
| 436 | case 6: | |
| 437 | case 7: | |
| 438 | case 16: | |
| 439 | case 19: | |
| 440 | case 20: | |
| 441 | fatalerror("Cart type \"%d\" means this is an Atari 5200 cart.\n", hdr_type); | |
| 442 | break; | |
| 443 | default: | |
| 444 | mame_printf_info("Cart type \"%d\" is currently unsupported.\n", hdr_type); | |
| 445 | break; | |
| 446 | } | |
| 447 | return cart_type; | |
| 448 | } | |
| 449 | ||
| 450 | static int a800_check_cart_type(device_image_interface &image) | |
| 451 | { | |
| 452 | const char *pcb_name; | |
| 453 | int type = A800_UNKNOWN; | |
| 454 | ||
| 455 | if (image.software_entry() == NULL) | |
| 456 | { | |
| 457 | UINT32 size = image.length(); | |
| 458 | ||
| 459 | // check if there is an header, if so extract cart_type from it, otherwise | |
| 460 | // try to guess the cart_type from the file size (notice that after the | |
| 461 | // a800_get_type call, we point at the start of the data) | |
| 462 | if ((size % 0x1000) == 0x10) | |
| 463 | type = a800_get_type(image); | |
| 464 | else if (size == 0x4000) | |
| 465 | type = A800_16K; | |
| 466 | else if (size == 0x2000) | |
| 467 | { | |
| 468 | if (strcmp(image.device().tag(),"cart2") == 0) | |
| 469 | type = A800_RIGHT_8K; | |
| 470 | else | |
| 471 | type = A800_8K; | |
| 472 | } | |
| 473 | } | |
| 474 | else | |
| 475 | { | |
| 476 | if ((pcb_name = image.get_feature("cart_type")) != NULL) | |
| 477 | type = a800_get_pcb_id(pcb_name); | |
| 478 | ||
| 479 | switch (type) | |
| 480 | { | |
| 481 | case A800_UNKNOWN: | |
| 482 | case A800_4K: | |
| 483 | case A800_RIGHT_4K: | |
| 484 | case A800_12K: | |
| 485 | case A800_8K: | |
| 486 | case A800_16K: | |
| 487 | case A800_RIGHT_8K: | |
| 488 | break; | |
| 489 | default: | |
| 490 | mame_printf_info("Cart type \"%s\" currently unsupported.\n", pcb_name); | |
| 491 | break; | |
| 492 | } | |
| 493 | } | |
| 494 | ||
| 495 | if ((strcmp(image.device().tag(),"cart2") == 0) && (type != A800_RIGHT_8K)) | |
| 496 | fatalerror("You cannot load this image '%s' in the right slot", image.filename()); | |
| 497 | ||
| 498 | return type; | |
| 499 | } | |
| 500 | ||
| 501 | DEVICE_IMAGE_LOAD( a800_cart ) | |
| 502 | { | |
| 503 | UINT32 size, start = 0; | |
| 504 | ||
| 505 | a800_cart_loaded = a800_cart_loaded & ~LEFT_CARTSLOT_MOUNTED; | |
| 506 | a800_cart_type = a800_check_cart_type(image); | |
| 507 | ||
| 508 | a800_setup_mappers(image.device().machine(), a800_cart_type); | |
| 509 | ||
| 510 | if (image.software_entry() == NULL) | |
| 511 | { | |
| 512 | size = image.length(); | |
| 513 | // if there is an header, skip it | |
| 514 | if ((size % 0x1000) == 0x10) | |
| 515 | { | |
| 516 | size -= 0x10; | |
| 517 | start = 0x10; | |
| 518 | } | |
| 519 | image.fread(image.device().machine().region("lslot")->base(), size - start); | |
| 520 | } | |
| 521 | else | |
| 522 | { | |
| 523 | size = image.get_software_region_length("rom"); | |
| 524 | memcpy(image.device().machine().region("lslot")->base(), image.get_software_region("rom"), size); | |
| 525 | } | |
| 526 | ||
| 527 | a800_cart_loaded |= (size > 0x0000) ? 1 : 0; | |
| 528 | ||
| 529 | logerror("%s loaded left cartridge '%s' size %dK\n", image.device().machine().system().name, image.filename(), size/1024); | |
| 530 | return IMAGE_INIT_PASS; | |
| 531 | } | |
| 532 | ||
| 533 | DEVICE_IMAGE_LOAD( a800_cart_right ) | |
| 534 | { | |
| 535 | UINT32 size, start = 0; | |
| 536 | ||
| 537 | a800_cart_loaded = a800_cart_loaded & ~RIGHT_CARTSLOT_MOUNTED; | |
| 538 | a800_cart_type = a800_check_cart_type(image); | |
| 539 | ||
| 540 | a800_setup_mappers(image.device().machine(), a800_cart_type); | |
| 541 | ||
| 542 | if (image.software_entry() == NULL) | |
| 543 | { | |
| 544 | size = image.length(); | |
| 545 | // if there is an header, skip it | |
| 546 | if ((size % 0x1000) == 0x10) | |
| 547 | { | |
| 548 | size -= 0x10; | |
| 549 | start = 0x10; | |
| 550 | } | |
| 551 | image.fread(image.device().machine().region("rslot")->base(), size - start); | |
| 552 | } | |
| 553 | else | |
| 554 | { | |
| 555 | size = image.get_software_region_length("rom"); | |
| 556 | memcpy(image.device().machine().region("rslot")->base(), image.get_software_region("rom"), size); | |
| 557 | } | |
| 558 | ||
| 559 | a800_cart_loaded |= (size > 0x0000) ? 2 : 0; | |
| 560 | ||
| 561 | logerror("%s loaded right cartridge '%s' size 8K\n", image.device().machine().system().name, image.filename()); | |
| 562 | return IMAGE_INIT_PASS; | |
| 563 | } | |
| 564 | ||
| 565 | DEVICE_IMAGE_UNLOAD( a800_cart ) | |
| 566 | { | |
| 567 | a800_cart_loaded = a800_cart_loaded & ~LEFT_CARTSLOT_MOUNTED; | |
| 568 | a800_cart_type = A800_UNKNOWN; | |
| 569 | a800_setbank(image.device().machine(), a800_cart_loaded); | |
| 570 | } | |
| 571 | ||
| 572 | DEVICE_IMAGE_UNLOAD( a800_cart_right ) | |
| 573 | { | |
| 574 | a800_cart_loaded = a800_cart_loaded & ~RIGHT_CARTSLOT_MOUNTED; | |
| 575 | a800_cart_type = A800_UNKNOWN; | |
| 576 | a800_setbank(image.device().machine(), a800_cart_loaded); | |
| 577 | } | |
| 578 | ||
| 579 | ||
| 580 | /************************************* | |
| 581 | * | |
| 582 | * Atari 800XL | |
| 583 | * | |
| 584 | *************************************/ | |
| 585 | ||
| 586 | MACHINE_START( a800xl ) | |
| 587 | { | |
| 588 | atari_machine_start(machine); | |
| 589 | ms_atari800xl_machine_start(machine, ATARI_800XL, TRUE); | |
| 590 | } | |
| 591 | ||
| 592 | /************************************* | |
| 593 | * | |
| 594 | * Atari 5200 console | |
| 595 | * | |
| 596 | *************************************/ | |
| 597 | ||
| 598 | MACHINE_START( a5200 ) | |
| 599 | { | |
| 600 | atari_machine_start(machine); | |
| 601 | ms_atari_machine_start(machine, ATARI_800XL, TRUE); | |
| 602 | } | |
| 603 | ||
| 604 | ||
| 605 | DEVICE_IMAGE_LOAD( a5200_cart ) | |
| 606 | { | |
| 607 | UINT8 *mem = image.device().machine().region("maincpu")->base(); | |
| 608 | UINT32 size; | |
| 609 | ||
| 610 | if (image.software_entry() == NULL) | |
| 611 | { | |
| 612 | /* load an optional (dual) cartidge */ | |
| 613 | size = image.fread(&mem[0x4000], 0x8000); | |
| 614 | } | |
| 615 | else | |
| 616 | { | |
| 617 | size = image.get_software_region_length("rom"); | |
| 618 | memcpy(mem + 0x4000, image.get_software_region("rom"), size); | |
| 619 | } | |
| 620 | ||
| 621 | if (size<0x8000) memmove(mem+0x4000+0x8000-size, mem+0x4000, size); | |
| 622 | // mirroring of smaller cartridges | |
| 623 | if (size <= 0x1000) memcpy(mem+0xa000, mem+0xb000, 0x1000); | |
| 624 | if (size <= 0x2000) memcpy(mem+0x8000, mem+0xa000, 0x2000); | |
| 625 | if (size <= 0x4000) | |
| 626 | { | |
| 627 | const char *info = hashfile_extrainfo(image); | |
| 628 | memcpy(&mem[0x4000], &mem[0x8000], 0x4000); | |
| 629 | if (info && !strcmp(info, "A13MIRRORING")) | |
| 630 | { | |
| 631 | memcpy(&mem[0x8000], &mem[0xa000], 0x2000); | |
| 632 | memcpy(&mem[0x6000], &mem[0x4000], 0x2000); | |
| 633 | } | |
| 634 | } | |
| 635 | logerror("A5200 loaded cartridge '%s' size %dK\n", image.filename() , size/1024); | |
| 636 | return IMAGE_INIT_PASS; | |
| 637 | } | |
| 638 | ||
| 639 | DEVICE_IMAGE_UNLOAD( a5200_cart ) | |
| 640 | { | |
| 641 | UINT8 *mem = image.device().machine().region("maincpu")->base(); | |
| 642 | /* zap the cartridge memory (again) */ | |
| 643 | memset(&mem[0x4000], 0x00, 0x8000); | |
| 644 | } | |
| 645 | ||
| 646 | /************************************* | |
| 647 | * | |
| 648 | * Atari XEGS | |
| 649 | * | |
| 650 | *************************************/ | |
| 651 | ||
| 652 | static UINT8 xegs_banks = 0; | |
| 653 | static UINT8 xegs_cart = 0; | |
| 654 | ||
| 655 | static WRITE8_HANDLER( xegs_bankswitch ) | |
| 656 | { | |
| 657 | UINT8 *cart = space->machine().region("user1")->base(); | |
| 658 | data &= xegs_banks - 1; | |
| 659 | memory_set_bankptr(space->machine(), "bank0", cart + data * 0x2000); | |
| 660 | } | |
| 661 | ||
| 662 | MACHINE_START( xegs ) | |
| 663 | { | |
| 664 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 665 | UINT8 *cart = space->machine().region("user1")->base(); | |
| 666 | UINT8 *cpu = space->machine().region("maincpu")->base(); | |
| 667 | ||
| 668 | atari_machine_start(machine); | |
| 669 | space->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(xegs_bankswitch)); | |
| 670 | ||
| 671 | if (xegs_cart) | |
| 672 | { | |
| 673 | memory_set_bankptr(machine, "bank0", cart); | |
| 674 | memory_set_bankptr(machine, "bank1", cart + (xegs_banks - 1) * 0x2000); | |
| 675 | } | |
| 676 | else | |
| 677 | { | |
| 678 | // point to built-in Missile Command (this does not work well, though... FIXME!!) | |
| 679 | memory_set_bankptr(machine, "bank0", cpu + 0x10000); | |
| 680 | memory_set_bankptr(machine, "bank1", cpu + 0x10000); | |
| 681 | } | |
| 682 | } | |
| 683 | ||
| 684 | DEVICE_IMAGE_LOAD( xegs_cart ) | |
| 685 | { | |
| 686 | UINT32 size; | |
| 687 | UINT8 *ptr = image.device().machine().region("user1")->base(); | |
| 688 | ||
| 689 | if (image.software_entry() == NULL) | |
| 690 | { | |
| 691 | // skip the header | |
| 692 | image.fseek(0x10, SEEK_SET); | |
| 693 | size = image.length() - 0x10; | |
| 694 | if (image.fread(ptr, size) != size) | |
| 695 | return IMAGE_INIT_FAIL; | |
| 696 | } | |
| 697 | else | |
| 698 | { | |
| 699 | size = image.get_software_region_length("rom"); | |
| 700 | memcpy(ptr, image.get_software_region("rom"), size); | |
| 701 | } | |
| 702 | ||
| 703 | xegs_banks = size / 0x2000; | |
| 704 | xegs_cart = 1; | |
| 705 | ||
| 706 | return IMAGE_INIT_PASS; | |
| 707 | } | |
| 708 | ||
| 709 | DEVICE_IMAGE_UNLOAD( xegs_cart ) | |
| 710 | { | |
| 711 | xegs_cart = 0; | |
| 712 | xegs_banks = 0; | |
| 713 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | ataridev.h | |
| 3 | ||
| 4 | */ | |
| 5 | ||
| 6 | #ifndef _ATARIDEV_H | |
| 7 | #define _ATARIDEV_H | |
| 8 | ||
| 9 | #define ATARI_5200 0 | |
| 10 | #define ATARI_400 1 | |
| 11 | #define ATARI_800 2 | |
| 12 | #define ATARI_600XL 3 | |
| 13 | #define ATARI_800XL 4 | |
| 14 | ||
| 15 | /*----------- defined in machine/ataricrt.c -----------*/ | |
| 16 | ||
| 17 | MACHINE_START( a400 ); | |
| 18 | MACHINE_START( a800 ); | |
| 19 | MACHINE_START( a800xl ); | |
| 20 | MACHINE_START( a5200 ); | |
| 21 | MACHINE_START( xegs ); | |
| 22 | ||
| 23 | DEVICE_IMAGE_LOAD( a800_cart ); | |
| 24 | DEVICE_IMAGE_UNLOAD( a800_cart ); | |
| 25 | ||
| 26 | DEVICE_IMAGE_LOAD( a800_cart_right ); | |
| 27 | DEVICE_IMAGE_UNLOAD( a800_cart_right ); | |
| 28 | ||
| 29 | DEVICE_IMAGE_LOAD( a5200_cart ); | |
| 30 | DEVICE_IMAGE_UNLOAD( a5200_cart ); | |
| 31 | ||
| 32 | DEVICE_IMAGE_LOAD( xegs_cart ); | |
| 33 | DEVICE_IMAGE_UNLOAD( xegs_cart ); | |
| 34 | ||
| 35 | ||
| 36 | /*----------- defined in machine/atarifdc.c -----------*/ | |
| 37 | /*************************************************************************** | |
| 38 | MACROS | |
| 39 | ***************************************************************************/ | |
| 40 | ||
| 41 | DECLARE_LEGACY_DEVICE(ATARI_FDC, atari_fdc); | |
| 42 | ||
| 43 | #define MCFG_ATARI_FDC_ADD(_tag) \ | |
| 44 | MCFG_DEVICE_ADD((_tag), ATARI_FDC, 0) | |
| 45 | ||
| 46 | ||
| 47 | /*************************************************************************** | |
| 48 | FUNCTION PROTOTYPES | |
| 49 | ***************************************************************************/ | |
| 50 | READ8_DEVICE_HANDLER( atari_serin_r ); | |
| 51 | WRITE8_DEVICE_HANDLER( atari_serout_w ); | |
| 52 | WRITE_LINE_DEVICE_HANDLER( atarifdc_pia_cb2_w ); | |
| 53 | ||
| 54 | #endif /* _ATARIDEV_H */ | |
| 55 |
| r0 | r11532 | |
|---|---|---|
| 1 | /****************************************************f*********************** | |
| 2 | ||
| 3 | Amiga floppy disk controller emulation | |
| 4 | ||
| 5 | - The drive spins at 300 RPM = 1 Rev every 200ms | |
| 6 | - At 2usec per bit, that's 12500 bytes per track, or 6250 words per track | |
| 7 | - At 4usec per bit, that's 6250 bytes per track, or 3125 words per track | |
| 8 | - Each standard amiga sector has 544 words per sector, and 11 sectors per track = 11968 bytes | |
| 9 | - ( 12500(max) - 11968(actual) ) = 532 per track gap bytes | |
| 10 | ||
| 11 | ***************************************************************************/ | |
| 12 | ||
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | #include "includes/amiga.h" | |
| 16 | #include "imagedev/flopdrv.h" | |
| 17 | #include "formats/ami_dsk.h" | |
| 18 | #include "amigafdc.h" | |
| 19 | #include "machine/6526cia.h" | |
| 20 | ||
| 21 | ||
| 22 | #define MAX_TRACK_BYTES 12500 | |
| 23 | #define ACTUAL_TRACK_BYTES 11968 | |
| 24 | #define GAP_TRACK_BYTES ( MAX_TRACK_BYTES - ACTUAL_TRACK_BYTES ) | |
| 25 | #define ONE_SECTOR_BYTES (544*2) | |
| 26 | #define ONE_REV_TIME 200 /* ms */ | |
| 27 | #define MAX_WORDS_PER_DMA_CYCLE 32 /* 64 bytes per dma cycle */ | |
| 28 | #define DISK_DETECT_DELAY 1 | |
| 29 | #define MAX_TRACKS 160 | |
| 30 | #define MAX_MFM_TRACK_LEN 16384 | |
| 31 | ||
| 32 | #define NUM_DRIVES 2 | |
| 33 | ||
| 34 | /* required prototype */ | |
| 35 | static void setup_fdc_buffer( device_t *device,int drive ); | |
| 36 | ||
| 37 | /*************************************************************************** | |
| 38 | TYPE DEFINITIONS | |
| 39 | ***************************************************************************/ | |
| 40 | typedef struct { | |
| 41 | int motor_on; | |
| 42 | int side; | |
| 43 | int dir; | |
| 44 | int wprot; | |
| 45 | int disk_changed; | |
| 46 | device_image_interface *f; | |
| 47 | UINT32 extinfo[MAX_TRACKS]; | |
| 48 | UINT32 extoffs[MAX_TRACKS]; | |
| 49 | int is_ext_image; | |
| 50 | int cyl; | |
| 51 | int tracklen; | |
| 52 | UINT8 mfm[MAX_MFM_TRACK_LEN]; | |
| 53 | int cached; | |
| 54 | emu_timer *rev_timer; | |
| 55 | emu_timer *sync_timer; | |
| 56 | emu_timer *dma_timer; | |
| 57 | int rev_timer_started; | |
| 58 | int pos; | |
| 59 | int len; | |
| 60 | offs_t ptr; | |
| 61 | } fdc_def; | |
| 62 | ||
| 63 | typedef struct _amiga_fdc_t amiga_fdc_t; | |
| 64 | struct _amiga_fdc_t | |
| 65 | { | |
| 66 | fdc_def fdc_status[NUM_DRIVES]; | |
| 67 | ||
| 68 | /* signals */ | |
| 69 | int fdc_sel; | |
| 70 | int fdc_dir; | |
| 71 | int fdc_side; | |
| 72 | int fdc_step; | |
| 73 | int fdc_rdy; | |
| 74 | }; | |
| 75 | ||
| 76 | /***************************************************************************** | |
| 77 | INLINE FUNCTIONS | |
| 78 | *****************************************************************************/ | |
| 79 | INLINE amiga_fdc_t *get_safe_token(device_t *device) | |
| 80 | { | |
| 81 | assert(device != NULL); | |
| 82 | assert(device->type() == AMIGA_FDC); | |
| 83 | ||
| 84 | return (amiga_fdc_t *)downcast<legacy_device_base *>(device)->token(); | |
| 85 | } | |
| 86 | ||
| 87 | static TIMER_CALLBACK(fdc_rev_proc); | |
| 88 | static TIMER_CALLBACK(fdc_dma_proc); | |
| 89 | static TIMER_CALLBACK(fdc_sync_proc); | |
| 90 | static void check_extended_image( device_t *device, int id ); | |
| 91 | ||
| 92 | static void amiga_load_proc(device_image_interface &image) | |
| 93 | { | |
| 94 | amiga_fdc_t *fdc = get_safe_token(image.device().owner()); | |
| 95 | int id = floppy_get_drive(&image.device()); | |
| 96 | fdc->fdc_status[id].disk_changed = DISK_DETECT_DELAY; | |
| 97 | fdc->fdc_status[id].f = ℑ | |
| 98 | fdc->fdc_status[id].cached = -1; | |
| 99 | fdc->fdc_status[id].motor_on = 0; | |
| 100 | fdc->fdc_status[id].rev_timer_started = 0; | |
| 101 | fdc->fdc_status[id].rev_timer->reset( ); | |
| 102 | fdc->fdc_status[id].sync_timer->reset( ); | |
| 103 | fdc->fdc_status[id].dma_timer->reset( ); | |
| 104 | fdc->fdc_rdy = 0; | |
| 105 | ||
| 106 | check_extended_image( image.device().owner(), id ); | |
| 107 | } | |
| 108 | ||
| 109 | static void amiga_unload_proc(device_image_interface &image) | |
| 110 | { | |
| 111 | amiga_fdc_t *fdc = get_safe_token(image.device().owner()); | |
| 112 | int id = floppy_get_drive(&image.device()); | |
| 113 | fdc->fdc_status[id].disk_changed = DISK_DETECT_DELAY; | |
| 114 | fdc->fdc_status[id].f = NULL; | |
| 115 | fdc->fdc_status[id].cached = -1; | |
| 116 | fdc->fdc_status[id].motor_on = 0; | |
| 117 | fdc->fdc_status[id].rev_timer_started = 0; | |
| 118 | fdc->fdc_status[id].rev_timer->reset( ); | |
| 119 | fdc->fdc_status[id].sync_timer->reset( ); | |
| 120 | fdc->fdc_status[id].dma_timer->reset( ); | |
| 121 | fdc->fdc_rdy = 0; | |
| 122 | } | |
| 123 | ||
| 124 | /*------------------------------------------------- | |
| 125 | DEVICE_START(amiga_fdc) | |
| 126 | -------------------------------------------------*/ | |
| 127 | device_t *amiga_floppy_get_device_child(device_t *device,int drive) | |
| 128 | { | |
| 129 | switch(drive) { | |
| 130 | case 0 : return device->subdevice(FLOPPY_0); | |
| 131 | case 1 : return device->subdevice(FLOPPY_1); | |
| 132 | } | |
| 133 | return NULL; | |
| 134 | } | |
| 135 | ||
| 136 | static DEVICE_START(amiga_fdc) | |
| 137 | { | |
| 138 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 139 | int id; | |
| 140 | for(id=0;id<2;id++) | |
| 141 | { | |
| 142 | fdc->fdc_status[id].rev_timer = device->machine().scheduler().timer_alloc(FUNC(fdc_rev_proc), (void*)device); | |
| 143 | fdc->fdc_status[id].dma_timer = device->machine().scheduler().timer_alloc(FUNC(fdc_dma_proc), (void*)device); | |
| 144 | fdc->fdc_status[id].sync_timer = device->machine().scheduler().timer_alloc(FUNC(fdc_sync_proc), (void*)device); | |
| 145 | floppy_install_load_proc(amiga_floppy_get_device_child(device, id), amiga_load_proc); | |
| 146 | floppy_install_unload_proc(amiga_floppy_get_device_child(device, id), amiga_unload_proc); | |
| 147 | fdc->fdc_status[id].motor_on = 0; | |
| 148 | fdc->fdc_status[id].side = 0; | |
| 149 | fdc->fdc_status[id].dir = 0; | |
| 150 | fdc->fdc_status[id].wprot = 1; | |
| 151 | fdc->fdc_status[id].cyl = 0; | |
| 152 | fdc->fdc_status[id].rev_timer_started = 0; | |
| 153 | fdc->fdc_status[id].cached = -1; | |
| 154 | fdc->fdc_status[id].pos = 0; | |
| 155 | fdc->fdc_status[id].len = 0; | |
| 156 | fdc->fdc_status[id].ptr = 0; | |
| 157 | fdc->fdc_status[id].f = NULL; | |
| 158 | fdc->fdc_status[id].is_ext_image = 0; | |
| 159 | fdc->fdc_status[id].tracklen = MAX_TRACK_BYTES; | |
| 160 | fdc->fdc_status[id].disk_changed = DISK_DETECT_DELAY; | |
| 161 | fdc->fdc_status[id].rev_timer->reset( ); | |
| 162 | fdc->fdc_status[id].sync_timer->reset( ); | |
| 163 | fdc->fdc_status[id].dma_timer->reset( ); | |
| 164 | memset( fdc->fdc_status[id].mfm, 0xaa, MAX_MFM_TRACK_LEN ); | |
| 165 | } | |
| 166 | fdc->fdc_sel = 0x0f; | |
| 167 | fdc->fdc_dir = 0; | |
| 168 | fdc->fdc_side = 1; | |
| 169 | fdc->fdc_step = 1; | |
| 170 | fdc->fdc_rdy = 0; | |
| 171 | ||
| 172 | } | |
| 173 | ||
| 174 | ||
| 175 | /*------------------------------------------------- | |
| 176 | DEVICE_RESET(amiga_fdc) | |
| 177 | -------------------------------------------------*/ | |
| 178 | ||
| 179 | static DEVICE_RESET(amiga_fdc) | |
| 180 | { | |
| 181 | } | |
| 182 | ||
| 183 | static void check_extended_image( device_t *device, int id ) | |
| 184 | { | |
| 185 | UINT8 header[8], data[4]; | |
| 186 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 187 | ||
| 188 | fdc->fdc_status[id].is_ext_image = 0; | |
| 189 | ||
| 190 | if ( fdc->fdc_status[id].f->fseek( 0, SEEK_SET ) ) | |
| 191 | { | |
| 192 | logerror("FDC: image_fseek failed!\n" ); | |
| 193 | return; | |
| 194 | } | |
| 195 | ||
| 196 | fdc->fdc_status[id].f->fread( &header, sizeof( header ) ); | |
| 197 | ||
| 198 | if ( memcmp( header, "UAE--ADF", sizeof( header ) ) == 0 ) | |
| 199 | { | |
| 200 | int i; | |
| 201 | ||
| 202 | for( i = 0; i < MAX_TRACKS; i++ ) | |
| 203 | { | |
| 204 | fdc->fdc_status[id].f->fread( &data, sizeof( data ) ); | |
| 205 | ||
| 206 | /* data[0,1] = SYNC - data[2,3] = LEN */ | |
| 207 | ||
| 208 | fdc->fdc_status[id].extinfo[i] = data[0]; | |
| 209 | fdc->fdc_status[id].extinfo[i] <<= 8; | |
| 210 | fdc->fdc_status[id].extinfo[i] |= data[1]; | |
| 211 | fdc->fdc_status[id].extinfo[i] <<= 8; | |
| 212 | fdc->fdc_status[id].extinfo[i] |= data[2]; | |
| 213 | fdc->fdc_status[id].extinfo[i] <<= 8; | |
| 214 | fdc->fdc_status[id].extinfo[i] |= data[3]; | |
| 215 | ||
| 216 | if ( i == 0 ) | |
| 217 | fdc->fdc_status[id].extoffs[i] = sizeof( header ) + ( MAX_TRACKS * sizeof( data ) ); | |
| 218 | else | |
| 219 | fdc->fdc_status[id].extoffs[i] = fdc->fdc_status[id].extoffs[i-1] + ( fdc->fdc_status[id].extinfo[i-1] & 0xffff ); | |
| 220 | } | |
| 221 | ||
| 222 | fdc->fdc_status[id].is_ext_image = 1; | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | static int fdc_get_curpos( device_t *device, int drive ) | |
| 227 | { | |
| 228 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 229 | double elapsed; | |
| 230 | int speed; | |
| 231 | int bytes; | |
| 232 | int pos; | |
| 233 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 234 | ||
| 235 | if ( fdc->fdc_status[drive].rev_timer_started == 0 ) { | |
| 236 | logerror("Rev timer not started on drive %d, cant get position!\n", drive ); | |
| 237 | return 0; | |
| 238 | } | |
| 239 | ||
| 240 | elapsed = fdc->fdc_status[drive].rev_timer ->elapsed( ).as_double(); | |
| 241 | speed = ( CUSTOM_REG(REG_ADKCON) & 0x100 ) ? 2 : 4; | |
| 242 | ||
| 243 | bytes = elapsed / attotime::from_usec( speed * 8 ).as_double(); | |
| 244 | pos = bytes % ( fdc->fdc_status[drive].tracklen ); | |
| 245 | ||
| 246 | return pos; | |
| 247 | } | |
| 248 | ||
| 249 | UINT16 amiga_fdc_get_byte (device_t *device) | |
| 250 | { | |
| 251 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 252 | int pos; | |
| 253 | int i, drive = -1; | |
| 254 | UINT16 ret; | |
| 255 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 256 | ||
| 257 | ret = ( ( CUSTOM_REG(REG_DSKLEN) >> 1 ) & 0x4000 ) & ( ( CUSTOM_REG(REG_DMACON) << 10 ) & 0x4000 ); | |
| 258 | ret |= ( CUSTOM_REG(REG_DSKLEN) >> 1 ) & 0x2000; | |
| 259 | ||
| 260 | for ( i = 0; i < NUM_DRIVES; i++ ) { | |
| 261 | if ( !( fdc->fdc_sel & ( 1 << i ) ) ) | |
| 262 | drive = i; | |
| 263 | } | |
| 264 | ||
| 265 | if ( drive == -1 ) | |
| 266 | return ret; | |
| 267 | ||
| 268 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 269 | return ret; | |
| 270 | ||
| 271 | setup_fdc_buffer( device,drive ); | |
| 272 | ||
| 273 | pos = fdc_get_curpos( device, drive ); | |
| 274 | ||
| 275 | if ( fdc->fdc_status[drive].mfm[pos] == ( CUSTOM_REG(REG_DSRSYNC) >> 8 ) && | |
| 276 | fdc->fdc_status[drive].mfm[pos+1] == ( CUSTOM_REG(REG_DSRSYNC) & 0xff ) ) | |
| 277 | ret |= 0x1000; | |
| 278 | ||
| 279 | if ( pos != fdc->fdc_status[drive].pos ) { | |
| 280 | ret |= 0x8000; | |
| 281 | fdc->fdc_status[drive].pos = pos; | |
| 282 | } | |
| 283 | ||
| 284 | ret |= fdc->fdc_status[drive].mfm[pos]; | |
| 285 | ||
| 286 | return ret; | |
| 287 | } | |
| 288 | ||
| 289 | static TIMER_CALLBACK(fdc_sync_proc) | |
| 290 | { | |
| 291 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 292 | int drive = param; | |
| 293 | UINT16 sync = CUSTOM_REG(REG_DSRSYNC); | |
| 294 | int cur_pos; | |
| 295 | int sector; | |
| 296 | int time; | |
| 297 | amiga_fdc_t *fdc = get_safe_token((device_t*)ptr); | |
| 298 | ||
| 299 | /* if floppy got ejected, stop */ | |
| 300 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 301 | goto bail; | |
| 302 | ||
| 303 | if ( fdc->fdc_status[drive].motor_on == 0 ) | |
| 304 | goto bail; | |
| 305 | ||
| 306 | cur_pos = fdc_get_curpos( (device_t*)ptr, drive ); | |
| 307 | ||
| 308 | if ( cur_pos <= ( GAP_TRACK_BYTES + 6 ) ) | |
| 309 | { | |
| 310 | sector = 0; | |
| 311 | } | |
| 312 | else | |
| 313 | { | |
| 314 | sector = ( cur_pos - ( GAP_TRACK_BYTES + 6 ) ) / ONE_SECTOR_BYTES; | |
| 315 | } | |
| 316 | ||
| 317 | setup_fdc_buffer( (device_t*)ptr, drive ); | |
| 318 | ||
| 319 | if ( cur_pos < 2 ) | |
| 320 | cur_pos = 2; | |
| 321 | ||
| 322 | if ( fdc->fdc_status[drive].mfm[cur_pos-2] == ( ( sync >> 8 ) & 0xff ) && | |
| 323 | fdc->fdc_status[drive].mfm[cur_pos-1] == ( sync & 0xff ) ) | |
| 324 | { | |
| 325 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 326 | ||
| 327 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKSYN, 0xffff); | |
| 328 | } | |
| 329 | ||
| 330 | if ( sector < 10 ) | |
| 331 | { | |
| 332 | /* start the sync timer */ | |
| 333 | time = ONE_SECTOR_BYTES; | |
| 334 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 335 | time *= 8; | |
| 336 | fdc->fdc_status[drive].sync_timer->adjust(attotime::from_usec( time ), drive); | |
| 337 | return; | |
| 338 | } | |
| 339 | ||
| 340 | bail: | |
| 341 | fdc->fdc_status[drive].sync_timer->reset( ); | |
| 342 | } | |
| 343 | ||
| 344 | static TIMER_CALLBACK(fdc_dma_proc) | |
| 345 | { | |
| 346 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 347 | int drive = param; | |
| 348 | amiga_fdc_t *fdc = get_safe_token((device_t*)ptr); | |
| 349 | ||
| 350 | /* if DMA got disabled by the time we got here, stop operations */ | |
| 351 | if ( ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) == 0 ) | |
| 352 | goto bail; | |
| 353 | ||
| 354 | if ( ( CUSTOM_REG(REG_DMACON) & 0x0210 ) == 0 ) | |
| 355 | goto bail; | |
| 356 | ||
| 357 | /* if floppy got ejected, also stop */ | |
| 358 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 359 | goto bail; | |
| 360 | ||
| 361 | if ( fdc->fdc_status[drive].motor_on == 0 ) | |
| 362 | goto bail; | |
| 363 | ||
| 364 | setup_fdc_buffer( (device_t*)ptr, drive ); | |
| 365 | ||
| 366 | if ( CUSTOM_REG(REG_DSKLEN) & 0x4000 ) /* disk write case, unsupported yet */ | |
| 367 | { | |
| 368 | if ( fdc->fdc_status[drive].len > 0 ) | |
| 369 | { | |
| 370 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 371 | ||
| 372 | logerror("Write to disk unsupported yet\n" ); | |
| 373 | ||
| 374 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff); | |
| 375 | } | |
| 376 | } | |
| 377 | else | |
| 378 | { | |
| 379 | offs_t offset = fdc->fdc_status[drive].ptr; | |
| 380 | int cur_pos = fdc->fdc_status[drive].pos; | |
| 381 | int len = fdc->fdc_status[drive].len; | |
| 382 | ||
| 383 | if ( len > MAX_WORDS_PER_DMA_CYCLE ) len = MAX_WORDS_PER_DMA_CYCLE; | |
| 384 | ||
| 385 | fdc->fdc_status[drive].len -= len; | |
| 386 | ||
| 387 | while ( len-- ) | |
| 388 | { | |
| 389 | int dat = ( fdc->fdc_status[drive].mfm[cur_pos++] ) << 8; | |
| 390 | ||
| 391 | cur_pos %= ( fdc->fdc_status[drive].tracklen ); | |
| 392 | ||
| 393 | dat |= fdc->fdc_status[drive].mfm[cur_pos++]; | |
| 394 | ||
| 395 | cur_pos %= ( fdc->fdc_status[drive].tracklen ); | |
| 396 | ||
| 397 | (*state->m_chip_ram_w)(state, offset, dat); | |
| 398 | ||
| 399 | offset += 2; | |
| 400 | } | |
| 401 | ||
| 402 | fdc->fdc_status[drive].ptr = offset; | |
| 403 | fdc->fdc_status[drive].pos = cur_pos; | |
| 404 | ||
| 405 | if ( fdc->fdc_status[drive].len <= 0 ) | |
| 406 | { | |
| 407 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 408 | ||
| 409 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff); | |
| 410 | } | |
| 411 | else | |
| 412 | { | |
| 413 | int time; | |
| 414 | double len_words = fdc->fdc_status[drive].len; | |
| 415 | if ( len_words > MAX_WORDS_PER_DMA_CYCLE ) len_words = MAX_WORDS_PER_DMA_CYCLE; | |
| 416 | ||
| 417 | time = len_words * 2; | |
| 418 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 419 | time *= 8; | |
| 420 | fdc->fdc_status[drive].dma_timer->adjust(attotime::from_usec( time ), drive); | |
| 421 | return; | |
| 422 | } | |
| 423 | } | |
| 424 | ||
| 425 | bail: | |
| 426 | fdc->fdc_status[drive].dma_timer->reset( ); | |
| 427 | } | |
| 428 | ||
| 429 | void amiga_fdc_setup_dma( device_t *device ) { | |
| 430 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 431 | int i, cur_pos, drive = -1, len_words = 0; | |
| 432 | int time = 0; | |
| 433 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 434 | ||
| 435 | for ( i = 0; i < NUM_DRIVES; i++ ) { | |
| 436 | if ( !( fdc->fdc_sel & ( 1 << i ) ) ) | |
| 437 | drive = i; | |
| 438 | } | |
| 439 | ||
| 440 | if ( drive == -1 ) { | |
| 441 | address_space *space = device->machine().device("maincpu")->memory().space(AS_PROGRAM); | |
| 442 | ||
| 443 | logerror("Disk DMA started with no drive selected!\n" ); | |
| 444 | amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff); | |
| 445 | return; | |
| 446 | } | |
| 447 | ||
| 448 | if ( ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) == 0 ) | |
| 449 | goto bail; | |
| 450 | ||
| 451 | if ( ( CUSTOM_REG(REG_DMACON) & 0x0210 ) == 0 ) | |
| 452 | goto bail; | |
| 453 | ||
| 454 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 455 | goto bail; | |
| 456 | ||
| 457 | setup_fdc_buffer( device,drive ); | |
| 458 | ||
| 459 | fdc->fdc_status[drive].len = CUSTOM_REG(REG_DSKLEN) & 0x3fff; | |
| 460 | fdc->fdc_status[drive].ptr = CUSTOM_REG_LONG(REG_DSKPTH); | |
| 461 | fdc->fdc_status[drive].pos = cur_pos = fdc_get_curpos( device, drive ); | |
| 462 | ||
| 463 | /* we'll do a set amount at a time */ | |
| 464 | len_words = fdc->fdc_status[drive].len; | |
| 465 | if ( len_words > MAX_WORDS_PER_DMA_CYCLE ) len_words = MAX_WORDS_PER_DMA_CYCLE; | |
| 466 | ||
| 467 | if ( CUSTOM_REG(REG_ADKCON) & 0x0400 ) { /* Wait for sync */ | |
| 468 | if ( CUSTOM_REG(REG_DSRSYNC) != 0x4489 ) { | |
| 469 | logerror("Attempting to read a non-standard SYNC\n" ); | |
| 470 | } | |
| 471 | ||
| 472 | i = cur_pos; | |
| 473 | do { | |
| 474 | if ( fdc->fdc_status[drive].mfm[i] == ( CUSTOM_REG(REG_DSRSYNC) >> 8 ) && | |
| 475 | fdc->fdc_status[drive].mfm[i+1] == ( CUSTOM_REG(REG_DSRSYNC) & 0xff ) ) | |
| 476 | break; | |
| 477 | ||
| 478 | i++; | |
| 479 | i %= ( fdc->fdc_status[drive].tracklen ); | |
| 480 | time++; | |
| 481 | } while( i != cur_pos ); | |
| 482 | ||
| 483 | if ( i == cur_pos && time != 0 ) { | |
| 484 | logerror("SYNC not found on track!\n" ); | |
| 485 | return; | |
| 486 | } else { | |
| 487 | fdc->fdc_status[drive].pos = i + 2; | |
| 488 | time += 2; | |
| 489 | } | |
| 490 | } | |
| 491 | ||
| 492 | time += len_words * 2; | |
| 493 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 494 | time *= 8; | |
| 495 | fdc->fdc_status[drive].dma_timer->adjust(attotime::from_usec( time ), drive); | |
| 496 | ||
| 497 | return; | |
| 498 | ||
| 499 | bail: | |
| 500 | fdc->fdc_status[drive].dma_timer->reset( ); | |
| 501 | } | |
| 502 | ||
| 503 | static void setup_fdc_buffer( device_t *device,int drive ) | |
| 504 | { | |
| 505 | int sector, offset, len; | |
| 506 | UINT8 temp_cyl[512*11]; | |
| 507 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 508 | ||
| 509 | /* no disk in drive */ | |
| 510 | if ( fdc->fdc_status[drive].f == NULL ) { | |
| 511 | memset( &fdc->fdc_status[drive].mfm[0], 0xaa, 32 ); | |
| 512 | fdc->fdc_status[drive].disk_changed = DISK_DETECT_DELAY; | |
| 513 | return; | |
| 514 | } | |
| 515 | ||
| 516 | len = 512*11; | |
| 517 | ||
| 518 | offset = ( fdc->fdc_status[drive].cyl << 1 ) | fdc->fdc_side; | |
| 519 | ||
| 520 | if ( fdc->fdc_status[drive].cached == offset ) | |
| 521 | return; | |
| 522 | ||
| 523 | #if 0 | |
| 524 | popmessage("T:%d S:%d", fdc->fdc_status[drive].cyl, fdc_side ); | |
| 525 | #endif | |
| 526 | ||
| 527 | if ( fdc->fdc_status[drive].is_ext_image ) | |
| 528 | { | |
| 529 | len = fdc->fdc_status[drive].extinfo[offset] & 0xffff; | |
| 530 | ||
| 531 | if ( len > ( MAX_MFM_TRACK_LEN - 2 ) ) | |
| 532 | len = MAX_MFM_TRACK_LEN - 2; | |
| 533 | ||
| 534 | if ( fdc->fdc_status[drive].f->fseek( fdc->fdc_status[drive].extoffs[offset], SEEK_SET ) ) | |
| 535 | { | |
| 536 | logerror("FDC: image_fseek failed!\n" ); | |
| 537 | fdc->fdc_status[drive].f = NULL; | |
| 538 | fdc->fdc_status[drive].disk_changed = DISK_DETECT_DELAY; | |
| 539 | return; | |
| 540 | } | |
| 541 | ||
| 542 | /* if SYNC is 0000, then its a regular amiga dos track image */ | |
| 543 | if ( ( fdc->fdc_status[drive].extinfo[offset] >> 16 ) == 0x0000 ) | |
| 544 | { | |
| 545 | fdc->fdc_status[drive].f->fread( temp_cyl, len ); | |
| 546 | /* fall through to regular load */ | |
| 547 | } | |
| 548 | else /* otherwise, it's a raw track */ | |
| 549 | { | |
| 550 | fdc->fdc_status[drive].mfm[0] = ( fdc->fdc_status[drive].extinfo[offset] >> 24 ) & 0xff; | |
| 551 | fdc->fdc_status[drive].mfm[1] = ( fdc->fdc_status[drive].extinfo[offset] >> 16 ) & 0xff; | |
| 552 | fdc->fdc_status[drive].f->fread( &fdc->fdc_status[drive].mfm[2], len ); | |
| 553 | fdc->fdc_status[drive].tracklen = len + 2; | |
| 554 | fdc->fdc_status[drive].cached = offset; | |
| 555 | return; | |
| 556 | } | |
| 557 | } | |
| 558 | else | |
| 559 | { | |
| 560 | if ( fdc->fdc_status[drive].f->fseek( offset * len, SEEK_SET ) ) | |
| 561 | { | |
| 562 | logerror("FDC: image_fseek failed!\n" ); | |
| 563 | fdc->fdc_status[drive].f = NULL; | |
| 564 | fdc->fdc_status[drive].disk_changed = DISK_DETECT_DELAY; | |
| 565 | return; | |
| 566 | } | |
| 567 | ||
| 568 | fdc->fdc_status[drive].f->fread( temp_cyl, len ); | |
| 569 | } | |
| 570 | ||
| 571 | fdc->fdc_status[drive].tracklen = MAX_TRACK_BYTES; | |
| 572 | ||
| 573 | memset( &fdc->fdc_status[drive].mfm[ONE_SECTOR_BYTES*11], 0xaa, GAP_TRACK_BYTES ); | |
| 574 | ||
| 575 | for ( sector = 0; sector < 11; sector++ ) { | |
| 576 | int x; | |
| 577 | UINT8 *dest = ( &fdc->fdc_status[drive].mfm[(ONE_SECTOR_BYTES*sector)] ); | |
| 578 | UINT8 *src = &temp_cyl[sector*512]; | |
| 579 | UINT32 tmp; | |
| 580 | UINT32 even, odd; | |
| 581 | UINT32 hck = 0, dck = 0; | |
| 582 | ||
| 583 | /* Preamble and sync */ | |
| 584 | *(dest + 0) = 0xaa; | |
| 585 | *(dest + 1) = 0xaa; | |
| 586 | *(dest + 2) = 0xaa; | |
| 587 | *(dest + 3) = 0xaa; | |
| 588 | *(dest + 4) = 0x44; | |
| 589 | *(dest + 5) = 0x89; | |
| 590 | *(dest + 6) = 0x44; | |
| 591 | *(dest + 7) = 0x89; | |
| 592 | ||
| 593 | /* Track and sector info */ | |
| 594 | ||
| 595 | tmp = 0xff000000 | (offset<<16) | (sector<<8) | (11 - sector); | |
| 596 | odd = (tmp & 0x55555555) | 0xaaaaaaaa; | |
| 597 | even = ( ( tmp >> 1 ) & 0x55555555 ) | 0xaaaaaaaa; | |
| 598 | *(dest + 8) = (UINT8) ((even & 0xff000000)>>24); | |
| 599 | *(dest + 9) = (UINT8) ((even & 0xff0000)>>16); | |
| 600 | *(dest + 10) = (UINT8) ((even & 0xff00)>>8); | |
| 601 | *(dest + 11) = (UINT8) ((even & 0xff)); | |
| 602 | *(dest + 12) = (UINT8) ((odd & 0xff000000)>>24); | |
| 603 | *(dest + 13) = (UINT8) ((odd & 0xff0000)>>16); | |
| 604 | *(dest + 14) = (UINT8) ((odd & 0xff00)>>8); | |
| 605 | *(dest + 15) = (UINT8) ((odd & 0xff)); | |
| 606 | ||
| 607 | /* Fill unused space */ | |
| 608 | ||
| 609 | for (x = 16 ; x < 48; x++) | |
| 610 | *(dest + x) = 0xaa; | |
| 611 | ||
| 612 | /* Encode data section of sector */ | |
| 613 | ||
| 614 | for (x = 64 ; x < 576; x++) | |
| 615 | { | |
| 616 | tmp = *(src + x - 64); | |
| 617 | odd = (tmp & 0x55); | |
| 618 | even = (tmp>>1) & 0x55; | |
| 619 | *(dest + x) = (UINT8) (even | 0xaa); | |
| 620 | *(dest + x + 512) = (UINT8) (odd | 0xaa); | |
| 621 | } | |
| 622 | ||
| 623 | /* Calculate checksum for unused space */ | |
| 624 | ||
| 625 | for(x = 8; x < 48; x += 4) | |
| 626 | hck ^= (((UINT32) *(dest + x))<<24) | (((UINT32) *(dest + x + 1))<<16) | | |
| 627 | (((UINT32) *(dest + x + 2))<<8) | ((UINT32) *(dest + x + 3)); | |
| 628 | ||
| 629 | even = odd = hck; | |
| 630 | odd >>= 1; | |
| 631 | even |= 0xaaaaaaaa; | |
| 632 | odd |= 0xaaaaaaaa; | |
| 633 | ||
| 634 | *(dest + 48) = (UINT8) ((odd & 0xff000000)>>24); | |
| 635 | *(dest + 49) = (UINT8) ((odd & 0xff0000)>>16); | |
| 636 | *(dest + 50) = (UINT8) ((odd & 0xff00)>>8); | |
| 637 | *(dest + 51) = (UINT8) (odd & 0xff); | |
| 638 | *(dest + 52) = (UINT8) ((even & 0xff000000)>>24); | |
| 639 | *(dest + 53) = (UINT8) ((even & 0xff0000)>>16); | |
| 640 | *(dest + 54) = (UINT8) ((even & 0xff00)>>8); | |
| 641 | *(dest + 55) = (UINT8) (even & 0xff); | |
| 642 | ||
| 643 | /* Calculate checksum for data section */ | |
| 644 | ||
| 645 | for(x = 64; x < 1088; x += 4) | |
| 646 | dck ^= (((UINT32) *(dest + x))<<24) | (((UINT32) *(dest + x + 1))<<16) | | |
| 647 | (((UINT32) *(dest + x + 2))<< 8) | ((UINT32) *(dest + x + 3)); | |
| 648 | even = odd = dck; | |
| 649 | odd >>= 1; | |
| 650 | even |= 0xaaaaaaaa; | |
| 651 | odd |= 0xaaaaaaaa; | |
| 652 | *(dest + 56) = (UINT8) ((odd & 0xff000000)>>24); | |
| 653 | *(dest + 57) = (UINT8) ((odd & 0xff0000)>>16); | |
| 654 | *(dest + 58) = (UINT8) ((odd & 0xff00)>>8); | |
| 655 | *(dest + 59) = (UINT8) (odd & 0xff); | |
| 656 | *(dest + 60) = (UINT8) ((even & 0xff000000)>>24); | |
| 657 | *(dest + 61) = (UINT8) ((even & 0xff0000)>>16); | |
| 658 | *(dest + 62) = (UINT8) ((even & 0xff00)>>8); | |
| 659 | *(dest + 63) = (UINT8) (even & 0xff); | |
| 660 | } | |
| 661 | ||
| 662 | // update MFM data with proper CLK signal | |
| 663 | int lastbit= 0; | |
| 664 | for(int i=0;i<MAX_TRACK_BYTES ;i++) | |
| 665 | { | |
| 666 | UINT8 c=fdc->fdc_status[drive].mfm[i]; | |
| 667 | UINT8 dat = 0; | |
| 668 | for(int j=0;j<8;j=j+2) | |
| 669 | { | |
| 670 | UINT8 c1=(c>>(6-j))&0x3; | |
| 671 | if(c1&0x1) | |
| 672 | { | |
| 673 | dat |= (0x01<<(6-j)); | |
| 674 | lastbit=1; | |
| 675 | } | |
| 676 | else | |
| 677 | { | |
| 678 | if(lastbit==0 && (c1&0x2)) | |
| 679 | { | |
| 680 | dat |= (0x02<<(6-j)); | |
| 681 | } | |
| 682 | else | |
| 683 | { | |
| 684 | dat |= (0x00<<(6-j)); | |
| 685 | } | |
| 686 | lastbit=0; | |
| 687 | } | |
| 688 | } | |
| 689 | fdc->fdc_status[drive].mfm[i] = dat; | |
| 690 | } | |
| 691 | fdc->fdc_status[drive].cached = offset; | |
| 692 | } | |
| 693 | ||
| 694 | static TIMER_CALLBACK(fdc_rev_proc) | |
| 695 | { | |
| 696 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 697 | int drive = param; | |
| 698 | int time; | |
| 699 | device_t *cia; | |
| 700 | amiga_fdc_t *fdc = get_safe_token((device_t*)ptr); | |
| 701 | ||
| 702 | /* Issue a index pulse when a disk revolution completes */ | |
| 703 | cia = machine.device("cia_1"); | |
| 704 | mos6526_flag_w(cia, 0); | |
| 705 | mos6526_flag_w(cia, 1); | |
| 706 | ||
| 707 | fdc->fdc_status[drive].rev_timer->adjust(attotime::from_msec( ONE_REV_TIME ), drive); | |
| 708 | fdc->fdc_status[drive].rev_timer_started = 1; | |
| 709 | ||
| 710 | if ( fdc->fdc_status[drive].is_ext_image == 0 ) | |
| 711 | { | |
| 712 | /* also start the sync timer */ | |
| 713 | time = GAP_TRACK_BYTES + 6; | |
| 714 | time *= ( CUSTOM_REG(REG_ADKCON) & 0x0100 ) ? 2 : 4; | |
| 715 | time *= 8; | |
| 716 | fdc->fdc_status[drive].sync_timer->adjust(attotime::from_usec( time ), drive); | |
| 717 | } | |
| 718 | } | |
| 719 | ||
| 720 | static void start_rev_timer( device_t *device,int drive ) { | |
| 721 | // double time; | |
| 722 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 723 | ||
| 724 | if ( fdc->fdc_status[drive].rev_timer_started ) { | |
| 725 | logerror("Revolution timer started twice?!\n" ); | |
| 726 | return; | |
| 727 | } | |
| 728 | ||
| 729 | fdc->fdc_status[drive].rev_timer->adjust(attotime::from_msec( ONE_REV_TIME ), drive); | |
| 730 | fdc->fdc_status[drive].rev_timer_started = 1; | |
| 731 | } | |
| 732 | ||
| 733 | static void stop_rev_timer( device_t *device,int drive ) { | |
| 734 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 735 | ||
| 736 | if ( fdc->fdc_status[drive].rev_timer_started == 0 ) { | |
| 737 | logerror("Revolution timer never started?!\n" ); | |
| 738 | return; | |
| 739 | } | |
| 740 | ||
| 741 | fdc->fdc_status[drive].rev_timer->reset( ); | |
| 742 | fdc->fdc_status[drive].rev_timer_started = 0; | |
| 743 | fdc->fdc_status[drive].dma_timer->reset( ); | |
| 744 | fdc->fdc_status[drive].sync_timer->reset( ); | |
| 745 | } | |
| 746 | ||
| 747 | static void fdc_setup_leds(device_t *device, int drive ) { | |
| 748 | ||
| 749 | char portname[12]; | |
| 750 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 751 | sprintf(portname, "drive_%d_led", drive); | |
| 752 | output_set_value(portname, fdc->fdc_status[drive].motor_on == 0 ? 0 : 1); | |
| 753 | ||
| 754 | if ( drive == 0 ) | |
| 755 | set_led_status(device->machine(), 1, fdc->fdc_status[drive].motor_on ); /* update internal drive led */ | |
| 756 | ||
| 757 | if ( drive == 1 ) | |
| 758 | set_led_status(device->machine(), 2, fdc->fdc_status[drive].motor_on ); /* update external drive led */ | |
| 759 | } | |
| 760 | ||
| 761 | static void fdc_stepdrive( device_t *device,int drive ) { | |
| 762 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 763 | ||
| 764 | if ( fdc->fdc_dir ) { | |
| 765 | if ( fdc->fdc_status[drive].cyl ) | |
| 766 | fdc->fdc_status[drive].cyl--; | |
| 767 | } else { | |
| 768 | if ( fdc->fdc_status[drive].cyl < 79 ) | |
| 769 | fdc->fdc_status[drive].cyl++; | |
| 770 | } | |
| 771 | ||
| 772 | /* Update disk detection if applicable */ | |
| 773 | if ( fdc->fdc_status[drive].f != NULL ) | |
| 774 | { | |
| 775 | if ( fdc->fdc_status[drive].disk_changed > 0 ) | |
| 776 | fdc->fdc_status[drive].disk_changed--; | |
| 777 | } | |
| 778 | } | |
| 779 | ||
| 780 | static void fdc_motor( device_t *device,int drive, int off ) { | |
| 781 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 782 | int on = !off; | |
| 783 | ||
| 784 | if ( ( fdc->fdc_status[drive].motor_on == 0 ) && on ) { | |
| 785 | fdc->fdc_status[drive].pos = 0; | |
| 786 | ||
| 787 | start_rev_timer( device,drive ); | |
| 788 | ||
| 789 | } else { | |
| 790 | if ( fdc->fdc_status[drive].motor_on && off ) | |
| 791 | stop_rev_timer(device, drive ); | |
| 792 | } | |
| 793 | ||
| 794 | fdc->fdc_status[drive].motor_on = on; | |
| 795 | } | |
| 796 | ||
| 797 | WRITE8_DEVICE_HANDLER( amiga_fdc_control_w ) | |
| 798 | { | |
| 799 | int step_pulse; | |
| 800 | int drive; | |
| 801 | ||
| 802 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 803 | ||
| 804 | if ( fdc->fdc_sel != ( ( data >> 3 ) & 15 ) ) | |
| 805 | fdc->fdc_rdy = 0; | |
| 806 | ||
| 807 | fdc->fdc_sel = ( data >> 3 ) & 15; | |
| 808 | fdc->fdc_side = 1 - ( ( data >> 2 ) & 1 ); | |
| 809 | fdc->fdc_dir = ( data >> 1 ) & 1; | |
| 810 | ||
| 811 | step_pulse = data & 1; | |
| 812 | ||
| 813 | if ( fdc->fdc_step != step_pulse ) { | |
| 814 | fdc->fdc_step = step_pulse; | |
| 815 | ||
| 816 | if ( fdc->fdc_step == 0 ) { | |
| 817 | for ( drive = 0; drive < NUM_DRIVES; drive++ ) { | |
| 818 | if ( !( fdc->fdc_sel & ( 1 << drive ) ) ) | |
| 819 | fdc_stepdrive( device, drive ); | |
| 820 | } | |
| 821 | } | |
| 822 | } | |
| 823 | ||
| 824 | for ( drive = 0; drive < NUM_DRIVES; drive++ ) { | |
| 825 | if ( !( fdc->fdc_sel & ( 1 << drive ) ) ) { | |
| 826 | fdc_motor( device, drive, ( data >> 7 ) & 1 ); | |
| 827 | fdc_setup_leds( device,drive ); | |
| 828 | } | |
| 829 | } | |
| 830 | } | |
| 831 | ||
| 832 | UINT8 amiga_fdc_status_r (device_t *device) | |
| 833 | { | |
| 834 | int drive = -1, ret = 0x3c; | |
| 835 | amiga_fdc_t *fdc = get_safe_token(device); | |
| 836 | for ( drive = 0; drive < NUM_DRIVES; drive++ ) { | |
| 837 | if ( !( fdc->fdc_sel & ( 1 << drive ) ) ) { | |
| 838 | ||
| 839 | if ( fdc->fdc_status[drive].motor_on ) { | |
| 840 | if ( fdc->fdc_rdy ) ret &= ~0x20; | |
| 841 | fdc->fdc_rdy = 1; | |
| 842 | } else { | |
| 843 | /* return drive id */ | |
| 844 | ret &= ~0x20; | |
| 845 | } | |
| 846 | ||
| 847 | if ( fdc->fdc_status[drive].cyl == 0 ) | |
| 848 | ret &= ~0x10; | |
| 849 | ||
| 850 | if ( fdc->fdc_status[drive].wprot ) | |
| 851 | ret &= ~0x08; | |
| 852 | ||
| 853 | if ( fdc->fdc_status[drive].disk_changed ) | |
| 854 | ret &= ~0x04; | |
| 855 | ||
| 856 | return ret; | |
| 857 | } | |
| 858 | } | |
| 859 | ||
| 860 | return ret; | |
| 861 | } | |
| 862 | ||
| 863 | static const floppy_config amiga_floppy_config = | |
| 864 | { | |
| 865 | DEVCB_NULL, | |
| 866 | DEVCB_NULL, | |
| 867 | DEVCB_NULL, | |
| 868 | DEVCB_NULL, | |
| 869 | DEVCB_NULL, | |
| 870 | FLOPPY_STANDARD_3_5_DSHD, | |
| 871 | FLOPPY_OPTIONS_NAME(amiga_only), | |
| 872 | NULL | |
| 873 | }; | |
| 874 | ||
| 875 | static MACHINE_CONFIG_FRAGMENT( amiga_fdc ) | |
| 876 | MCFG_FLOPPY_2_DRIVES_ADD(amiga_floppy_config) | |
| 877 | MACHINE_CONFIG_END | |
| 878 | ||
| 879 | ||
| 880 | DEVICE_GET_INFO( amiga_fdc ) | |
| 881 | { | |
| 882 | switch (state) | |
| 883 | { | |
| 884 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 885 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; | |
| 886 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(amiga_fdc_t); break; | |
| 887 | ||
| 888 | /* --- the following bits of info are returned as pointers --- */ | |
| 889 | case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(amiga_fdc); break; | |
| 890 | ||
| 891 | /* --- the following bits of info are returned as pointers to data or functions --- */ | |
| 892 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(amiga_fdc); break; | |
| 893 | case DEVINFO_FCT_STOP: /* Nothing */ break; | |
| 894 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(amiga_fdc); break; | |
| 895 | ||
| 896 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 897 | case DEVINFO_STR_NAME: strcpy(info->s, "Amiga FDC"); break; | |
| 898 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Amiga FDC"); break; | |
| 899 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; | |
| 900 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; | |
| 901 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; | |
| 902 | } | |
| 903 | } | |
| 904 | ||
| 905 | DEFINE_LEGACY_DEVICE(AMIGA_FDC, amiga_fdc); |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Amiga keyboard controller emulation | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | ||
| 8 | #include "emu.h" | |
| 9 | #include "includes/amiga.h" | |
| 10 | #include "amigakbd.h" | |
| 11 | #include "machine/6526cia.h" | |
| 12 | ||
| 13 | ||
| 14 | #define KEYBOARD_BUFFER_SIZE 256 | |
| 15 | ||
| 16 | typedef struct | |
| 17 | { | |
| 18 | UINT8 *buf; | |
| 19 | int buf_pos; | |
| 20 | int cur_pos; | |
| 21 | emu_timer *timer; | |
| 22 | } amigakbd_t; | |
| 23 | static amigakbd_t kbd; | |
| 24 | ||
| 25 | static void kbd_sendscancode( running_machine &machine, UINT8 scancode ) | |
| 26 | { | |
| 27 | int j; | |
| 28 | device_t *cia = machine.device("cia_0"); | |
| 29 | ||
| 30 | /* send over to the cia A */ | |
| 31 | for( j = 0; j < 8; j++ ) | |
| 32 | { | |
| 33 | mos6526_cnt_w( cia, 0 ); /* lower cnt */ | |
| 34 | mos6526_sp_w( cia, BIT(scancode << j, 7) ); /* set the serial data */ | |
| 35 | mos6526_cnt_w( cia, 1 ); /* raise cnt */ | |
| 36 | } | |
| 37 | } | |
| 38 | ||
| 39 | static TIMER_CALLBACK( kbd_update_callback ) | |
| 40 | { | |
| 41 | UINT8 scancode; | |
| 42 | ||
| 43 | (void)param; | |
| 44 | ||
| 45 | /* if we don't have pending data, bail */ | |
| 46 | ||
| 47 | if ( kbd.buf_pos == kbd.cur_pos ) | |
| 48 | return; | |
| 49 | ||
| 50 | /* fetch the next scan code and send it to the Amiga */ | |
| 51 | scancode = kbd.buf[kbd.cur_pos++]; | |
| 52 | kbd.cur_pos %= KEYBOARD_BUFFER_SIZE; | |
| 53 | kbd_sendscancode( machine, scancode ); | |
| 54 | ||
| 55 | /* if we still have more data, schedule another update */ | |
| 56 | if ( kbd.buf_pos != kbd.cur_pos ) | |
| 57 | { | |
| 58 | kbd.timer->adjust(machine.primary_screen->frame_period() / 4); | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | static INPUT_CHANGED( kbd_update ) | |
| 63 | { | |
| 64 | int index = (int)(FPTR)param, i; | |
| 65 | UINT32 oldvalue = oldval * field.mask, newvalue = newval * field.mask; | |
| 66 | UINT32 delta = oldvalue ^ newvalue; | |
| 67 | ||
| 68 | /* Special case Page UP, which we will use as Action Replay button */ | |
| 69 | if ( (index == 3) && ( delta & 0x80000000 ) && ( newvalue & 0x80000000 ) ) | |
| 70 | { | |
| 71 | const amiga_machine_interface *amiga_intf = amiga_get_interface(field.machine()); | |
| 72 | ||
| 73 | if ( amiga_intf != NULL && amiga_intf->nmi_callback ) | |
| 74 | { | |
| 75 | (*amiga_intf->nmi_callback)(field.machine()); | |
| 76 | } | |
| 77 | } | |
| 78 | else | |
| 79 | { | |
| 80 | int key_buf_was_empty = ( kbd.buf_pos == kbd.cur_pos ) ? 1 : 0; | |
| 81 | ||
| 82 | for( i = 0; i < 32; i++ ) | |
| 83 | { | |
| 84 | if ( delta & ( 1 << i ) ) | |
| 85 | { | |
| 86 | int down = ( newvalue & ( 1 << i ) ) ? 0 : 1; | |
| 87 | int scancode = ( ( (index*32)+i ) << 1 ) | down; | |
| 88 | int amigacode = ~scancode; | |
| 89 | ||
| 90 | /* add the keycode to the buffer */ | |
| 91 | kbd.buf[kbd.buf_pos++] = amigacode & 0xff; | |
| 92 | kbd.buf_pos %= KEYBOARD_BUFFER_SIZE; | |
| 93 | } | |
| 94 | } | |
| 95 | ||
| 96 | /* if the buffer was empty and we have new data, start a timer to send the keystrokes */ | |
| 97 | if ( key_buf_was_empty && ( kbd.buf_pos != kbd.cur_pos ) ) | |
| 98 | { | |
| 99 | kbd.timer->adjust(field.machine().primary_screen->frame_period() / 4); | |
| 100 | } | |
| 101 | } | |
| 102 | } | |
| 103 | ||
| 104 | void amigakbd_init( running_machine &machine ) | |
| 105 | { | |
| 106 | /* allocate a keyboard buffer */ | |
| 107 | kbd.buf = auto_alloc_array(machine, UINT8, KEYBOARD_BUFFER_SIZE); | |
| 108 | kbd.buf_pos = 0; | |
| 109 | kbd.cur_pos = 0; | |
| 110 | kbd.timer = machine.scheduler().timer_alloc(FUNC(kbd_update_callback)); | |
| 111 | kbd.timer->reset(); | |
| 112 | } | |
| 113 | ||
| 114 | /*********************************************************************************************/ | |
| 115 | ||
| 116 | /* Layout is for the US A500 keyboard */ | |
| 117 | ||
| 118 | INPUT_PORTS_START( amiga_us_keyboard ) | |
| 119 | PORT_START("amiga_keyboard_0") | |
| 120 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // 00 | |
| 121 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 01 | |
| 122 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // 02 | |
| 123 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 03 | |
| 124 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 04 | |
| 125 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 05 | |
| 126 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // 06 | |
| 127 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // 07 | |
| 128 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // 08 | |
| 129 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // 09 | |
| 130 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // 0A | |
| 131 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 0B | |
| 132 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') // 0C | |
| 133 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') PORT_CHAR('\xA6') // 0D | |
| 134 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 0) // 0E | |
| 135 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 0F | |
| 136 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 10 | |
| 137 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 11 | |
| 138 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 12 | |
| 139 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 13 | |
| 140 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 14 | |
| 141 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 15 | |
| 142 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 16 | |
| 143 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 17 | |
| 144 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 18 | |
| 145 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // 19 | |
| 146 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') // 1A | |
| 147 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') // 1B | |
| 148 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 0) // 1C | |
| 149 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 1D | |
| 150 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 1E | |
| 151 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 1F | |
| 152 | ||
| 153 | PORT_START("amiga_keyboard_1") | |
| 154 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 20 | |
| 155 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 21 | |
| 156 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // 22 | |
| 157 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 23 | |
| 158 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 24 | |
| 159 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 25 | |
| 160 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // 26 | |
| 161 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 27 | |
| 162 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 28 | |
| 163 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // 29 | |
| 164 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') // 2A | |
| 165 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 2B | |
| 166 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 2C | |
| 167 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 2D | |
| 168 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 2E | |
| 169 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 2F | |
| 170 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 30 | |
| 171 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 31 | |
| 172 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // 32 | |
| 173 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 33 | |
| 174 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 34 | |
| 175 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 35 | |
| 176 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 36 | |
| 177 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 37 | |
| 178 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') // 38 | |
| 179 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') // 39 | |
| 180 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // 3A | |
| 181 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 3B | |
| 182 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))// 3C | |
| 183 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 3D | |
| 184 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 3E | |
| 185 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 3F | |
| 186 | ||
| 187 | PORT_START("amiga_keyboard_2") | |
| 188 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 40 | |
| 189 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) // 41 | |
| 190 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') // 42 | |
| 191 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // 43 | |
| 192 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // 44 | |
| 193 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) // 45 | |
| 194 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // 46 | |
| 195 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 47 | |
| 196 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 48 | |
| 197 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 49 | |
| 198 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 4A | |
| 199 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 4B | |
| 200 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) // 4C | |
| 201 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) // 4D | |
| 202 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // 4E | |
| 203 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // 4F | |
| 204 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // 50 | |
| 205 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // 51 | |
| 206 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 52 | |
| 207 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // 53 | |
| 208 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // 54 | |
| 209 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // 55 | |
| 210 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // 56 | |
| 211 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // 57 | |
| 212 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // 58 | |
| 213 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // 59 | |
| 214 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 5A | |
| 215 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 5B | |
| 216 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 5C | |
| 217 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 5D | |
| 218 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) // 5E | |
| 219 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // 5F | |
| 220 | ||
| 221 | PORT_START("amiga_keyboard_3") | |
| 222 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 60 | |
| 223 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 61 | |
| 224 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) // 62 | |
| 225 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))// 63 | |
| 226 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Alt (Left)") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // 64 | |
| 227 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Alt (Right)") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) // 65 | |
| 228 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Amiga A (Left)") PORT_CODE(KEYCODE_LWIN) // 66 | |
| 229 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Amiga A (Right)") PORT_CODE(KEYCODE_RWIN) // 67 | |
| 230 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 68 | |
| 231 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 69 | |
| 232 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6A | |
| 233 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6B | |
| 234 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6C | |
| 235 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6D | |
| 236 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6E | |
| 237 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6F | |
| 238 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 70 | |
| 239 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 71 | |
| 240 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 72 | |
| 241 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 73 | |
| 242 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 74 | |
| 243 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 75 | |
| 244 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 76 | |
| 245 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 77 | |
| 246 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 78 | |
| 247 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 79 | |
| 248 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7A | |
| 249 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7B | |
| 250 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7C | |
| 251 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7D | |
| 252 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7E | |
| 253 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_CODE(KEYCODE_PGUP) // 7F NMI button | |
| 254 | INPUT_PORTS_END |
| r0 | r11532 | |
|---|---|---|
| 1 | #ifndef AMIGAFDC_H | |
| 2 | #define AMIGAFDC_H | |
| 3 | ||
| 4 | WRITE8_DEVICE_HANDLER( amiga_fdc_control_w ); | |
| 5 | UINT8 amiga_fdc_status_r (device_t *device); | |
| 6 | UINT16 amiga_fdc_get_byte (device_t *device); | |
| 7 | void amiga_fdc_setup_dma( device_t *device ); | |
| 8 | ||
| 9 | /*************************************************************************** | |
| 10 | MACROS | |
| 11 | ***************************************************************************/ | |
| 12 | ||
| 13 | DECLARE_LEGACY_DEVICE(AMIGA_FDC, amiga_fdc); | |
| 14 | ||
| 15 | #define MCFG_AMIGA_FDC_ADD(_tag) \ | |
| 16 | MCFG_DEVICE_ADD((_tag), AMIGA_FDC, 0) | |
| 17 | ||
| 18 | #endif /* AMIGAFDC_H */ |
| r0 | r11532 | |
|---|---|---|
| 1 | #ifndef AMIGAKBD_H | |
| 2 | #define AMIGAKBD_H | |
| 3 | ||
| 4 | void amigakbd_init( running_machine &machine ); | |
| 5 | ||
| 6 | INPUT_PORTS_EXTERN( amiga_us_keyboard ); | |
| 7 | ||
| 8 | #endif /* AMIGAKBD_H */ |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Amiga cartridge emulation | |
| 4 | ||
| 5 | TODO: | |
| 6 | - Investigate why the AR2/3 sometimes garble the video on exit from the cart | |
| 7 | - Add Nordic Power and similar carts | |
| 8 | - Add HRTMon A1200 cart | |
| 9 | ||
| 10 | ***************************************************************************/ | |
| 11 | ||
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "includes/amiga.h" | |
| 15 | #include "cpu/m68000/m68000.h" | |
| 16 | #include "machine/6526cia.h" | |
| 17 | #include "machine/amigacrt.h" | |
| 18 | ||
| 19 | enum | |
| 20 | { | |
| 21 | /* supported cartridges */ | |
| 22 | ACTION_REPLAY = 0, | |
| 23 | ACTION_REPLAY_MKII, | |
| 24 | ACTION_REPLAY_MKIII | |
| 25 | }; | |
| 26 | ||
| 27 | typedef struct | |
| 28 | { | |
| 29 | int cart_type; | |
| 30 | int ar1_spurious; | |
| 31 | UINT16 ar23_mode; | |
| 32 | } amigacrt_t; | |
| 33 | static amigacrt_t amigacrt; | |
| 34 | ||
| 35 | /*************************************************************************** | |
| 36 | ||
| 37 | Utilities | |
| 38 | ||
| 39 | ***************************************************************************/ | |
| 40 | ||
| 41 | static int check_kickstart_12_13( running_machine &machine, const char *cart_name ) | |
| 42 | { | |
| 43 | UINT16 * ksmem = (UINT16 *)machine.region( "user1" )->base(); | |
| 44 | ||
| 45 | if ( ksmem[2] == 0x00FC ) | |
| 46 | return 1; | |
| 47 | ||
| 48 | logerror( "%s requires Kickstart version 1.2 or 1.3 - Cart not installed\n", cart_name ); | |
| 49 | ||
| 50 | return 0; | |
| 51 | } | |
| 52 | ||
| 53 | /*************************************************************************** | |
| 54 | ||
| 55 | Amiga Action Replay 1 | |
| 56 | ||
| 57 | Whenever you push the button, an NMI interrupt is generated. | |
| 58 | ||
| 59 | The cartridge protects itself from being removed from memory by | |
| 60 | generating an interrupt whenever either the spurious interrupt | |
| 61 | vector is written at $60, or the nmi interrupt vector is written at | |
| 62 | $7c. If the spurious interrupt vector at $60 is written, then | |
| 63 | a NMI is generated, and the spurious irq vector is restored. If the | |
| 64 | NMI vector at $7c is written, then a spurious interrupt is generated, | |
| 65 | and the NMI vector is restored. | |
| 66 | ||
| 67 | When breakpoints are set, the target address is replaced by a trap | |
| 68 | instruction, and the original contents of the address are kept in | |
| 69 | the cartridge's RAM. A trap handler is installed pointing to $40 | |
| 70 | in RAM, where code that clears memory address $60 followed by two | |
| 71 | nops are written. There seems to be a small delay between the write | |
| 72 | to $60 and until the actual NMI is generated, since the cart expects | |
| 73 | the PC to be at $46 (at the second nop). | |
| 74 | ||
| 75 | ***************************************************************************/ | |
| 76 | ||
| 77 | static IRQ_CALLBACK(amiga_ar1_irqack) | |
| 78 | { | |
| 79 | if ( irqline == 7 && amigacrt.ar1_spurious ) | |
| 80 | { | |
| 81 | return M68K_INT_ACK_SPURIOUS; | |
| 82 | } | |
| 83 | ||
| 84 | return (24+irqline); | |
| 85 | } | |
| 86 | ||
| 87 | static TIMER_CALLBACK( amiga_ar1_delayed_nmi ) | |
| 88 | { | |
| 89 | (void)param; | |
| 90 | cputag_set_input_line(machine, "maincpu", 7, PULSE_LINE); | |
| 91 | } | |
| 92 | ||
| 93 | static void amiga_ar1_nmi( running_machine &machine ) | |
| 94 | { | |
| 95 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 96 | /* get the cart's built-in ram */ | |
| 97 | UINT16 *ar_ram = (UINT16 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_write_ptr(0x9fc000); | |
| 98 | ||
| 99 | if ( ar_ram != NULL ) | |
| 100 | { | |
| 101 | int i; | |
| 102 | ||
| 103 | /* copy custom register values */ | |
| 104 | for( i = 0; i < 256; i++ ) | |
| 105 | ar_ram[0x1800+i] = CUSTOM_REG(i); | |
| 106 | ||
| 107 | /* trigger NMI irq */ | |
| 108 | amigacrt.ar1_spurious = 0; | |
| 109 | machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(28), FUNC(amiga_ar1_delayed_nmi)); | |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | static WRITE16_HANDLER( amiga_ar1_chipmem_w ) | |
| 114 | { | |
| 115 | amiga_state *state = space->machine().driver_data<amiga_state>(); | |
| 116 | int pc = cpu_get_pc(&space->device()); | |
| 117 | ||
| 118 | /* see if we're inside the AR1 rom */ | |
| 119 | if ( ((pc >> 16) & 0xff ) != 0xf0 ) | |
| 120 | { | |
| 121 | /* if we're not, see if either the Spurious IRQ vector | |
| 122 | or the NMI vector are being overwritten */ | |
| 123 | if ( offset == (0x60/2) || offset == (0x7c/2) ) | |
| 124 | { | |
| 125 | /* trigger an NMI or spurious irq */ | |
| 126 | amigacrt.ar1_spurious = (offset == 0x60/2) ? 0 : 1; | |
| 127 | space->machine().scheduler().timer_set(space->machine().device<cpu_device>("maincpu")->cycles_to_attotime(28), FUNC(amiga_ar1_delayed_nmi)); | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | (*state->m_chip_ram_w)(state, offset * 2, data ); | |
| 132 | } | |
| 133 | ||
| 134 | static void amiga_ar1_check_overlay( running_machine &machine ) | |
| 135 | { | |
| 136 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, 0x00007f, FUNC(amiga_ar1_chipmem_w)); | |
| 137 | } | |
| 138 | ||
| 139 | static void amiga_ar1_init( running_machine &machine ) | |
| 140 | { | |
| 141 | void *ar_ram; | |
| 142 | ||
| 143 | /* check kickstart version */ | |
| 144 | if ( !check_kickstart_12_13( machine, "Amiga Action Replay" ) ) | |
| 145 | { | |
| 146 | amigacrt.cart_type = -1; | |
| 147 | return; | |
| 148 | } | |
| 149 | ||
| 150 | /* setup the cart ram */ | |
| 151 | ar_ram = auto_alloc_array(machine, UINT8, 0x4000); | |
| 152 | memset(ar_ram, 0, 0x4000); | |
| 153 | ||
| 154 | /* Install ROM */ | |
| 155 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xf00000, 0xf7ffff, "bank2"); | |
| 156 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xf00000, 0xf7ffff); | |
| 157 | ||
| 158 | /* Install RAM */ | |
| 159 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x9fc000, 0x9fffff, "bank3"); | |
| 160 | ||
| 161 | /* Configure Banks */ | |
| 162 | memory_set_bankptr(machine, "bank2", machine.region("user2")->base()); | |
| 163 | memory_set_bankptr(machine, "bank3", ar_ram); | |
| 164 | ||
| 165 | amigacrt.ar1_spurious = 0; | |
| 166 | ||
| 167 | /* Install IRQ ACK callback */ | |
| 168 | device_set_irq_callback(machine.device("maincpu"), amiga_ar1_irqack); | |
| 169 | } | |
| 170 | ||
| 171 | /*************************************************************************** | |
| 172 | ||
| 173 | Amiga Action Replay MKII/MKIII | |
| 174 | ||
| 175 | Whenever you push the button, an overlay of the cartridge appears | |
| 176 | in RAM and an NMI interrupt is generated. Only reads are overlayed. | |
| 177 | Writes go directly to chipmem (so that the CPU can write the stack | |
| 178 | information for the NMI). Once the interrupt is taken, the cart | |
| 179 | disables the ROM overlay and checks it's internal mode register | |
| 180 | to see why it was invoked. | |
| 181 | ||
| 182 | When a breakpoint is set the cart replaces the target instruction | |
| 183 | with a trap, and adds a trap handler that it locates in the $100-$120 | |
| 184 | area. The handler simply has one instruction: TST.B $BFE001. This cia | |
| 185 | access is monitored, and the conditions match (PC < 120 and a previous | |
| 186 | command requested the monitoring of the cia) then the cart is invoked. | |
| 187 | ||
| 188 | ***************************************************************************/ | |
| 189 | ||
| 190 | static void amiga_ar23_freeze( running_machine &machine ); | |
| 191 | ||
| 192 | static READ16_HANDLER( amiga_ar23_cia_r ) | |
| 193 | { | |
| 194 | int pc = cpu_get_pc(&space->device()); | |
| 195 | ||
| 196 | if ( ACCESSING_BITS_0_7 && offset == 2048 && pc >= 0x40 && pc < 0x120 ) | |
| 197 | { | |
| 198 | amiga_ar23_freeze(space->machine()); | |
| 199 | } | |
| 200 | ||
| 201 | return amiga_cia_r( space, offset, mem_mask ); | |
| 202 | } | |
| 203 | ||
| 204 | static WRITE16_HANDLER( amiga_ar23_mode_w ) | |
| 205 | { | |
| 206 | if ( data & 2 ) | |
| 207 | { | |
| 208 | space->install_legacy_read_handler(0xbfd000, 0xbfefff, FUNC(amiga_ar23_cia_r)); | |
| 209 | } | |
| 210 | else | |
| 211 | { | |
| 212 | space->install_legacy_read_handler(0xbfd000, 0xbfefff, FUNC(amiga_cia_r)); | |
| 213 | } | |
| 214 | ||
| 215 | amigacrt.ar23_mode = (data&0x3); | |
| 216 | if ( amigacrt.ar23_mode == 0 ) | |
| 217 | amigacrt.ar23_mode = 1; | |
| 218 | ||
| 219 | } | |
| 220 | ||
| 221 | static READ16_HANDLER( amiga_ar23_mode_r ) | |
| 222 | { | |
| 223 | amiga_state *state = space->machine().driver_data<amiga_state>(); | |
| 224 | UINT16 *mem = (UINT16 *)space->machine().region( "user2" )->base(); | |
| 225 | ||
| 226 | if ( ACCESSING_BITS_0_7 ) | |
| 227 | { | |
| 228 | if ( offset < 2 ) | |
| 229 | return (mem[offset] | (amigacrt.ar23_mode&3)); | |
| 230 | ||
| 231 | if ( offset == 0x03 ) /* disable cart oberlay on chip mem */ | |
| 232 | { | |
| 233 | UINT32 mirror_mask = state->m_chip_ram_size; | |
| 234 | ||
| 235 | memory_set_bank(space->machine(), "bank1", 0); | |
| 236 | ||
| 237 | while( (mirror_mask<<1) < 0x100000 ) | |
| 238 | { | |
| 239 | mirror_mask |= ( mirror_mask << 1 ); | |
| 240 | } | |
| 241 | ||
| 242 | /* overlay disabled, map RAM on 0x000000 */ | |
| 243 | space->install_write_bank(0x000000, state->m_chip_ram_size - 1, 0, mirror_mask, "bank1"); | |
| 244 | } | |
| 245 | } | |
| 246 | ||
| 247 | return mem[offset]; | |
| 248 | } | |
| 249 | ||
| 250 | static WRITE16_HANDLER( amiga_ar23_chipmem_w ) | |
| 251 | { | |
| 252 | amiga_state *state = space->machine().driver_data<amiga_state>(); | |
| 253 | if ( offset == (0x08/2) ) | |
| 254 | { | |
| 255 | if ( amigacrt.ar23_mode & 1 ) | |
| 256 | amiga_ar23_freeze(space->machine()); | |
| 257 | } | |
| 258 | ||
| 259 | (*state->m_chip_ram_w)(state, offset * 2, data ); | |
| 260 | } | |
| 261 | ||
| 262 | static void amiga_ar23_freeze( running_machine &machine ) | |
| 263 | { | |
| 264 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 265 | int pc = cpu_get_pc(machine.device("maincpu")); | |
| 266 | ||
| 267 | /* only freeze if we're not inside the cart's ROM */ | |
| 268 | if ( ((pc >> 16) & 0xfe ) != 0x40 ) | |
| 269 | { | |
| 270 | /* get the cart's built-in ram */ | |
| 271 | UINT16 *ar_ram = (UINT16 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_write_ptr(0x440000); | |
| 272 | ||
| 273 | if ( ar_ram != NULL ) | |
| 274 | { | |
| 275 | int i; | |
| 276 | ||
| 277 | for( i = 0; i < 0x100; i++ ) | |
| 278 | ar_ram[0x7800+i] = CUSTOM_REG(i); | |
| 279 | } | |
| 280 | ||
| 281 | /* overlay the cart rom's in chipram */ | |
| 282 | memory_set_bank(machine, "bank1", 2); | |
| 283 | ||
| 284 | /* writes go to chipram */ | |
| 285 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, state->m_chip_ram_size - 1, FUNC(amiga_ar23_chipmem_w)); | |
| 286 | ||
| 287 | /* trigger NMI irq */ | |
| 288 | cputag_set_input_line(machine, "maincpu", 7, PULSE_LINE); | |
| 289 | } | |
| 290 | } | |
| 291 | ||
| 292 | static void amiga_ar23_nmi( running_machine &machine ) | |
| 293 | { | |
| 294 | amigacrt.ar23_mode = 0; | |
| 295 | amiga_ar23_freeze(machine); | |
| 296 | } | |
| 297 | ||
| 298 | #if 0 | |
| 299 | static WRITE16_HANDLER( amiga_ar23_custom_w ) | |
| 300 | { | |
| 301 | int pc = cpu_get_pc(&space->device()); | |
| 302 | ||
| 303 | /* see if we're inside the AR2 rom */ | |
| 304 | if ( ((pc >> 16) & 0xfe ) != 0x40 ) | |
| 305 | { | |
| 306 | /* get the cart's built-in ram */ | |
| 307 | UINT16 *ar_ram = (UINT16 *)memory_get_write_ptr(0, AS_PROGRAM, 0x440000); | |
| 308 | ||
| 309 | if ( ar_ram != NULL ) | |
| 310 | { | |
| 311 | ar_ram[0x7800+offset] = data; | |
| 312 | } | |
| 313 | } | |
| 314 | ||
| 315 | amiga_custom_w( offset, data, mem_mask ); | |
| 316 | } | |
| 317 | ||
| 318 | static READ16_HANDLER( amiga_ar23_custom_r ) | |
| 319 | { | |
| 320 | UINT16 data = amiga_custom_r( offset, mem_mask ); | |
| 321 | ||
| 322 | int pc = cpu_get_pc(&space->device()); | |
| 323 | ||
| 324 | /* see if we're inside the AR2 rom */ | |
| 325 | if ( ((pc >> 16) & 0xfe ) != 0x40 ) | |
| 326 | { | |
| 327 | /* get the cart's built-in ram */ | |
| 328 | UINT16 *ar_ram = (UINT16 *)memory_get_write_ptr(0, AS_PROGRAM, 0x440000); | |
| 329 | ||
| 330 | if ( ar_ram != NULL ) | |
| 331 | { | |
| 332 | ar_ram[0x7800+offset] = data; | |
| 333 | } | |
| 334 | } | |
| 335 | ||
| 336 | return data; | |
| 337 | } | |
| 338 | #endif | |
| 339 | ||
| 340 | static void amiga_ar23_check_overlay( running_machine &machine ) | |
| 341 | { | |
| 342 | amigacrt.ar23_mode = 3; | |
| 343 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, 0x00000f, FUNC(amiga_ar23_chipmem_w)); | |
| 344 | } | |
| 345 | ||
| 346 | static void amiga_ar23_init( running_machine &machine, int ar3 ) | |
| 347 | { | |
| 348 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 349 | UINT32 mirror = 0x20000, size = 0x1ffff; | |
| 350 | void *ar_ram; | |
| 351 | ||
| 352 | /* check kickstart version */ | |
| 353 | if ( !check_kickstart_12_13( machine, "Action Replay MKII or MKIII" ) ) | |
| 354 | { | |
| 355 | amigacrt.cart_type = -1; | |
| 356 | return; | |
| 357 | } | |
| 358 | ||
| 359 | /* setup the cart ram */ | |
| 360 | ar_ram = auto_alloc_array_clear(machine, UINT8,0x10000); | |
| 361 | ||
| 362 | if ( ar3 ) | |
| 363 | { | |
| 364 | mirror = 0; | |
| 365 | size = 0x3ffff; | |
| 366 | } | |
| 367 | ||
| 368 | /* Install ROM */ | |
| 369 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x400000, 0x400000+size, 0, mirror, "bank2"); | |
| 370 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x400000, 0x400000+size, 0, mirror); | |
| 371 | ||
| 372 | /* Install RAM */ | |
| 373 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x440000, 0x44ffff, "bank3"); | |
| 374 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x440000, 0x44ffff, "bank3"); | |
| 375 | ||
| 376 | /* Install Custom chip monitor */ | |
| 377 | // machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xdff000, 0xdff1ff, FUNC(amiga_ar23_custom_r)); | |
| 378 | // machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xdff000, 0xdff1ff, FUNC(amiga_ar23_custom_w)); | |
| 379 | ||
| 380 | /* Install status/mode handlers */ | |
| 381 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400007, 0, mirror, FUNC(amiga_ar23_mode_r)); | |
| 382 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400000, 0x400003, 0, mirror, FUNC(amiga_ar23_mode_w)); | |
| 383 | ||
| 384 | /* Configure Banks */ | |
| 385 | memory_set_bankptr(machine, "bank2", machine.region("user2")->base()); | |
| 386 | memory_set_bankptr(machine, "bank3", ar_ram); | |
| 387 | ||
| 388 | memory_configure_bank(machine, "bank1", 0, 2, state->m_chip_ram, 0); | |
| 389 | memory_configure_bank(machine, "bank1", 1, 2, machine.region("user1")->base(), 0); | |
| 390 | memory_configure_bank(machine, "bank1", 2, 2, machine.region("user2")->base(), 0); | |
| 391 | ||
| 392 | amigacrt.ar23_mode = 3; | |
| 393 | } | |
| 394 | ||
| 395 | /*************************************************************************** | |
| 396 | ||
| 397 | MAME/MESS hooks | |
| 398 | ||
| 399 | ***************************************************************************/ | |
| 400 | ||
| 401 | void amiga_cart_init( running_machine &machine ) | |
| 402 | { | |
| 403 | /* see what is there */ | |
| 404 | UINT16 *mem = (UINT16 *)machine.region( "user2" )->base(); | |
| 405 | ||
| 406 | amigacrt.cart_type = -1; | |
| 407 | ||
| 408 | if ( mem != NULL ) | |
| 409 | { | |
| 410 | if ( mem[0x00] == 0x1111 ) | |
| 411 | { | |
| 412 | amigacrt.cart_type = ACTION_REPLAY; | |
| 413 | amiga_ar1_init(machine); | |
| 414 | } | |
| 415 | else if ( mem[0x0C] == 0x4D6B ) | |
| 416 | { | |
| 417 | amigacrt.cart_type = ACTION_REPLAY_MKII; | |
| 418 | amiga_ar23_init(machine, 0); | |
| 419 | } | |
| 420 | else if ( mem[0x0C] == 0x4D4B ) | |
| 421 | { | |
| 422 | amigacrt.cart_type = ACTION_REPLAY_MKIII; | |
| 423 | amiga_ar23_init(machine, 1); | |
| 424 | } | |
| 425 | } | |
| 426 | } | |
| 427 | ||
| 428 | void amiga_cart_check_overlay( running_machine &machine ) | |
| 429 | { | |
| 430 | if ( amigacrt.cart_type < 0 ) | |
| 431 | return; | |
| 432 | ||
| 433 | switch( amigacrt.cart_type ) | |
| 434 | { | |
| 435 | case ACTION_REPLAY: | |
| 436 | amiga_ar1_check_overlay(machine); | |
| 437 | break; | |
| 438 | ||
| 439 | case ACTION_REPLAY_MKII: | |
| 440 | case ACTION_REPLAY_MKIII: | |
| 441 | amiga_ar23_check_overlay(machine); | |
| 442 | break; | |
| 443 | } | |
| 444 | } | |
| 445 | ||
| 446 | void amiga_cart_nmi( running_machine &machine ) | |
| 447 | { | |
| 448 | if ( amigacrt.cart_type < 0 ) | |
| 449 | return; | |
| 450 | ||
| 451 | switch( amigacrt.cart_type ) | |
| 452 | { | |
| 453 | case ACTION_REPLAY: | |
| 454 | amiga_ar1_nmi(machine); | |
| 455 | break; | |
| 456 | ||
| 457 | case ACTION_REPLAY_MKII: | |
| 458 | case ACTION_REPLAY_MKIII: | |
| 459 | amiga_ar23_nmi(machine); | |
| 460 | break; | |
| 461 | } | |
| 462 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | #ifndef AMIGACRT_H | |
| 2 | #define AMIGACRT_H | |
| 3 | ||
| 4 | void amiga_cart_init( running_machine &machine ); | |
| 5 | void amiga_cart_check_overlay( running_machine &machine ); | |
| 6 | void amiga_cart_nmi( running_machine &machine ); | |
| 7 | ||
| 8 | #endif /* AMIGACRT_H */ |
| r0 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES Cart PCBs Emulation | |
| 4 | ||
| 5 | ****************************************************************************************/ | |
| 6 | ||
| 7 | typedef struct _nes_pcb nes_pcb; | |
| 8 | struct _nes_pcb | |
| 9 | { | |
| 10 | const char *pcb_name; | |
| 11 | int pcb_id; | |
| 12 | }; | |
| 13 | ||
| 14 | // Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it | |
| 15 | static const nes_pcb pcb_list[] = | |
| 16 | { | |
| 17 | /* Nintendo HROM, NROM, RROM, SROM & STROM */ | |
| 18 | { "HVC-HROM", STD_NROM }, | |
| 19 | { "HVC-NROM", STD_NROM }, | |
| 20 | { "HVC-NROM-128", STD_NROM }, | |
| 21 | { "HVC-NROM-256", STD_NROM }, | |
| 22 | { "HVC-RROM", STD_NROM }, | |
| 23 | { "HVC-RROM-128", STD_NROM }, | |
| 24 | { "HVC-RTROM", STD_NROM }, | |
| 25 | { "HVC-SROM", STD_NROM }, | |
| 26 | { "HVC-STROM", STD_NROM }, | |
| 27 | { "NES-HROM", STD_NROM }, | |
| 28 | { "NES-NROM", STD_NROM }, | |
| 29 | { "NES-NROM-128", STD_NROM }, | |
| 30 | { "NES-NROM-256", STD_NROM }, | |
| 31 | { "NES-RROM", STD_NROM }, | |
| 32 | { "NES-RROM-128", STD_NROM }, | |
| 33 | { "NES-SROM", STD_NROM }, | |
| 34 | { "NES-STROM", STD_NROM }, | |
| 35 | /* "No mapper" boards by other manufacturer */ | |
| 36 | { "IREM-NROM-128", STD_NROM }, | |
| 37 | { "IREM-NROM-256", STD_NROM }, | |
| 38 | { "BANDAI-NROM-128", STD_NROM }, | |
| 39 | { "BANDAI-NROM-256", STD_NROM }, | |
| 40 | { "KONAMI-NROM-128", STD_NROM }, | |
| 41 | { "SETA-NROM-128", STD_NROM }, | |
| 42 | { "SUNSOFT-NROM-128", STD_NROM }, | |
| 43 | { "SUNSOFT-NROM-256", STD_NROM }, | |
| 44 | { "TAITO-NROM-128", STD_NROM }, | |
| 45 | { "TAITO-NROM-256", STD_NROM }, | |
| 46 | { "NAMCOT-3301", STD_NROM }, | |
| 47 | { "NAMCOT-3302", STD_NROM }, | |
| 48 | { "NAMCOT-3303", STD_NROM }, | |
| 49 | { "NAMCOT-3304", STD_NROM }, | |
| 50 | { "NAMCOT-3305", STD_NROM }, | |
| 51 | { "NAMCOT-3311", STD_NROM }, | |
| 52 | { "NAMCOT-3312", STD_NROM }, | |
| 53 | { "NAMCOT-3411", STD_NROM }, | |
| 54 | { "JALECO-JF-01", STD_NROM }, | |
| 55 | { "JALECO-JF-02", STD_NROM }, | |
| 56 | { "JALECO-JF-03", STD_NROM }, | |
| 57 | { "JALECO-JF-04", STD_NROM }, | |
| 58 | { "TENGEN-800003", STD_NROM }, | |
| 59 | { "SACHEN-NROM", STD_NROM }, | |
| 60 | /* Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) */ | |
| 61 | { "HVC-FAMILYBASIC", HVC_FAMBASIC }, | |
| 62 | /* Game Genie */ | |
| 63 | { "CAMERICA-GAMEGENIE", GG_NROM }, | |
| 64 | // | |
| 65 | /* Nintendo UNROM/UOROM */ | |
| 66 | { "HVC-UNROM", STD_UXROM }, | |
| 67 | { "HVC-UNEPROM", STD_UXROM }, | |
| 68 | { "HVC-UOROM", STD_UXROM }, | |
| 69 | { "NES-UNROM", STD_UXROM }, | |
| 70 | { "NES-UNEPROM", STD_UXROM }, | |
| 71 | { "NES-UOROM", STD_UXROM }, | |
| 72 | { "HVC-UNROM+74HC08", UXROM_CC }, | |
| 73 | /* UxROM boards by other manufacturer */ | |
| 74 | { "IREM-UNROM", STD_UXROM }, | |
| 75 | { "KONAMI-UNROM", STD_UXROM }, | |
| 76 | { "TAITO-UNROM", STD_UXROM }, | |
| 77 | { "JALECO-JF-15", STD_UXROM }, | |
| 78 | { "JALECO-JF-18", STD_UXROM }, | |
| 79 | { "JALECO-JF-39", STD_UXROM }, | |
| 80 | // | |
| 81 | /* Nintendo CNROM */ | |
| 82 | { "HVC-CNROM", STD_CNROM }, | |
| 83 | { "NES-CNROM", STD_CNROM }, | |
| 84 | /* CxROM boards by other manufacturer */ | |
| 85 | { "BANDAI-CNROM", STD_CNROM }, | |
| 86 | { "BANDAI-74*161/32", STD_CNROM }, | |
| 87 | { "KONAMI-CNROM", STD_CNROM }, | |
| 88 | { "NAMCOT-CNROM+WRAM", STD_CNROM }, | |
| 89 | { "TAITO-CNROM", STD_CNROM }, | |
| 90 | { "AVE-74*161", STD_CNROM }, | |
| 91 | { "NTDEC-N715061", STD_CNROM }, | |
| 92 | { "NTDEC-N715062", STD_CNROM }, | |
| 93 | { "SACHEN-CNROM", STD_CNROM }, | |
| 94 | /* Bandai Aerobics Studio (CNROM boards + special audio chip) */ | |
| 95 | { "BANDAI-PT-554", BANDAI_PT554 }, | |
| 96 | /* FIXME: Is this the same as mapper 3? */ | |
| 97 | { "TENGEN-800008", TENGEN_800008 }, | |
| 98 | // | |
| 99 | /* Nintendo AxROM */ | |
| 100 | { "HVC-AMROM", STD_AXROM }, | |
| 101 | { "HVC-AN1ROM", STD_AXROM }, | |
| 102 | { "HVC-ANROM", STD_AXROM }, | |
| 103 | { "HVC-AOROM", STD_AXROM }, | |
| 104 | { "NES-AMROM", STD_AXROM }, | |
| 105 | { "NES-AN1ROM", STD_AXROM }, | |
| 106 | { "NES-ANROM", STD_AXROM }, | |
| 107 | { "NES-AOROM", STD_AXROM }, | |
| 108 | /* AxROM boards by other manufacturer */ | |
| 109 | { "ACCLAIM-AOROM", STD_AXROM }, | |
| 110 | // | |
| 111 | /* Nintendo PxROM */ | |
| 112 | { "HVC-PEEOROM", STD_PXROM }, | |
| 113 | { "HVC-PNROM", STD_PXROM }, | |
| 114 | { "NES-PEEOROM", STD_PXROM }, | |
| 115 | { "NES-PNROM", STD_PXROM }, | |
| 116 | // | |
| 117 | /* Nintendo FxROM */ | |
| 118 | { "HVC-FJROM", STD_FXROM }, | |
| 119 | { "HVC-FKROM", STD_FXROM }, | |
| 120 | { "NES-FJROM", STD_FXROM }, | |
| 121 | { "NES-FKROM", STD_FXROM }, | |
| 122 | // | |
| 123 | /* Nintendo BXROM */ | |
| 124 | { "HVC-BNROM", STD_BXROM }, | |
| 125 | { "NES-BNROM", STD_BXROM }, | |
| 126 | /* BxROM boards by other manufacturer */ | |
| 127 | { "IREM-BNROM", STD_BXROM }, | |
| 128 | // | |
| 129 | /* Nintendo CPROM */ | |
| 130 | { "HVC-CPROM", STD_CPROM }, | |
| 131 | { "NES-CPROM", STD_CPROM }, | |
| 132 | // | |
| 133 | /* Nintendo GNROM & MHROM */ | |
| 134 | { "HVC-GNROM", STD_GXROM }, | |
| 135 | { "NES-GNROM", STD_GXROM }, | |
| 136 | { "HVC-MHROM", STD_MXROM }, | |
| 137 | { "NES-MHROM", STD_MXROM }, | |
| 138 | { "PAL-MH", STD_MXROM }, | |
| 139 | /* GxROM boards by other manufacturer */ | |
| 140 | { "BANDAI-GNROM", STD_GXROM }, | |
| 141 | // | |
| 142 | /* Nintendo NxROM */ | |
| 143 | { "HVC-NTBROM", STD_NXROM }, | |
| 144 | { "NES-NTBROM", STD_NXROM }, | |
| 145 | /* NxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */ | |
| 146 | { "SUNSOFT-4", STD_NXROM }, | |
| 147 | { "SUNSOFT-DCS", SUNSOFT_DCS }, | |
| 148 | { "TENGEN-800042", STD_NXROM }, | |
| 149 | // | |
| 150 | /* Nintendo JxROM */ | |
| 151 | { "HVC-JLROM", STD_JXROM }, | |
| 152 | { "HVC-JSROM", STD_JXROM }, | |
| 153 | { "NES-JLROM", STD_JXROM }, | |
| 154 | { "NES-JSROM", STD_JXROM }, | |
| 155 | { "NES-BTR", STD_JXROM }, | |
| 156 | /* JxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */ | |
| 157 | { "SUNSOFT-5A", STD_JXROM }, | |
| 158 | { "SUNSOFT-5B", STD_JXROM }, | |
| 159 | { "SUNSOFT-FME-7", STD_JXROM }, | |
| 160 | // | |
| 161 | /* Nintendo UN1ROM */ | |
| 162 | { "HVC-UN1ROM", STD_UN1ROM }, | |
| 163 | { "NES-UN1ROM", STD_UN1ROM }, | |
| 164 | // | |
| 165 | /* Nintendo SxROM */ | |
| 166 | { "HVC-SAROM", STD_SXROM }, | |
| 167 | { "HVC-SBROM", STD_SXROM }, | |
| 168 | { "HVC-SC1ROM", STD_SXROM }, | |
| 169 | { "HVC-SCROM", STD_SXROM }, | |
| 170 | { "HVC-SEROM", STD_SXROM }, | |
| 171 | { "HVC-SF1ROM", STD_SXROM }, | |
| 172 | { "HVC-SFROM", STD_SXROM }, | |
| 173 | { "HVC-SGROM", STD_SXROM }, | |
| 174 | { "HVC-SH1ROM", STD_SXROM }, | |
| 175 | { "HVC-SHROM", STD_SXROM }, | |
| 176 | { "HVC-SIROM", STD_SXROM }, | |
| 177 | { "HVC-SJROM", STD_SXROM }, | |
| 178 | { "HVC-SKROM", STD_SXROM }, | |
| 179 | { "HVC-SKEPROM", STD_SXROM }, | |
| 180 | { "HVC-SL1ROM", STD_SXROM }, | |
| 181 | { "HVC-SL2ROM", STD_SXROM }, | |
| 182 | { "HVC-SL3ROM", STD_SXROM }, | |
| 183 | { "HVC-SLROM", STD_SXROM }, | |
| 184 | { "HVC-SLRROM", STD_SXROM }, | |
| 185 | { "HVC-SMROM", STD_SXROM }, | |
| 186 | { "HVC-SNROM", STD_SXROM }, | |
| 187 | { "HVC-SUROM", STD_SXROM }, | |
| 188 | { "HVC-SXROM", STD_SXROM }, | |
| 189 | { "NES-SAROM", STD_SXROM }, | |
| 190 | { "NES-SBROM", STD_SXROM }, | |
| 191 | { "NES-SC1ROM", STD_SXROM }, | |
| 192 | { "NES-SCROM", STD_SXROM }, | |
| 193 | { "NES-SEROM", STD_SXROM }, | |
| 194 | { "NES-SF1ROM", STD_SXROM }, | |
| 195 | { "NES-SFROM", STD_SXROM }, | |
| 196 | { "NES-SGROM", STD_SXROM }, | |
| 197 | { "NES-SH1ROM", STD_SXROM }, | |
| 198 | { "NES-SHROM", STD_SXROM }, | |
| 199 | { "NES-SIROM", STD_SXROM }, | |
| 200 | { "NES-SJROM", STD_SXROM }, | |
| 201 | { "NES-SKROM", STD_SXROM }, | |
| 202 | { "NES-SKEPROM", STD_SXROM }, | |
| 203 | { "NES-SL1ROM", STD_SXROM }, | |
| 204 | { "NES-SL2ROM", STD_SXROM }, | |
| 205 | { "NES-SL3ROM", STD_SXROM }, | |
| 206 | { "NES-SLROM", STD_SXROM }, | |
| 207 | { "NES-SLRROM", STD_SXROM }, | |
| 208 | { "NES-SMROM", STD_SXROM }, | |
| 209 | { "NES-SNROM", STD_SXROM }, | |
| 210 | { "NES-SUROM", STD_SXROM }, | |
| 211 | { "NES-SXROM", STD_SXROM }, | |
| 212 | { "NES-WH", STD_SXROM }, | |
| 213 | { "NES-SOROM", STD_SOROM }, | |
| 214 | { "HVC-SOROM", STD_SOROM }, | |
| 215 | /* SxROM boards by other manufacturer */ | |
| 216 | { "KONAMI-SLROM", STD_SXROM }, | |
| 217 | { "VIRGIN-SNROM", STD_SXROM }, | |
| 218 | // | |
| 219 | /* Nintendo TxROM */ | |
| 220 | { "HVC-TBROM", STD_TXROM }, | |
| 221 | { "HVC-TEROM", STD_TXROM }, | |
| 222 | { "HVC-TFROM", STD_TXROM }, | |
| 223 | { "HVC-TGROM", STD_TXROM }, | |
| 224 | { "HVC-TKROM", STD_TXROM }, | |
| 225 | { "HVC-TL1ROM", STD_TXROM }, | |
| 226 | { "HVC-TL2ROM", STD_TXROM }, | |
| 227 | { "HVC-TLROM", STD_TXROM }, | |
| 228 | { "HVC-TNROM", STD_TXROM }, | |
| 229 | { "HVC-TR1ROM", STD_TVROM }, | |
| 230 | { "HVC-TSROM", STD_TXROM }, | |
| 231 | { "HVC-TVROM", STD_TVROM }, | |
| 232 | { "NES-B4", STD_TXROM }, | |
| 233 | { "NES-TBROM", STD_TXROM }, | |
| 234 | { "NES-TEROM", STD_TXROM }, | |
| 235 | { "NES-TFROM", STD_TXROM }, | |
| 236 | { "NES-TGROM", STD_TXROM }, | |
| 237 | { "NES-TKROM", STD_TXROM }, | |
| 238 | { "NES-TL1ROM", STD_TXROM }, | |
| 239 | { "NES-TL2ROM", STD_TXROM }, | |
| 240 | { "NES-TLROM", STD_TXROM }, | |
| 241 | { "NES-TNROM", STD_TXROM }, | |
| 242 | { "NES-TR1ROM", STD_TVROM }, | |
| 243 | { "NES-TSROM", STD_TXROM }, | |
| 244 | { "NES-TVROM", STD_TVROM }, | |
| 245 | /* TxROM boards by other manufacturer */ | |
| 246 | { "ACCLAIM-MC-ACC", STD_TXROM }, | |
| 247 | { "ACCLAIM-TLROM", STD_TXROM }, | |
| 248 | { "KONAMI-TLROM", STD_TXROM }, | |
| 249 | // | |
| 250 | /* Nintendo DxROM */ | |
| 251 | { "HVC-DE1ROM", STD_DXROM }, | |
| 252 | { "HVC-DEROM", STD_DXROM }, | |
| 253 | { "HVC-DRROM", STD_DRROM }, | |
| 254 | { "NES-DE1ROM", STD_DXROM }, | |
| 255 | { "NES-DEROM", STD_DXROM }, | |
| 256 | { "NES-DRROM", STD_DRROM }, | |
| 257 | /* DxROM boards by other manufacturer */ | |
| 258 | { "NAMCOT-3401", STD_DXROM }, | |
| 259 | { "NAMCOT-3405", STD_DXROM }, | |
| 260 | { "NAMCOT-3406", STD_DXROM }, | |
| 261 | { "NAMCOT-3407", STD_DXROM }, | |
| 262 | { "NAMCOT-3413", STD_DXROM }, | |
| 263 | { "NAMCOT-3414", STD_DXROM }, | |
| 264 | { "NAMCOT-3415", STD_DXROM }, | |
| 265 | { "NAMCOT-3416", STD_DXROM }, | |
| 266 | { "NAMCOT-3417", STD_DXROM }, | |
| 267 | { "NAMCOT-3451", STD_DXROM }, | |
| 268 | { "TENGEN-800002", STD_DXROM }, | |
| 269 | { "TENGEN-800004", STD_DRROM }, | |
| 270 | { "TENGEN-800030", STD_DXROM }, | |
| 271 | // | |
| 272 | /* Nintendo HKROM */ | |
| 273 | { "HVC-HKROM", STD_HKROM }, | |
| 274 | { "NES-HKROM", STD_HKROM }, | |
| 275 | // | |
| 276 | /* Nintendo BNROM */ | |
| 277 | { "HVC-TQROM", STD_TQROM }, | |
| 278 | { "NES-TQROM", STD_TQROM }, | |
| 279 | // | |
| 280 | /* Nintendo TxSROM */ | |
| 281 | { "HVC-TKSROM", STD_TXSROM }, | |
| 282 | { "HVC-TLSROM", STD_TXSROM }, | |
| 283 | { "NES-TKSROM", STD_TXSROM }, | |
| 284 | { "NES-TLSROM", STD_TXSROM }, | |
| 285 | // | |
| 286 | /* Nintendo ExROM */ | |
| 287 | { "HVC-EKROM", STD_EXROM }, | |
| 288 | { "HVC-ELROM", STD_EXROM }, | |
| 289 | { "HVC-ETROM", STD_EXROM }, | |
| 290 | { "HVC-EWROM", STD_EXROM }, | |
| 291 | { "NES-EKROM", STD_EXROM }, | |
| 292 | { "NES-ELROM", STD_EXROM }, | |
| 293 | { "NES-ETROM", STD_EXROM }, | |
| 294 | { "NES-EWROM", STD_EXROM }, | |
| 295 | // | |
| 296 | /* Nintendo Custom boards */ | |
| 297 | { "PAL-ZZ", PAL_ZZ }, | |
| 298 | { "NES-QJ", NES_QJ }, | |
| 299 | { "NES-EVENT", UNSUPPORTED_BOARD }, | |
| 300 | // | |
| 301 | /* Discrete board IC_74x139x74 */ | |
| 302 | { "JALECO-JF-05", DIS_74X139X74 }, | |
| 303 | { "JALECO-JF-06", DIS_74X139X74 }, | |
| 304 | { "JALECO-JF-07", DIS_74X139X74 }, | |
| 305 | { "JALECO-JF-08", DIS_74X139X74 }, | |
| 306 | { "JALECO-JF-09", DIS_74X139X74 }, | |
| 307 | { "JALECO-JF-10", DIS_74X139X74 }, | |
| 308 | { "KONAMI-74*139/74", DIS_74X139X74 }, | |
| 309 | { "TAITO-74*139/74", DIS_74X139X74 }, | |
| 310 | /* Discrete board IC_74x377 */ | |
| 311 | { "AGCI-47516", DIS_74X377 }, | |
| 312 | { "AVE-NINA-07", DIS_74X377 }, | |
| 313 | { "COLORDREAMS-74*377", DIS_74X377 }, | |
| 314 | /* Discrete board IC_74x161x161x32 */ | |
| 315 | { "BANDAI-74*161/161/32", DIS_74X161X161X32 }, | |
| 316 | { "TAITO-74*161/161/32", DIS_74X161X161X32 }, | |
| 317 | /* Discrete board IC_74x161x138 */ | |
| 318 | { "BIT-CORP-74*161/138", DIS_74X161X138 }, | |
| 319 | // | |
| 320 | { "BANDAI-LZ93D50", BANDAI_LZ93 }, | |
| 321 | { "BANDAI-LZ93D50+24C01", BANDAI_LZ93EX }, | |
| 322 | { "BANDAI-LZ93D50+24C02", BANDAI_LZ93EX }, | |
| 323 | { "BANDAI-FCG-1", BANDAI_FCG }, | |
| 324 | { "BANDAI-FCG-2", BANDAI_FCG }, | |
| 325 | { "BANDAI-JUMP2", BANDAI_JUMP2 }, | |
| 326 | { "BANDAI-DATACH", BANDAI_DATACH }, | |
| 327 | { "BANDAI-KARAOKE", BANDAI_KARAOKE }, | |
| 328 | { "BANDAI-OEKAKIDS", BANDAI_OEKAKIDS }, | |
| 329 | { "IREM-FCG-1", BANDAI_FCG }, | |
| 330 | // | |
| 331 | { "IREM-G101", IREM_G101 }, | |
| 332 | { "IREM-74*161/161/21/138", IREM_LROG017 }, | |
| 333 | { "IREM-H-3001", IREM_H3001 }, | |
| 334 | { "IREM-H3001", IREM_H3001 }, | |
| 335 | { "IREM-HOLYDIVER", IREM_HOLYDIV }, | |
| 336 | { "IREM-TAM-S1", IREM_TAM_S1 }, | |
| 337 | // | |
| 338 | { "JALECO-JF-23", JALECO_SS88006 }, | |
| 339 | { "JALECO-JF-24", JALECO_SS88006 }, | |
| 340 | { "JALECO-JF-25", JALECO_SS88006 }, | |
| 341 | { "JALECO-JF-27", JALECO_SS88006 }, | |
| 342 | { "JALECO-JF-29", JALECO_SS88006 }, | |
| 343 | { "JALECO-JF-30", JALECO_SS88006 }, | |
| 344 | { "JALECO-JF-31", JALECO_SS88006 }, | |
| 345 | { "JALECO-JF-32", JALECO_SS88006 }, | |
| 346 | { "JALECO-JF-33", JALECO_SS88006 }, | |
| 347 | { "JALECO-JF-34", JALECO_SS88006 }, | |
| 348 | { "JALECO-JF-35", JALECO_SS88006 }, | |
| 349 | { "JALECO-JF-36", JALECO_SS88006 }, | |
| 350 | { "JALECO-JF-37", JALECO_SS88006 }, | |
| 351 | { "JALECO-JF-38", JALECO_SS88006 }, | |
| 352 | { "JALECO-JF-40", JALECO_SS88006 }, | |
| 353 | { "JALECO-JF-41", JALECO_SS88006 }, | |
| 354 | { "JALECO-JF-11", JALECO_JF11 }, | |
| 355 | { "JALECO-JF-12", JALECO_JF11 }, | |
| 356 | { "JALECO-JF-14", JALECO_JF11 }, | |
| 357 | { "JALECO-JF-13", JALECO_JF13 }, | |
| 358 | { "JALECO-JF-16", JALECO_JF16 }, | |
| 359 | { "JALECO-JF-17", JALECO_JF17 }, | |
| 360 | { "JALECO-JF-26", JALECO_JF17 }, | |
| 361 | { "JALECO-JF-28", JALECO_JF17 }, | |
| 362 | { "JALECO-JF-19", JALECO_JF19 }, | |
| 363 | { "JALECO-JF-21", JALECO_JF19 }, | |
| 364 | // | |
| 365 | { "KONAMI-VRC-1", KONAMI_VRC1 }, | |
| 366 | { "JALECO-JF-20", KONAMI_VRC1 }, | |
| 367 | { "JALECO-JF-22", KONAMI_VRC1 }, | |
| 368 | { "KONAMI-VRC-2", KONAMI_VRC2 }, | |
| 369 | { "KONAMI-VRC-3", KONAMI_VRC3 }, | |
| 370 | { "KONAMI-VRC-4", KONAMI_VRC4 }, | |
| 371 | { "KONAMI-VRC-6", KONAMI_VRC6 }, | |
| 372 | { "KONAMI-VRC-7", KONAMI_VRC7 }, | |
| 373 | { "UNL-VRC7", KONAMI_VRC7 }, | |
| 374 | // | |
| 375 | { "NAMCOT-163", NAMCOT_163 }, | |
| 376 | { "NAMCOT-175", NAMCOT_163 }, | |
| 377 | { "NAMCOT-340", NAMCOT_163 }, | |
| 378 | { "NAMCOT-3425", NAMCOT_3425 }, | |
| 379 | { "NAMCOT-3433", NAMCOT_34X3 }, | |
| 380 | { "NAMCOT-3443", NAMCOT_34X3 }, | |
| 381 | { "NAMCOT-3446", NAMCOT_3446 }, | |
| 382 | { "NAMCOT-3453", NAMCOT_3453 }, | |
| 383 | // | |
| 384 | { "SUNSOFT-1", SUNSOFT_1 }, | |
| 385 | { "SUNSOFT-2", SUNSOFT_2 }, | |
| 386 | { "SUNSOFT-3", SUNSOFT_3 }, | |
| 387 | // | |
| 388 | { "TAITO-TC0190FMC", TAITO_TC0190FMC }, | |
| 389 | { "TAITO-TC0190FMC+PAL16R4", TAITO_TC0190FMCP }, | |
| 390 | { "TAITO-TC0350FMR", TAITO_TC0190FMC }, | |
| 391 | { "TAITO-X1-005", TAITO_X1_005 }, // two variants exist, depending on pin17 & pin31 connections | |
| 392 | { "TAITO-X1-017", TAITO_X1_017 }, | |
| 393 | // | |
| 394 | { "AGCI-50282", AGCI_50282 }, | |
| 395 | { "AVE-NINA-01", AVE_NINA01 }, | |
| 396 | { "AVE-NINA-02", AVE_NINA01 }, | |
| 397 | { "AVE-NINA-03", AVE_NINA06 }, | |
| 398 | { "AVE-NINA-06", AVE_NINA06 }, | |
| 399 | { "AVE-MB-91", AVE_NINA06 }, | |
| 400 | { "TXC-74*138/175", AVE_NINA06 }, | |
| 401 | { "UNL-SA-016-1M", AVE_NINA06 }, | |
| 402 | { "CAMERICA-ALGN", CAMERICA_BF9093 }, | |
| 403 | { "CAMERICA-BF9093", CAMERICA_BF9093 }, | |
| 404 | { "CAMERICA-BF9097", CAMERICA_BF9097 }, | |
| 405 | { "CAMERICA-ALGQ", CAMERICA_BF9096 }, | |
| 406 | { "CAMERICA-BF9096", CAMERICA_BF9096 }, | |
| 407 | { "CAMERICA-GOLDENFIVE", CAMERICA_GOLDENFIVE }, | |
| 408 | { "CNE-DECATHLON", CNE_DECATHLON }, | |
| 409 | { "CNE-PSB", CNE_FSB }, | |
| 410 | { "CNE-SHLZ", CNE_SHLZ }, | |
| 411 | { "JYCOMPANY-A", UNSUPPORTED_BOARD }, // mapper 90 | |
| 412 | { "JYCOMPANY-B", UNSUPPORTED_BOARD }, // mapper 209 | |
| 413 | { "JYCOMPANY-C", UNSUPPORTED_BOARD }, // mapper 211 | |
| 414 | { "NTDEC-112", NTDEC_ASDER }, // mapper 112 (better rename this board tag, to avoid confusion with TC-112!! | |
| 415 | { "NTDEC-TC-112", NTDEC_FIGHTINGHERO }, | |
| 416 | { "NTDEC-193", NTDEC_FIGHTINGHERO }, // mapper 193 | |
| 417 | { "UNL-TEK90", UNSUPPORTED_BOARD }, // related to JY Company? (i.e. mappers 90, 209, 211?) | |
| 418 | { "UNL-SA-002", SACHEN_TCU02 }, | |
| 419 | { "UNL-SA-009", SACHEN_SA009 }, | |
| 420 | { "UNL-SA-0036", SACHEN_SA0036 }, | |
| 421 | { "UNL-SA-0037", SACHEN_SA0037 }, | |
| 422 | { "UNL-SA-72007", SACHEN_SA72007 }, | |
| 423 | { "UNL-SA-72008", SACHEN_SA72008 }, | |
| 424 | { "UNL-SA-NROM", SACHEN_TCA01 }, | |
| 425 | { "UNL-SACHEN-TCA01", SACHEN_TCA01 }, | |
| 426 | { "SACHEN-8259A", SACHEN_8259A }, | |
| 427 | { "UNL-SACHEN-8259A", SACHEN_8259A }, | |
| 428 | { "SACHEN-8259B", SACHEN_8259B }, | |
| 429 | { "UNL-SACHEN-8259B", SACHEN_8259B }, | |
| 430 | { "SACHEN-8259C", SACHEN_8259C }, | |
| 431 | { "UNL-SACHEN-8259C", SACHEN_8259C }, | |
| 432 | { "SACHEN-8259D", SACHEN_8259D }, | |
| 433 | { "UNL-SACHEN-8259D", SACHEN_8259D }, | |
| 434 | { "UNL-SACHEN-74LS374N", SACHEN_74LS374 }, | |
| 435 | { "UNL-SACHEN-74LS374N-A", SACHEN_74LS374_A }, /* FIXME: Made up boards the different mirroring handling */ | |
| 436 | { "UNL-TC-U01-1.5M", SACHEN_TCU01 }, | |
| 437 | { "TENGEN-800032", TENGEN_800032 }, | |
| 438 | { "TENGEN-800037", TENGEN_800037 }, | |
| 439 | { "WAIXING-A", WAIXING_TYPE_A }, | |
| 440 | { "WAIXING-A-1", WAIXING_TYPE_A_1 }, /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi) */ | |
| 441 | { "WAIXING-B", WAIXING_TYPE_B }, | |
| 442 | { "WAIXING-C", WAIXING_TYPE_C }, | |
| 443 | { "WAIXING-D", WAIXING_TYPE_D }, | |
| 444 | { "WAIXING-E", WAIXING_TYPE_E }, | |
| 445 | { "WAIXING-F", WAIXING_TYPE_F }, | |
| 446 | { "WAIXING-G", WAIXING_TYPE_G }, | |
| 447 | { "WAIXING-H", WAIXING_TYPE_H }, | |
| 448 | { "WAIXING-I", WAIXING_TYPE_I }, | |
| 449 | { "WAIXING-J", WAIXING_TYPE_J }, | |
| 450 | { "WAIXING-SGZLZ", WAIXING_SGZLZ }, | |
| 451 | { "WAIXING-SEC", WAIXING_SECURITY }, | |
| 452 | { "WAIXING-SGZ", WAIXING_SGZ }, | |
| 453 | { "WAIXING-PS2", WAIXING_PS2 }, | |
| 454 | { "WAIXING-FFV", WAIXING_FFV }, | |
| 455 | { "WAIXING-ZS", WAIXING_ZS }, | |
| 456 | { "WAIXING-DQ8", WAIXING_DQ8 }, | |
| 457 | { "WAIXING-SH2", WAIXING_SH2 }, | |
| 458 | // | |
| 459 | { "TXC-TW", TXC_TW }, | |
| 460 | { "TXC-STRIKEWOLF", TXC_STRIKEWOLF }, | |
| 461 | { "TXC-MXMDHTWO", TXC_MXMDHTWO }, | |
| 462 | { "UNL-22211", TXC_22211A }, | |
| 463 | /* FIXME: Made up boards the different mirroring handling */ | |
| 464 | { "UNL-22211-A", TXC_22211A }, | |
| 465 | { "UNL-22211-B", TXC_22211B }, | |
| 466 | { "UNL-22211-C", TXC_22211C }, | |
| 467 | { "UNL-REXSOFT-DBZ5", REXSOFT_DBZ5 }, | |
| 468 | { "UNL-SL1632", REXSOFT_SL1632 }, | |
| 469 | { "SUBOR-BOARD-0", SUBOR_TYPE0 }, | |
| 470 | { "SUBOR-BOARD-1", SUBOR_TYPE1 }, | |
| 471 | { "SOMERITEAM-SL-12", SOMERI_SL12 }, // mapper 116 | |
| 472 | { "UNL-CONY", CONY_BOARD }, | |
| 473 | { "UNL-GOUDER", GOUDER_37017 }, | |
| 474 | { "UNL-NITRA", NITRA_TDA }, | |
| 475 | { "UNL-HOSENKAN", HOSENKAN_BOARD }, | |
| 476 | { "UNL-SUPERGAME", SUPERGAME_LIONKING }, | |
| 477 | { "UNL-PANDAPRINCE", KAY_PANDAPRINCE }, | |
| 478 | { "DREAMTECH01", DREAMTECH_BOARD }, | |
| 479 | { "DAOU-306", OPENCORP_DAOU306 }, | |
| 480 | { "HES", HES_BOARD }, | |
| 481 | /* FIXME: Made up boards the different mirroring handling? */ | |
| 482 | { "HES-6IN1", HES6IN1_BOARD }, | |
| 483 | { "SUPERGAME-BOOGERMAN", SUPERGAME_BOOGERMAN }, | |
| 484 | { "FUTUREMEDIA", FUTUREMEDIA_BOARD }, | |
| 485 | { "FUKUTAKE", FUKUTAKE_BOARD }, | |
| 486 | { "MAGICSERIES", MAGICSERIES_MD }, | |
| 487 | { "KASING", KASING_BOARD }, | |
| 488 | { "HENGGEDIANZI", HENGEDIANZI_BOARD }, | |
| 489 | { "HENGGEDIANZI-XJZB", HENGEDIANZI_XJZB }, | |
| 490 | { "KAISER-KS7058", KAISER_KS7058 }, | |
| 491 | { "KAISER-KS202", KAISER_KS202 },// mapper 56 | |
| 492 | { "KAISER-KS7022", KAISER_KS7022 },// mapper 175 | |
| 493 | { "UNL-KS7017", KAISER_KS7017 }, | |
| 494 | { "UNL-KS7032", KAISER_KS7032 }, // mapper 142 | |
| 495 | { "RCM-GS2015", RCM_GS2015 }, | |
| 496 | { "RCM-TETRISFAMILY", RCM_TETRISFAMILY }, | |
| 497 | { "UNL-NINJARYU", UNSUPPORTED_BOARD },// mapper 111 | |
| 498 | { "UNL-NANJING", NANJING_BOARD },// mapper 163 | |
| 499 | { "WHIRLWIND-2706", WHIRLWIND_2706 }, | |
| 500 | { "UNL-H2288", UNL_H2288 }, | |
| 501 | { "UNL-DANCE", UNSUPPORTED_BOARD }, | |
| 502 | { "UNL-EDU2000", UNL_EDU2K }, | |
| 503 | { "UNL-SHERO", UNSUPPORTED_BOARD /*SACHEN_SHERO*/ }, | |
| 504 | { "UNL-TF1201", UNSUPPORTED_BOARD /*UNL_TF1201*/ }, | |
| 505 | { "RUMBLESTATION", RUMBLESTATION_BOARD }, // mapper 46 | |
| 506 | { "UNL-WORLDHERO", UNSUPPORTED_BOARD },// mapper 27 | |
| 507 | { "UNL-A9746", UNSUPPORTED_BOARD },// mapper 219 | |
| 508 | { "UNL-603-5052", UNL_603_5052 },// mapper 238? | |
| 509 | { "UNL-SHJY3", UNL_SHJY3 },// mapper 253 | |
| 510 | { "UNL-RACERMATE", UNL_RACERMATE },// mapper 168 | |
| 511 | { "UNL-N625092", UNL_N625092 }, | |
| 512 | { "BMC-N625092", UNL_N625092 }, | |
| 513 | { "UNL-SC-127", UNL_SC127 }, | |
| 514 | { "UNL-SMB2J", UNL_SMB2J }, | |
| 515 | { "BTL-SMB2C", UNL_SMB2J }, | |
| 516 | { "UNL-MK2", UNL_MK2 }, | |
| 517 | { "UNL-XZY", UNL_XZY }, | |
| 518 | { "UNL-KOF96", UNL_KOF96 }, | |
| 519 | { "UNL-SUPERFIGHTER3", UNL_SUPERFIGHTER3 }, | |
| 520 | { "UNL-8237", UNL_8237 }, | |
| 521 | { "UNL-AX5705", UNL_AX5705 }, | |
| 522 | { "UNL-CC-21", UNL_CC21 }, | |
| 523 | { "UNL-KOF97", UNL_KOF97 }, | |
| 524 | { "UNL-T-230", UNL_T230 }, | |
| 525 | { "UNL-STUDYNGAME", UNL_STUDYNGAME }, // mapper 39 | |
| 526 | { "UNL-OneBus", UNSUPPORTED_BOARD }, | |
| 527 | // | |
| 528 | { "BTL-SMB2A", BTL_SMB2A }, | |
| 529 | { "BTL-MARIOBABY", BTL_MARIOBABY }, | |
| 530 | { "BTL-AISENSHINICOL", BTL_AISENSHINICOL }, | |
| 531 | { "BTL-SMB2B", BTL_SMB2B }, | |
| 532 | { "BTL-SMB3", BTL_SMB3 }, | |
| 533 | { "BTL-SUPERBROS11", BTL_SUPERBROS11 }, | |
| 534 | { "BTL-DRAGONNINJA", BTL_DRAGONNINJA }, | |
| 535 | { "BTL-MARIO1-MALEE2", UNSUPPORTED_BOARD }, // mapper 55? | |
| 536 | { "BTL-2708", UNSUPPORTED_BOARD },// mapper 103 | |
| 537 | { "BTL-TOBIDASEDAISAKUSEN", BTL_TOBIDASE },// mapper 120 | |
| 538 | { "BTL-SHUIGUANPIPE", UNSUPPORTED_BOARD },// mapper 183 | |
| 539 | { "BTL-PIKACHUY2K", BTL_PIKACHUY2K },// mapper 254 | |
| 540 | // | |
| 541 | { "BMC-190IN1", BMC_190IN1 }, | |
| 542 | { "BMC-64IN1NOREPEAT", BMC_64IN1NR }, | |
| 543 | { "BMC-A65AS", BMC_A65AS }, | |
| 544 | { "BMC-GS-2004", BMC_GS2004 }, | |
| 545 | { "BMC-GS-2013", BMC_GS2013 }, | |
| 546 | { "BMC-NOVELDIAMOND9999999IN1", BMC_NOVELDIAMOND }, | |
| 547 | { "BMC-9999999IN1", BMC_9999999IN1 }, // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 ?? | |
| 548 | { "BMC-SUPER24IN1SC03", BMC_S24IN1SC03 }, | |
| 549 | { "BMC-SUPERHIK8IN1", BMC_HIK8IN1 }, | |
| 550 | { "BMC-T-262", BMC_T262 }, | |
| 551 | { "BMC-WS", BMC_WS }, | |
| 552 | { "MLT-ACTION52", ACTENT_ACT52 }, | |
| 553 | { "MLT-CALTRON6IN1", CALTRON_6IN1 }, | |
| 554 | { "MLT-MAXI15", UNSUPPORTED_BOARD}, // mapper 234 | |
| 555 | { "BMC-SUPERBIG-7IN1", BMC_SUPERBIG_7IN1 }, | |
| 556 | { "BMC-SUPERHIK-4IN1", BMC_SUPERHIK_4IN1 }, | |
| 557 | { "BMC-BALLGAMES-11IN1", BMC_BALLGAMES_11IN1 }, | |
| 558 | { "BMC-MARIOPARTY-7IN1", BMC_MARIOPARTY_7IN1 }, | |
| 559 | { "BMC-GKA", BMC_GKA }, | |
| 560 | { "BMC-GKB", BMC_GKB }, | |
| 561 | { "BMC-SUPER700IN1", BMC_SUPER_700IN1 }, | |
| 562 | { "BMC-FAMILY-4646B", BMC_FAMILY_4646B }, | |
| 563 | { "BMC-36IN1", BMC_36IN1 }, | |
| 564 | { "BMC-21IN1", BMC_21IN1 }, | |
| 565 | { "BMC-150IN1", BMC_150IN1 }, | |
| 566 | { "BMC-35IN1", BMC_35IN1 }, | |
| 567 | { "BMC-64IN1", BMC_64IN1 }, | |
| 568 | { "BMC-15IN1", BMC_15IN1 }, | |
| 569 | { "BMC-SUPERHIK-300IN1", BMC_SUPERHIK_300IN1 }, | |
| 570 | { "BMC-SUPERGUN-20IN1", BMC_SUPERGUN_20IN1 }, | |
| 571 | { "BMC-GOLDENCARD-6IN1", BMC_GOLDENCARD_6IN1 }, | |
| 572 | { "BMC-72IN1", BMC_72IN1 }, | |
| 573 | { "BMC-76IN1", BMC_76IN1 }, | |
| 574 | { "BMC-SUPER42IN1", BMC_SUPER_42IN1 }, | |
| 575 | { "BMC-1200IN1", BMC_1200IN1 }, | |
| 576 | { "BMC-31IN1", BMC_31IN1 }, | |
| 577 | { "BMC-22GAMES", BMC_22GAMES }, | |
| 578 | { "BMC-20IN1", BMC_20IN1 }, | |
| 579 | { "BMC-110IN1", BMC_110IN1 }, | |
| 580 | { "BMC-810544-C-A1", BMC_810544 }, | |
| 581 | { "BMC-411120-C", UNSUPPORTED_BOARD }, | |
| 582 | { "BMC-830118C", UNSUPPORTED_BOARD }, | |
| 583 | { "BMC-12-IN-1", UNSUPPORTED_BOARD }, | |
| 584 | { "BMC-NTD-03", BMC_NTD_03 }, | |
| 585 | { "BMC-8157", UNSUPPORTED_BOARD /*BMC_8157*/ }, | |
| 586 | { "BMC-BS-5", BMC_BENSHENG_BS5 }, | |
| 587 | { "BMC-FK23C", BMC_FK23C }, | |
| 588 | { "BMC-FK23CA", BMC_FK23CA }, | |
| 589 | { "BMC-GHOSTBUSTERS63IN1", BMC_G63IN1 }, | |
| 590 | { "BMC-SUPERVISION16IN1", UNSUPPORTED_BOARD }, // mapper 53 | |
| 591 | { "BMC-RESETBASED-4IN1", UNSUPPORTED_BOARD },// mapper 60 with 64k prg and 32k chr | |
| 592 | { "BMC-VT5201", BMC_VT5201 },// mapper 60 otherwise | |
| 593 | { "BMC-D1038", BMC_VT5201 }, // mapper 60? | |
| 594 | { "BMC-42IN1RESETSWITCH", UNSUPPORTED_BOARD }, // mapper 60? | |
| 595 | { "BMC-SUPER22GAMES", UNSUPPORTED_BOARD },// mapper 233 | |
| 596 | { "BMC-GOLDENGAME-150IN1", UNSUPPORTED_BOARD },// mapper 235 with 2M PRG | |
| 597 | { "BMC-GOLDENGAME-260IN1", UNSUPPORTED_BOARD },// mapper 235 with 4M PRG | |
| 598 | { "BMC-70IN1", UNSUPPORTED_BOARD }, // mapper 236? | |
| 599 | { "BMC-70IN1B", UNSUPPORTED_BOARD }, // mapper 236? | |
| 600 | { "BMC-SUPERHIK-KOF", UNSUPPORTED_BOARD },// mapper 251 | |
| 601 | { "BMC-POWERJOY", BMC_PJOY84 }, | |
| 602 | // are there dumps of games with these boards? | |
| 603 | { "BMC-13IN1JY110", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 604 | { "BMC-GK-192", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 605 | { "KONAMI-QTAI", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 606 | { "UNL-3D-BLOCK", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 607 | { "UNL-C-N22M", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 608 | { "UNL-PEC-586", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info] | |
| 609 | // | |
| 610 | { "UNKNOWN", UNKNOWN_BOARD } // a few pirate dumps uses the wrong mapper... | |
| 611 | }; | |
| 612 | ||
| 613 | const nes_pcb *nes_pcb_lookup( const char *board ) | |
| 614 | { | |
| 615 | int i; | |
| 616 | for (i = 0; i < ARRAY_LENGTH(pcb_list); i++) | |
| 617 | { | |
| 618 | if (!mame_stricmp(pcb_list[i].pcb_name, board)) | |
| 619 | return &pcb_list[i]; | |
| 620 | } | |
| 621 | return NULL; | |
| 622 | } | |
| 623 | ||
| 624 | int nes_get_pcb_id( running_machine &machine, const char *feature ) | |
| 625 | { | |
| 626 | const nes_pcb *pcb = nes_pcb_lookup(feature); | |
| 627 | ||
| 628 | if (pcb == NULL) | |
| 629 | fatalerror("Unimplemented PCB type %s\n", feature); | |
| 630 | ||
| 631 | return pcb->pcb_id; | |
| 632 | } | |
| 633 | ||
| 634 | /************************************************ | |
| 635 | ||
| 636 | PCB Emulation (to be moved to MAME later) | |
| 637 | ||
| 638 | In the end, iNES, UNIF and xml should be | |
| 639 | simply handled through a look-up table | |
| 640 | which associates the mapper/board/feature | |
| 641 | to the correct pcb_id and then the core | |
| 642 | function pcb_handlers_setup should be called | |
| 643 | to set-up the expected handlers and callbacks | |
| 644 | ||
| 645 | Similarly, PC-10, VSNES and NES-based | |
| 646 | multigame boards, should simply call | |
| 647 | pcb_handlers_setup with the proper pcb_id | |
| 648 | at the beginning, rather than use ad hoc | |
| 649 | implementations. | |
| 650 | ||
| 651 | ************************************************/ | |
| 652 | ||
| 653 | // helper function for the few mappers reading from 0x8000-0xffff for protection | |
| 654 | INLINE UINT8 mmc_hi_access_rom( running_machine &machine, UINT32 offset ) | |
| 655 | { | |
| 656 | nes_state *state = machine.driver_data<nes_state>(); | |
| 657 | ||
| 658 | // usual ROM access | |
| 659 | switch (offset & 0x6000) | |
| 660 | { | |
| 661 | case 0x0000: | |
| 662 | return state->m_rom[0x10000 + state->m_prg_bank[0] * 0x2000 + (offset & 0x1fff)]; | |
| 663 | case 0x2000: | |
| 664 | return state->m_rom[0x10000 + state->m_prg_bank[1] * 0x2000 + (offset & 0x1fff)]; | |
| 665 | case 0x4000: | |
| 666 | return state->m_rom[0x10000 + state->m_prg_bank[2] * 0x2000 + (offset & 0x1fff)]; | |
| 667 | case 0x6000: | |
| 668 | return state->m_rom[0x10000 + state->m_prg_bank[3] * 0x2000 + (offset & 0x1fff)]; | |
| 669 | } | |
| 670 | return 0; | |
| 671 | } | |
| 672 | ||
| 673 | /************************************************************* | |
| 674 | ||
| 675 | NROM board emulation | |
| 676 | ||
| 677 | Games: Mario Bros., Super Mario Bros., Tennis and most of | |
| 678 | the first generation games | |
| 679 | ||
| 680 | iNES: mapper 0 | |
| 681 | ||
| 682 | In MESS: Supported, no need of specific handlers or IRQ | |
| 683 | ||
| 684 | *************************************************************/ | |
| 685 | ||
| 686 | /************************************************************* | |
| 687 | ||
| 688 | UxROM board emulation | |
| 689 | ||
| 690 | Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan, | |
| 691 | Metal Gear | |
| 692 | ||
| 693 | writes to 0x8000-0xffff change PRG 16K lower banks | |
| 694 | ||
| 695 | missing BC? | |
| 696 | ||
| 697 | iNES: mapper 2 | |
| 698 | ||
| 699 | In MESS: Supported. | |
| 700 | ||
| 701 | *************************************************************/ | |
| 702 | ||
| 703 | static WRITE8_HANDLER( uxrom_w ) | |
| 704 | { | |
| 705 | LOG_MMC(("uxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 706 | ||
| 707 | prg16_89ab(space->machine(), data); | |
| 708 | } | |
| 709 | ||
| 710 | /************************************************************* | |
| 711 | ||
| 712 | Nihon Bussan UNROM M5 | |
| 713 | ||
| 714 | Games: Crazy Climber Jpn | |
| 715 | ||
| 716 | Very simple mapper: prg16_89ab is always set to bank 0, | |
| 717 | while prg16_cdef is set by writes to 0x8000-0xffff. The game | |
| 718 | uses a custom controller. | |
| 719 | ||
| 720 | iNES: mapper 180 | |
| 721 | ||
| 722 | In MESS: Supported. | |
| 723 | ||
| 724 | *************************************************************/ | |
| 725 | ||
| 726 | static WRITE8_HANDLER( uxrom_cc_w ) | |
| 727 | { | |
| 728 | LOG_MMC(("uxrom_cc_w, offset: %04x, data: %02x\n", offset, data)); | |
| 729 | ||
| 730 | prg16_cdef(space->machine(), data); | |
| 731 | } | |
| 732 | ||
| 733 | /************************************************************* | |
| 734 | ||
| 735 | UN1ROM board emulation | |
| 736 | ||
| 737 | Games: Senjou no Okami | |
| 738 | ||
| 739 | writes to 0x8000-0xffff change PRG 16K lower banks | |
| 740 | ||
| 741 | missing BC? | |
| 742 | ||
| 743 | iNES: mapper 94 | |
| 744 | ||
| 745 | In MESS: Supported. | |
| 746 | ||
| 747 | *************************************************************/ | |
| 748 | ||
| 749 | static WRITE8_HANDLER( un1rom_w ) | |
| 750 | { | |
| 751 | LOG_MMC(("un1rom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 752 | ||
| 753 | prg16_89ab(space->machine(), data >> 2); | |
| 754 | } | |
| 755 | ||
| 756 | /************************************************************* | |
| 757 | ||
| 758 | CNROM board emulation | |
| 759 | ||
| 760 | Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy, | |
| 761 | Adventure Island, Flipull, Friday 13th, GeGeGe no | |
| 762 | Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's | |
| 763 | Secret Castle | |
| 764 | ||
| 765 | writes to 0x8000-0xffff change CHR 8K banks | |
| 766 | ||
| 767 | missing BC? | |
| 768 | ||
| 769 | iNES: mappers 3 & 185 (the latter for games using Pins as | |
| 770 | protection) | |
| 771 | ||
| 772 | Notice that BANDAI_PT554 board (Aerobics Studio) uses very | |
| 773 | similar hardware but with an additional sound chip which | |
| 774 | gets writes to 0x6000 (currently unemulated in MESS) | |
| 775 | ||
| 776 | In MESS: Supported | |
| 777 | ||
| 778 | *************************************************************/ | |
| 779 | ||
| 780 | static WRITE8_HANDLER( cnrom_w ) | |
| 781 | { | |
| 782 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 783 | LOG_MMC(("cnrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 784 | ||
| 785 | if (state->m_ce_mask) | |
| 786 | { | |
| 787 | chr8(space->machine(), data & ~state->m_ce_mask, CHRROM); | |
| 788 | ||
| 789 | if ((data & state->m_ce_mask) == state->m_ce_state) | |
| 790 | state->m_chr_open_bus = 0; | |
| 791 | else | |
| 792 | state->m_chr_open_bus = 1; | |
| 793 | } | |
| 794 | else | |
| 795 | chr8(space->machine(), data, CHRROM); | |
| 796 | } | |
| 797 | ||
| 798 | /************************************************************* | |
| 799 | ||
| 800 | Bandai PT-554 board emulation | |
| 801 | ||
| 802 | This is used by Aerobics Studio. It is basically a CNROM board | |
| 803 | with an additional sound chip which is not currently emulated by | |
| 804 | MESS | |
| 805 | ||
| 806 | iNES: mapper 3? | |
| 807 | ||
| 808 | *************************************************************/ | |
| 809 | ||
| 810 | static WRITE8_HANDLER( bandai_pt554_m_w ) | |
| 811 | { | |
| 812 | LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data)); | |
| 813 | ||
| 814 | // according to NEStopia, this is the effect | |
| 815 | if (!BIT(data, 6)) | |
| 816 | { | |
| 817 | // send command (data & 0x07) to sound chip | |
| 818 | } | |
| 819 | } | |
| 820 | ||
| 821 | /************************************************************* | |
| 822 | ||
| 823 | CPROM board emulation | |
| 824 | ||
| 825 | Games: Videomation | |
| 826 | ||
| 827 | writes to 0x8000-0xffff change CHR 4K lower banks | |
| 828 | ||
| 829 | iNES: mapper 13 | |
| 830 | ||
| 831 | In MESS: Supported | |
| 832 | ||
| 833 | *************************************************************/ | |
| 834 | ||
| 835 | static WRITE8_HANDLER( cprom_w ) | |
| 836 | { | |
| 837 | LOG_MMC(("cprom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 838 | chr4_4(space->machine(), data, CHRRAM); | |
| 839 | } | |
| 840 | ||
| 841 | /************************************************************* | |
| 842 | ||
| 843 | AxROM board emulation | |
| 844 | ||
| 845 | Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice | |
| 846 | ||
| 847 | writes to 0x8000-0xffff change PRG banks + sets mirroring | |
| 848 | ||
| 849 | missing BC for AMROM? | |
| 850 | ||
| 851 | iNES: mapper 7 | |
| 852 | ||
| 853 | In MESS: Supported | |
| 854 | ||
| 855 | *************************************************************/ | |
| 856 | ||
| 857 | static WRITE8_HANDLER( axrom_w ) | |
| 858 | { | |
| 859 | LOG_MMC(("axrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 860 | ||
| 861 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 862 | prg32(space->machine(), data); | |
| 863 | } | |
| 864 | ||
| 865 | /************************************************************* | |
| 866 | ||
| 867 | BxROM board emulation | |
| 868 | ||
| 869 | writes to 0x8000-0xffff change PRG banks | |
| 870 | ||
| 871 | missing BC? | |
| 872 | ||
| 873 | iNES: mapper 34 | |
| 874 | ||
| 875 | *************************************************************/ | |
| 876 | ||
| 877 | static WRITE8_HANDLER( bxrom_w ) | |
| 878 | { | |
| 879 | /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */ | |
| 880 | /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */ | |
| 881 | LOG_MMC(("bxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 882 | ||
| 883 | prg32(space->machine(), data); | |
| 884 | } | |
| 885 | ||
| 886 | /************************************************************* | |
| 887 | ||
| 888 | GxROM/MxROM board emulation | |
| 889 | ||
| 890 | writes to 0x8000-0xffff change PRG and CHR banks | |
| 891 | ||
| 892 | missing BC? | |
| 893 | ||
| 894 | iNES: mapper 66 | |
| 895 | ||
| 896 | *************************************************************/ | |
| 897 | ||
| 898 | static WRITE8_HANDLER( gxrom_w ) | |
| 899 | { | |
| 900 | LOG_MMC(("gxrom_w, offset %04x, data: %02x\n", offset, data)); | |
| 901 | ||
| 902 | prg32(space->machine(), (data & 0xf0) >> 4); | |
| 903 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 904 | } | |
| 905 | ||
| 906 | /************************************************************* | |
| 907 | ||
| 908 | SxROM (MMC1 based) board emulation | |
| 909 | ||
| 910 | iNES: mapper 1 (and 155 for the MMC1A variant which does not | |
| 911 | have WRAM disable bit) | |
| 912 | ||
| 913 | *************************************************************/ | |
| 914 | ||
| 915 | static TIMER_CALLBACK( mmc1_resync_callback ) | |
| 916 | { | |
| 917 | nes_state *state = machine.driver_data<nes_state>(); | |
| 918 | state->m_mmc1_reg_write_enable = 1; | |
| 919 | } | |
| 920 | ||
| 921 | ||
| 922 | static void mmc1_set_wram( address_space *space, int board ) | |
| 923 | { | |
| 924 | running_machine &machine = space->machine(); | |
| 925 | nes_state *state = machine.driver_data<nes_state>(); | |
| 926 | UINT8 bank = BIT(state->m_mmc_reg[0], 4) ? BIT(state->m_mmc_reg[1], 4) : BIT(state->m_mmc_reg[1], 3); | |
| 927 | ||
| 928 | switch (board) | |
| 929 | { | |
| 930 | case STD_SXROM: // here also reads are disabled! | |
| 931 | if (!BIT(state->m_mmc_reg[3], 4)) | |
| 932 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 933 | else | |
| 934 | { | |
| 935 | space->unmap_readwrite(0x6000, 0x7fff); | |
| 936 | break; | |
| 937 | } | |
| 938 | case STD_SXROM_A: // ignore WRAM enable bit | |
| 939 | if (state->m_battery_size > 0x2000) | |
| 940 | wram_bank(machine, ((state->m_mmc_reg[1] & 3) >> 2), NES_BATTERY); | |
| 941 | else if (state->m_battery_size) | |
| 942 | wram_bank(machine, 0, NES_BATTERY); | |
| 943 | break; | |
| 944 | case STD_SOROM: // there are 2 WRAM banks only and battery is bank 2 for the cart (hence, we invert bank, because we have battery first) | |
| 945 | if (!BIT(state->m_mmc_reg[3], 4)) | |
| 946 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 947 | else | |
| 948 | { | |
| 949 | space->unmap_readwrite(0x6000, 0x7fff); | |
| 950 | break; | |
| 951 | } | |
| 952 | case STD_SOROM_A: // ignore WRAM enable bit | |
| 953 | wram_bank(machine, 0, bank ? NES_BATTERY : NES_WRAM); | |
| 954 | break; | |
| 955 | } | |
| 956 | } | |
| 957 | ||
| 958 | static void mmc1_set_prg( running_machine &machine ) | |
| 959 | { | |
| 960 | nes_state *state = machine.driver_data<nes_state>(); | |
| 961 | UINT8 prg_mode, prg_offset; | |
| 962 | ||
| 963 | prg_mode = state->m_mmc_reg[0] & 0x0c; | |
| 964 | /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode, | |
| 965 | prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4, | |
| 966 | mmc_reg[3] sets banks at 0x8000; if it is 0, mmc_reg[3] sets banks at 0xc000. */ | |
| 967 | ||
| 968 | prg_offset = state->m_mmc_reg[1] & 0x10; | |
| 969 | /* In principle, mmc_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1. | |
| 970 | However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be | |
| 971 | set to the same value, or else pages will constantly be swapped as graphics render! | |
| 972 | Hence, we use only mmc_reg[1]&0x10 for prg_offset */ | |
| 973 | ||
| 974 | switch (prg_mode) | |
| 975 | { | |
| 976 | case 0x00: | |
| 977 | case 0x04: | |
| 978 | // printf("PRG 32 bank %d \n", (prg_offset + state->m_mmc_reg[3]) >> 1); | |
| 979 | prg32(machine, (prg_offset + state->m_mmc_reg[3]) >> 1); | |
| 980 | break; | |
| 981 | case 0x08: | |
| 982 | // printf("PRG 16 bank %d (high) \n", prg_offset + state->m_mmc_reg[3]); | |
| 983 | prg16_89ab(machine, prg_offset + 0); | |
| 984 | prg16_cdef(machine, prg_offset + state->m_mmc_reg[3]); | |
| 985 | break; | |
| 986 | case 0x0c: | |
| 987 | // printf("PRG 16 bank %d (low) \n", prg_offset + state->m_mmc_reg[3]); | |
| 988 | prg16_89ab(machine, prg_offset + state->m_mmc_reg[3]); | |
| 989 | prg16_cdef(machine, prg_offset + 0x0f); | |
| 990 | break; | |
| 991 | } | |
| 992 | } | |
| 993 | ||
| 994 | static void mmc1_set_prg_wram( address_space *space, int board ) | |
| 995 | { | |
| 996 | mmc1_set_prg(space->machine()); | |
| 997 | mmc1_set_wram(space, board); | |
| 998 | } | |
| 999 | ||
| 1000 | static void mmc1_set_chr( running_machine &machine ) | |
| 1001 | { | |
| 1002 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1003 | UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4); | |
| 1004 | ||
| 1005 | if (chr_mode) | |
| 1006 | { | |
| 1007 | chr4_0(machine, state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source); | |
| 1008 | chr4_4(machine, state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source); | |
| 1009 | } | |
| 1010 | else | |
| 1011 | chr8(machine, (state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source); | |
| 1012 | } | |
| 1013 | ||
| 1014 | static void common_sxrom_write_handler( address_space *space, offs_t offset, UINT8 data, int board ) | |
| 1015 | { | |
| 1016 | running_machine &machine = space->machine(); | |
| 1017 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1018 | /* Note that there is only one latch and shift counter, shared amongst the 4 regs */ | |
| 1019 | /* Space Shuttle will not work if they have independent variables. */ | |
| 1020 | ||
| 1021 | /* here we would need to add an if(cpu_cycles_passed>1) test, and | |
| 1022 | if requirement is not met simply return without writing anything. | |
| 1023 | Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic | |
| 1024 | Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on | |
| 1025 | this behavior!! */ | |
| 1026 | if (state->m_mmc1_reg_write_enable == 0) | |
| 1027 | { | |
| 1028 | return; | |
| 1029 | } | |
| 1030 | else | |
| 1031 | { | |
| 1032 | state->m_mmc1_reg_write_enable = 0; | |
| 1033 | space->machine().scheduler().synchronize(FUNC(mmc1_resync_callback)); | |
| 1034 | } | |
| 1035 | ||
| 1036 | if (data & 0x80) | |
| 1037 | { | |
| 1038 | state->m_mmc1_count = 0; | |
| 1039 | state->m_mmc1_latch = 0; | |
| 1040 | ||
| 1041 | /* Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars */ | |
| 1042 | state->m_mmc_reg[0] |= 0x0c; | |
| 1043 | mmc1_set_prg_wram(space, board); | |
| 1044 | return; | |
| 1045 | } | |
| 1046 | ||
| 1047 | if (state->m_mmc1_count < 5) | |
| 1048 | { | |
| 1049 | if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0; | |
| 1050 | state->m_mmc1_latch >>= 1; | |
| 1051 | state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; | |
| 1052 | state->m_mmc1_count++; | |
| 1053 | } | |
| 1054 | ||
| 1055 | if (state->m_mmc1_count == 5) | |
| 1056 | { | |
| 1057 | switch (offset & 0x6000) /* Which reg shall we write to? */ | |
| 1058 | { | |
| 1059 | case 0x0000: | |
| 1060 | state->m_mmc_reg[0] = state->m_mmc1_latch; | |
| 1061 | ||
| 1062 | switch (state->m_mmc_reg[0] & 0x03) | |
| 1063 | { | |
| 1064 | case 0: set_nt_mirroring(machine, PPU_MIRROR_LOW); break; | |
| 1065 | case 1: set_nt_mirroring(machine, PPU_MIRROR_HIGH); break; | |
| 1066 | case 2: set_nt_mirroring(machine, PPU_MIRROR_VERT); break; | |
| 1067 | case 3: set_nt_mirroring(machine, PPU_MIRROR_HORZ); break; | |
| 1068 | } | |
| 1069 | mmc1_set_chr(machine); | |
| 1070 | mmc1_set_prg_wram(space, board); | |
| 1071 | break; | |
| 1072 | case 0x2000: | |
| 1073 | state->m_mmc_reg[1] = state->m_mmc1_latch; | |
| 1074 | mmc1_set_chr(machine); | |
| 1075 | mmc1_set_prg_wram(space, board); | |
| 1076 | break; | |
| 1077 | case 0x4000: | |
| 1078 | state->m_mmc_reg[2] = state->m_mmc1_latch; | |
| 1079 | mmc1_set_chr(machine); | |
| 1080 | break; | |
| 1081 | case 0x6000: | |
| 1082 | state->m_mmc_reg[3] = state->m_mmc1_latch; | |
| 1083 | mmc1_set_prg_wram(space, board); | |
| 1084 | break; | |
| 1085 | } | |
| 1086 | state->m_mmc1_count = 0; | |
| 1087 | } | |
| 1088 | } | |
| 1089 | ||
| 1090 | static WRITE8_HANDLER( sxrom_w ) | |
| 1091 | { | |
| 1092 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1093 | ||
| 1094 | LOG_MMC(("sxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1095 | common_sxrom_write_handler(space, offset, data, state->m_pcb_id); | |
| 1096 | } | |
| 1097 | ||
| 1098 | /************************************************************* | |
| 1099 | ||
| 1100 | PxROM (MMC2 based) board emulation | |
| 1101 | ||
| 1102 | Games: Punch Out!!, Mike Tyson's Punch Out!! | |
| 1103 | ||
| 1104 | iNES: mapper 9 | |
| 1105 | ||
| 1106 | In MESS: Supported | |
| 1107 | ||
| 1108 | *************************************************************/ | |
| 1109 | ||
| 1110 | static void mmc2_latch( device_t *device, offs_t offset ) | |
| 1111 | { | |
| 1112 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1113 | if ((offset & 0x3ff0) == 0x0fd0) | |
| 1114 | { | |
| 1115 | LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", state->m_mmc_reg[0])); | |
| 1116 | state->m_mmc_latch1 = 0xfd; | |
| 1117 | chr4_0(device->machine(), state->m_mmc_reg[0], CHRROM); | |
| 1118 | } | |
| 1119 | else if ((offset & 0x3ff0) == 0x0fe0) | |
| 1120 | { | |
| 1121 | LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", state->m_mmc_reg[1])); | |
| 1122 | state->m_mmc_latch1 = 0xfe; | |
| 1123 | chr4_0(device->machine(), state->m_mmc_reg[1], CHRROM); | |
| 1124 | } | |
| 1125 | else if ((offset & 0x3ff0) == 0x1fd0) | |
| 1126 | { | |
| 1127 | LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", state->m_mmc_reg[2])); | |
| 1128 | state->m_mmc_latch2 = 0xfd; | |
| 1129 | chr4_4(device->machine(), state->m_mmc_reg[2], CHRROM); | |
| 1130 | } | |
| 1131 | else if ((offset & 0x3ff0) == 0x1fe0) | |
| 1132 | { | |
| 1133 | LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", state->m_mmc_reg[3])); | |
| 1134 | state->m_mmc_latch2 = 0xfe; | |
| 1135 | chr4_4(device->machine(), state->m_mmc_reg[3], CHRROM); | |
| 1136 | } | |
| 1137 | } | |
| 1138 | ||
| 1139 | static WRITE8_HANDLER( pxrom_w ) | |
| 1140 | { | |
| 1141 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1142 | LOG_MMC(("pxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1143 | switch (offset & 0x7000) | |
| 1144 | { | |
| 1145 | case 0x2000: | |
| 1146 | prg8_89(space->machine(), data); | |
| 1147 | break; | |
| 1148 | case 0x3000: | |
| 1149 | state->m_mmc_reg[0] = data; | |
| 1150 | if (state->m_mmc_latch1 == 0xfd) | |
| 1151 | chr4_0(space->machine(), state->m_mmc_reg[0], CHRROM); | |
| 1152 | break; | |
| 1153 | case 0x4000: | |
| 1154 | state->m_mmc_reg[1] = data; | |
| 1155 | if (state->m_mmc_latch1 == 0xfe) | |
| 1156 | chr4_0(space->machine(), state->m_mmc_reg[1], CHRROM); | |
| 1157 | break; | |
| 1158 | case 0x5000: | |
| 1159 | state->m_mmc_reg[2] = data; | |
| 1160 | if (state->m_mmc_latch2 == 0xfd) | |
| 1161 | chr4_4(space->machine(), state->m_mmc_reg[2], CHRROM); | |
| 1162 | break; | |
| 1163 | case 0x6000: | |
| 1164 | state->m_mmc_reg[3] = data; | |
| 1165 | if (state->m_mmc_latch2 == 0xfe) | |
| 1166 | chr4_4(space->machine(), state->m_mmc_reg[3], CHRROM); | |
| 1167 | break; | |
| 1168 | case 0x7000: | |
| 1169 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 1170 | break; | |
| 1171 | default: | |
| 1172 | LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data)); | |
| 1173 | break; | |
| 1174 | } | |
| 1175 | } | |
| 1176 | ||
| 1177 | /************************************************************* | |
| 1178 | ||
| 1179 | FxROM (MMC4 based) board emulation | |
| 1180 | ||
| 1181 | Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden | |
| 1182 | ||
| 1183 | iNES: mapper 10 | |
| 1184 | ||
| 1185 | In MESS: Supported | |
| 1186 | ||
| 1187 | *************************************************************/ | |
| 1188 | ||
| 1189 | static WRITE8_HANDLER( fxrom_w ) | |
| 1190 | { | |
| 1191 | LOG_MMC(("fxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1192 | switch (offset & 0x7000) | |
| 1193 | { | |
| 1194 | case 0x2000: | |
| 1195 | prg16_89ab(space->machine(), data); | |
| 1196 | break; | |
| 1197 | default: | |
| 1198 | pxrom_w(space, offset, data); | |
| 1199 | break; | |
| 1200 | } | |
| 1201 | } | |
| 1202 | ||
| 1203 | /************************************************************* | |
| 1204 | ||
| 1205 | TxROM (MMC3 based) board emulation | |
| 1206 | ||
| 1207 | iNES: mapper 4 | |
| 1208 | ||
| 1209 | *************************************************************/ | |
| 1210 | ||
| 1211 | static void mmc3_set_wram( address_space *space ) | |
| 1212 | { | |
| 1213 | running_machine &machine = space->machine(); | |
| 1214 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1215 | ||
| 1216 | // skip this function if we are emulating a MMC3 clone with mid writes | |
| 1217 | if (state->m_mmc_write_mid != NULL) | |
| 1218 | return; | |
| 1219 | ||
| 1220 | if (BIT(state->m_mmc3_wram_protect, 7)) | |
| 1221 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 1222 | else | |
| 1223 | { | |
| 1224 | space->unmap_readwrite(0x6000, 0x7fff); | |
| 1225 | return; | |
| 1226 | } | |
| 1227 | ||
| 1228 | if (!BIT(state->m_mmc3_wram_protect, 6)) | |
| 1229 | space->install_write_bank(0x6000, 0x7fff, "bank5"); | |
| 1230 | else | |
| 1231 | { | |
| 1232 | space->unmap_write(0x6000, 0x7fff); | |
| 1233 | return; | |
| 1234 | } | |
| 1235 | } | |
| 1236 | ||
| 1237 | static void mmc3_set_prg( running_machine &machine, int prg_base, int prg_mask ) | |
| 1238 | { | |
| 1239 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1240 | UINT8 prg_flip = (state->m_mmc3_latch & 0x40) ? 2 : 0; | |
| 1241 | ||
| 1242 | state->m_mmc3_prg_cb(machine, 0, prg_base | (state->m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); | |
| 1243 | state->m_mmc3_prg_cb(machine, 1, prg_base | (state->m_mmc_prg_bank[1] & prg_mask)); | |
| 1244 | state->m_mmc3_prg_cb(machine, 2, prg_base | (state->m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); | |
| 1245 | state->m_mmc3_prg_cb(machine, 3, prg_base | (state->m_mmc_prg_bank[3] & prg_mask)); | |
| 1246 | } | |
| 1247 | ||
| 1248 | static void mmc3_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask ) | |
| 1249 | { | |
| 1250 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1251 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 1252 | ||
| 1253 | state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); | |
| 1254 | state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); | |
| 1255 | state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); | |
| 1256 | state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); | |
| 1257 | state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr); | |
| 1258 | state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr); | |
| 1259 | state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr); | |
| 1260 | state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr); | |
| 1261 | } | |
| 1262 | ||
| 1263 | /* Here, IRQ counter decrements every scanline. */ | |
| 1264 | static void mmc3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 1265 | { | |
| 1266 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1267 | ||
| 1268 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 1269 | { | |
| 1270 | int priorCount = state->m_IRQ_count; | |
| 1271 | if ((state->m_IRQ_count == 0) || state->m_IRQ_clear) | |
| 1272 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 1273 | else | |
| 1274 | state->m_IRQ_count--; | |
| 1275 | ||
| 1276 | if (state->m_IRQ_enable && !blanked && (state->m_IRQ_count == 0) && (priorCount || state->m_IRQ_clear /*|| !state->m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq! | |
| 1277 | { | |
| 1278 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 1279 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 1280 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1281 | } | |
| 1282 | } | |
| 1283 | state->m_IRQ_clear = 0; | |
| 1284 | } | |
| 1285 | ||
| 1286 | static WRITE8_HANDLER( txrom_w ) | |
| 1287 | { | |
| 1288 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1289 | UINT8 mmc_helper, cmd; | |
| 1290 | ||
| 1291 | LOG_MMC(("txrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1292 | ||
| 1293 | switch (offset & 0x6001) | |
| 1294 | { | |
| 1295 | case 0x0000: | |
| 1296 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 1297 | state->m_mmc3_latch = data; | |
| 1298 | ||
| 1299 | /* Has PRG Mode changed? */ | |
| 1300 | if (mmc_helper & 0x40) | |
| 1301 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1302 | ||
| 1303 | /* Has CHR Mode changed? */ | |
| 1304 | if (mmc_helper & 0x80) | |
| 1305 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1306 | break; | |
| 1307 | ||
| 1308 | case 0x0001: | |
| 1309 | cmd = state->m_mmc3_latch & 0x07; | |
| 1310 | switch (cmd) | |
| 1311 | { | |
| 1312 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 1313 | case 2: case 3: case 4: case 5: | |
| 1314 | state->m_mmc_vrom_bank[cmd] = data; | |
| 1315 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1316 | break; | |
| 1317 | case 6: | |
| 1318 | case 7: | |
| 1319 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 1320 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1321 | break; | |
| 1322 | } | |
| 1323 | break; | |
| 1324 | ||
| 1325 | case 0x2000: | |
| 1326 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 1327 | break; | |
| 1328 | ||
| 1329 | case 0x2001: | |
| 1330 | state->m_mmc3_wram_protect = data; | |
| 1331 | mmc3_set_wram(space); | |
| 1332 | break; | |
| 1333 | ||
| 1334 | case 0x4000: | |
| 1335 | state->m_IRQ_count_latch = data; | |
| 1336 | break; | |
| 1337 | ||
| 1338 | case 0x4001: | |
| 1339 | state->m_IRQ_count = 0; | |
| 1340 | break; | |
| 1341 | ||
| 1342 | case 0x6000: | |
| 1343 | state->m_IRQ_enable = 0; | |
| 1344 | break; | |
| 1345 | ||
| 1346 | case 0x6001: | |
| 1347 | state->m_IRQ_enable = 1; | |
| 1348 | break; | |
| 1349 | ||
| 1350 | default: | |
| 1351 | logerror("txrom_w uncaught: %04x value: %02x\n", offset + 0x8000, data); | |
| 1352 | break; | |
| 1353 | } | |
| 1354 | } | |
| 1355 | ||
| 1356 | /************************************************************* | |
| 1357 | ||
| 1358 | HKROM (MMC6 based) board emulation | |
| 1359 | ||
| 1360 | iNES: mapper 4 | |
| 1361 | ||
| 1362 | *************************************************************/ | |
| 1363 | ||
| 1364 | static WRITE8_HANDLER( hkrom_m_w ) | |
| 1365 | { | |
| 1366 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1367 | UINT8 write_hi, write_lo; | |
| 1368 | LOG_MMC(("hkrom_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1369 | ||
| 1370 | if (offset < 0x1000) | |
| 1371 | return; | |
| 1372 | ||
| 1373 | // banks can be written only if both read & write is enabled! | |
| 1374 | write_hi = ((state->m_mmc6_reg & 0xc0) == 0xc0); | |
| 1375 | write_lo = ((state->m_mmc6_reg & 0x30) == 0x30); | |
| 1376 | ||
| 1377 | if (BIT(offset, 9) && write_hi) // access to upper 1k | |
| 1378 | state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data; | |
| 1379 | ||
| 1380 | if (!BIT(offset, 9) && write_lo) // access to lower 1k | |
| 1381 | state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data; | |
| 1382 | } | |
| 1383 | ||
| 1384 | static READ8_HANDLER( hkrom_m_r ) | |
| 1385 | { | |
| 1386 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1387 | LOG_MMC(("hkrom_m_r, offset: %04x\n", offset)); | |
| 1388 | ||
| 1389 | if (offset < 0x1000) | |
| 1390 | return 0xff; // here it should be open bus | |
| 1391 | ||
| 1392 | if (!(state->m_mmc6_reg & 0xa0)) | |
| 1393 | return 0xff; // here it should be open bus | |
| 1394 | ||
| 1395 | if (BIT(offset, 9) && BIT(state->m_mmc6_reg, 7)) // access to upper 1k when upper read is enabled | |
| 1396 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 1397 | ||
| 1398 | if (!BIT(offset, 9) && BIT(state->m_mmc6_reg, 5)) // access to lower 1k when lower read is enabled | |
| 1399 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 1400 | ||
| 1401 | // If only one bank is enabled for reading, the other reads back as zero | |
| 1402 | return 0x00; | |
| 1403 | } | |
| 1404 | ||
| 1405 | static WRITE8_HANDLER( hkrom_w ) | |
| 1406 | { | |
| 1407 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1408 | UINT8 mmc6_helper; | |
| 1409 | LOG_MMC(("hkrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1410 | ||
| 1411 | switch (offset & 0x6001) | |
| 1412 | { | |
| 1413 | case 0x0000: | |
| 1414 | mmc6_helper = state->m_mmc3_latch ^ data; | |
| 1415 | state->m_mmc3_latch = data; | |
| 1416 | ||
| 1417 | if (!state->m_mmc_latch2 && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write | |
| 1418 | state->m_mmc_latch2 = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game) | |
| 1419 | ||
| 1420 | /* Has PRG Mode changed? */ | |
| 1421 | if (BIT(mmc6_helper, 6)) | |
| 1422 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1423 | ||
| 1424 | /* Has CHR Mode changed? */ | |
| 1425 | if (BIT(mmc6_helper, 7)) | |
| 1426 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1427 | break; | |
| 1428 | ||
| 1429 | case 0x2001: | |
| 1430 | if (state->m_mmc_latch2) | |
| 1431 | state->m_mmc6_reg = data; | |
| 1432 | break; | |
| 1433 | ||
| 1434 | case 0x4001: | |
| 1435 | state->m_IRQ_count = 0; | |
| 1436 | state->m_IRQ_clear = 1; | |
| 1437 | break; | |
| 1438 | ||
| 1439 | default: | |
| 1440 | txrom_w(space, offset, data); | |
| 1441 | break; | |
| 1442 | } | |
| 1443 | } | |
| 1444 | ||
| 1445 | /************************************************************* | |
| 1446 | ||
| 1447 | TxSROM (MMC3 based) board emulation | |
| 1448 | ||
| 1449 | Games: Armadillo, Play Action Football, Pro Hockey, RPG | |
| 1450 | Jinsei Game, Y's 3 | |
| 1451 | ||
| 1452 | iNES: mapper 118 | |
| 1453 | ||
| 1454 | In MESS: Supported. It also uses mmc3_irq. | |
| 1455 | ||
| 1456 | *************************************************************/ | |
| 1457 | ||
| 1458 | static void txsrom_set_mirror( running_machine &machine ) | |
| 1459 | { | |
| 1460 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1461 | if (state->m_mmc3_latch & 0x80) | |
| 1462 | { | |
| 1463 | set_nt_page(machine, 0, CIRAM, (state->m_mmc_vrom_bank[2] & 0x80) >> 7, 1); | |
| 1464 | set_nt_page(machine, 1, CIRAM, (state->m_mmc_vrom_bank[3] & 0x80) >> 7, 1); | |
| 1465 | set_nt_page(machine, 2, CIRAM, (state->m_mmc_vrom_bank[4] & 0x80) >> 7, 1); | |
| 1466 | set_nt_page(machine, 3, CIRAM, (state->m_mmc_vrom_bank[5] & 0x80) >> 7, 1); | |
| 1467 | } | |
| 1468 | else | |
| 1469 | { | |
| 1470 | set_nt_page(machine, 0, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1); | |
| 1471 | set_nt_page(machine, 1, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1); | |
| 1472 | set_nt_page(machine, 2, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1); | |
| 1473 | set_nt_page(machine, 3, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1); | |
| 1474 | } | |
| 1475 | } | |
| 1476 | ||
| 1477 | static void txsrom_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 1478 | { | |
| 1479 | txsrom_set_mirror(machine); // we could probably update only for one (e.g. the first) call, to slightly optimize the code | |
| 1480 | chr1_x(machine, start, bank, source); | |
| 1481 | } | |
| 1482 | ||
| 1483 | static WRITE8_HANDLER( txsrom_w ) | |
| 1484 | { | |
| 1485 | LOG_MMC(("txsrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1486 | ||
| 1487 | switch (offset & 0x6001) | |
| 1488 | { | |
| 1489 | case 0x2000: | |
| 1490 | break; | |
| 1491 | ||
| 1492 | default: | |
| 1493 | txrom_w(space, offset, data); | |
| 1494 | break; | |
| 1495 | } | |
| 1496 | } | |
| 1497 | ||
| 1498 | /************************************************************* | |
| 1499 | ||
| 1500 | TQROM (MMC3 based) board emulation | |
| 1501 | ||
| 1502 | Games: Pin Bot, High Speed | |
| 1503 | ||
| 1504 | iNES: mapper 119 | |
| 1505 | ||
| 1506 | In MESS: Supported. It also uses mmc3_irq. | |
| 1507 | ||
| 1508 | *************************************************************/ | |
| 1509 | ||
| 1510 | static void tqrom_set_chr( running_machine &machine ) | |
| 1511 | { | |
| 1512 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1513 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 1514 | UINT8 chr_src[6], chr_mask[6]; | |
| 1515 | int i; | |
| 1516 | ||
| 1517 | for (i = 0; i < 6; i++) | |
| 1518 | { | |
| 1519 | chr_src[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM; | |
| 1520 | chr_mask[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f; | |
| 1521 | } | |
| 1522 | ||
| 1523 | chr1_x(machine, chr_page ^ 0, ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask[0]), chr_src[0]); | |
| 1524 | chr1_x(machine, chr_page ^ 1, ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask[0]), chr_src[0]); | |
| 1525 | chr1_x(machine, chr_page ^ 2, ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask[1]), chr_src[1]); | |
| 1526 | chr1_x(machine, chr_page ^ 3, ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask[1]), chr_src[1]); | |
| 1527 | chr1_x(machine, chr_page ^ 4, (state->m_mmc_vrom_bank[2] & chr_mask[2]), chr_src[2]); | |
| 1528 | chr1_x(machine, chr_page ^ 5, (state->m_mmc_vrom_bank[3] & chr_mask[3]), chr_src[3]); | |
| 1529 | chr1_x(machine, chr_page ^ 6, (state->m_mmc_vrom_bank[4] & chr_mask[4]), chr_src[4]); | |
| 1530 | chr1_x(machine, chr_page ^ 7, (state->m_mmc_vrom_bank[5] & chr_mask[5]), chr_src[5]); | |
| 1531 | } | |
| 1532 | ||
| 1533 | static WRITE8_HANDLER( tqrom_w ) | |
| 1534 | { | |
| 1535 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1536 | UINT8 mmc_helper, cmd; | |
| 1537 | LOG_MMC(("tqrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1538 | ||
| 1539 | switch (offset & 0x6001) | |
| 1540 | { | |
| 1541 | case 0x0000: | |
| 1542 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 1543 | state->m_mmc3_latch = data; | |
| 1544 | ||
| 1545 | /* Has PRG Mode changed? */ | |
| 1546 | if (mmc_helper & 0x40) | |
| 1547 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1548 | ||
| 1549 | /* Has CHR Mode changed? */ | |
| 1550 | if (mmc_helper & 0x80) | |
| 1551 | tqrom_set_chr(space->machine()); | |
| 1552 | break; | |
| 1553 | case 0x0001: /* $8001 */ | |
| 1554 | cmd = state->m_mmc3_latch & 0x07; | |
| 1555 | switch (cmd) | |
| 1556 | { | |
| 1557 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 1558 | case 2: case 3: case 4: case 5: | |
| 1559 | state->m_mmc_vrom_bank[cmd] = data; | |
| 1560 | tqrom_set_chr(space->machine()); | |
| 1561 | break; | |
| 1562 | case 6: | |
| 1563 | case 7: | |
| 1564 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 1565 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1566 | break; | |
| 1567 | } | |
| 1568 | break; | |
| 1569 | ||
| 1570 | default: | |
| 1571 | txrom_w(space, offset, data); | |
| 1572 | break; | |
| 1573 | } | |
| 1574 | } | |
| 1575 | ||
| 1576 | /************************************************************* | |
| 1577 | ||
| 1578 | PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart | |
| 1579 | Super Mario Bros. + Tetris + Nintendo World Cup) | |
| 1580 | ||
| 1581 | iNES: mapper 37 | |
| 1582 | ||
| 1583 | *************************************************************/ | |
| 1584 | ||
| 1585 | static WRITE8_HANDLER( zz_m_w ) | |
| 1586 | { | |
| 1587 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1588 | UINT8 mmc_helper = data & 0x07; | |
| 1589 | LOG_MMC(("zz_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1590 | ||
| 1591 | state->m_mmc_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0); | |
| 1592 | state->m_mmc_prg_mask = (mmc_helper << 1) | 0x07; | |
| 1593 | state->m_mmc_chr_base = BIT(mmc_helper, 2) << 7; | |
| 1594 | state->m_mmc_chr_mask = 0x7f; | |
| 1595 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1596 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1597 | } | |
| 1598 | ||
| 1599 | /************************************************************* | |
| 1600 | ||
| 1601 | NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart | |
| 1602 | Super Spike V'Ball + Nintendo World Cup) | |
| 1603 | ||
| 1604 | iNES: mapper 47 | |
| 1605 | ||
| 1606 | *************************************************************/ | |
| 1607 | ||
| 1608 | static WRITE8_HANDLER( qj_m_w ) | |
| 1609 | { | |
| 1610 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1611 | LOG_MMC(("qj_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 1612 | ||
| 1613 | state->m_mmc_prg_base = BIT(data, 0) << 4; | |
| 1614 | state->m_mmc_prg_mask = 0x0f; | |
| 1615 | state->m_mmc_chr_base = BIT(data, 0) << 7; | |
| 1616 | state->m_mmc_chr_mask = 0x7f; | |
| 1617 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 1618 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 1619 | } | |
| 1620 | ||
| 1621 | /************************************************************* | |
| 1622 | ||
| 1623 | ExROM (MMC5 based) board emulation | |
| 1624 | ||
| 1625 | Games: Castlevania III, Just Breed, many Koei titles | |
| 1626 | ||
| 1627 | iNES: mapper 5 | |
| 1628 | ||
| 1629 | MESS status: Mostly Unsupported | |
| 1630 | ||
| 1631 | *************************************************************/ | |
| 1632 | ||
| 1633 | #if 0 | |
| 1634 | static void mmc5_update_chr_a( running_machine &machine ) | |
| 1635 | { | |
| 1636 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1637 | switch (state->m_mmc5_chr_mode) | |
| 1638 | { | |
| 1639 | case 0: // 8k banks | |
| 1640 | chr8(machine, state->m_mmc5_vrom_regA[7] & 0xff, CHRROM); | |
| 1641 | break; | |
| 1642 | ||
| 1643 | case 1: // 4k banks | |
| 1644 | chr4_0(machine, state->m_mmc5_vrom_regA[3] & 0xff, CHRROM); | |
| 1645 | chr4_4(machine, state->m_mmc5_vrom_regA[7] & 0xff, CHRROM); | |
| 1646 | break; | |
| 1647 | ||
| 1648 | case 2: // 2k banks | |
| 1649 | chr2_0(machine, state->m_mmc5_vrom_regA[1], CHRROM); | |
| 1650 | chr2_2(machine, state->m_mmc5_vrom_regA[3], CHRROM); | |
| 1651 | chr2_4(machine, state->m_mmc5_vrom_regA[5], CHRROM); | |
| 1652 | chr2_6(machine, state->m_mmc5_vrom_regA[7], CHRROM); | |
| 1653 | break; | |
| 1654 | ||
| 1655 | case 3: // 1k banks | |
| 1656 | chr1_0(machine, state->m_mmc5_vrom_regA[0], CHRROM); | |
| 1657 | chr1_1(machine, state->m_mmc5_vrom_regA[1], CHRROM); | |
| 1658 | chr1_2(machine, state->m_mmc5_vrom_regA[2], CHRROM); | |
| 1659 | chr1_3(machine, state->m_mmc5_vrom_regA[3], CHRROM); | |
| 1660 | chr1_4(machine, state->m_mmc5_vrom_regA[4], CHRROM); | |
| 1661 | chr1_5(machine, state->m_mmc5_vrom_regA[5], CHRROM); | |
| 1662 | chr1_6(machine, state->m_mmc5_vrom_regA[6], CHRROM); | |
| 1663 | chr1_7(machine, state->m_mmc5_vrom_regA[7], CHRROM); | |
| 1664 | break; | |
| 1665 | } | |
| 1666 | } | |
| 1667 | ||
| 1668 | static void mmc5_update_chr_b( running_machine &machine ) | |
| 1669 | { | |
| 1670 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1671 | switch (state->m_mmc5_chr_mode) | |
| 1672 | { | |
| 1673 | case 0: // 8k banks | |
| 1674 | chr8(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM); | |
| 1675 | break; | |
| 1676 | ||
| 1677 | case 1: // 4k banks | |
| 1678 | chr4_0(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM); | |
| 1679 | chr4_4(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM); | |
| 1680 | break; | |
| 1681 | ||
| 1682 | case 2: // 2k banks | |
| 1683 | chr2_0(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1684 | chr2_2(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1685 | chr2_4(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1686 | chr2_6(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1687 | break; | |
| 1688 | ||
| 1689 | case 3: // 1k banks | |
| 1690 | chr1_0(machine, state->m_mmc5_vrom_regB[0], CHRROM); | |
| 1691 | chr1_1(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1692 | chr1_2(machine, state->m_mmc5_vrom_regB[2], CHRROM); | |
| 1693 | chr1_3(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1694 | chr1_4(machine, state->m_mmc5_vrom_regB[0], CHRROM); | |
| 1695 | chr1_5(machine, state->m_mmc5_vrom_regB[1], CHRROM); | |
| 1696 | chr1_6(machine, state->m_mmc5_vrom_regB[2], CHRROM); | |
| 1697 | chr1_7(machine, state->m_mmc5_vrom_regB[3], CHRROM); | |
| 1698 | break; | |
| 1699 | } | |
| 1700 | } | |
| 1701 | #endif | |
| 1702 | ||
| 1703 | static void mmc5_update_prg( running_machine &machine ) | |
| 1704 | { | |
| 1705 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1706 | int bank1, bank2, bank3; | |
| 1707 | ||
| 1708 | switch (state->m_mmc5_prg_mode) | |
| 1709 | { | |
| 1710 | case 0: // 32k banks | |
| 1711 | prg32(machine, state->m_mmc5_prg_regs[3] >> 2); | |
| 1712 | break; | |
| 1713 | ||
| 1714 | case 1: // 16k banks | |
| 1715 | // printf("problema 1: %x\n", state->m_mmc5_prg_regs[1]); | |
| 1716 | bank1 = state->m_mmc5_prg_regs[1]; | |
| 1717 | ||
| 1718 | if (!BIT(bank1, 7)) | |
| 1719 | { | |
| 1720 | state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06); | |
| 1721 | state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1; | |
| 1722 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 1723 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 1724 | } | |
| 1725 | else | |
| 1726 | prg16_89ab(machine, bank1 >> 1); | |
| 1727 | ||
| 1728 | prg16_cdef(machine, state->m_mmc5_prg_regs[3] >> 1); | |
| 1729 | break; | |
| 1730 | ||
| 1731 | case 2: // 16k-8k banks | |
| 1732 | // printf("problema 2: %x %x\n", state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]); | |
| 1733 | bank1 = state->m_mmc5_prg_regs[1]; | |
| 1734 | bank3 = state->m_mmc5_prg_regs[2]; | |
| 1735 | ||
| 1736 | if (!BIT(bank1, 7)) | |
| 1737 | { | |
| 1738 | state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06); | |
| 1739 | state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1; | |
| 1740 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 1741 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 1742 | } | |
| 1743 | else | |
| 1744 | prg16_89ab(machine, (bank1 & 0x7f) >> 1); | |
| 1745 | ||
| 1746 | if (!BIT(bank3, 7)) | |
| 1747 | { | |
| 1748 | state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07); | |
| 1749 | memory_set_bank(machine, "bank3", state->m_prg_bank[2]); | |
| 1750 | } | |
| 1751 | else | |
| 1752 | prg8_cd(machine, bank3 & 0x7f); | |
| 1753 | ||
| 1754 | prg8_ef(machine, state->m_mmc5_prg_regs[3]); | |
| 1755 | break; | |
| 1756 | ||
| 1757 | case 3: // 8k banks | |
| 1758 | // printf("problema 3: %x %x %x\n", state->m_mmc5_prg_regs[0], state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]); | |
| 1759 | bank1 = state->m_mmc5_prg_regs[0]; | |
| 1760 | bank2 = state->m_mmc5_prg_regs[1]; | |
| 1761 | bank3 = state->m_mmc5_prg_regs[2]; | |
| 1762 | ||
| 1763 | if (!BIT(bank1, 7)) | |
| 1764 | { | |
| 1765 | state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x07); | |
| 1766 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 1767 | } | |
| 1768 | else | |
| 1769 | prg8_89(machine, bank1 & 0x7f); | |
| 1770 | ||
| 1771 | if (!BIT(bank2, 7)) | |
| 1772 | { | |
| 1773 | state->m_prg_bank[1] = state->m_prg_chunks + (bank2 & 0x07); | |
| 1774 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 1775 | } | |
| 1776 | else | |
| 1777 | prg8_ab(machine, bank2 & 0x7f); | |
| 1778 | ||
| 1779 | if (!BIT(bank3, 7)) | |
| 1780 | { | |
| 1781 | state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07); | |
| 1782 | memory_set_bank(machine, "bank3", state->m_prg_bank[2]); | |
| 1783 | } | |
| 1784 | else | |
| 1785 | prg8_cd(machine, bank3 & 0x7f); | |
| 1786 | ||
| 1787 | prg8_ef(machine, state->m_mmc5_prg_regs[3]); | |
| 1788 | break; | |
| 1789 | } | |
| 1790 | } | |
| 1791 | ||
| 1792 | static void mmc5_update_render_mode( running_machine &machine ) | |
| 1793 | { | |
| 1794 | } | |
| 1795 | ||
| 1796 | static void mmc5_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 1797 | { | |
| 1798 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1799 | ||
| 1800 | #if 1 | |
| 1801 | if (scanline == 0) | |
| 1802 | state->m_IRQ_status |= 0x40; | |
| 1803 | else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 1804 | state->m_IRQ_status &= ~0x40; | |
| 1805 | #endif | |
| 1806 | ||
| 1807 | if (scanline == state->m_IRQ_count) | |
| 1808 | { | |
| 1809 | if (state->m_IRQ_enable) | |
| 1810 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1811 | ||
| 1812 | state->m_IRQ_status = 0xff; | |
| 1813 | } | |
| 1814 | ||
| 1815 | /* FIXME: this is ok, but then we would need to update them again when we have the BG Hblank | |
| 1816 | I leave it commented out until the PPU is updated for this */ | |
| 1817 | // if (ppu2c0x_is_sprite_8x16(state->m_ppu) || state->m_mmc5_last_chr_a) | |
| 1818 | // mmc5_update_chr_a(device->machine()); | |
| 1819 | // else | |
| 1820 | // mmc5_update_chr_b(device->machine()); | |
| 1821 | } | |
| 1822 | ||
| 1823 | static void mmc5_ppu_mirror( running_machine &machine, int page, int src ) | |
| 1824 | { | |
| 1825 | switch (src) | |
| 1826 | { | |
| 1827 | case 0: /* CIRAM0 */ | |
| 1828 | set_nt_page(machine, page, CIRAM, 0, 1); | |
| 1829 | break; | |
| 1830 | case 1: /* CIRAM1 */ | |
| 1831 | set_nt_page(machine, page, CIRAM, 1, 1); | |
| 1832 | break; | |
| 1833 | case 2: /* ExRAM */ | |
| 1834 | set_nt_page(machine, page, EXRAM, 0, 1); // actually only works during rendering. | |
| 1835 | break; | |
| 1836 | case 3: /* Fill Registers */ | |
| 1837 | set_nt_page(machine, page, MMC5FILL, 0, 0); | |
| 1838 | break; | |
| 1839 | default: | |
| 1840 | fatalerror("This should never happen"); | |
| 1841 | break; | |
| 1842 | } | |
| 1843 | } | |
| 1844 | ||
| 1845 | static READ8_HANDLER( exrom_l_r ) | |
| 1846 | { | |
| 1847 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1848 | int retVal; | |
| 1849 | ||
| 1850 | /* $5c00 - $5fff: extended videoram attributes */ | |
| 1851 | if ((offset >= 0x1b00) && (offset <= 0x1eff)) | |
| 1852 | { | |
| 1853 | return state->m_mapper_ram[offset - 0x1b00]; | |
| 1854 | } | |
| 1855 | ||
| 1856 | switch (offset) | |
| 1857 | { | |
| 1858 | case 0x1104: /* $5204 */ | |
| 1859 | #if 0 | |
| 1860 | if (current_scanline == MMC5_scanline) | |
| 1861 | return 0x80; | |
| 1862 | else | |
| 1863 | return 0x00; | |
| 1864 | #else | |
| 1865 | retVal = state->m_IRQ_status; | |
| 1866 | state->m_IRQ_status &= ~0x80; | |
| 1867 | return retVal; | |
| 1868 | #endif | |
| 1869 | ||
| 1870 | case 0x1105: /* $5205 */ | |
| 1871 | return (state->m_mult1 * state->m_mult2) & 0xff; | |
| 1872 | case 0x1106: /* $5206 */ | |
| 1873 | return ((state->m_mult1 * state->m_mult2) & 0xff00) >> 8; | |
| 1874 | ||
| 1875 | default: | |
| 1876 | logerror("** MMC5 uncaught read, offset: %04x\n", offset + 0x4100); | |
| 1877 | return 0x00; | |
| 1878 | } | |
| 1879 | } | |
| 1880 | ||
| 1881 | ||
| 1882 | static WRITE8_HANDLER( exrom_l_w ) | |
| 1883 | { | |
| 1884 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1885 | ||
| 1886 | // LOG_MMC(("Mapper 5 write, offset: %04x, data: %02x\n", offset + 0x4100, data)); | |
| 1887 | /* Send $5000-$5015 to the sound chip */ | |
| 1888 | if ((offset >= 0xf00) && (offset <= 0xf15)) | |
| 1889 | { | |
| 1890 | nes_psg_w(state->m_sound, offset & 0x1f, data); | |
| 1891 | return; | |
| 1892 | } | |
| 1893 | ||
| 1894 | /* $5c00 - $5fff: extended videoram attributes */ | |
| 1895 | if ((offset >= 0x1b00) && (offset <= 0x1eff)) | |
| 1896 | { | |
| 1897 | if (state->m_MMC5_vram_protect == 0x03) | |
| 1898 | state->m_mapper_ram[offset - 0x1b00] = data; | |
| 1899 | return; | |
| 1900 | } | |
| 1901 | ||
| 1902 | switch (offset) | |
| 1903 | { | |
| 1904 | case 0x1000: /* $5100 */ | |
| 1905 | state->m_mmc5_prg_mode = data & 0x03; | |
| 1906 | // mmc5_update_prg(space->machine()); | |
| 1907 | LOG_MMC(("MMC5 rom bank mode: %02x\n", data)); | |
| 1908 | break; | |
| 1909 | ||
| 1910 | case 0x1001: /* $5101 */ | |
| 1911 | state->m_mmc5_chr_mode = data & 0x03; | |
| 1912 | // update chr | |
| 1913 | LOG_MMC(("MMC5 vrom bank mode: %02x\n", data)); | |
| 1914 | break; | |
| 1915 | ||
| 1916 | case 0x1002: /* $5102 */ | |
| 1917 | if (data == 0x02) | |
| 1918 | state->m_MMC5_vram_protect |= 1; | |
| 1919 | else | |
| 1920 | state->m_MMC5_vram_protect = 0; | |
| 1921 | LOG_MMC(("MMC5 vram protect 1: %02x\n", data)); | |
| 1922 | break; | |
| 1923 | case 0x1003: /* 5103 */ | |
| 1924 | if (data == 0x01) | |
| 1925 | state->m_MMC5_vram_protect |= 2; | |
| 1926 | else | |
| 1927 | state->m_MMC5_vram_protect = 0; | |
| 1928 | LOG_MMC(("MMC5 vram protect 2: %02x\n", data)); | |
| 1929 | break; | |
| 1930 | ||
| 1931 | case 0x1004: /* $5104 - Extra VRAM (EXRAM) control */ | |
| 1932 | state->m_mmc5_vram_control = data & 0x03; | |
| 1933 | // update render | |
| 1934 | mmc5_update_render_mode(space->machine()); | |
| 1935 | LOG_MMC(("MMC5 exram control: %02x\n", data)); | |
| 1936 | break; | |
| 1937 | ||
| 1938 | case 0x1005: /* $5105 */ | |
| 1939 | mmc5_ppu_mirror(space->machine(), 0, data & 0x03); | |
| 1940 | mmc5_ppu_mirror(space->machine(), 1, (data & 0x0c) >> 2); | |
| 1941 | mmc5_ppu_mirror(space->machine(), 2, (data & 0x30) >> 4); | |
| 1942 | mmc5_ppu_mirror(space->machine(), 3, (data & 0xc0) >> 6); | |
| 1943 | // update render | |
| 1944 | mmc5_update_render_mode(space->machine()); | |
| 1945 | break; | |
| 1946 | ||
| 1947 | /* tile data for MMC5 flood-fill NT mode */ | |
| 1948 | case 0x1006: | |
| 1949 | state->m_MMC5_floodtile = data; | |
| 1950 | break; | |
| 1951 | ||
| 1952 | /* attr data for MMC5 flood-fill NT mode */ | |
| 1953 | case 0x1007: | |
| 1954 | switch (data & 3) | |
| 1955 | { | |
| 1956 | default: | |
| 1957 | case 0: state->m_MMC5_floodattr = 0x00; break; | |
| 1958 | case 1: state->m_MMC5_floodattr = 0x55; break; | |
| 1959 | case 2: state->m_MMC5_floodattr = 0xaa; break; | |
| 1960 | case 3: state->m_MMC5_floodattr = 0xff; break; | |
| 1961 | } | |
| 1962 | break; | |
| 1963 | ||
| 1964 | case 0x1013: /* $5113 */ | |
| 1965 | LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07)); | |
| 1966 | // FIXME: a few Koei games have both WRAM & BWRAM but here we don't support this (yet) | |
| 1967 | if (state->m_battery) | |
| 1968 | wram_bank(space->machine(), data, NES_BATTERY); | |
| 1969 | else | |
| 1970 | wram_bank(space->machine(), data, NES_WRAM); | |
| 1971 | break; | |
| 1972 | ||
| 1973 | ||
| 1974 | case 0x1014: /* $5114 */ | |
| 1975 | case 0x1015: /* $5115 */ | |
| 1976 | case 0x1016: /* $5116 */ | |
| 1977 | case 0x1017: /* $5117 */ | |
| 1978 | state->m_mmc5_prg_regs[offset & 3] = data; | |
| 1979 | mmc5_update_prg(space->machine()); | |
| 1980 | break; | |
| 1981 | ||
| 1982 | #if 0 | |
| 1983 | // these do not work as expected... I guess we definitely need the bank update at proper times (with BG vs. sprite timing) | |
| 1984 | case 0x1020: /* $5120 */ | |
| 1985 | case 0x1021: /* $5121 */ | |
| 1986 | case 0x1022: /* $5122 */ | |
| 1987 | case 0x1023: /* $5123 */ | |
| 1988 | case 0x1024: /* $5124 */ | |
| 1989 | case 0x1025: /* $5125 */ | |
| 1990 | case 0x1026: /* $5126 */ | |
| 1991 | case 0x1027: /* $5127 */ | |
| 1992 | data |= (state->m_mmc5_chr_high << 8); | |
| 1993 | if (!state->m_mmc5_last_chr_a) | |
| 1994 | { | |
| 1995 | state->m_mmc5_vrom_regA[offset & 0x07] = data; | |
| 1996 | state->m_mmc5_last_chr_a = 1; | |
| 1997 | if (ppu2c0x_get_current_scanline(state->m_ppu) == 240 || !ppu2c0x_is_sprite_8x16(state->m_ppu)) | |
| 1998 | mmc5_update_chr_a(space->machine()); | |
| 1999 | } | |
| 2000 | break; | |
| 2001 | ||
| 2002 | ||
| 2003 | case 0x1028: /* $5128 */ | |
| 2004 | case 0x1029: /* $5129 */ | |
| 2005 | case 0x102a: /* $512a */ | |
| 2006 | case 0x102b: /* $512b */ | |
| 2007 | data |= (state->m_mmc5_chr_high << 8); | |
| 2008 | state->m_mmc5_vrom_regB[offset & 0x03] = data; | |
| 2009 | state->m_mmc5_last_chr_a = 0; | |
| 2010 | if (ppu2c0x_get_current_scanline(state->m_ppu) == 240 || !ppu2c0x_is_sprite_8x16(state->m_ppu)) | |
| 2011 | mmc5_update_chr_b(space->machine()); | |
| 2012 | break; | |
| 2013 | ||
| 2014 | case 0x1030: /* $5130 */ | |
| 2015 | state->m_mmc5_chr_high = data & 0x03; | |
| 2016 | if (state->m_mmc5_vram_control == 1) | |
| 2017 | { | |
| 2018 | // in this case state->m_mmc5_chr_high selects which 256KB of CHR ROM | |
| 2019 | // is to be used for all background tiles on the screen. | |
| 2020 | } | |
| 2021 | break; | |
| 2022 | ||
| 2023 | #endif | |
| 2024 | ||
| 2025 | case 0x1020: /* $5120 */ | |
| 2026 | LOG_MMC(("MMC5 $5120 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2027 | switch (state->m_mmc5_chr_mode) | |
| 2028 | { | |
| 2029 | case 0x03: | |
| 2030 | /* 1k switch */ | |
| 2031 | state->m_MMC5_vrom_bank[0] = data | (state->m_mmc5_high_chr << 8); | |
| 2032 | // mapper5_sync_vrom(0); | |
| 2033 | chr1_0(space->machine(), state->m_MMC5_vrom_bank[0], CHRROM); | |
| 2034 | // state->m_nes_vram_sprite[0] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2035 | // vrom_next[0] = 4; | |
| 2036 | // vrom_page_a = 1; | |
| 2037 | // vrom_page_b = 0; | |
| 2038 | break; | |
| 2039 | } | |
| 2040 | break; | |
| 2041 | case 0x1021: /* $5121 */ | |
| 2042 | LOG_MMC(("MMC5 $5121 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2043 | switch (state->m_mmc5_chr_mode) | |
| 2044 | { | |
| 2045 | case 0x02: | |
| 2046 | /* 2k switch */ | |
| 2047 | chr2_0(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2048 | break; | |
| 2049 | case 0x03: | |
| 2050 | /* 1k switch */ | |
| 2051 | state->m_MMC5_vrom_bank[1] = data | (state->m_mmc5_high_chr << 8); | |
| 2052 | // mapper5_sync_vrom(0); | |
| 2053 | chr1_1(space->machine(), state->m_MMC5_vrom_bank[1], CHRROM); | |
| 2054 | // state->m_nes_vram_sprite[1] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2055 | // vrom_next[1] = 5; | |
| 2056 | // vrom_page_a = 1; | |
| 2057 | // vrom_page_b = 0; | |
| 2058 | break; | |
| 2059 | } | |
| 2060 | break; | |
| 2061 | case 0x1022: /* $5122 */ | |
| 2062 | LOG_MMC(("MMC5 $5122 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2063 | switch (state->m_mmc5_chr_mode) | |
| 2064 | { | |
| 2065 | case 0x03: | |
| 2066 | /* 1k switch */ | |
| 2067 | state->m_MMC5_vrom_bank[2] = data | (state->m_mmc5_high_chr << 8); | |
| 2068 | // mapper5_sync_vrom(0); | |
| 2069 | chr1_2(space->machine(), state->m_MMC5_vrom_bank[2], CHRROM); | |
| 2070 | // state->m_nes_vram_sprite[2] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2071 | // vrom_next[2] = 6; | |
| 2072 | // vrom_page_a = 1; | |
| 2073 | // vrom_page_b = 0; | |
| 2074 | break; | |
| 2075 | } | |
| 2076 | break; | |
| 2077 | case 0x1023: /* $5123 */ | |
| 2078 | LOG_MMC(("MMC5 $5123 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2079 | switch (state->m_mmc5_chr_mode) | |
| 2080 | { | |
| 2081 | case 0x01: | |
| 2082 | chr4_0(space->machine(), data, CHRROM); | |
| 2083 | break; | |
| 2084 | case 0x02: | |
| 2085 | /* 2k switch */ | |
| 2086 | chr2_2(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2087 | break; | |
| 2088 | case 0x03: | |
| 2089 | /* 1k switch */ | |
| 2090 | state->m_MMC5_vrom_bank[3] = data | (state->m_mmc5_high_chr << 8); | |
| 2091 | // mapper5_sync_vrom(0); | |
| 2092 | chr1_3(space->machine(), state->m_MMC5_vrom_bank[3], CHRROM); | |
| 2093 | // state->m_nes_vram_sprite[3] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2094 | // vrom_next[3] = 7; | |
| 2095 | // vrom_page_a = 1; | |
| 2096 | // vrom_page_b = 0; | |
| 2097 | break; | |
| 2098 | } | |
| 2099 | break; | |
| 2100 | case 0x1024: /* $5124 */ | |
| 2101 | LOG_MMC(("MMC5 $5124 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2102 | switch (state->m_mmc5_chr_mode) | |
| 2103 | { | |
| 2104 | case 0x03: | |
| 2105 | /* 1k switch */ | |
| 2106 | state->m_MMC5_vrom_bank[4] = data | (state->m_mmc5_high_chr << 8); | |
| 2107 | // mapper5_sync_vrom(0); | |
| 2108 | chr1_4(space->machine(), state->m_MMC5_vrom_bank[4], CHRROM); | |
| 2109 | // state->m_nes_vram_sprite[4] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2110 | // vrom_next[0] = 0; | |
| 2111 | // vrom_page_a = 0; | |
| 2112 | // vrom_page_b = 0; | |
| 2113 | break; | |
| 2114 | } | |
| 2115 | break; | |
| 2116 | case 0x1025: /* $5125 */ | |
| 2117 | LOG_MMC(("MMC5 $5125 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2118 | switch (state->m_mmc5_chr_mode) | |
| 2119 | { | |
| 2120 | case 0x02: | |
| 2121 | /* 2k switch */ | |
| 2122 | chr2_4(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2123 | break; | |
| 2124 | case 0x03: | |
| 2125 | /* 1k switch */ | |
| 2126 | state->m_MMC5_vrom_bank[5] = data | (state->m_mmc5_high_chr << 8); | |
| 2127 | // mapper5_sync_vrom(0); | |
| 2128 | chr1_5(space->machine(), state->m_MMC5_vrom_bank[5], CHRROM); | |
| 2129 | // state->m_nes_vram_sprite[5] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2130 | // vrom_next[1] = 1; | |
| 2131 | // vrom_page_a = 0; | |
| 2132 | // vrom_page_b = 0; | |
| 2133 | break; | |
| 2134 | } | |
| 2135 | break; | |
| 2136 | case 0x1026: /* $5126 */ | |
| 2137 | LOG_MMC(("MMC5 $5126 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2138 | switch (state->m_mmc5_chr_mode) | |
| 2139 | { | |
| 2140 | case 0x03: | |
| 2141 | /* 1k switch */ | |
| 2142 | state->m_MMC5_vrom_bank[6] = data | (state->m_mmc5_high_chr << 8); | |
| 2143 | // mapper5_sync_vrom(0); | |
| 2144 | chr1_6(space->machine(), state->m_MMC5_vrom_bank[6], CHRROM); | |
| 2145 | // state->m_nes_vram_sprite[6] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2146 | // vrom_next[2] = 2; | |
| 2147 | // vrom_page_a = 0; | |
| 2148 | // vrom_page_b = 0; | |
| 2149 | break; | |
| 2150 | } | |
| 2151 | break; | |
| 2152 | case 0x1027: /* $5127 */ | |
| 2153 | LOG_MMC(("MMC5 $5127 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2154 | switch (state->m_mmc5_chr_mode) | |
| 2155 | { | |
| 2156 | case 0x00: | |
| 2157 | /* 8k switch */ | |
| 2158 | chr8(space->machine(), data, CHRROM); | |
| 2159 | break; | |
| 2160 | case 0x01: | |
| 2161 | /* 4k switch */ | |
| 2162 | chr4_4(space->machine(), data, CHRROM); | |
| 2163 | break; | |
| 2164 | case 0x02: | |
| 2165 | /* 2k switch */ | |
| 2166 | chr2_6(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2167 | break; | |
| 2168 | case 0x03: | |
| 2169 | /* 1k switch */ | |
| 2170 | state->m_MMC5_vrom_bank[7] = data | (state->m_mmc5_high_chr << 8); | |
| 2171 | // mapper5_sync_vrom(0); | |
| 2172 | chr1_7(space->machine(), state->m_MMC5_vrom_bank[7], CHRROM); | |
| 2173 | // state->m_nes_vram_sprite[7] = state->m_MMC5_vrom_bank[0] * 64; | |
| 2174 | // vrom_next[3] = 3; | |
| 2175 | // vrom_page_a = 0; | |
| 2176 | // vrom_page_b = 0; | |
| 2177 | break; | |
| 2178 | } | |
| 2179 | break; | |
| 2180 | case 0x1028: /* $5128 */ | |
| 2181 | LOG_MMC(("MMC5 $5128 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2182 | switch (state->m_mmc5_chr_mode) | |
| 2183 | { | |
| 2184 | case 0x03: | |
| 2185 | /* 1k switch */ | |
| 2186 | state->m_MMC5_vrom_bank[8] = data | (state->m_mmc5_high_chr << 8); | |
| 2187 | // nes_vram[vrom_next[0]] = data * 64; | |
| 2188 | // nes_vram[0 + (vrom_page_a*4)] = data * 64; | |
| 2189 | // nes_vram[0] = data * 64; | |
| 2190 | chr1_4(space->machine(), state->m_MMC5_vrom_bank[8], CHRROM); | |
| 2191 | // mapper5_sync_vrom(1); | |
| 2192 | if (!state->m_vrom_page_b) | |
| 2193 | { | |
| 2194 | state->m_vrom_page_a ^= 0x01; | |
| 2195 | state->m_vrom_page_b = 1; | |
| 2196 | } | |
| 2197 | break; | |
| 2198 | } | |
| 2199 | break; | |
| 2200 | case 0x1029: /* $5129 */ | |
| 2201 | LOG_MMC(("MMC5 $5129 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2202 | switch (state->m_mmc5_chr_mode) | |
| 2203 | { | |
| 2204 | case 0x02: | |
| 2205 | /* 2k switch */ | |
| 2206 | chr2_0(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2207 | chr2_4(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2208 | break; | |
| 2209 | case 0x03: | |
| 2210 | /* 1k switch */ | |
| 2211 | state->m_MMC5_vrom_bank[9] = data | (state->m_mmc5_high_chr << 8); | |
| 2212 | // nes_vram[vrom_next[1]] = data * 64; | |
| 2213 | // nes_vram[1 + (vrom_page_a*4)] = data * 64; | |
| 2214 | // nes_vram[1] = data * 64; | |
| 2215 | chr1_5(space->machine(), state->m_MMC5_vrom_bank[9], CHRROM); | |
| 2216 | // mapper5_sync_vrom(1); | |
| 2217 | if (!state->m_vrom_page_b) | |
| 2218 | { | |
| 2219 | state->m_vrom_page_a ^= 0x01; | |
| 2220 | state->m_vrom_page_b = 1; | |
| 2221 | } | |
| 2222 | break; | |
| 2223 | } | |
| 2224 | break; | |
| 2225 | case 0x102a: /* $512a */ | |
| 2226 | LOG_MMC(("MMC5 $512a vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2227 | switch (state->m_mmc5_chr_mode) | |
| 2228 | { | |
| 2229 | case 0x03: | |
| 2230 | /* 1k switch */ | |
| 2231 | state->m_MMC5_vrom_bank[10] = data | (state->m_mmc5_high_chr << 8); | |
| 2232 | // nes_vram[vrom_next[2]] = data * 64; | |
| 2233 | // nes_vram[2 + (vrom_page_a*4)] = data * 64; | |
| 2234 | // nes_vram[2] = data * 64; | |
| 2235 | chr1_6(space->machine(), state->m_MMC5_vrom_bank[10], CHRROM); | |
| 2236 | // mapper5_sync_vrom(1); | |
| 2237 | if (!state->m_vrom_page_b) | |
| 2238 | { | |
| 2239 | state->m_vrom_page_a ^= 0x01; | |
| 2240 | state->m_vrom_page_b = 1; | |
| 2241 | } | |
| 2242 | break; | |
| 2243 | } | |
| 2244 | break; | |
| 2245 | case 0x102b: /* $512b */ | |
| 2246 | LOG_MMC(("MMC5 $512b vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode)); | |
| 2247 | switch (state->m_mmc5_chr_mode) | |
| 2248 | { | |
| 2249 | case 0x00: | |
| 2250 | /* 8k switch */ | |
| 2251 | /* switches in first half of an 8K bank!) */ | |
| 2252 | chr4_0(space->machine(), data << 1, CHRROM); | |
| 2253 | chr4_4(space->machine(), data << 1, CHRROM); | |
| 2254 | break; | |
| 2255 | case 0x01: | |
| 2256 | /* 4k switch */ | |
| 2257 | chr4_0(space->machine(), data, CHRROM); | |
| 2258 | chr4_4(space->machine(), data, CHRROM); | |
| 2259 | break; | |
| 2260 | case 0x02: | |
| 2261 | /* 2k switch */ | |
| 2262 | chr2_2(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2263 | chr2_6(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM); | |
| 2264 | break; | |
| 2265 | case 0x03: | |
| 2266 | /* 1k switch */ | |
| 2267 | state->m_MMC5_vrom_bank[11] = data | (state->m_mmc5_high_chr << 8); | |
| 2268 | // nes_vram[vrom_next[3]] = data * 64; | |
| 2269 | // nes_vram[3 + (vrom_page_a*4)] = data * 64; | |
| 2270 | // nes_vram[3] = data * 64; | |
| 2271 | chr1_7(space->machine(), state->m_MMC5_vrom_bank[11], CHRROM); | |
| 2272 | // mapper5_sync_vrom(1); | |
| 2273 | if (!state->m_vrom_page_b) | |
| 2274 | { | |
| 2275 | state->m_vrom_page_a ^= 0x01; | |
| 2276 | state->m_vrom_page_b = 1; | |
| 2277 | } | |
| 2278 | break; | |
| 2279 | } | |
| 2280 | break; | |
| 2281 | ||
| 2282 | case 0x1030: /* $5130 */ | |
| 2283 | state->m_mmc5_high_chr = data & 0x03; | |
| 2284 | if (state->m_mmc5_vram_control == 1) | |
| 2285 | { | |
| 2286 | // in this case state->m_mmc5_high_chr selects which 256KB of CHR ROM | |
| 2287 | // is to be used for all background tiles on the screen. | |
| 2288 | } | |
| 2289 | break; | |
| 2290 | ||
| 2291 | ||
| 2292 | case 0x1100: /* $5200 */ | |
| 2293 | state->m_mmc5_split_scr = data; | |
| 2294 | // in EX2 and EX3 modes, no split screen | |
| 2295 | if (state->m_mmc5_vram_control & 0x02) | |
| 2296 | state->m_mmc5_split_scr &= 0x7f; | |
| 2297 | state->m_mmc5_split_ctrl = data; | |
| 2298 | break; | |
| 2299 | ||
| 2300 | case 0x1101: /* $5201 */ | |
| 2301 | state->m_mmc5_split_yst = (data >= 240) ? data - 16 : data; | |
| 2302 | break; | |
| 2303 | ||
| 2304 | case 0x1102: /* $5202 */ | |
| 2305 | state->m_mmc5_split_bank = data; | |
| 2306 | break; | |
| 2307 | ||
| 2308 | case 0x1103: /* $5203 */ | |
| 2309 | state->m_IRQ_count = data; | |
| 2310 | state->m_MMC5_scanline = data; | |
| 2311 | LOG_MMC(("MMC5 irq scanline: %d\n", state->m_IRQ_count)); | |
| 2312 | break; | |
| 2313 | case 0x1104: /* $5204 */ | |
| 2314 | state->m_IRQ_enable = data & 0x80; | |
| 2315 | LOG_MMC(("MMC5 irq enable: %02x\n", data)); | |
| 2316 | break; | |
| 2317 | case 0x1105: /* $5205 */ | |
| 2318 | state->m_mult1 = data; | |
| 2319 | break; | |
| 2320 | case 0x1106: /* $5206 */ | |
| 2321 | state->m_mult2 = data; | |
| 2322 | break; | |
| 2323 | ||
| 2324 | default: | |
| 2325 | logerror("** MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data); | |
| 2326 | break; | |
| 2327 | } | |
| 2328 | } | |
| 2329 | ||
| 2330 | /************************************************************* | |
| 2331 | ||
| 2332 | NTBROM & Sunsoft-4 board emulation | |
| 2333 | ||
| 2334 | Part of this can be used also for Sunsoft Double Cassette | |
| 2335 | System... which games use it? | |
| 2336 | ||
| 2337 | iNES: mapper 68 | |
| 2338 | ||
| 2339 | *************************************************************/ | |
| 2340 | ||
| 2341 | static void ntbrom_mirror( running_machine &machine, int mirror, int mirr0, int mirr1 ) | |
| 2342 | { | |
| 2343 | switch (mirror) | |
| 2344 | { | |
| 2345 | case 0x00: | |
| 2346 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 2347 | break; | |
| 2348 | case 0x01: | |
| 2349 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 2350 | break; | |
| 2351 | case 0x02: | |
| 2352 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 2353 | break; | |
| 2354 | case 0x03: | |
| 2355 | set_nt_mirroring(machine, PPU_MIRROR_HIGH); | |
| 2356 | break; | |
| 2357 | case 0x10: | |
| 2358 | set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0); | |
| 2359 | set_nt_page(machine, 1, ROM, mirr1 | 0x80, 0); | |
| 2360 | set_nt_page(machine, 2, ROM, mirr0 | 0x80, 0); | |
| 2361 | set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0); | |
| 2362 | break; | |
| 2363 | case 0x11: | |
| 2364 | set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0); | |
| 2365 | set_nt_page(machine, 1, ROM, mirr0 | 0x80, 0); | |
| 2366 | set_nt_page(machine, 2, ROM, mirr1 | 0x80, 0); | |
| 2367 | set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0); | |
| 2368 | break; | |
| 2369 | case 0x12: | |
| 2370 | set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0); | |
| 2371 | set_nt_page(machine, 1, ROM, mirr0 | 0x80, 0); | |
| 2372 | set_nt_page(machine, 2, ROM, mirr0 | 0x80, 0); | |
| 2373 | set_nt_page(machine, 3, ROM, mirr0 | 0x80, 0); | |
| 2374 | break; | |
| 2375 | case 0x13: | |
| 2376 | set_nt_page(machine, 0, ROM, mirr1 | 0x80, 0); | |
| 2377 | set_nt_page(machine, 1, ROM, mirr1 | 0x80, 0); | |
| 2378 | set_nt_page(machine, 2, ROM, mirr1 | 0x80, 0); | |
| 2379 | set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0); | |
| 2380 | break; | |
| 2381 | } | |
| 2382 | } | |
| 2383 | ||
| 2384 | static WRITE8_HANDLER( ntbrom_w ) | |
| 2385 | { | |
| 2386 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2387 | ||
| 2388 | LOG_MMC(("ntbrom_w, offset %04x, data: %02x\n", offset, data)); | |
| 2389 | ||
| 2390 | switch (offset & 0x7000) | |
| 2391 | { | |
| 2392 | case 0x0000: | |
| 2393 | chr2_0(space->machine(), data, CHRROM); | |
| 2394 | break; | |
| 2395 | case 0x1000: | |
| 2396 | chr2_2(space->machine(), data, CHRROM); | |
| 2397 | break; | |
| 2398 | case 0x2000: | |
| 2399 | chr2_4(space->machine(), data, CHRROM); | |
| 2400 | break; | |
| 2401 | case 0x3000: | |
| 2402 | chr2_6(space->machine(), data, CHRROM); | |
| 2403 | break; | |
| 2404 | case 0x4000: | |
| 2405 | state->m_mmc_latch1 = data & 0x7f; | |
| 2406 | ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2); | |
| 2407 | break; | |
| 2408 | case 0x5000: | |
| 2409 | state->m_mmc_latch2 = data & 0x7f; | |
| 2410 | ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2); | |
| 2411 | break; | |
| 2412 | case 0x6000: | |
| 2413 | state->m_mmc_reg[0] = data & 0x13; | |
| 2414 | ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2); | |
| 2415 | break; | |
| 2416 | case 0x7000: | |
| 2417 | prg16_89ab(space->machine(), data); | |
| 2418 | break; | |
| 2419 | default: | |
| 2420 | LOG_MMC(("ntbrom_w uncaught write, offset: %04x, data: %02x\n", offset, data)); | |
| 2421 | break; | |
| 2422 | } | |
| 2423 | } | |
| 2424 | ||
| 2425 | /************************************************************* | |
| 2426 | ||
| 2427 | JxROM & Sunsoft 5A / 5B / FME7 board emulation | |
| 2428 | ||
| 2429 | Notice that Sunsoft-5B = FME7 + sound chip (the latter being | |
| 2430 | currently unemulated in MESS) | |
| 2431 | ||
| 2432 | iNES: mapper 69 | |
| 2433 | ||
| 2434 | *************************************************************/ | |
| 2435 | ||
| 2436 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 2437 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 2438 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 2439 | static void jxrom_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 2440 | { | |
| 2441 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 2442 | ||
| 2443 | /* TODO: change to reflect the actual number of cycles spent */ | |
| 2444 | if ((state->m_IRQ_enable & 0x80) && (state->m_IRQ_enable & 0x01)) | |
| 2445 | { | |
| 2446 | if (state->m_IRQ_count <= 114) | |
| 2447 | { | |
| 2448 | state->m_IRQ_count = 0xffff; | |
| 2449 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 2450 | } | |
| 2451 | else | |
| 2452 | state->m_IRQ_count -= 114; | |
| 2453 | } | |
| 2454 | else if (state->m_IRQ_enable & 0x01) // if enable bit 7 is not set, only decrement the counter! | |
| 2455 | { | |
| 2456 | if (state->m_IRQ_count <= 114) | |
| 2457 | state->m_IRQ_count = 0xffff; | |
| 2458 | else | |
| 2459 | state->m_IRQ_count -= 114; | |
| 2460 | } | |
| 2461 | } | |
| 2462 | ||
| 2463 | static WRITE8_HANDLER( jxrom_w ) | |
| 2464 | { | |
| 2465 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2466 | LOG_MMC(("jxrom_w, offset %04x, data: %02x\n", offset, data)); | |
| 2467 | ||
| 2468 | switch (offset & 0x6000) | |
| 2469 | { | |
| 2470 | case 0x0000: | |
| 2471 | state->m_mmc_latch1 = data & 0x0f; | |
| 2472 | break; | |
| 2473 | ||
| 2474 | case 0x2000: | |
| 2475 | switch (state->m_mmc_latch1) | |
| 2476 | { | |
| 2477 | case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: | |
| 2478 | chr1_x(space->machine(), state->m_mmc_latch1, data, CHRROM); | |
| 2479 | break; | |
| 2480 | ||
| 2481 | case 8: | |
| 2482 | if (!(data & 0x40)) | |
| 2483 | { | |
| 2484 | // is PRG ROM | |
| 2485 | space->unmap_write(0x6000, 0x7fff); | |
| 2486 | prg8_67(space->machine(), data & 0x3f); | |
| 2487 | } | |
| 2488 | else if (data & 0x80) | |
| 2489 | { | |
| 2490 | // is PRG RAM | |
| 2491 | space->install_write_bank(0x6000, 0x7fff, "bank5"); | |
| 2492 | state->m_prg_bank[4] = state->m_battery_bank5_start + (data & 0x3f); | |
| 2493 | memory_set_bank(space->machine(), "bank5", state->m_prg_bank[4]); | |
| 2494 | } | |
| 2495 | break; | |
| 2496 | ||
| 2497 | case 9: | |
| 2498 | prg8_89(space->machine(), data); | |
| 2499 | break; | |
| 2500 | case 0x0a: | |
| 2501 | prg8_ab(space->machine(), data); | |
| 2502 | break; | |
| 2503 | case 0x0b: | |
| 2504 | prg8_cd(space->machine(), data); | |
| 2505 | break; | |
| 2506 | case 0x0c: | |
| 2507 | switch (data & 0x03) | |
| 2508 | { | |
| 2509 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 2510 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 2511 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 2512 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 2513 | } | |
| 2514 | break; | |
| 2515 | case 0x0d: | |
| 2516 | state->m_IRQ_enable = data; | |
| 2517 | break; | |
| 2518 | case 0x0e: | |
| 2519 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 2520 | break; | |
| 2521 | case 0x0f: | |
| 2522 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 2523 | break; | |
| 2524 | } | |
| 2525 | break; | |
| 2526 | ||
| 2527 | /* Here we would have sound command for Sunsoft 5b variant */ | |
| 2528 | // case 0x4000: | |
| 2529 | // case 0x6000: | |
| 2530 | ||
| 2531 | case 0x4000: | |
| 2532 | LOG_MMC(("Sunsoft-5B Sound: Register select write, data: %02x\n", data)); | |
| 2533 | break; | |
| 2534 | case 0x6000: | |
| 2535 | LOG_MMC(("Sunsoft-5B Sound: Register write, data: %02x\n", data)); | |
| 2536 | break; | |
| 2537 | default: | |
| 2538 | logerror("jxrom_w uncaught %04x value: %02x\n", offset + 0x8000, data); | |
| 2539 | break; | |
| 2540 | } | |
| 2541 | } | |
| 2542 | ||
| 2543 | /************************************************************* | |
| 2544 | ||
| 2545 | DxROM & Namcot 3433 - 3443 board emulation | |
| 2546 | ||
| 2547 | Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty | |
| 2548 | ||
| 2549 | These are the same board, but DRROM (and Tengen 800004) have | |
| 2550 | 4-screen mirroring | |
| 2551 | ||
| 2552 | iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring) | |
| 2553 | ||
| 2554 | *************************************************************/ | |
| 2555 | ||
| 2556 | static WRITE8_HANDLER( dxrom_w ) | |
| 2557 | { | |
| 2558 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2559 | LOG_MMC(("dxrom_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2560 | ||
| 2561 | if (offset >= 0x2000) | |
| 2562 | return; | |
| 2563 | ||
| 2564 | switch (offset & 1) | |
| 2565 | { | |
| 2566 | case 1: | |
| 2567 | switch (state->m_mmc_latch1 & 0x07) | |
| 2568 | { | |
| 2569 | case 0: chr2_0(space->machine(), data >> 1, CHRROM); break; | |
| 2570 | case 1: chr2_2(space->machine(), data >> 1, CHRROM); break; | |
| 2571 | case 2: chr1_4(space->machine(), data | 0x40, CHRROM); break; | |
| 2572 | case 3: chr1_5(space->machine(), data | 0x40, CHRROM); break; | |
| 2573 | case 4: chr1_6(space->machine(), data | 0x40, CHRROM); break; | |
| 2574 | case 5: chr1_7(space->machine(), data | 0x40, CHRROM); break; | |
| 2575 | case 6: prg8_89(space->machine(), data); break; | |
| 2576 | case 7: prg8_ab(space->machine(), data); break; | |
| 2577 | } | |
| 2578 | break; | |
| 2579 | case 0: | |
| 2580 | state->m_mmc_latch1 = data; | |
| 2581 | break; | |
| 2582 | } | |
| 2583 | } | |
| 2584 | ||
| 2585 | ||
| 2586 | /************************************************************* | |
| 2587 | ||
| 2588 | Namcot 3453 board emulation | |
| 2589 | ||
| 2590 | Games: Devil Man | |
| 2591 | ||
| 2592 | These are the same as Namcot 34x3, but with additional mirroring | |
| 2593 | control | |
| 2594 | ||
| 2595 | iNES: mapper 154 | |
| 2596 | ||
| 2597 | *************************************************************/ | |
| 2598 | ||
| 2599 | static WRITE8_HANDLER( namcot3453_w ) | |
| 2600 | { | |
| 2601 | LOG_MMC(("namcot3453_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2602 | ||
| 2603 | // additional mirroring control when writing to even addresses | |
| 2604 | if (!(offset & 1)) | |
| 2605 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 2606 | ||
| 2607 | dxrom_w(space, offset, data); | |
| 2608 | } | |
| 2609 | ||
| 2610 | /************************************************************* | |
| 2611 | ||
| 2612 | Namcot 3446 board emulation | |
| 2613 | ||
| 2614 | Games: Digital Devil Monogatari - Megami Tensei | |
| 2615 | ||
| 2616 | These are similar Namcot 34x3, but different bankswitch capabilities | |
| 2617 | ||
| 2618 | iNES: mapper 76 | |
| 2619 | ||
| 2620 | *************************************************************/ | |
| 2621 | ||
| 2622 | static WRITE8_HANDLER( namcot3446_w ) | |
| 2623 | { | |
| 2624 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2625 | LOG_MMC(("namcot3446_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2626 | ||
| 2627 | // NEStopia does not have this! | |
| 2628 | if (offset >= 0x2000) | |
| 2629 | { | |
| 2630 | if (!(offset & 1)) | |
| 2631 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 2632 | return; | |
| 2633 | } | |
| 2634 | ||
| 2635 | switch (offset & 1) | |
| 2636 | { | |
| 2637 | case 1: | |
| 2638 | switch (state->m_mmc_latch1 & 0x07) | |
| 2639 | { | |
| 2640 | case 2: chr2_0(space->machine(), data, CHRROM); break; | |
| 2641 | case 3: chr2_2(space->machine(), data, CHRROM); break; | |
| 2642 | case 4: chr2_4(space->machine(), data, CHRROM); break; | |
| 2643 | case 5: chr2_6(space->machine(), data, CHRROM); break; | |
| 2644 | case 6: BIT(state->m_mmc_latch1, 6) ? prg8_cd(space->machine(), data) : prg8_89(space->machine(), data); break; | |
| 2645 | case 7: prg8_ab(space->machine(), data); break; | |
| 2646 | } | |
| 2647 | break; | |
| 2648 | case 0: | |
| 2649 | state->m_mmc_latch1 = data; | |
| 2650 | break; | |
| 2651 | } | |
| 2652 | } | |
| 2653 | ||
| 2654 | /************************************************************* | |
| 2655 | ||
| 2656 | Namcot 3425 board emulation | |
| 2657 | ||
| 2658 | Games: Dragon Buster | |
| 2659 | ||
| 2660 | These are similar Namcot 34x3, but with NT mirroring (two | |
| 2661 | different modes) | |
| 2662 | ||
| 2663 | iNES: mapper 95 | |
| 2664 | ||
| 2665 | *************************************************************/ | |
| 2666 | ||
| 2667 | static WRITE8_HANDLER( namcot3425_w ) | |
| 2668 | { | |
| 2669 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2670 | UINT8 mode; | |
| 2671 | LOG_MMC(("namcot3425_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2672 | if (offset >= 0x2000) | |
| 2673 | return; | |
| 2674 | ||
| 2675 | switch (offset & 1) | |
| 2676 | { | |
| 2677 | case 1: | |
| 2678 | mode = state->m_mmc_latch1 & 0x07; | |
| 2679 | switch (mode) | |
| 2680 | { | |
| 2681 | case 0: chr2_0(space->machine(), data >> 1, CHRROM); break; | |
| 2682 | case 1: chr2_2(space->machine(), data >> 1, CHRROM); break; | |
| 2683 | case 2: | |
| 2684 | case 3: | |
| 2685 | case 4: | |
| 2686 | case 5: | |
| 2687 | chr1_x(space->machine(), 2 + mode, data, CHRROM); | |
| 2688 | state->m_mmc_reg[mode - 2] = BIT(data, 5); | |
| 2689 | if (!BIT(state->m_mmc_latch1, 7)) | |
| 2690 | { | |
| 2691 | set_nt_page(space->machine(), 0, CIRAM, state->m_mmc_reg[0], 1); | |
| 2692 | set_nt_page(space->machine(), 1, CIRAM, state->m_mmc_reg[1], 1); | |
| 2693 | set_nt_page(space->machine(), 2, CIRAM, state->m_mmc_reg[2], 1); | |
| 2694 | set_nt_page(space->machine(), 3, CIRAM, state->m_mmc_reg[3], 1); | |
| 2695 | } | |
| 2696 | else | |
| 2697 | set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); | |
| 2698 | break; | |
| 2699 | case 6: prg8_89(space->machine(), data); break; | |
| 2700 | case 7: prg8_ab(space->machine(), data); break; | |
| 2701 | } | |
| 2702 | break; | |
| 2703 | case 0: | |
| 2704 | state->m_mmc_latch1 = data; | |
| 2705 | break; | |
| 2706 | } | |
| 2707 | } | |
| 2708 | ||
| 2709 | /************************************************************* | |
| 2710 | ||
| 2711 | Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation | |
| 2712 | ||
| 2713 | Games: many Color Dreams and Wisdom Tree titles | |
| 2714 | ||
| 2715 | iNES: mapper 11 | |
| 2716 | ||
| 2717 | In MESS: Supported | |
| 2718 | ||
| 2719 | *************************************************************/ | |
| 2720 | ||
| 2721 | static WRITE8_HANDLER( dis_74x377_w ) | |
| 2722 | { | |
| 2723 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2724 | LOG_MMC(("dis_74x377_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2725 | ||
| 2726 | chr8(space->machine(), data >> 4, state->m_mmc_chr_source); | |
| 2727 | prg32(space->machine(), data & 0x0f); | |
| 2728 | } | |
| 2729 | ||
| 2730 | /************************************************************* | |
| 2731 | ||
| 2732 | Discrete Logic board IC 74x139x74 by Konami & Jaleco | |
| 2733 | ||
| 2734 | iNES: mapper 87 | |
| 2735 | ||
| 2736 | *************************************************************/ | |
| 2737 | ||
| 2738 | static WRITE8_HANDLER( dis_74x139x74_m_w ) | |
| 2739 | { | |
| 2740 | LOG_MMC(("dis_74x139x74_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2741 | ||
| 2742 | chr8(space->machine(), ((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM); | |
| 2743 | } | |
| 2744 | ||
| 2745 | /************************************************************* | |
| 2746 | ||
| 2747 | Discrete Logic board IC 74x161x138 | |
| 2748 | ||
| 2749 | Games: Crime Busters | |
| 2750 | ||
| 2751 | iNES: mapper 38 | |
| 2752 | ||
| 2753 | *************************************************************/ | |
| 2754 | ||
| 2755 | static WRITE8_HANDLER( dis_74x161x138_m_w ) | |
| 2756 | { | |
| 2757 | LOG_MMC(("dis_74x161x138_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2758 | ||
| 2759 | chr8(space->machine(), data >> 2, CHRROM); | |
| 2760 | prg32(space->machine(), data); | |
| 2761 | } | |
| 2762 | ||
| 2763 | /************************************************************* | |
| 2764 | ||
| 2765 | Discrete Logic board IC 74x161x161x32 | |
| 2766 | ||
| 2767 | There are two variants (one with hardwired mirroring, the | |
| 2768 | other with a mirroring control), making necessary two distinct | |
| 2769 | mappers & pcb_id | |
| 2770 | ||
| 2771 | iNES: mappers 70 & 152 | |
| 2772 | ||
| 2773 | *************************************************************/ | |
| 2774 | ||
| 2775 | static WRITE8_HANDLER( dis_74x161x161x32_w ) | |
| 2776 | { | |
| 2777 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2778 | LOG_MMC(("dis_74x161x161x32_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2779 | ||
| 2780 | if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring | |
| 2781 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 2782 | chr8(space->machine(), data, CHRROM); | |
| 2783 | prg16_89ab(space->machine(), data >> 4); | |
| 2784 | } | |
| 2785 | ||
| 2786 | /************************************************************* | |
| 2787 | ||
| 2788 | Bandai LZ93D50 boards emulation | |
| 2789 | ||
| 2790 | There are several variants: plain board with or without SRAM, | |
| 2791 | board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode | |
| 2792 | Reader (DATACH). | |
| 2793 | We currently only emulate the base hardware. | |
| 2794 | ||
| 2795 | Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden, | |
| 2796 | Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam | |
| 2797 | Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam | |
| 2798 | Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump, | |
| 2799 | Famicom Jump II [no EEPROM], Datach Games | |
| 2800 | ||
| 2801 | At the moment, we don't support EEPROM I/O | |
| 2802 | ||
| 2803 | iNES: mappers 16, 153, 157 & 159 | |
| 2804 | ||
| 2805 | In MESS: Supported | |
| 2806 | ||
| 2807 | *************************************************************/ | |
| 2808 | ||
| 2809 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 2810 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 2811 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 2812 | static void bandai_lz_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 2813 | { | |
| 2814 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 2815 | ||
| 2816 | /* 114 is the number of cycles per scanline */ | |
| 2817 | /* TODO: change to reflect the actual number of cycles spent */ | |
| 2818 | if (state->m_IRQ_enable) | |
| 2819 | { | |
| 2820 | if (state->m_IRQ_count <= 114) | |
| 2821 | { | |
| 2822 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 2823 | state->m_IRQ_count = (0xffff - 114 + state->m_IRQ_count); // wrap around the 16 bits counter | |
| 2824 | } | |
| 2825 | state->m_IRQ_count -= 114; | |
| 2826 | } | |
| 2827 | } | |
| 2828 | ||
| 2829 | static WRITE8_HANDLER( lz93d50_w ) | |
| 2830 | { | |
| 2831 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2832 | LOG_MMC(("lz93d50_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2833 | ||
| 2834 | switch (offset & 0x000f) | |
| 2835 | { | |
| 2836 | case 0: case 1: case 2: case 3: | |
| 2837 | case 4: case 5: case 6: case 7: | |
| 2838 | chr1_x(space->machine(), offset & 0x07, data, state->m_mmc_chr_source); | |
| 2839 | break; | |
| 2840 | case 8: | |
| 2841 | prg16_89ab(space->machine(), data); | |
| 2842 | break; | |
| 2843 | case 9: | |
| 2844 | switch (data & 0x03) | |
| 2845 | { | |
| 2846 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 2847 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 2848 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 2849 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 2850 | } | |
| 2851 | break; | |
| 2852 | case 0x0a: | |
| 2853 | state->m_IRQ_enable = data & 0x01; | |
| 2854 | break; | |
| 2855 | case 0x0b: | |
| 2856 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 2857 | break; | |
| 2858 | case 0x0c: | |
| 2859 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 2860 | break; | |
| 2861 | default: | |
| 2862 | logerror("lz93d50_w uncaught write, offset: %04x, data: %02x\n", offset, data); | |
| 2863 | break; | |
| 2864 | } | |
| 2865 | } | |
| 2866 | ||
| 2867 | static WRITE8_HANDLER( lz93d50_m_w ) | |
| 2868 | { | |
| 2869 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2870 | LOG_MMC(("lz93d50_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2871 | ||
| 2872 | if (!state->m_battery && !state->m_wram) | |
| 2873 | lz93d50_w(space, offset & 0x0f, data); | |
| 2874 | else if (state->m_battery) | |
| 2875 | state->m_battery_ram[offset] = data; | |
| 2876 | else | |
| 2877 | state->m_wram[offset] = data; | |
| 2878 | } | |
| 2879 | ||
| 2880 | static void fjump2_set_prg( running_machine &machine ) | |
| 2881 | { | |
| 2882 | nes_state *state = machine.driver_data<nes_state>(); | |
| 2883 | UINT8 mmc_helper = 0; | |
| 2884 | int i; | |
| 2885 | ||
| 2886 | for (i = 0; i < 8; i++) | |
| 2887 | mmc_helper |= ((state->m_mmc_reg[i] & 0x01) << 4); | |
| 2888 | ||
| 2889 | prg16_89ab(machine, mmc_helper | state->m_mmc_latch1); | |
| 2890 | prg16_cdef(machine, mmc_helper | 0x0f); | |
| 2891 | } | |
| 2892 | ||
| 2893 | static WRITE8_HANDLER( fjump2_w ) | |
| 2894 | { | |
| 2895 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2896 | LOG_MMC(("fjump2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2897 | ||
| 2898 | switch (offset & 0x000f) | |
| 2899 | { | |
| 2900 | case 0: case 1: case 2: case 3: | |
| 2901 | case 4: case 5: case 6: case 7: | |
| 2902 | state->m_mmc_reg[offset & 0x000f] = data; | |
| 2903 | fjump2_set_prg(space->machine()); | |
| 2904 | break; | |
| 2905 | case 8: | |
| 2906 | state->m_mmc_latch1 = (data & 0x0f); | |
| 2907 | fjump2_set_prg(space->machine()); | |
| 2908 | break; | |
| 2909 | default: | |
| 2910 | lz93d50_m_w(space, offset & 0x0f, data); | |
| 2911 | break; | |
| 2912 | } | |
| 2913 | } | |
| 2914 | ||
| 2915 | /************************************************************* | |
| 2916 | ||
| 2917 | Bandai Karaoke Studio board emulation | |
| 2918 | ||
| 2919 | Games: Karaoke Studio | |
| 2920 | ||
| 2921 | Note: we currently do not emulate the mic | |
| 2922 | ||
| 2923 | iNES: mapper 188 | |
| 2924 | ||
| 2925 | *************************************************************/ | |
| 2926 | ||
| 2927 | static WRITE8_HANDLER( bandai_ks_w ) | |
| 2928 | { | |
| 2929 | LOG_MMC(("bandai_ks_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2930 | ||
| 2931 | prg16_89ab(space->machine(), data ^ 0x08); | |
| 2932 | } | |
| 2933 | ||
| 2934 | /************************************************************* | |
| 2935 | ||
| 2936 | Bandai Oeka Kids board emulation | |
| 2937 | ||
| 2938 | Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka | |
| 2939 | Kids - Anpanman to Oekaki Shiyou!! | |
| 2940 | ||
| 2941 | iNES: mapper 96 | |
| 2942 | ||
| 2943 | In MESS: Preliminary Support. | |
| 2944 | ||
| 2945 | *************************************************************/ | |
| 2946 | ||
| 2947 | static WRITE8_HANDLER( bandai_ok_w ) | |
| 2948 | { | |
| 2949 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 2950 | UINT8 mmc_helper; | |
| 2951 | LOG_MMC(("mapper96_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2952 | ||
| 2953 | prg32(space->machine(), data); | |
| 2954 | ||
| 2955 | state->m_mmc_latch1 = data; | |
| 2956 | mmc_helper = (state->m_mmc_latch1 & 0x03) | (data & 0x04); | |
| 2957 | chr4_0(space->machine(), mmc_helper, CHRRAM); | |
| 2958 | chr4_4(space->machine(), 0x03 | (data & 0x04), CHRRAM); | |
| 2959 | } | |
| 2960 | ||
| 2961 | /************************************************************* | |
| 2962 | ||
| 2963 | Irem LROG017 - Discrete board emulation (74*161/161/21/138) | |
| 2964 | ||
| 2965 | Games: Napoleon Senki | |
| 2966 | ||
| 2967 | iNES: mapper 77 | |
| 2968 | ||
| 2969 | *************************************************************/ | |
| 2970 | ||
| 2971 | static WRITE8_HANDLER( lrog017_w ) | |
| 2972 | { | |
| 2973 | LOG_MMC(("lrog017_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2974 | ||
| 2975 | prg32(space->machine(), data); | |
| 2976 | chr2_0(space->machine(), (data >> 4), CHRROM); | |
| 2977 | } | |
| 2978 | ||
| 2979 | /************************************************************* | |
| 2980 | ||
| 2981 | Irem Holy Diver board emulation | |
| 2982 | ||
| 2983 | iNES: mapper 78 (shared with JF-16) | |
| 2984 | ||
| 2985 | *************************************************************/ | |
| 2986 | ||
| 2987 | static WRITE8_HANDLER( irem_hd_w ) | |
| 2988 | { | |
| 2989 | LOG_MMC(("irem_hd_w, offset: %04x, data: %02x\n", offset, data)); | |
| 2990 | ||
| 2991 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 2992 | chr8(space->machine(), data >> 4, CHRROM); | |
| 2993 | prg16_89ab(space->machine(), data); | |
| 2994 | } | |
| 2995 | ||
| 2996 | /************************************************************* | |
| 2997 | ||
| 2998 | Irem TAM-S1 board emulation | |
| 2999 | ||
| 3000 | Games: Kaiketsu Yanchamaru | |
| 3001 | ||
| 3002 | iNES: mapper 97 | |
| 3003 | ||
| 3004 | In MESS: Supported. | |
| 3005 | ||
| 3006 | *************************************************************/ | |
| 3007 | ||
| 3008 | static WRITE8_HANDLER( tam_s1_w ) | |
| 3009 | { | |
| 3010 | LOG_MMC(("tam_s1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3011 | ||
| 3012 | if (offset < 0x4000) | |
| 3013 | { | |
| 3014 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 3015 | prg16_cdef(space->machine(), data); | |
| 3016 | } | |
| 3017 | } | |
| 3018 | ||
| 3019 | /************************************************************* | |
| 3020 | ||
| 3021 | Irem G-101 board emulation | |
| 3022 | ||
| 3023 | Major League uses hardwired mirroring | |
| 3024 | ||
| 3025 | iNES: mapper 32 | |
| 3026 | ||
| 3027 | *************************************************************/ | |
| 3028 | ||
| 3029 | static WRITE8_HANDLER( g101_w ) | |
| 3030 | { | |
| 3031 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3032 | LOG_MMC(("g101_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3033 | ||
| 3034 | switch (offset & 0x7000) | |
| 3035 | { | |
| 3036 | case 0x0000: | |
| 3037 | // NEStopia here differs a little bit | |
| 3038 | state->m_mmc_latch1 ? prg8_cd(space->machine(), data) : prg8_89(space->machine(), data); | |
| 3039 | break; | |
| 3040 | case 0x1000: | |
| 3041 | state->m_mmc_latch1 = BIT(data, 1); | |
| 3042 | if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring | |
| 3043 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 3044 | break; | |
| 3045 | case 0x2000: | |
| 3046 | prg8_ab(space->machine(), data); | |
| 3047 | break; | |
| 3048 | case 0x3000: | |
| 3049 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 3050 | break; | |
| 3051 | } | |
| 3052 | } | |
| 3053 | ||
| 3054 | /************************************************************* | |
| 3055 | ||
| 3056 | Irem H-3001 board emulation | |
| 3057 | ||
| 3058 | Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu, | |
| 3059 | Kaiketsu Yanchamaru 3, Spartan X 2 | |
| 3060 | ||
| 3061 | iNES: mapper 65 | |
| 3062 | ||
| 3063 | In MESS: Supported. | |
| 3064 | ||
| 3065 | *************************************************************/ | |
| 3066 | ||
| 3067 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 3068 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 3069 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 3070 | static void h3001_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3071 | { | |
| 3072 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3073 | if (state->m_IRQ_enable) | |
| 3074 | { | |
| 3075 | state->m_IRQ_count -= 114; | |
| 3076 | ||
| 3077 | if (state->m_IRQ_count <= 114) | |
| 3078 | { | |
| 3079 | state->m_IRQ_enable = 0; | |
| 3080 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3081 | } | |
| 3082 | } | |
| 3083 | } | |
| 3084 | ||
| 3085 | static WRITE8_HANDLER( h3001_w ) | |
| 3086 | { | |
| 3087 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3088 | LOG_MMC(("h3001_w, offset %04x, data: %02x\n", offset, data)); | |
| 3089 | ||
| 3090 | switch (offset & 0x7fff) | |
| 3091 | { | |
| 3092 | case 0x0000: | |
| 3093 | prg8_89(space->machine(), data); | |
| 3094 | break; | |
| 3095 | ||
| 3096 | case 0x1001: | |
| 3097 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 3098 | break; | |
| 3099 | ||
| 3100 | case 0x1003: | |
| 3101 | state->m_IRQ_enable = data & 0x80; | |
| 3102 | break; | |
| 3103 | ||
| 3104 | case 0x1004: | |
| 3105 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3106 | break; | |
| 3107 | ||
| 3108 | case 0x1005: | |
| 3109 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x00ff) | (data << 8); | |
| 3110 | break; | |
| 3111 | ||
| 3112 | case 0x1006: | |
| 3113 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff00) | data; | |
| 3114 | break; | |
| 3115 | ||
| 3116 | case 0x2000: | |
| 3117 | prg8_ab(space->machine(), data); | |
| 3118 | break; | |
| 3119 | ||
| 3120 | case 0x3000: case 0x3001: case 0x3002: case 0x3003: | |
| 3121 | case 0x3004: case 0x3005: case 0x3006: case 0x3007: | |
| 3122 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 3123 | break; | |
| 3124 | ||
| 3125 | case 0x4000: | |
| 3126 | prg8_cd(space->machine(), data); | |
| 3127 | break; | |
| 3128 | ||
| 3129 | default: | |
| 3130 | break; | |
| 3131 | } | |
| 3132 | } | |
| 3133 | ||
| 3134 | /************************************************************* | |
| 3135 | ||
| 3136 | Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ..., | |
| 3137 | JF-38, JF-40, JF-41 | |
| 3138 | ||
| 3139 | Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru, | |
| 3140 | Pizza Pop, Plasma Ball | |
| 3141 | ||
| 3142 | iNES: mapper 18 | |
| 3143 | ||
| 3144 | In MESS: Supported | |
| 3145 | ||
| 3146 | *************************************************************/ | |
| 3147 | ||
| 3148 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 3149 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 3150 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 3151 | static void ss88006_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3152 | { | |
| 3153 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3154 | ||
| 3155 | /* Increment & check the IRQ scanline counter */ | |
| 3156 | if (state->m_IRQ_enable) | |
| 3157 | { | |
| 3158 | LOG_MMC(("scanline: %d, irq count: %04x\n", scanline, state->m_IRQ_count)); | |
| 3159 | if (state->m_IRQ_mode & 0x08) | |
| 3160 | { | |
| 3161 | if ((state->m_IRQ_count & 0x000f) < 114) // always true, but we only update the IRQ once per scanlines so we cannot be more precise :( | |
| 3162 | { | |
| 3163 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3164 | state->m_IRQ_count = (state->m_IRQ_count & ~0x000f) | (0x0f - (114 & 0x0f) + (state->m_IRQ_count & 0x000f)); // sort of wrap around the counter | |
| 3165 | } | |
| 3166 | // decrements should not affect upper bits, so we don't do anything here (114 > 0x0f) | |
| 3167 | } | |
| 3168 | else if (state->m_IRQ_mode & 0x04) | |
| 3169 | { | |
| 3170 | if ((state->m_IRQ_count & 0x00ff) < 114) | |
| 3171 | { | |
| 3172 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3173 | state->m_IRQ_count = (state->m_IRQ_count & ~0x00ff) | (0xff - 114 + (state->m_IRQ_count & 0x00ff)); // wrap around the 8 bits counter | |
| 3174 | } | |
| 3175 | else | |
| 3176 | state->m_IRQ_count -= 114; | |
| 3177 | } | |
| 3178 | else if (state->m_IRQ_mode & 0x02) | |
| 3179 | { | |
| 3180 | if ((state->m_IRQ_count & 0x0fff) < 114) | |
| 3181 | { | |
| 3182 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3183 | state->m_IRQ_count = (state->m_IRQ_count & ~0x0fff) | (0xfff - 114 + (state->m_IRQ_count & 0x0fff)); // wrap around the 12 bits counter | |
| 3184 | } | |
| 3185 | else | |
| 3186 | state->m_IRQ_count -= 114; | |
| 3187 | } | |
| 3188 | else if (state->m_IRQ_count < 114) | |
| 3189 | { | |
| 3190 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3191 | state->m_IRQ_count = (0xffff - 114 + state->m_IRQ_count); // wrap around the 16 bits counter | |
| 3192 | } | |
| 3193 | else | |
| 3194 | state->m_IRQ_count -= 114; | |
| 3195 | } | |
| 3196 | } | |
| 3197 | ||
| 3198 | static WRITE8_HANDLER( ss88006_w ) | |
| 3199 | { | |
| 3200 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3201 | UINT8 bank; | |
| 3202 | LOG_MMC(("mapper18_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3203 | ||
| 3204 | switch (offset & 0x7003) | |
| 3205 | { | |
| 3206 | case 0x0000: | |
| 3207 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f); | |
| 3208 | prg8_89(space->machine(), state->m_mmc_prg_bank[0]); | |
| 3209 | break; | |
| 3210 | case 0x0001: | |
| 3211 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x0f) | (data << 4); | |
| 3212 | prg8_89(space->machine(), state->m_mmc_prg_bank[0]); | |
| 3213 | break; | |
| 3214 | case 0x0002: | |
| 3215 | state->m_mmc_prg_bank[1] = (state->m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f); | |
| 3216 | prg8_ab(space->machine(), state->m_mmc_prg_bank[1]); | |
| 3217 | break; | |
| 3218 | case 0x0003: | |
| 3219 | state->m_mmc_prg_bank[1] = (state->m_mmc_prg_bank[1] & 0x0f) | (data << 4); | |
| 3220 | prg8_ab(space->machine(), state->m_mmc_prg_bank[1]); | |
| 3221 | break; | |
| 3222 | case 0x1000: | |
| 3223 | state->m_mmc_prg_bank[2] = (state->m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f); | |
| 3224 | prg8_cd(space->machine(), state->m_mmc_prg_bank[2]); | |
| 3225 | break; | |
| 3226 | case 0x1001: | |
| 3227 | state->m_mmc_prg_bank[2] = (state->m_mmc_prg_bank[2] & 0x0f) | (data << 4); | |
| 3228 | prg8_cd(space->machine(), state->m_mmc_prg_bank[2]); | |
| 3229 | break; | |
| 3230 | ||
| 3231 | /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */ | |
| 3232 | /* believe it's related to battery-backed ram enable/disable */ | |
| 3233 | ||
| 3234 | case 0x2000: case 0x2001: case 0x2002: case 0x2003: | |
| 3235 | case 0x3000: case 0x3001: case 0x3002: case 0x3003: | |
| 3236 | case 0x4000: case 0x4001: case 0x4002: case 0x4003: | |
| 3237 | case 0x5000: case 0x5001: case 0x5002: case 0x5003: | |
| 3238 | bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1); | |
| 3239 | if (offset & 0x0001) | |
| 3240 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4); | |
| 3241 | else | |
| 3242 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 3243 | ||
| 3244 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 3245 | break; | |
| 3246 | ||
| 3247 | case 0x6000: | |
| 3248 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xfff0) | (data & 0x0f); | |
| 3249 | break; | |
| 3250 | case 0x6001: | |
| 3251 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff0f) | ((data & 0x0f) << 4); | |
| 3252 | break; | |
| 3253 | case 0x6002: | |
| 3254 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0ff) | ((data & 0x0f) << 8); | |
| 3255 | break; | |
| 3256 | case 0x6003: | |
| 3257 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0fff) | ((data & 0x0f) << 12); | |
| 3258 | break; | |
| 3259 | ||
| 3260 | case 0x7000: | |
| 3261 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3262 | break; | |
| 3263 | case 0x7001: | |
| 3264 | state->m_IRQ_enable = data & 0x01; | |
| 3265 | state->m_IRQ_mode = data & 0x0e; | |
| 3266 | break; | |
| 3267 | ||
| 3268 | case 0x7002: | |
| 3269 | switch (data & 0x03) | |
| 3270 | { | |
| 3271 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3272 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3273 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3274 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3275 | } | |
| 3276 | break; | |
| 3277 | ||
| 3278 | default: | |
| 3279 | logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data); | |
| 3280 | break; | |
| 3281 | } | |
| 3282 | } | |
| 3283 | ||
| 3284 | /************************************************************* | |
| 3285 | ||
| 3286 | Jaleco JF-11, JF-12 & JF-14 boards emulation | |
| 3287 | ||
| 3288 | Games: Bio Senshi Dan, Mississippi Satsujin Jiken | |
| 3289 | ||
| 3290 | iNES: mapper 140 | |
| 3291 | ||
| 3292 | In MESS: Supported. | |
| 3293 | ||
| 3294 | *************************************************************/ | |
| 3295 | ||
| 3296 | static WRITE8_HANDLER( jf11_m_w ) | |
| 3297 | { | |
| 3298 | LOG_MMC(("jf11_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3299 | chr8(space->machine(), data, CHRROM); | |
| 3300 | prg32(space->machine(), data >> 4); | |
| 3301 | } | |
| 3302 | ||
| 3303 | /************************************************************* | |
| 3304 | ||
| 3305 | Jaleco JF-13 board emulation | |
| 3306 | ||
| 3307 | Games: Moero Pro Yakyuu | |
| 3308 | ||
| 3309 | Note: we don't emulate the additional sound hardware. | |
| 3310 | ||
| 3311 | iNES: mapper 86 | |
| 3312 | ||
| 3313 | In MESS: Supported. | |
| 3314 | ||
| 3315 | *************************************************************/ | |
| 3316 | ||
| 3317 | static WRITE8_HANDLER( jf13_m_w ) | |
| 3318 | { | |
| 3319 | LOG_MMC(("jf13_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3320 | ||
| 3321 | if (offset == 0) | |
| 3322 | { | |
| 3323 | prg32(space->machine(), (data >> 4) & 0x03); | |
| 3324 | chr8(space->machine(), ((data >> 4) & 0x04) | (data & 0x03), CHRROM); | |
| 3325 | } | |
| 3326 | ||
| 3327 | if (offset == 0x1000) | |
| 3328 | { | |
| 3329 | LOG_MMC(("Jaleco JF-13 sound write, data: %02x\n", data)); | |
| 3330 | // according to NEStopia, this is the effect | |
| 3331 | if ((data & 0x30) == 0x20) | |
| 3332 | { | |
| 3333 | // send command (data & 0x1f) to sound chip | |
| 3334 | } | |
| 3335 | } | |
| 3336 | } | |
| 3337 | ||
| 3338 | /************************************************************* | |
| 3339 | ||
| 3340 | Jaleco JF-16 board emulation | |
| 3341 | ||
| 3342 | iNES: mapper 78 (shared with a diff Irem board) | |
| 3343 | ||
| 3344 | *************************************************************/ | |
| 3345 | ||
| 3346 | static WRITE8_HANDLER( jf16_w ) | |
| 3347 | { | |
| 3348 | LOG_MMC(("jf16_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3349 | ||
| 3350 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 3351 | chr8(space->machine(), data >> 4, CHRROM); | |
| 3352 | prg16_89ab(space->machine(), data); | |
| 3353 | } | |
| 3354 | ||
| 3355 | /************************************************************* | |
| 3356 | ||
| 3357 | Jaleco JF-17, JF-26 & JF-28 boards emulation | |
| 3358 | ||
| 3359 | Note: we don't emulate the additional sound hardware. | |
| 3360 | ||
| 3361 | Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball | |
| 3362 | Quest Jpn | |
| 3363 | ||
| 3364 | iNES: mapper 72 | |
| 3365 | ||
| 3366 | In MESS: Supported. | |
| 3367 | ||
| 3368 | *************************************************************/ | |
| 3369 | ||
| 3370 | static WRITE8_HANDLER( jf17_w ) | |
| 3371 | { | |
| 3372 | LOG_MMC(("jf17_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3373 | ||
| 3374 | if (BIT(data, 7)) | |
| 3375 | prg16_89ab(space->machine(), data & 0x0f); | |
| 3376 | if (BIT(data, 6)) | |
| 3377 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 3378 | if (BIT(data, 5) && !BIT(data,4)) | |
| 3379 | LOG_MMC(("Jaleco JF-17 sound write, data: %02x\n", data & 0x1f)); | |
| 3380 | } | |
| 3381 | ||
| 3382 | /************************************************************* | |
| 3383 | ||
| 3384 | Jaleco JF-19 & JF-21 boards emulation | |
| 3385 | ||
| 3386 | Note: we don't emulate the additional sound hardware. | |
| 3387 | ||
| 3388 | Games: Moero Pro Soccer, Moero Pro Yakyuu '88 | |
| 3389 | ||
| 3390 | iNES: mapper 92 | |
| 3391 | ||
| 3392 | In MESS: Supported (no samples). | |
| 3393 | ||
| 3394 | *************************************************************/ | |
| 3395 | ||
| 3396 | static WRITE8_HANDLER( jf19_w ) | |
| 3397 | { | |
| 3398 | LOG_MMC(("jf19_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3399 | ||
| 3400 | if (BIT(data, 7)) | |
| 3401 | prg16_cdef(space->machine(), data & 0x0f); | |
| 3402 | if (BIT(data, 6)) | |
| 3403 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 3404 | if (BIT(data, 5) && !BIT(data,4)) | |
| 3405 | LOG_MMC(("Jaleco JF-19 sound write, data: %02x\n", data & 0x1f)); | |
| 3406 | } | |
| 3407 | ||
| 3408 | /************************************************************* | |
| 3409 | ||
| 3410 | Konami VRC1 and Jaleco JF20, JF22 | |
| 3411 | ||
| 3412 | Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom | |
| 3413 | ||
| 3414 | iNES: mapper 75 | |
| 3415 | ||
| 3416 | In MESS: Supported. | |
| 3417 | ||
| 3418 | *************************************************************/ | |
| 3419 | ||
| 3420 | static WRITE8_HANDLER( konami_vrc1_w ) | |
| 3421 | { | |
| 3422 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3423 | LOG_MMC(("konami_vrc1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3424 | ||
| 3425 | switch (offset & 0x7000) | |
| 3426 | { | |
| 3427 | case 0x0000: | |
| 3428 | prg8_89(space->machine(), data); | |
| 3429 | break; | |
| 3430 | case 0x1000: | |
| 3431 | set_nt_mirroring(space->machine(), (data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 3432 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3); | |
| 3433 | state->m_mmc_vrom_bank[1] = (state->m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2); | |
| 3434 | chr4_0(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 3435 | chr4_4(space->machine(), state->m_mmc_vrom_bank[1], CHRROM); | |
| 3436 | break; | |
| 3437 | case 0x2000: | |
| 3438 | prg8_ab(space->machine(), data); | |
| 3439 | break; | |
| 3440 | case 0x4000: | |
| 3441 | prg8_cd(space->machine(), data); | |
| 3442 | break; | |
| 3443 | case 0x6000: | |
| 3444 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f); | |
| 3445 | chr4_0(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 3446 | break; | |
| 3447 | case 0x7000: | |
| 3448 | state->m_mmc_vrom_bank[1] = (state->m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f); | |
| 3449 | chr4_4(space->machine(), state->m_mmc_vrom_bank[1], CHRROM); | |
| 3450 | break; | |
| 3451 | } | |
| 3452 | } | |
| 3453 | ||
| 3454 | /************************************************************* | |
| 3455 | ||
| 3456 | Konami VRC-2 | |
| 3457 | ||
| 3458 | In MESS: Supported. | |
| 3459 | ||
| 3460 | *************************************************************/ | |
| 3461 | ||
| 3462 | static WRITE8_HANDLER( konami_vrc2_w ) | |
| 3463 | { | |
| 3464 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3465 | UINT8 bank, shift, mask; | |
| 3466 | UINT32 shifted_offs = (offset & 0x7000) | |
| 3467 | | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200) | |
| 3468 | | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100); | |
| 3469 | LOG_MMC(("konami_vrc2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3470 | ||
| 3471 | if (offset < 0x1000) | |
| 3472 | prg8_89(space->machine(), data); | |
| 3473 | else if (offset < 0x2000) | |
| 3474 | { | |
| 3475 | switch (data & 0x03) | |
| 3476 | { | |
| 3477 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3478 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3479 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3480 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3481 | } | |
| 3482 | } | |
| 3483 | else if (offset < 0x3000) | |
| 3484 | prg8_ab(space->machine(), data); | |
| 3485 | else if (offset < 0x7000) | |
| 3486 | { | |
| 3487 | bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9); | |
| 3488 | shift = BIT(shifted_offs, 8) * 4; | |
| 3489 | mask = (0xf0 >> shift); | |
| 3490 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & mask) | |
| 3491 | | (((data >> state->m_vrc_ls_chr) & 0x0f) << shift); | |
| 3492 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 3493 | } | |
| 3494 | else | |
| 3495 | logerror("konami_vrc2_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); | |
| 3496 | } | |
| 3497 | ||
| 3498 | /************************************************************* | |
| 3499 | ||
| 3500 | Konami VRC3 | |
| 3501 | ||
| 3502 | Games: Salamander | |
| 3503 | ||
| 3504 | iNES: mapper 73 | |
| 3505 | ||
| 3506 | In MESS: Supported. It also uses konami_irq. | |
| 3507 | ||
| 3508 | *************************************************************/ | |
| 3509 | ||
| 3510 | static WRITE8_HANDLER( konami_vrc3_w ) | |
| 3511 | { | |
| 3512 | LOG_MMC(("konami_vrc3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3513 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3514 | ||
| 3515 | switch (offset & 0x7000) | |
| 3516 | { | |
| 3517 | case 0x0000: | |
| 3518 | case 0x1000: | |
| 3519 | /* dunno which address controls these */ | |
| 3520 | state->m_IRQ_count_latch = data; | |
| 3521 | state->m_IRQ_enable_latch = data; | |
| 3522 | break; | |
| 3523 | case 0x2000: | |
| 3524 | state->m_IRQ_enable = data; | |
| 3525 | break; | |
| 3526 | case 0x3000: | |
| 3527 | state->m_IRQ_count &= ~0x0f; | |
| 3528 | state->m_IRQ_count |= data & 0x0f; | |
| 3529 | break; | |
| 3530 | case 0x4000: | |
| 3531 | state->m_IRQ_count &= ~0xf0; | |
| 3532 | state->m_IRQ_count |= (data & 0x0f) << 4; | |
| 3533 | break; | |
| 3534 | case 0x7000: | |
| 3535 | prg16_89ab(space->machine(), data); | |
| 3536 | break; | |
| 3537 | default: | |
| 3538 | logerror("konami_vrc3_w uncaught write, offset %04x, data: %02x\n", offset, data); | |
| 3539 | break; | |
| 3540 | } | |
| 3541 | } | |
| 3542 | ||
| 3543 | /************************************************************* | |
| 3544 | ||
| 3545 | Konami VRC-4 | |
| 3546 | ||
| 3547 | In MESS: Supported | |
| 3548 | ||
| 3549 | *************************************************************/ | |
| 3550 | ||
| 3551 | static void vrc4_set_prg( running_machine &machine ) | |
| 3552 | { | |
| 3553 | nes_state *state = machine.driver_data<nes_state>(); | |
| 3554 | if (state->m_mmc_latch1 & 0x02) | |
| 3555 | { | |
| 3556 | prg8_89(machine, 0xfe); | |
| 3557 | prg8_cd(machine, state->m_mmc_prg_bank[0]); | |
| 3558 | } | |
| 3559 | else | |
| 3560 | { | |
| 3561 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 3562 | prg8_cd(machine, 0xfe); | |
| 3563 | } | |
| 3564 | } | |
| 3565 | ||
| 3566 | static void konami_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3567 | { | |
| 3568 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3569 | /* Increment & check the IRQ scanline counter */ | |
| 3570 | if (state->m_IRQ_enable && (++state->m_IRQ_count == 0x100)) | |
| 3571 | { | |
| 3572 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3573 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3574 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3575 | } | |
| 3576 | } | |
| 3577 | ||
| 3578 | static WRITE8_HANDLER( konami_vrc4_w ) | |
| 3579 | { | |
| 3580 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3581 | UINT8 bank, shift, mask; | |
| 3582 | UINT32 shifted_offs = (offset & 0x7000) | |
| 3583 | | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200) | |
| 3584 | | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100); | |
| 3585 | LOG_MMC(("konami_vrc4_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3586 | ||
| 3587 | if (offset < 0x1000) | |
| 3588 | { | |
| 3589 | state->m_mmc_prg_bank[0] = data; | |
| 3590 | vrc4_set_prg(space->machine()); | |
| 3591 | } | |
| 3592 | else if (offset >= 0x2000 && offset < 0x3000) | |
| 3593 | prg8_ab(space->machine(), data); | |
| 3594 | else | |
| 3595 | { | |
| 3596 | switch (shifted_offs & 0x7300) | |
| 3597 | { | |
| 3598 | case 0x1000: | |
| 3599 | case 0x1100: | |
| 3600 | switch (data & 0x03) | |
| 3601 | { | |
| 3602 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3603 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3604 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3605 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3606 | } | |
| 3607 | break; | |
| 3608 | case 0x1200: | |
| 3609 | case 0x1300: | |
| 3610 | state->m_mmc_latch1 = data & 0x02; | |
| 3611 | vrc4_set_prg(space->machine()); | |
| 3612 | break; | |
| 3613 | case 0x3000: | |
| 3614 | case 0x3100: | |
| 3615 | case 0x3200: | |
| 3616 | case 0x3300: | |
| 3617 | case 0x4000: | |
| 3618 | case 0x4100: | |
| 3619 | case 0x4200: | |
| 3620 | case 0x4300: | |
| 3621 | case 0x5000: | |
| 3622 | case 0x5100: | |
| 3623 | case 0x5200: | |
| 3624 | case 0x5300: | |
| 3625 | case 0x6000: | |
| 3626 | case 0x6100: | |
| 3627 | case 0x6200: | |
| 3628 | case 0x6300: | |
| 3629 | bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9); | |
| 3630 | shift = BIT(shifted_offs, 8) * 4; | |
| 3631 | mask = (0xf0 >> shift); | |
| 3632 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift); | |
| 3633 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 3634 | break; | |
| 3635 | case 0x7000: | |
| 3636 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f); | |
| 3637 | break; | |
| 3638 | case 0x7100: | |
| 3639 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4); | |
| 3640 | break; | |
| 3641 | case 0x7200: | |
| 3642 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 3643 | state->m_IRQ_enable = data & 0x02; | |
| 3644 | state->m_IRQ_enable_latch = data & 0x01; | |
| 3645 | if (data & 0x02) | |
| 3646 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3647 | break; | |
| 3648 | case 0x7300: | |
| 3649 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3650 | break; | |
| 3651 | default: | |
| 3652 | logerror("konami_vrc4_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data); | |
| 3653 | break; | |
| 3654 | } | |
| 3655 | } | |
| 3656 | } | |
| 3657 | ||
| 3658 | /************************************************************* | |
| 3659 | ||
| 3660 | Konami VRC-6 | |
| 3661 | ||
| 3662 | In MESS: Supported. It also uses konami_irq (there are IRQ | |
| 3663 | issues though: see Akumajou Densetsu intro). | |
| 3664 | ||
| 3665 | *************************************************************/ | |
| 3666 | ||
| 3667 | static WRITE8_HANDLER( konami_vrc6_w ) | |
| 3668 | { | |
| 3669 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3670 | UINT8 bank; | |
| 3671 | UINT32 shifted_offs = (offset & 0x7000) | |
| 3672 | | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200) | |
| 3673 | | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100); | |
| 3674 | LOG_MMC(("konami_vrc6_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3675 | ||
| 3676 | if (offset < 0x1000) | |
| 3677 | prg16_89ab(space->machine(), data); | |
| 3678 | else if (offset >= 0x4000 && offset < 0x5000) | |
| 3679 | prg8_cd(space->machine(), data); | |
| 3680 | else | |
| 3681 | { | |
| 3682 | switch (shifted_offs & 0x7300) | |
| 3683 | { | |
| 3684 | case 0x1000: | |
| 3685 | case 0x1100: | |
| 3686 | case 0x1200: | |
| 3687 | case 0x2000: | |
| 3688 | case 0x2100: | |
| 3689 | case 0x2200: | |
| 3690 | case 0x3000: | |
| 3691 | case 0x3100: | |
| 3692 | case 0x3200: | |
| 3693 | LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", shifted_offs & 0x7300, data)); | |
| 3694 | break; | |
| 3695 | case 0x3300: | |
| 3696 | switch (data & 0x0c) | |
| 3697 | { | |
| 3698 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3699 | case 0x04: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3700 | case 0x08: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3701 | case 0x0c: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3702 | } | |
| 3703 | break; | |
| 3704 | case 0x5000: | |
| 3705 | case 0x5100: | |
| 3706 | case 0x5200: | |
| 3707 | case 0x5300: | |
| 3708 | case 0x6000: | |
| 3709 | case 0x6100: | |
| 3710 | case 0x6200: | |
| 3711 | case 0x6300: | |
| 3712 | bank = ((shifted_offs & 0x7000) - 0x5000) / 0x0400 + ((shifted_offs & 0x0300) >> 8); | |
| 3713 | chr1_x(space->machine(), bank, data, CHRROM); | |
| 3714 | break; | |
| 3715 | case 0x7000: | |
| 3716 | state->m_IRQ_count_latch = data; | |
| 3717 | break; | |
| 3718 | case 0x7100: | |
| 3719 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 3720 | state->m_IRQ_enable = data & 0x02; | |
| 3721 | state->m_IRQ_enable_latch = data & 0x01; | |
| 3722 | if (data & 0x02) | |
| 3723 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3724 | break; | |
| 3725 | case 0x7200: | |
| 3726 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3727 | break; | |
| 3728 | default: | |
| 3729 | logerror("konami_vrc6_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data); | |
| 3730 | break; | |
| 3731 | } | |
| 3732 | } | |
| 3733 | } | |
| 3734 | ||
| 3735 | /************************************************************* | |
| 3736 | ||
| 3737 | Konami VRC7 | |
| 3738 | ||
| 3739 | Games: Lagrange Point, Tiny Toon Adventures 2 | |
| 3740 | ||
| 3741 | iNES: mapper 85 | |
| 3742 | ||
| 3743 | In MESS: Supported. It also uses konami_irq. | |
| 3744 | ||
| 3745 | *************************************************************/ | |
| 3746 | ||
| 3747 | static WRITE8_HANDLER( konami_vrc7_w ) | |
| 3748 | { | |
| 3749 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3750 | UINT8 bank; | |
| 3751 | LOG_MMC(("konami_vrc7_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3752 | ||
| 3753 | switch (offset & 0x7018) | |
| 3754 | { | |
| 3755 | case 0x0000: | |
| 3756 | prg8_89(space->machine(), data); | |
| 3757 | break; | |
| 3758 | case 0x0008: | |
| 3759 | case 0x0010: | |
| 3760 | case 0x0018: | |
| 3761 | prg8_ab(space->machine(), data); | |
| 3762 | break; | |
| 3763 | ||
| 3764 | case 0x1000: | |
| 3765 | prg8_cd(space->machine(), data); | |
| 3766 | break; | |
| 3767 | ||
| 3768 | /* TODO: there are sound regs in here */ | |
| 3769 | ||
| 3770 | case 0x2000: | |
| 3771 | case 0x2008: | |
| 3772 | case 0x2010: | |
| 3773 | case 0x2018: | |
| 3774 | case 0x3000: | |
| 3775 | case 0x3008: | |
| 3776 | case 0x3010: | |
| 3777 | case 0x3018: | |
| 3778 | case 0x4000: | |
| 3779 | case 0x4008: | |
| 3780 | case 0x4010: | |
| 3781 | case 0x4018: | |
| 3782 | case 0x5000: | |
| 3783 | case 0x5008: | |
| 3784 | case 0x5010: | |
| 3785 | case 0x5018: | |
| 3786 | bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0); | |
| 3787 | chr1_x(space->machine(), bank, data, state->m_mmc_chr_source); | |
| 3788 | break; | |
| 3789 | ||
| 3790 | case 0x6000: | |
| 3791 | switch (data & 0x03) | |
| 3792 | { | |
| 3793 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 3794 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 3795 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 3796 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 3797 | } | |
| 3798 | break; | |
| 3799 | case 0x6008: case 0x6010: case 0x6018: | |
| 3800 | state->m_IRQ_count_latch = data; | |
| 3801 | break; | |
| 3802 | case 0x7000: | |
| 3803 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 3804 | state->m_IRQ_enable = data & 0x02; | |
| 3805 | state->m_IRQ_enable_latch = data & 0x01; | |
| 3806 | if (data & 0x02) | |
| 3807 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 3808 | break; | |
| 3809 | case 0x7008: case 0x7010: case 0x7018: | |
| 3810 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 3811 | break; | |
| 3812 | ||
| 3813 | default: | |
| 3814 | logerror("konami_vrc7_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); | |
| 3815 | break; | |
| 3816 | } | |
| 3817 | } | |
| 3818 | ||
| 3819 | /************************************************************* | |
| 3820 | ||
| 3821 | Namcot-163 board emulation | |
| 3822 | ||
| 3823 | Games: Battle Fleet, Family Circuit '91, Famista '90, '91, | |
| 3824 | '92 & '94, Megami Tensei II, Top Striker, Wagyan Land 2 & 3 | |
| 3825 | ||
| 3826 | iNES: mapper 19 | |
| 3827 | ||
| 3828 | In MESS: Supported | |
| 3829 | ||
| 3830 | *************************************************************/ | |
| 3831 | ||
| 3832 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 3833 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 3834 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 3835 | static void namcot_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 3836 | { | |
| 3837 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 3838 | ||
| 3839 | if (state->m_IRQ_enable) | |
| 3840 | { | |
| 3841 | if (state->m_IRQ_count >= (0x7fff - 114)) | |
| 3842 | { | |
| 3843 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 3844 | state->m_IRQ_count = 0; | |
| 3845 | } | |
| 3846 | else | |
| 3847 | state->m_IRQ_count += 114; | |
| 3848 | } | |
| 3849 | } | |
| 3850 | ||
| 3851 | static WRITE8_HANDLER( namcot163_l_w ) | |
| 3852 | { | |
| 3853 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3854 | LOG_MMC(("namcot163_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3855 | offset += 0x100; | |
| 3856 | ||
| 3857 | switch (offset & 0x1800) | |
| 3858 | { | |
| 3859 | case 0x0800: | |
| 3860 | LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data)); | |
| 3861 | break; | |
| 3862 | case 0x1000: /* low byte of IRQ */ | |
| 3863 | state->m_IRQ_count = (state->m_IRQ_count & 0x7f00) | data; | |
| 3864 | break; | |
| 3865 | case 0x1800: /* high byte of IRQ, IRQ enable in high bit */ | |
| 3866 | state->m_IRQ_count = (state->m_IRQ_count & 0xff) | ((data & 0x7f) << 8); | |
| 3867 | state->m_IRQ_enable = data & 0x80; | |
| 3868 | break; | |
| 3869 | } | |
| 3870 | } | |
| 3871 | ||
| 3872 | static READ8_HANDLER( namcot163_l_r ) | |
| 3873 | { | |
| 3874 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3875 | LOG_MMC(("namcot163_l_r, offset: %04x\n", offset)); | |
| 3876 | offset += 0x100; | |
| 3877 | ||
| 3878 | switch (offset & 0x1800) | |
| 3879 | { | |
| 3880 | case 0x1000: | |
| 3881 | return state->m_IRQ_count & 0xff; | |
| 3882 | case 0x1800: | |
| 3883 | return (state->m_IRQ_count >> 8) & 0xff; | |
| 3884 | case 0x0800: | |
| 3885 | LOG_MMC(("Namcot-163 sound reg read\n")); | |
| 3886 | default: | |
| 3887 | return 0x00; | |
| 3888 | } | |
| 3889 | } | |
| 3890 | ||
| 3891 | static void namcot163_set_mirror( running_machine &machine, UINT8 page, UINT8 data ) | |
| 3892 | { | |
| 3893 | if (!(data < 0xe0)) | |
| 3894 | set_nt_page(machine, page, CIRAM, data & 0x01, 1); | |
| 3895 | else | |
| 3896 | set_nt_page(machine, page, ROM, data, 0); | |
| 3897 | } | |
| 3898 | ||
| 3899 | static WRITE8_HANDLER( namcot163_w ) | |
| 3900 | { | |
| 3901 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3902 | LOG_MMC(("namcot163_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3903 | switch (offset & 0x7800) | |
| 3904 | { | |
| 3905 | case 0x0000: case 0x0800: | |
| 3906 | case 0x1000: case 0x1800: | |
| 3907 | case 0x2000: case 0x2800: | |
| 3908 | case 0x3000: case 0x3800: | |
| 3909 | chr1_x(space->machine(), offset / 0x800, data, CHRROM); | |
| 3910 | break; | |
| 3911 | case 0x4000: | |
| 3912 | namcot163_set_mirror(space->machine(), 0, data); | |
| 3913 | break; | |
| 3914 | case 0x4800: | |
| 3915 | namcot163_set_mirror(space->machine(), 1, data); | |
| 3916 | break; | |
| 3917 | case 0x5000: | |
| 3918 | namcot163_set_mirror(space->machine(), 2, data); | |
| 3919 | break; | |
| 3920 | case 0x5800: | |
| 3921 | namcot163_set_mirror(space->machine(), 3, data); | |
| 3922 | break; | |
| 3923 | case 0x6000: | |
| 3924 | prg8_89(space->machine(), data & 0x3f); | |
| 3925 | break; | |
| 3926 | case 0x6800: | |
| 3927 | state->m_mmc_latch1 = data & 0xc0; // this should enable High CHRRAM, but we still have to properly implement it! | |
| 3928 | prg8_ab(space->machine(), data & 0x3f); | |
| 3929 | break; | |
| 3930 | case 0x7000: | |
| 3931 | prg8_cd(space->machine(), data & 0x3f); | |
| 3932 | break; | |
| 3933 | case 0x7800: | |
| 3934 | LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data)); | |
| 3935 | break; | |
| 3936 | } | |
| 3937 | } | |
| 3938 | ||
| 3939 | /************************************************************* | |
| 3940 | ||
| 3941 | Sunsoft-1 board emulation | |
| 3942 | ||
| 3943 | Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no | |
| 3944 | Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone | |
| 3945 | ||
| 3946 | iNES: mapper 184 (Fantasy Zone uses this board with no | |
| 3947 | CHRROM, and the register switches PRG banks) | |
| 3948 | ||
| 3949 | *************************************************************/ | |
| 3950 | ||
| 3951 | static WRITE8_HANDLER( sunsoft1_m_w ) | |
| 3952 | { | |
| 3953 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3954 | LOG_MMC(("sunsoft1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3955 | ||
| 3956 | if (state->m_chr_chunks) | |
| 3957 | { | |
| 3958 | chr4_0(space->machine(), data & 0x0f, CHRROM); | |
| 3959 | chr4_4(space->machine(), data >> 4, CHRROM); | |
| 3960 | } | |
| 3961 | else | |
| 3962 | prg16_89ab(space->machine(), data & 0x0f); | |
| 3963 | } | |
| 3964 | ||
| 3965 | /************************************************************* | |
| 3966 | ||
| 3967 | Sunsoft-2 board emulation | |
| 3968 | ||
| 3969 | The two games using this board have incompatible mirroring | |
| 3970 | wiring, making necessary two distinct mappers & pcb_id | |
| 3971 | ||
| 3972 | iNES: mapper 89 & 93 | |
| 3973 | ||
| 3974 | *************************************************************/ | |
| 3975 | ||
| 3976 | static WRITE8_HANDLER( sunsoft2_w ) | |
| 3977 | { | |
| 3978 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 3979 | UINT8 sunsoft_helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00); | |
| 3980 | LOG_MMC(("sunsoft2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 3981 | ||
| 3982 | if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring | |
| 3983 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 3984 | if (state->m_chr_chunks) | |
| 3985 | chr8(space->machine(), sunsoft_helper, CHRROM); | |
| 3986 | ||
| 3987 | prg16_89ab(space->machine(), data >> 4); | |
| 3988 | } | |
| 3989 | ||
| 3990 | /************************************************************* | |
| 3991 | ||
| 3992 | Sunsoft-3 board emulation | |
| 3993 | ||
| 3994 | The two games using this board have incompatible mirroring | |
| 3995 | wiring, making necessary two distinct mappers & pcb_id | |
| 3996 | ||
| 3997 | iNES: mapper 67 | |
| 3998 | ||
| 3999 | *************************************************************/ | |
| 4000 | ||
| 4001 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 4002 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 4003 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 4004 | static void sunsoft3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 4005 | { | |
| 4006 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 4007 | ||
| 4008 | /* TODO: change to reflect the actual number of cycles spent: both using 114 or cycling 114,114,113 | |
| 4009 | produces a 1-line glitch in Fantasy Zone 2: it really requires the counter to be updated each CPU cycle! */ | |
| 4010 | if (state->m_IRQ_enable) | |
| 4011 | { | |
| 4012 | if (state->m_IRQ_count <= 114) | |
| 4013 | { | |
| 4014 | state->m_IRQ_enable = 0; | |
| 4015 | state->m_IRQ_count = 0xffff; | |
| 4016 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 4017 | } | |
| 4018 | else | |
| 4019 | state->m_IRQ_count -= 114; | |
| 4020 | } | |
| 4021 | } | |
| 4022 | ||
| 4023 | static WRITE8_HANDLER( sunsoft3_w ) | |
| 4024 | { | |
| 4025 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4026 | LOG_MMC(("sunsoft3_w, offset %04x, data: %02x\n", offset, data)); | |
| 4027 | ||
| 4028 | switch (offset & 0x7800) | |
| 4029 | { | |
| 4030 | case 0x0800: | |
| 4031 | chr2_0(space->machine(), data, CHRROM); | |
| 4032 | break; | |
| 4033 | case 0x1800: | |
| 4034 | chr2_2(space->machine(), data, CHRROM); | |
| 4035 | break; | |
| 4036 | case 0x2800: | |
| 4037 | chr2_4(space->machine(), data, CHRROM); | |
| 4038 | break; | |
| 4039 | case 0x3800: | |
| 4040 | chr2_6(space->machine(), data, CHRROM); | |
| 4041 | break; | |
| 4042 | case 0x4000: | |
| 4043 | case 0x4800: | |
| 4044 | state->m_IRQ_toggle ^= 1; | |
| 4045 | if (state->m_IRQ_toggle) | |
| 4046 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 4047 | else | |
| 4048 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 4049 | break; | |
| 4050 | case 0x5800: | |
| 4051 | state->m_IRQ_enable = BIT(data, 4); | |
| 4052 | state->m_IRQ_toggle = 0; | |
| 4053 | break; | |
| 4054 | case 0x6800: | |
| 4055 | switch (data & 3) | |
| 4056 | { | |
| 4057 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 4058 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 4059 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 4060 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 4061 | } | |
| 4062 | break; | |
| 4063 | case 0x7800: | |
| 4064 | prg16_89ab(space->machine(), data); | |
| 4065 | break; | |
| 4066 | default: | |
| 4067 | LOG_MMC(("sunsoft3_w uncaught write, offset: %04x, data: %02x\n", offset, data)); | |
| 4068 | break; | |
| 4069 | } | |
| 4070 | } | |
| 4071 | ||
| 4072 | /************************************************************* | |
| 4073 | ||
| 4074 | Taito TC0190FMC + board emulation | |
| 4075 | ||
| 4076 | Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don, | |
| 4077 | Insector X, Operation Wolf, Power Blazer, Takeshi no | |
| 4078 | Sengoku Fuuunji | |
| 4079 | ||
| 4080 | iNES: mapper 33 | |
| 4081 | ||
| 4082 | In MESS: Supported. | |
| 4083 | ||
| 4084 | *************************************************************/ | |
| 4085 | ||
| 4086 | static WRITE8_HANDLER( tc0190fmc_w ) | |
| 4087 | { | |
| 4088 | LOG_MMC(("tc0190fmc_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4089 | ||
| 4090 | switch (offset & 0x7003) | |
| 4091 | { | |
| 4092 | case 0x0000: | |
| 4093 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4094 | prg8_89(space->machine(), data); | |
| 4095 | break; | |
| 4096 | case 0x0001: | |
| 4097 | prg8_ab(space->machine(), data); | |
| 4098 | break; | |
| 4099 | case 0x0002: | |
| 4100 | chr2_0(space->machine(), data, CHRROM); | |
| 4101 | break; | |
| 4102 | case 0x0003: | |
| 4103 | chr2_2(space->machine(), data, CHRROM); | |
| 4104 | break; | |
| 4105 | case 0x2000: | |
| 4106 | chr1_4(space->machine(), data, CHRROM); | |
| 4107 | break; | |
| 4108 | case 0x2001: | |
| 4109 | chr1_5(space->machine(), data, CHRROM); | |
| 4110 | break; | |
| 4111 | case 0x2002: | |
| 4112 | chr1_6(space->machine(), data, CHRROM); | |
| 4113 | break; | |
| 4114 | case 0x2003: | |
| 4115 | chr1_7(space->machine(), data, CHRROM); | |
| 4116 | break; | |
| 4117 | } | |
| 4118 | } | |
| 4119 | ||
| 4120 | /************************************************************* | |
| 4121 | ||
| 4122 | Taito TC0190FMC + PAL16R4 board emulation | |
| 4123 | ||
| 4124 | Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2, | |
| 4125 | Captain Saver, Don Doko Don 2, Flintstones, Jetsons | |
| 4126 | ||
| 4127 | This is basically Mapper 33 + IRQ. Notably, IRQ works the | |
| 4128 | same as MMC3 irq, BUT latch values are "inverted" (XOR'ed | |
| 4129 | with 0xff) and there is a little delay (not implemented yet) | |
| 4130 | We simply use MMC3 IRQ and XOR the value written in the | |
| 4131 | register 0xc000 below | |
| 4132 | ||
| 4133 | iNES: mapper 48 | |
| 4134 | ||
| 4135 | In MESS: Supported. | |
| 4136 | ||
| 4137 | *************************************************************/ | |
| 4138 | ||
| 4139 | static WRITE8_HANDLER( tc0190fmc_p16_w ) | |
| 4140 | { | |
| 4141 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4142 | LOG_MMC(("tc0190fmc_p16_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4143 | ||
| 4144 | switch (offset & 0x7003) | |
| 4145 | { | |
| 4146 | case 0x0000: | |
| 4147 | prg8_89(space->machine(), data); | |
| 4148 | break; | |
| 4149 | case 0x0001: | |
| 4150 | case 0x0002: | |
| 4151 | case 0x0003: | |
| 4152 | case 0x2000: | |
| 4153 | case 0x2001: | |
| 4154 | case 0x2002: | |
| 4155 | case 0x2003: | |
| 4156 | tc0190fmc_w(space, offset, data); | |
| 4157 | break; | |
| 4158 | case 0x4000: | |
| 4159 | state->m_IRQ_count_latch = (0x100 - data) & 0xff; | |
| 4160 | break; | |
| 4161 | case 0x4001: | |
| 4162 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 4163 | break; | |
| 4164 | case 0x4002: | |
| 4165 | state->m_IRQ_enable = 1; | |
| 4166 | break; | |
| 4167 | case 0x4003: | |
| 4168 | state->m_IRQ_enable = 0; | |
| 4169 | break; | |
| 4170 | case 0x6000: | |
| 4171 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4172 | break; | |
| 4173 | } | |
| 4174 | } | |
| 4175 | ||
| 4176 | /************************************************************* | |
| 4177 | ||
| 4178 | Taito X1-005 board emulation | |
| 4179 | ||
| 4180 | Actually, Fudou Myouou Den uses a variant of the board with | |
| 4181 | CIRAM, making necessary two distinct mappers & pcb_id. | |
| 4182 | ||
| 4183 | Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9 | |
| 4184 | and the 0x80 ram! | |
| 4185 | ||
| 4186 | iNES: mappers 80 & 207 | |
| 4187 | ||
| 4188 | *************************************************************/ | |
| 4189 | ||
| 4190 | static WRITE8_HANDLER( x1005_m_w ) | |
| 4191 | { | |
| 4192 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4193 | LOG_MMC(("x1005_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4194 | ||
| 4195 | switch (offset) | |
| 4196 | { | |
| 4197 | case 0x1ef0: | |
| 4198 | chr2_0(space->machine(), (data & 0x7f) >> 1, CHRROM); | |
| 4199 | break; | |
| 4200 | case 0x1ef1: | |
| 4201 | chr2_2(space->machine(), (data & 0x7f) >> 1, CHRROM); | |
| 4202 | break; | |
| 4203 | case 0x1ef2: | |
| 4204 | chr1_4(space->machine(), data, CHRROM); | |
| 4205 | break; | |
| 4206 | case 0x1ef3: | |
| 4207 | chr1_5(space->machine(), data, CHRROM); | |
| 4208 | break; | |
| 4209 | case 0x1ef4: | |
| 4210 | chr1_6(space->machine(), data, CHRROM); | |
| 4211 | break; | |
| 4212 | case 0x1ef5: | |
| 4213 | chr1_7(space->machine(), data, CHRROM); | |
| 4214 | break; | |
| 4215 | case 0x1ef6: | |
| 4216 | case 0x1ef7: | |
| 4217 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 4218 | break; | |
| 4219 | case 0x1ef8: | |
| 4220 | case 0x1ef9: | |
| 4221 | state->m_mmc_latch1 = data; | |
| 4222 | break; | |
| 4223 | case 0x1efa: | |
| 4224 | case 0x1efb: | |
| 4225 | prg8_89(space->machine(), data); | |
| 4226 | break; | |
| 4227 | case 0x1efc: | |
| 4228 | case 0x1efd: | |
| 4229 | prg8_ab(space->machine(), data); | |
| 4230 | break; | |
| 4231 | case 0x1efe: | |
| 4232 | case 0x1eff: | |
| 4233 | prg8_cd(space->machine(), data); | |
| 4234 | break; | |
| 4235 | default: | |
| 4236 | logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data); | |
| 4237 | break; | |
| 4238 | } | |
| 4239 | ||
| 4240 | if (offset >= 0x1f00 && state->m_mapper_ram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4241 | state->m_mapper_ram[offset & (state->m_mapper_ram_size - 1)] = data; | |
| 4242 | else if (offset >= 0x1f00 && state->m_mapper_bram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4243 | state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data; | |
| 4244 | } | |
| 4245 | ||
| 4246 | static READ8_HANDLER( x1005_m_r ) | |
| 4247 | { | |
| 4248 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4249 | LOG_MMC(("x1005a_m_r, offset: %04x\n", offset)); | |
| 4250 | ||
| 4251 | if (offset >= 0x1f00 && state->m_mapper_ram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4252 | return state->m_mapper_ram[offset & (state->m_mapper_ram_size - 1)]; | |
| 4253 | else if (offset >= 0x1f00 && state->m_mapper_bram != NULL && state->m_mmc_latch1 == 0xa3) | |
| 4254 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4255 | ||
| 4256 | return 0xff; | |
| 4257 | } | |
| 4258 | ||
| 4259 | static WRITE8_HANDLER( x1005a_m_w ) | |
| 4260 | { | |
| 4261 | LOG_MMC(("x1005a_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4262 | ||
| 4263 | // similar to x1005_m_w but mirroring is handled differently | |
| 4264 | if (offset == 0x1ef6 || offset == 0x1ef7) | |
| 4265 | return; | |
| 4266 | ||
| 4267 | switch (offset) | |
| 4268 | { | |
| 4269 | case 0x1ef0: | |
| 4270 | set_nt_page(space->machine(), 0, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4271 | set_nt_page(space->machine(), 1, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4272 | break; | |
| 4273 | case 0x1ef1: | |
| 4274 | set_nt_page(space->machine(), 2, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4275 | set_nt_page(space->machine(), 3, CIRAM, (data & 0x80) ? 1 : 0, 1); | |
| 4276 | break; | |
| 4277 | } | |
| 4278 | ||
| 4279 | x1005_m_w(space, offset, data); | |
| 4280 | } | |
| 4281 | ||
| 4282 | /************************************************************* | |
| 4283 | ||
| 4284 | Taito X1-017 board emulation | |
| 4285 | ||
| 4286 | We miss to emulate the security check at 0x6000-0x73ff | |
| 4287 | and the ram! | |
| 4288 | ||
| 4289 | Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri | |
| 4290 | Stadium, SD Keiji - Blader | |
| 4291 | ||
| 4292 | iNES: mapper 82 | |
| 4293 | ||
| 4294 | In MESS: Supported. | |
| 4295 | ||
| 4296 | *************************************************************/ | |
| 4297 | ||
| 4298 | static void x1017_set_chr( running_machine &machine ) | |
| 4299 | { | |
| 4300 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4301 | if (state->m_mmc_latch1) | |
| 4302 | { | |
| 4303 | chr2_4(machine, state->m_mmc_vrom_bank[0] >> 1, CHRROM); | |
| 4304 | chr2_6(machine, state->m_mmc_vrom_bank[1] >> 1, CHRROM); | |
| 4305 | } | |
| 4306 | else | |
| 4307 | { | |
| 4308 | chr2_0(machine, state->m_mmc_vrom_bank[0] >> 1, CHRROM); | |
| 4309 | chr2_2(machine, state->m_mmc_vrom_bank[1] >> 1, CHRROM); | |
| 4310 | } | |
| 4311 | chr1_x(machine, 4 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[2], CHRROM); | |
| 4312 | chr1_x(machine, 5 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[3], CHRROM); | |
| 4313 | chr1_x(machine, 6 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[4], CHRROM); | |
| 4314 | chr1_x(machine, 7 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[5], CHRROM); | |
| 4315 | } | |
| 4316 | ||
| 4317 | static WRITE8_HANDLER( x1017_m_w ) | |
| 4318 | { | |
| 4319 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4320 | UINT8 reg = offset & 0x07; | |
| 4321 | LOG_MMC(("x1017_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4322 | ||
| 4323 | switch (offset) | |
| 4324 | { | |
| 4325 | case 0x1ef0: | |
| 4326 | case 0x1ef1: | |
| 4327 | if (state->m_mmc_vrom_bank[reg] != data) | |
| 4328 | { | |
| 4329 | state->m_mmc_vrom_bank[reg] = data; | |
| 4330 | x1017_set_chr(space->machine()); | |
| 4331 | } | |
| 4332 | break; | |
| 4333 | case 0x1ef2: | |
| 4334 | case 0x1ef3: | |
| 4335 | case 0x1ef4: | |
| 4336 | case 0x1ef5: | |
| 4337 | if (state->m_mmc_vrom_bank[reg] != data) | |
| 4338 | { | |
| 4339 | state->m_mmc_vrom_bank[reg] = data; | |
| 4340 | x1017_set_chr(space->machine()); | |
| 4341 | } | |
| 4342 | break; | |
| 4343 | case 0x1ef6: | |
| 4344 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 4345 | state->m_mmc_latch1 = ((data & 0x02) << 1); | |
| 4346 | x1017_set_chr(space->machine()); | |
| 4347 | break; | |
| 4348 | case 0x1ef7: | |
| 4349 | case 0x1ef8: | |
| 4350 | case 0x1ef9: | |
| 4351 | state->m_mmc_reg[(offset & 0x0f) - 7] = data; | |
| 4352 | break; | |
| 4353 | case 0x1efa: | |
| 4354 | prg8_89(space->machine(), data >> 2); | |
| 4355 | break; | |
| 4356 | case 0x1efb: | |
| 4357 | prg8_ab(space->machine(), data >> 2); | |
| 4358 | break; | |
| 4359 | case 0x1efc: | |
| 4360 | prg8_cd(space->machine(), data >> 2); | |
| 4361 | break; | |
| 4362 | default: | |
| 4363 | logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data); | |
| 4364 | break; | |
| 4365 | } | |
| 4366 | } | |
| 4367 | ||
| 4368 | static READ8_HANDLER( x1017_m_r ) | |
| 4369 | { | |
| 4370 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4371 | LOG_MMC(("x1017_m_r, offset: %04x\n", offset)); | |
| 4372 | ||
| 4373 | // 2+2+1 KB of Internal RAM can be independently enabled/disabled! | |
| 4374 | if (offset < 0x0800 && state->m_mapper_bram != NULL && state->m_mmc_reg[0] == 0xca) | |
| 4375 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4376 | if (offset < 0x1000 && state->m_mapper_bram != NULL && state->m_mmc_reg[1] == 0x69) | |
| 4377 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4378 | if (offset < 0x1800 && state->m_mapper_bram != NULL && state->m_mmc_reg[2] == 0x84) | |
| 4379 | return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)]; | |
| 4380 | ||
| 4381 | return 0xff; | |
| 4382 | } | |
| 4383 | ||
| 4384 | /************************************************************* | |
| 4385 | ||
| 4386 | MISC UNLICENSED BOARDS | |
| 4387 | ||
| 4388 | *************************************************************/ | |
| 4389 | ||
| 4390 | /************************************************************* | |
| 4391 | ||
| 4392 | AGCI 50282 bootleg board emulation | |
| 4393 | ||
| 4394 | Games: Death Race | |
| 4395 | ||
| 4396 | iNES: mapper 144 | |
| 4397 | ||
| 4398 | In MESS: Supported. | |
| 4399 | ||
| 4400 | *************************************************************/ | |
| 4401 | ||
| 4402 | static WRITE8_HANDLER( agci_50282_w ) | |
| 4403 | { | |
| 4404 | LOG_MMC(("agci_50282_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4405 | ||
| 4406 | offset += 0x8000; | |
| 4407 | data |= (space->read_byte(offset) & 1); | |
| 4408 | ||
| 4409 | chr8(space->machine(), data >> 4, CHRROM); | |
| 4410 | prg32(space->machine(), data); | |
| 4411 | } | |
| 4412 | ||
| 4413 | /************************************************************* | |
| 4414 | ||
| 4415 | AVE NINA-001 board emulation | |
| 4416 | ||
| 4417 | iNES: mapper 34 | |
| 4418 | ||
| 4419 | *************************************************************/ | |
| 4420 | ||
| 4421 | static WRITE8_HANDLER( nina01_m_w ) | |
| 4422 | { | |
| 4423 | LOG_MMC(("nina01_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4424 | ||
| 4425 | switch (offset) | |
| 4426 | { | |
| 4427 | case 0x1ffd: | |
| 4428 | prg32(space->machine(), data); | |
| 4429 | break; | |
| 4430 | case 0x1ffe: | |
| 4431 | chr4_0(space->machine(), data, CHRROM); | |
| 4432 | break; | |
| 4433 | case 0x1fff: | |
| 4434 | chr4_4(space->machine(), data, CHRROM); | |
| 4435 | break; | |
| 4436 | } | |
| 4437 | } | |
| 4438 | ||
| 4439 | /************************************************************* | |
| 4440 | ||
| 4441 | AVE NINA-003, NINA-006 and MB-91 boards emulation | |
| 4442 | ||
| 4443 | Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid, | |
| 4444 | Solitaire, Ultimate League Soccer | |
| 4445 | ||
| 4446 | iNES: mapper 79 | |
| 4447 | ||
| 4448 | In MESS: Supported. | |
| 4449 | ||
| 4450 | *************************************************************/ | |
| 4451 | ||
| 4452 | static WRITE8_HANDLER( nina06_l_w ) | |
| 4453 | { | |
| 4454 | LOG_MMC(("nina06_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4455 | ||
| 4456 | if (!(offset & 0x0100)) | |
| 4457 | { | |
| 4458 | prg32(space->machine(), data >> 3); | |
| 4459 | chr8(space->machine(), data, CHRROM); | |
| 4460 | } | |
| 4461 | } | |
| 4462 | ||
| 4463 | /************************************************************* | |
| 4464 | ||
| 4465 | Active Entertainment Action 52 board emulation | |
| 4466 | ||
| 4467 | iNES: mapper 228 | |
| 4468 | ||
| 4469 | *************************************************************/ | |
| 4470 | ||
| 4471 | static WRITE8_HANDLER( ae_act52_w ) | |
| 4472 | { | |
| 4473 | int pbank, cbank; | |
| 4474 | UINT8 pmode; | |
| 4475 | LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4476 | ||
| 4477 | set_nt_mirroring(space->machine(), BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4478 | ||
| 4479 | cbank = (data & 0x03) | ((offset & 0x0f) << 2); | |
| 4480 | chr8(space->machine(), cbank, CHRROM); | |
| 4481 | ||
| 4482 | pmode = offset & 0x20; | |
| 4483 | pbank = (offset & 0x1fc0) >> 6; | |
| 4484 | if (pmode) | |
| 4485 | { | |
| 4486 | prg16_89ab(space->machine(), pbank); | |
| 4487 | prg16_cdef(space->machine(), pbank); | |
| 4488 | } | |
| 4489 | else | |
| 4490 | prg32(space->machine(), pbank >> 1); | |
| 4491 | } | |
| 4492 | ||
| 4493 | ||
| 4494 | /************************************************************* | |
| 4495 | ||
| 4496 | C & E Bootleg Board for Decathlon | |
| 4497 | ||
| 4498 | Games: Decathlon | |
| 4499 | ||
| 4500 | Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to | |
| 4501 | data & 3; writes to 0x80a5-0x80e4 set chr8 to data & 7 | |
| 4502 | ||
| 4503 | iNES: mapper 244 | |
| 4504 | ||
| 4505 | In MESS: Supported. | |
| 4506 | ||
| 4507 | *************************************************************/ | |
| 4508 | ||
| 4509 | static WRITE8_HANDLER( cne_decathl_w ) | |
| 4510 | { | |
| 4511 | LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4512 | ||
| 4513 | if (offset < 0x0065) | |
| 4514 | return; | |
| 4515 | if (offset < 0x00a5) | |
| 4516 | { | |
| 4517 | prg32(space->machine(), (offset - 0x0065) & 0x03); | |
| 4518 | return; | |
| 4519 | } | |
| 4520 | if (offset < 0x00e5) | |
| 4521 | { | |
| 4522 | chr8(space->machine(), (offset - 0x00a5) & 0x07, CHRROM); | |
| 4523 | } | |
| 4524 | } | |
| 4525 | ||
| 4526 | /************************************************************* | |
| 4527 | ||
| 4528 | C & E Bootleg Board for Fong Shen Bang | |
| 4529 | ||
| 4530 | Games: Fong Shen Bang - Zhu Lu Zhi Zhan | |
| 4531 | ||
| 4532 | Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks. | |
| 4533 | Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd | |
| 4534 | and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2, | |
| 4535 | chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM. | |
| 4536 | ||
| 4537 | iNES: mapper 246 | |
| 4538 | ||
| 4539 | In MESS: Supported. | |
| 4540 | ||
| 4541 | *************************************************************/ | |
| 4542 | ||
| 4543 | static WRITE8_HANDLER( cne_fsb_m_w ) | |
| 4544 | { | |
| 4545 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4546 | LOG_MMC(("cne_fsb_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4547 | ||
| 4548 | if (offset < 0x0800) | |
| 4549 | { | |
| 4550 | switch (offset & 0x0007) | |
| 4551 | { | |
| 4552 | case 0x0000: | |
| 4553 | prg8_89(space->machine(), data); | |
| 4554 | break; | |
| 4555 | case 0x0001: | |
| 4556 | prg8_ab(space->machine(), data); | |
| 4557 | break; | |
| 4558 | case 0x0002: | |
| 4559 | prg8_cd(space->machine(), data); | |
| 4560 | break; | |
| 4561 | case 0x0003: | |
| 4562 | prg8_ef(space->machine(), data); | |
| 4563 | break; | |
| 4564 | case 0x0004: | |
| 4565 | chr2_0(space->machine(), data, CHRROM); | |
| 4566 | break; | |
| 4567 | case 0x0005: | |
| 4568 | chr2_2(space->machine(), data, CHRROM); | |
| 4569 | break; | |
| 4570 | case 0x0006: | |
| 4571 | chr2_4(space->machine(), data, CHRROM); | |
| 4572 | break; | |
| 4573 | case 0x0007: | |
| 4574 | chr2_6(space->machine(), data, CHRROM); | |
| 4575 | break; | |
| 4576 | } | |
| 4577 | } | |
| 4578 | else | |
| 4579 | state->m_battery_ram[offset] = data; | |
| 4580 | } | |
| 4581 | ||
| 4582 | /************************************************************* | |
| 4583 | ||
| 4584 | C & E Bootleg Board for Sheng Huo Lie Zhuan | |
| 4585 | ||
| 4586 | Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan | |
| 4587 | ||
| 4588 | Simple Mapper: writes to 0x4020-0x5fff sets prg32 to | |
| 4589 | data>>4 and chr8 to data&f. We currently do not map | |
| 4590 | writes to 0x4020-0x40ff (to do: verify if this produces | |
| 4591 | issues) | |
| 4592 | ||
| 4593 | iNES: mapper 240 | |
| 4594 | ||
| 4595 | In MESS: Supported. | |
| 4596 | ||
| 4597 | *************************************************************/ | |
| 4598 | ||
| 4599 | static WRITE8_HANDLER( cne_shlz_l_w ) | |
| 4600 | { | |
| 4601 | LOG_MMC(("cne_shlz_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4602 | ||
| 4603 | prg32(space->machine(), data >> 4); | |
| 4604 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 4605 | } | |
| 4606 | ||
| 4607 | /************************************************************* | |
| 4608 | ||
| 4609 | Caltron 6 in 1 Board | |
| 4610 | ||
| 4611 | Games: 6 in 1 by Caltron | |
| 4612 | ||
| 4613 | iNES: mapper 41 | |
| 4614 | ||
| 4615 | In MESS: Supported. | |
| 4616 | ||
| 4617 | *************************************************************/ | |
| 4618 | ||
| 4619 | static WRITE8_HANDLER( caltron6in1_m_w ) | |
| 4620 | { | |
| 4621 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4622 | LOG_MMC(("caltron6in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4623 | ||
| 4624 | state->m_mmc_latch1 = offset & 0xff; | |
| 4625 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 4626 | prg32(space->machine(), offset & 0x07); | |
| 4627 | } | |
| 4628 | ||
| 4629 | static WRITE8_HANDLER( caltron6in1_w ) | |
| 4630 | { | |
| 4631 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4632 | LOG_MMC(("caltron6in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4633 | ||
| 4634 | if (state->m_mmc_latch1 & 0x04) | |
| 4635 | chr8(space->machine(), ((state->m_mmc_latch1 & 0x18) >> 1) | (data & 0x03), CHRROM); | |
| 4636 | } | |
| 4637 | ||
| 4638 | /************************************************************* | |
| 4639 | ||
| 4640 | Camerica Boards (BF9093, BF9097, BF909X, ALGNV11) | |
| 4641 | ||
| 4642 | Games: Linus Spacehead's Cosmic Crusade, Micro Machines, | |
| 4643 | Mig-29, Stunt Kids | |
| 4644 | ||
| 4645 | To emulate NT mirroring for BF9097 board (missing in BF9093) | |
| 4646 | we use crc_hack, however Fire Hawk is broken (but without | |
| 4647 | mirroring there would be no helicopter graphics). | |
| 4648 | ||
| 4649 | iNES: mapper 71 | |
| 4650 | ||
| 4651 | In MESS: Partially Supported. | |
| 4652 | ||
| 4653 | *************************************************************/ | |
| 4654 | ||
| 4655 | static WRITE8_HANDLER( bf9093_w ) | |
| 4656 | { | |
| 4657 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4658 | LOG_MMC(("bf9093_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4659 | ||
| 4660 | switch (offset & 0x7000) | |
| 4661 | { | |
| 4662 | case 0x0000: | |
| 4663 | case 0x1000: | |
| 4664 | if (!state->m_hard_mirroring) | |
| 4665 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 4666 | break; | |
| 4667 | case 0x4000: | |
| 4668 | case 0x5000: | |
| 4669 | case 0x6000: | |
| 4670 | case 0x7000: | |
| 4671 | prg16_89ab(space->machine(), data); | |
| 4672 | break; | |
| 4673 | } | |
| 4674 | } | |
| 4675 | ||
| 4676 | /************************************************************* | |
| 4677 | ||
| 4678 | Camerica BF9096 & ALGQV11 Boards | |
| 4679 | ||
| 4680 | Games: Quattro Adventure, Quattro Arcade, Quattro Sports | |
| 4681 | ||
| 4682 | Writes to 0x8000-0x9fff set prg block to (data&0x18)>>1, | |
| 4683 | writes to 0xa000-0xbfff set prg page to data&3. selected | |
| 4684 | prg are: prg16_89ab = block|page, prg_cdef = 3|page. | |
| 4685 | For more info on the hardware to bypass the NES lockout, see | |
| 4686 | Kevtris' Camerica Mappers documentation. | |
| 4687 | ||
| 4688 | iNES: mapper 232 | |
| 4689 | ||
| 4690 | In MESS: Supported. | |
| 4691 | ||
| 4692 | *************************************************************/ | |
| 4693 | ||
| 4694 | static void bf9096_set_prg( running_machine &machine ) | |
| 4695 | { | |
| 4696 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4697 | prg16_89ab(machine, (state->m_mmc_latch2 & 0x03) | ((state->m_mmc_latch1 & 0x18) >> 1)); | |
| 4698 | prg16_cdef(machine, 0x03 | ((state->m_mmc_latch1 & 0x18) >> 1)); | |
| 4699 | } | |
| 4700 | ||
| 4701 | static WRITE8_HANDLER( bf9096_w ) | |
| 4702 | { | |
| 4703 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4704 | LOG_MMC(("bf9096_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4705 | ||
| 4706 | if (offset < 0x2000) | |
| 4707 | state->m_mmc_latch1 = data; | |
| 4708 | else | |
| 4709 | state->m_mmc_latch2 = data; | |
| 4710 | ||
| 4711 | bf9096_set_prg(space->machine()); | |
| 4712 | } | |
| 4713 | ||
| 4714 | /************************************************************* | |
| 4715 | ||
| 4716 | Camerica Golden Five board | |
| 4717 | ||
| 4718 | Games: Pegasus 5 in 1 | |
| 4719 | ||
| 4720 | iNES: mapper 104 | |
| 4721 | ||
| 4722 | In MESS: Supported. | |
| 4723 | ||
| 4724 | *************************************************************/ | |
| 4725 | ||
| 4726 | static WRITE8_HANDLER( golden5_w ) | |
| 4727 | { | |
| 4728 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4729 | LOG_MMC(("golden5_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4730 | ||
| 4731 | if (offset < 0x4000) | |
| 4732 | { | |
| 4733 | if (data & 0x08) | |
| 4734 | { | |
| 4735 | state->m_mmc_prg_bank[0] = ((data & 0x07) << 4) | (state->m_mmc_prg_bank[0] & 0x0f); | |
| 4736 | prg16_89ab(space->machine(), state->m_mmc_prg_bank[0]); | |
| 4737 | prg16_cdef(space->machine(), ((data & 0x07) << 4) | 0x0f); | |
| 4738 | } | |
| 4739 | ||
| 4740 | } | |
| 4741 | else | |
| 4742 | { | |
| 4743 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x70) | (data & 0x0f); | |
| 4744 | prg16_89ab(space->machine(), state->m_mmc_prg_bank[0]); | |
| 4745 | } | |
| 4746 | } | |
| 4747 | ||
| 4748 | /************************************************************* | |
| 4749 | ||
| 4750 | Cony Bootleg Board | |
| 4751 | ||
| 4752 | Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II | |
| 4753 | Pro, World Heroes 2 | |
| 4754 | ||
| 4755 | iNES: mapper 83 | |
| 4756 | ||
| 4757 | In MESS: Supported. | |
| 4758 | ||
| 4759 | *************************************************************/ | |
| 4760 | ||
| 4761 | static WRITE8_HANDLER( cony_l_w ) | |
| 4762 | { | |
| 4763 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4764 | LOG_MMC(("cony_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4765 | ||
| 4766 | if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff | |
| 4767 | state->m_mapper83_low_reg[offset & 0x03] = data; | |
| 4768 | } | |
| 4769 | ||
| 4770 | static READ8_HANDLER( cony_l_r ) | |
| 4771 | { | |
| 4772 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4773 | LOG_MMC(("cony_l_r, offset: %04x\n", offset)); | |
| 4774 | ||
| 4775 | if (offset == 0x0f00) // 0x5000 | |
| 4776 | { | |
| 4777 | // read dipswitch bit! - currently unimplemented | |
| 4778 | } | |
| 4779 | if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff | |
| 4780 | return state->m_mapper83_low_reg[offset & 0x03]; | |
| 4781 | else | |
| 4782 | return 0x00; | |
| 4783 | } | |
| 4784 | ||
| 4785 | static void cony_set_prg( running_machine &machine ) | |
| 4786 | { | |
| 4787 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4788 | prg16_89ab(machine, state->m_mapper83_reg[8] & 0x3f); | |
| 4789 | prg16_cdef(machine, (state->m_mapper83_reg[8] & 0x30) | 0x0f); | |
| 4790 | } | |
| 4791 | ||
| 4792 | static void cony_set_chr( running_machine &machine ) | |
| 4793 | { | |
| 4794 | nes_state *state = machine.driver_data<nes_state>(); | |
| 4795 | // FIXME: here we emulate at least 3 different boards!!! | |
| 4796 | // one board switches 1k VROM banks only | |
| 4797 | // one writes to 0x8000 and then switches 2k VROM banks only | |
| 4798 | // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only | |
| 4799 | // we should split them and possibly document the proper behavior of each variant | |
| 4800 | if (state->m_mmc_latch1 && !state->m_mmc_latch2) | |
| 4801 | { | |
| 4802 | chr2_0(machine, state->m_mapper83_reg[0], CHRROM); | |
| 4803 | chr2_2(machine, state->m_mapper83_reg[1], CHRROM); | |
| 4804 | chr2_4(machine, state->m_mapper83_reg[6], CHRROM); | |
| 4805 | chr2_6(machine, state->m_mapper83_reg[7], CHRROM); | |
| 4806 | } | |
| 4807 | else | |
| 4808 | { | |
| 4809 | chr1_0(machine, state->m_mapper83_reg[0] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4810 | chr1_1(machine, state->m_mapper83_reg[1] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4811 | chr1_2(machine, state->m_mapper83_reg[2] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4812 | chr1_3(machine, state->m_mapper83_reg[3] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4813 | chr1_4(machine, state->m_mapper83_reg[4] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4814 | chr1_5(machine, state->m_mapper83_reg[5] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4815 | chr1_6(machine, state->m_mapper83_reg[6] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4816 | chr1_7(machine, state->m_mapper83_reg[7] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM); | |
| 4817 | } | |
| 4818 | } | |
| 4819 | ||
| 4820 | static WRITE8_HANDLER( cony_w ) | |
| 4821 | { | |
| 4822 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4823 | LOG_MMC(("cony_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4824 | ||
| 4825 | switch (offset) | |
| 4826 | { | |
| 4827 | case 0x0000: | |
| 4828 | state->m_mmc_latch1 = 1; | |
| 4829 | case 0x3000: | |
| 4830 | case 0x30ff: | |
| 4831 | case 0x31ff: | |
| 4832 | state->m_mapper83_reg[8] = data; | |
| 4833 | cony_set_prg(space->machine()); | |
| 4834 | cony_set_chr(space->machine()); | |
| 4835 | break; | |
| 4836 | case 0x0100: | |
| 4837 | state->m_mmc_reg[0] = data & 0x80; | |
| 4838 | switch (data & 0x03) | |
| 4839 | { | |
| 4840 | case 0: | |
| 4841 | set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); | |
| 4842 | break; | |
| 4843 | case 1: | |
| 4844 | set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); | |
| 4845 | break; | |
| 4846 | case 2: | |
| 4847 | set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); | |
| 4848 | break; | |
| 4849 | case 3: | |
| 4850 | set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); | |
| 4851 | break; | |
| 4852 | } | |
| 4853 | break; | |
| 4854 | case 0x0200: | |
| 4855 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 4856 | break; | |
| 4857 | case 0x0201: | |
| 4858 | state->m_IRQ_enable = state->m_mmc_reg[0]; | |
| 4859 | state->m_IRQ_count = (data << 8) | (state->m_IRQ_count & 0xff); | |
| 4860 | break; | |
| 4861 | case 0x0300: | |
| 4862 | prg8_89(space->machine(), data); | |
| 4863 | break; | |
| 4864 | case 0x0301: | |
| 4865 | prg8_ab(space->machine(), data); | |
| 4866 | break; | |
| 4867 | case 0x0302: | |
| 4868 | prg8_cd(space->machine(), data); | |
| 4869 | break; | |
| 4870 | case 0x0312: | |
| 4871 | case 0x0313: | |
| 4872 | case 0x0314: | |
| 4873 | case 0x0315: | |
| 4874 | state->m_mmc_latch2 = 1; | |
| 4875 | case 0x0310: | |
| 4876 | case 0x0311: | |
| 4877 | case 0x0316: | |
| 4878 | case 0x0317: | |
| 4879 | state->m_mapper83_reg[offset - 0x0310] = data; | |
| 4880 | cony_set_chr(space->machine()); | |
| 4881 | break; | |
| 4882 | case 0x0318: | |
| 4883 | state->m_mapper83_reg[9] = data; | |
| 4884 | cony_set_prg(space->machine()); | |
| 4885 | break; | |
| 4886 | } | |
| 4887 | } | |
| 4888 | ||
| 4889 | /************************************************************* | |
| 4890 | ||
| 4891 | Board DREAMTECH01 | |
| 4892 | ||
| 4893 | Games: Korean Igo | |
| 4894 | ||
| 4895 | In MESS: Supported | |
| 4896 | ||
| 4897 | *************************************************************/ | |
| 4898 | ||
| 4899 | static WRITE8_HANDLER( dreamtech_l_w ) | |
| 4900 | { | |
| 4901 | LOG_MMC(("dreamtech_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 4902 | offset += 0x100; | |
| 4903 | ||
| 4904 | if (offset == 0x1020) /* 0x5020 */ | |
| 4905 | prg16_89ab(space->machine(), data); | |
| 4906 | } | |
| 4907 | ||
| 4908 | /************************************************************* | |
| 4909 | ||
| 4910 | Bootleg Board by Fukutake | |
| 4911 | ||
| 4912 | Games: Study Box | |
| 4913 | ||
| 4914 | iNES: mapper 186 | |
| 4915 | ||
| 4916 | In MESS: Unsupported. | |
| 4917 | ||
| 4918 | ||
| 4919 | *************************************************************/ | |
| 4920 | ||
| 4921 | static WRITE8_HANDLER( fukutake_l_w ) | |
| 4922 | { | |
| 4923 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4924 | LOG_MMC(("fukutake_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 4925 | offset += 0x100; | |
| 4926 | ||
| 4927 | if (offset >= 0x200 && offset < 0x400) | |
| 4928 | { | |
| 4929 | if (offset & 1) | |
| 4930 | prg16_89ab(space->machine(), data); | |
| 4931 | else | |
| 4932 | wram_bank(space->machine(), data >> 6, NES_WRAM); | |
| 4933 | } | |
| 4934 | else if (offset >= 0x400 && offset < 0xf00) | |
| 4935 | state->m_mapper_ram[offset - 0x400] = data; | |
| 4936 | } | |
| 4937 | ||
| 4938 | static READ8_HANDLER( fukutake_l_r ) | |
| 4939 | { | |
| 4940 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4941 | LOG_MMC(("fukutake_l_r offset: %04x\n", offset)); | |
| 4942 | offset += 0x100; | |
| 4943 | ||
| 4944 | if (offset >= 0x200 && offset < 0x400) | |
| 4945 | { | |
| 4946 | if (offset == 0x200 || offset == 0x201 || offset == 0x203) | |
| 4947 | return 0x00; | |
| 4948 | else if (offset == 0x202) | |
| 4949 | return 0x40; | |
| 4950 | else | |
| 4951 | return 0xff; | |
| 4952 | } | |
| 4953 | else if (offset >= 0x400 && offset < 0xf00) | |
| 4954 | return state->m_mapper_ram[offset - 0x400]; | |
| 4955 | ||
| 4956 | return 0; | |
| 4957 | } | |
| 4958 | ||
| 4959 | /************************************************************* | |
| 4960 | ||
| 4961 | Bootleg Board by Future Media | |
| 4962 | ||
| 4963 | Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun | |
| 4964 | ||
| 4965 | iNES: mapper 117 | |
| 4966 | ||
| 4967 | In MESS: Unsupported. | |
| 4968 | ||
| 4969 | *************************************************************/ | |
| 4970 | ||
| 4971 | static void futuremedia_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 4972 | { | |
| 4973 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 4974 | // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 4975 | { | |
| 4976 | if (state->m_IRQ_enable && state->m_IRQ_count) | |
| 4977 | { | |
| 4978 | state->m_IRQ_count--; | |
| 4979 | if (!state->m_IRQ_count) | |
| 4980 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 4981 | } | |
| 4982 | } | |
| 4983 | } | |
| 4984 | ||
| 4985 | static WRITE8_HANDLER( futuremedia_w ) | |
| 4986 | { | |
| 4987 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 4988 | LOG_MMC(("futuremedia_w, offset: %04x, data: %02x\n", offset, data)); | |
| 4989 | ||
| 4990 | switch (offset) | |
| 4991 | { | |
| 4992 | case 0x0000: | |
| 4993 | prg8_89(space->machine(), data); | |
| 4994 | break; | |
| 4995 | case 0x0001: | |
| 4996 | prg8_ab(space->machine(), data); | |
| 4997 | break; | |
| 4998 | case 0x0002: | |
| 4999 | prg8_cd(space->machine(), data); | |
| 5000 | break; | |
| 5001 | case 0x0003: | |
| 5002 | prg8_ef(space->machine(), data); | |
| 5003 | break; | |
| 5004 | case 0x2000: | |
| 5005 | case 0x2001: | |
| 5006 | case 0x2002: | |
| 5007 | case 0x2003: | |
| 5008 | case 0x2004: | |
| 5009 | case 0x2005: | |
| 5010 | case 0x2006: | |
| 5011 | case 0x2007: | |
| 5012 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 5013 | break; | |
| 5014 | ||
| 5015 | case 0x5000: | |
| 5016 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5017 | break; | |
| 5018 | ||
| 5019 | case 0x4001: | |
| 5020 | state->m_IRQ_count_latch = data; | |
| 5021 | break; | |
| 5022 | case 0x4002: | |
| 5023 | // IRQ cleared | |
| 5024 | break; | |
| 5025 | case 0x4003: | |
| 5026 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 5027 | break; | |
| 5028 | case 0x6000: | |
| 5029 | state->m_IRQ_enable = data & 0x01; | |
| 5030 | break; | |
| 5031 | } | |
| 5032 | } | |
| 5033 | ||
| 5034 | /************************************************************* | |
| 5035 | ||
| 5036 | Bootleg Board 37017 (?) by Gouder | |
| 5037 | ||
| 5038 | Games: Street Fighter IV | |
| 5039 | ||
| 5040 | MMC3 clone. It also requires reads from 0x5000-0x7fff. | |
| 5041 | ||
| 5042 | iNES: mapper 208 | |
| 5043 | ||
| 5044 | In MESS: Preliminary Support. | |
| 5045 | ||
| 5046 | *************************************************************/ | |
| 5047 | ||
| 5048 | static WRITE8_HANDLER( gouder_sf4_l_w ) | |
| 5049 | { | |
| 5050 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5051 | static const UINT8 conv_table[256] = | |
| 5052 | { | |
| 5053 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, | |
| 5054 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, | |
| 5055 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, | |
| 5056 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, | |
| 5057 | 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5058 | 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5059 | 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5060 | 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5061 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, | |
| 5062 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, | |
| 5063 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, | |
| 5064 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, | |
| 5065 | 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5066 | 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5067 | 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 5068 | 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
| 5069 | }; | |
| 5070 | ||
| 5071 | LOG_MMC(("gouder_sf4_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5072 | ||
| 5073 | if (!(offset < 0x1700)) | |
| 5074 | state->m_mmc_reg[offset & 0x03] = data ^ conv_table[state->m_mmc_reg[4]]; | |
| 5075 | else if (!(offset < 0xf00)) | |
| 5076 | state->m_mmc_reg[4] = data; | |
| 5077 | else if (!(offset < 0x700)) | |
| 5078 | prg32(space->machine(), ((data >> 3) & 0x02) | (data & 0x01)); | |
| 5079 | } | |
| 5080 | ||
| 5081 | static READ8_HANDLER( gouder_sf4_l_r ) | |
| 5082 | { | |
| 5083 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5084 | LOG_MMC(("gouder_sf4_l_r, offset: %04x\n", offset)); | |
| 5085 | ||
| 5086 | if (!(offset < 0x1700)) | |
| 5087 | return state->m_mmc_reg[offset & 0x03]; | |
| 5088 | ||
| 5089 | return 0x00; | |
| 5090 | } | |
| 5091 | ||
| 5092 | /* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ | |
| 5093 | static void gouder_sf4_prg_cb( running_machine &machine, int start, int bank ) | |
| 5094 | { | |
| 5095 | return; | |
| 5096 | } | |
| 5097 | ||
| 5098 | ||
| 5099 | /************************************************************* | |
| 5100 | ||
| 5101 | Bootleg Board by Henggedianzi | |
| 5102 | ||
| 5103 | Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu | |
| 5104 | Chou Ji | |
| 5105 | ||
| 5106 | Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets | |
| 5107 | NT mirroring. | |
| 5108 | ||
| 5109 | iNES: mapper 177 | |
| 5110 | ||
| 5111 | In MESS: Supported. | |
| 5112 | ||
| 5113 | *************************************************************/ | |
| 5114 | ||
| 5115 | static WRITE8_HANDLER( henggedianzi_w ) | |
| 5116 | { | |
| 5117 | LOG_MMC(("henggedianzi_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5118 | ||
| 5119 | prg32(space->machine(), data); | |
| 5120 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5121 | } | |
| 5122 | ||
| 5123 | /************************************************************* | |
| 5124 | ||
| 5125 | Bootleg Board by Henggedianzi | |
| 5126 | ||
| 5127 | Games: Xing He Zhan Shi | |
| 5128 | ||
| 5129 | Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000- | |
| 5130 | 0xffff set NT mirroring | |
| 5131 | ||
| 5132 | iNES: mapper 179 | |
| 5133 | ||
| 5134 | In MESS: Supported. | |
| 5135 | ||
| 5136 | *************************************************************/ | |
| 5137 | ||
| 5138 | static WRITE8_HANDLER( heng_xjzb_l_w ) | |
| 5139 | { | |
| 5140 | LOG_MMC(("heng_xjzb_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5141 | offset += 0x4100; | |
| 5142 | ||
| 5143 | if (offset & 0x5000) | |
| 5144 | prg32(space->machine(), data >> 1); | |
| 5145 | } | |
| 5146 | ||
| 5147 | static WRITE8_HANDLER( heng_xjzb_w ) | |
| 5148 | { | |
| 5149 | LOG_MMC(("heng_xjzb_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5150 | ||
| 5151 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5152 | } | |
| 5153 | ||
| 5154 | /************************************************************* | |
| 5155 | ||
| 5156 | Bootleg Board by HES (also used by others) | |
| 5157 | ||
| 5158 | Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder, | |
| 5159 | Total Funpack | |
| 5160 | ||
| 5161 | Actually, two variant: one for HES 6-in-1 with mirroring control | |
| 5162 | and one for AV Soccer and others with hardwired mirroring | |
| 5163 | ||
| 5164 | iNES: mapper 113 | |
| 5165 | ||
| 5166 | In MESS: Supported. | |
| 5167 | ||
| 5168 | *************************************************************/ | |
| 5169 | ||
| 5170 | static WRITE8_HANDLER( hes6in1_l_w ) | |
| 5171 | { | |
| 5172 | LOG_MMC(("hes6in1_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5173 | ||
| 5174 | if (!(offset & 0x100)) | |
| 5175 | { | |
| 5176 | prg32(space->machine(), (data & 0x38) >> 3); | |
| 5177 | chr8(space->machine(), (data & 0x07) | ((data & 0x40) >> 3), CHRROM); | |
| 5178 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 5179 | } | |
| 5180 | } | |
| 5181 | ||
| 5182 | static WRITE8_HANDLER( hes_l_w ) | |
| 5183 | { | |
| 5184 | LOG_MMC(("hes_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5185 | ||
| 5186 | if (!(offset & 0x100)) | |
| 5187 | { | |
| 5188 | prg32(space->machine(), (data & 0x38) >> 3); | |
| 5189 | chr8(space->machine(), (data & 0x07) | ((data & 0x40) >> 3), CHRROM); | |
| 5190 | } | |
| 5191 | } | |
| 5192 | ||
| 5193 | /************************************************************* | |
| 5194 | ||
| 5195 | Bootleg Board by Hosenkan | |
| 5196 | ||
| 5197 | Games: Pocahontas, Super Donkey Kong | |
| 5198 | ||
| 5199 | iNES: mapper 182 | |
| 5200 | ||
| 5201 | In MESS: Supported. | |
| 5202 | ||
| 5203 | *************************************************************/ | |
| 5204 | ||
| 5205 | static WRITE8_HANDLER( hosenkan_w ) | |
| 5206 | { | |
| 5207 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5208 | LOG_MMC(("hosenkan_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5209 | ||
| 5210 | switch (offset & 0x7003) | |
| 5211 | { | |
| 5212 | case 0x0001: | |
| 5213 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5214 | break; | |
| 5215 | case 0x2000: | |
| 5216 | state->m_mmc_latch1 = data; | |
| 5217 | break; | |
| 5218 | case 0x4000: | |
| 5219 | switch (state->m_mmc_latch1) | |
| 5220 | { | |
| 5221 | case 0: | |
| 5222 | chr2_0(space->machine(), data >> 1, CHRROM); | |
| 5223 | break; | |
| 5224 | case 1: | |
| 5225 | chr1_5(space->machine(), data, CHRROM); | |
| 5226 | break; | |
| 5227 | case 2: | |
| 5228 | chr2_2(space->machine(), data >> 1, CHRROM); | |
| 5229 | break; | |
| 5230 | case 3: | |
| 5231 | chr1_7(space->machine(), data, CHRROM); | |
| 5232 | break; | |
| 5233 | case 4: | |
| 5234 | prg8_89(space->machine(), data); | |
| 5235 | break; | |
| 5236 | case 5: | |
| 5237 | prg8_ab(space->machine(), data); | |
| 5238 | break; | |
| 5239 | case 6: | |
| 5240 | chr1_4(space->machine(), data, CHRROM); | |
| 5241 | break; | |
| 5242 | case 7: | |
| 5243 | chr1_6(space->machine(), data, CHRROM); | |
| 5244 | break; | |
| 5245 | } | |
| 5246 | break; | |
| 5247 | case 0x6003: | |
| 5248 | if (data) | |
| 5249 | { | |
| 5250 | state->m_IRQ_count = data; | |
| 5251 | state->m_IRQ_enable = 1; | |
| 5252 | } | |
| 5253 | else | |
| 5254 | state->m_IRQ_enable = 0; | |
| 5255 | break; | |
| 5256 | } | |
| 5257 | } | |
| 5258 | ||
| 5259 | /************************************************************* | |
| 5260 | ||
| 5261 | Kaiser Board KS7058 | |
| 5262 | ||
| 5263 | Games: Tui Do Woo Ma Jeung | |
| 5264 | ||
| 5265 | Writes to 0xf000-0xffff set 4k chr banks. Namely, if | |
| 5266 | offset&0x80 is 0 the lower 4k are set, if it is 1 the | |
| 5267 | upper 4k are set. | |
| 5268 | ||
| 5269 | iNES: mapper 171 | |
| 5270 | ||
| 5271 | In MESS: Supported. | |
| 5272 | ||
| 5273 | *************************************************************/ | |
| 5274 | ||
| 5275 | static WRITE8_HANDLER( ks7058_w ) | |
| 5276 | { | |
| 5277 | LOG_MMC(("ks7058_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5278 | ||
| 5279 | switch (offset & 0x7080) | |
| 5280 | { | |
| 5281 | case 0x7000: | |
| 5282 | chr4_0(space->machine(), data, CHRROM); | |
| 5283 | break; | |
| 5284 | case 0x7080: | |
| 5285 | chr4_4(space->machine(), data, CHRROM); | |
| 5286 | break; | |
| 5287 | } | |
| 5288 | } | |
| 5289 | ||
| 5290 | /************************************************************* | |
| 5291 | ||
| 5292 | Kaiser Board KS7022 | |
| 5293 | ||
| 5294 | Games: 15 in 1 | |
| 5295 | ||
| 5296 | iNES: mapper 175 | |
| 5297 | ||
| 5298 | In MESS: Supported? | |
| 5299 | ||
| 5300 | *************************************************************/ | |
| 5301 | ||
| 5302 | static WRITE8_HANDLER( ks7022_w ) | |
| 5303 | { | |
| 5304 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5305 | LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5306 | ||
| 5307 | if (offset == 0) | |
| 5308 | set_nt_mirroring(space->machine(), BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5309 | ||
| 5310 | if (offset == 0x2000) | |
| 5311 | state->m_mmc_latch1 = data & 0x0f; | |
| 5312 | } | |
| 5313 | ||
| 5314 | static READ8_HANDLER( ks7022_r ) | |
| 5315 | { | |
| 5316 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5317 | LOG_MMC(("ks7022_r, offset: %04x\n", offset)); | |
| 5318 | ||
| 5319 | if (offset == 0x7ffc) | |
| 5320 | { | |
| 5321 | chr8(space->machine(), state->m_mmc_latch1, CHRROM); | |
| 5322 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 5323 | prg16_cdef(space->machine(), state->m_mmc_latch1); | |
| 5324 | } | |
| 5325 | ||
| 5326 | return mmc_hi_access_rom(space->machine(), offset); | |
| 5327 | } | |
| 5328 | ||
| 5329 | /************************************************************* | |
| 5330 | ||
| 5331 | Kaiser Board KS7032 | |
| 5332 | ||
| 5333 | Games: | |
| 5334 | ||
| 5335 | iNES: | |
| 5336 | ||
| 5337 | In MESS: | |
| 5338 | ||
| 5339 | *************************************************************/ | |
| 5340 | ||
| 5341 | static void ks7032_prg_update( running_machine &machine ) | |
| 5342 | { | |
| 5343 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5344 | ||
| 5345 | prg8_67(machine, state->m_mmc_reg[4]); | |
| 5346 | prg8_89(machine, state->m_mmc_reg[1]); | |
| 5347 | prg8_ab(machine, state->m_mmc_reg[2]); | |
| 5348 | prg8_cd(machine, state->m_mmc_reg[3]); | |
| 5349 | } | |
| 5350 | ||
| 5351 | static void ks7032_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 5352 | { | |
| 5353 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 5354 | ||
| 5355 | if (state->m_IRQ_enable) | |
| 5356 | { | |
| 5357 | if (state->m_IRQ_count >= (0xffff - 114)) | |
| 5358 | { | |
| 5359 | state->m_IRQ_enable = 0; | |
| 5360 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 5361 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 5362 | } | |
| 5363 | else | |
| 5364 | state->m_IRQ_count += 114; | |
| 5365 | } | |
| 5366 | } | |
| 5367 | ||
| 5368 | static WRITE8_HANDLER( ks7032_w ) | |
| 5369 | { | |
| 5370 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5371 | LOG_MMC(("ks7032_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5372 | ||
| 5373 | switch (offset & 0x7000) | |
| 5374 | { | |
| 5375 | case 0x0000: | |
| 5376 | state->m_IRQ_count = (state->m_IRQ_count & 0xfff0) | (data & 0x0f); | |
| 5377 | break; | |
| 5378 | case 0x1000: | |
| 5379 | state->m_IRQ_count = (state->m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4); | |
| 5380 | break; | |
| 5381 | case 0x2000: | |
| 5382 | state->m_IRQ_count = (state->m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8); | |
| 5383 | break; | |
| 5384 | case 0x3000: | |
| 5385 | state->m_IRQ_count = (state->m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12); | |
| 5386 | break; | |
| 5387 | case 0x4000: | |
| 5388 | state->m_IRQ_enable = 1; | |
| 5389 | break; | |
| 5390 | case 0x6000: | |
| 5391 | state->m_mmc_latch1 = data & 0x07; | |
| 5392 | break; | |
| 5393 | case 0x7000: | |
| 5394 | state->m_mmc_reg[state->m_mmc_latch1] = data; | |
| 5395 | ks7032_prg_update(space->machine()); | |
| 5396 | break; | |
| 5397 | } | |
| 5398 | } | |
| 5399 | ||
| 5400 | /************************************************************* | |
| 5401 | ||
| 5402 | Kaiser Board KS202 | |
| 5403 | ||
| 5404 | Games: | |
| 5405 | ||
| 5406 | iNES: | |
| 5407 | ||
| 5408 | In MESS: Supported? | |
| 5409 | ||
| 5410 | *************************************************************/ | |
| 5411 | ||
| 5412 | ||
| 5413 | static WRITE8_HANDLER( ks202_w ) | |
| 5414 | { | |
| 5415 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5416 | LOG_MMC(("ks202_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5417 | ||
| 5418 | switch (offset & 0x7000) | |
| 5419 | { | |
| 5420 | case 0x0000: | |
| 5421 | state->m_IRQ_count = (state->m_IRQ_count & 0xfff0) | (data & 0x0f); | |
| 5422 | break; | |
| 5423 | case 0x1000: | |
| 5424 | state->m_IRQ_count = (state->m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4); | |
| 5425 | break; | |
| 5426 | case 0x2000: | |
| 5427 | state->m_IRQ_count = (state->m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8); | |
| 5428 | break; | |
| 5429 | case 0x3000: | |
| 5430 | state->m_IRQ_count = (state->m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12); | |
| 5431 | break; | |
| 5432 | case 0x4000: | |
| 5433 | state->m_IRQ_enable = 1; | |
| 5434 | break; | |
| 5435 | case 0x6000: | |
| 5436 | state->m_mmc_latch1 = data & 0x07; | |
| 5437 | break; | |
| 5438 | case 0x7000: | |
| 5439 | state->m_mmc_reg[state->m_mmc_latch1] = data; | |
| 5440 | ks7032_prg_update(space->machine()); | |
| 5441 | switch (offset & 0xc00) | |
| 5442 | { | |
| 5443 | case 0x800: | |
| 5444 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 5445 | break; | |
| 5446 | case 0xc00: | |
| 5447 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 5448 | break; | |
| 5449 | } | |
| 5450 | break; | |
| 5451 | } | |
| 5452 | } | |
| 5453 | ||
| 5454 | /************************************************************* | |
| 5455 | ||
| 5456 | Kaiser Board KS7017 | |
| 5457 | ||
| 5458 | Games: | |
| 5459 | ||
| 5460 | iNES: | |
| 5461 | ||
| 5462 | In MESS: Not working | |
| 5463 | ||
| 5464 | *************************************************************/ | |
| 5465 | ||
| 5466 | static void mmc_fds_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 5467 | { | |
| 5468 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 5469 | ||
| 5470 | if (state->m_IRQ_enable) | |
| 5471 | { | |
| 5472 | if (state->m_IRQ_count <= 114) | |
| 5473 | { | |
| 5474 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 5475 | state->m_IRQ_enable = 0; | |
| 5476 | state->m_IRQ_status |= 0x01; | |
| 5477 | } | |
| 5478 | else | |
| 5479 | state->m_IRQ_count -= 114; | |
| 5480 | } | |
| 5481 | } | |
| 5482 | ||
| 5483 | static WRITE8_HANDLER( ks7017_l_w ) | |
| 5484 | { | |
| 5485 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5486 | LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5487 | ||
| 5488 | offset += 0x100; | |
| 5489 | ||
| 5490 | if (offset >= 0xa00 && offset < 0xb00) | |
| 5491 | state->m_mmc_latch1 = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04); | |
| 5492 | ||
| 5493 | if (offset >= 0x1000 && offset < 0x1100) | |
| 5494 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 5495 | } | |
| 5496 | ||
| 5497 | WRITE8_HANDLER( ks7017_extra_w ) | |
| 5498 | { | |
| 5499 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5500 | LOG_MMC(("ks7017_extra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5501 | ||
| 5502 | offset += 0x20; | |
| 5503 | ||
| 5504 | if (offset == 0x0020) /* 0x4020 */ | |
| 5505 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 5506 | ||
| 5507 | if (offset == 0x0021) /* 0x4021 */ | |
| 5508 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 5509 | ||
| 5510 | if (offset == 0x0025) /* 0x4025 */ | |
| 5511 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5512 | } | |
| 5513 | ||
| 5514 | READ8_HANDLER( ks7017_extra_r ) | |
| 5515 | { | |
| 5516 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5517 | LOG_MMC(("ks7017_extra_r, offset: %04x\n", offset)); | |
| 5518 | ||
| 5519 | state->m_IRQ_status &= ~0x01; | |
| 5520 | return state->m_IRQ_status; | |
| 5521 | } | |
| 5522 | ||
| 5523 | /************************************************************* | |
| 5524 | ||
| 5525 | Bootleg Board by Kay (for Panda Prince) | |
| 5526 | ||
| 5527 | Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97 | |
| 5528 | (and its title hack MK6), UMK3, Super Lion King 2 | |
| 5529 | ||
| 5530 | MMC3 clone. This is basically KOF96 board + protection | |
| 5531 | ||
| 5532 | iNES: mapper 121 | |
| 5533 | ||
| 5534 | In MESS: Most game works, with some graphical issues. | |
| 5535 | ||
| 5536 | *************************************************************/ | |
| 5537 | ||
| 5538 | static WRITE8_HANDLER( kay_pp_l_w ) | |
| 5539 | { | |
| 5540 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5541 | LOG_MMC(("kay_pp_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5542 | offset += 0x100; | |
| 5543 | ||
| 5544 | if (offset >= 0x1000) | |
| 5545 | { | |
| 5546 | switch (data & 0x03) | |
| 5547 | { | |
| 5548 | case 0x00: | |
| 5549 | case 0x01: | |
| 5550 | state->m_mmc_reg[0] = 0x83; | |
| 5551 | break; | |
| 5552 | case 0x02: | |
| 5553 | state->m_mmc_reg[0] = 0x42; | |
| 5554 | break; | |
| 5555 | case 0x03: | |
| 5556 | state->m_mmc_reg[0] = 0x00; | |
| 5557 | break; | |
| 5558 | } | |
| 5559 | } | |
| 5560 | } | |
| 5561 | ||
| 5562 | static READ8_HANDLER( kay_pp_l_r ) | |
| 5563 | { | |
| 5564 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5565 | LOG_MMC(("kay_pp_l_r, offset: %04x\n", offset)); | |
| 5566 | offset += 0x100; | |
| 5567 | ||
| 5568 | if (offset >= 0x1000) | |
| 5569 | return state->m_mmc_reg[0]; | |
| 5570 | else | |
| 5571 | return 0xff; | |
| 5572 | } | |
| 5573 | ||
| 5574 | static void kay_pp_update_regs( running_machine &machine ) | |
| 5575 | { | |
| 5576 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5577 | ||
| 5578 | switch (state->m_mmc_reg[5] & 0x3f) | |
| 5579 | { | |
| 5580 | case 0x20: | |
| 5581 | case 0x29: | |
| 5582 | case 0x2b: | |
| 5583 | case 0x3f: | |
| 5584 | state->m_mmc_reg[7] = 1; | |
| 5585 | state->m_mmc_reg[1] = state->m_mmc_reg[6]; | |
| 5586 | break; | |
| 5587 | case 0x26: | |
| 5588 | state->m_mmc_reg[7] = 0; | |
| 5589 | state->m_mmc_reg[1] = state->m_mmc_reg[6]; | |
| 5590 | break; | |
| 5591 | case 0x2c: | |
| 5592 | state->m_mmc_reg[7] = 1; | |
| 5593 | if (state->m_mmc_reg[6]) | |
| 5594 | state->m_mmc_reg[1] = state->m_mmc_reg[6]; | |
| 5595 | break; | |
| 5596 | ||
| 5597 | case 0x28: | |
| 5598 | state->m_mmc_reg[7] = 0; | |
| 5599 | state->m_mmc_reg[2] = state->m_mmc_reg[6]; | |
| 5600 | break; | |
| 5601 | ||
| 5602 | case 0x2a: | |
| 5603 | state->m_mmc_reg[7] = 0; | |
| 5604 | state->m_mmc_reg[3] = state->m_mmc_reg[6]; | |
| 5605 | break; | |
| 5606 | ||
| 5607 | case 0x2f: | |
| 5608 | break; | |
| 5609 | ||
| 5610 | default: | |
| 5611 | state->m_mmc_reg[5] = 0; | |
| 5612 | break; | |
| 5613 | } | |
| 5614 | } | |
| 5615 | ||
| 5616 | static void kay_pp_prg_cb( running_machine &machine, int start, int bank ) | |
| 5617 | { | |
| 5618 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5619 | ||
| 5620 | if (state->m_mmc_reg[5] & 0x3f) | |
| 5621 | { | |
| 5622 | prg8_x(machine, start, bank & 0x3f); | |
| 5623 | prg8_ef(machine, state->m_mmc_reg[1]); | |
| 5624 | prg8_cd(machine, state->m_mmc_reg[2]); | |
| 5625 | prg8_ab(machine, state->m_mmc_reg[3]); | |
| 5626 | } | |
| 5627 | else | |
| 5628 | prg8_x(machine, start, bank & 0x3f); | |
| 5629 | } | |
| 5630 | ||
| 5631 | static void kay_pp_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 5632 | { | |
| 5633 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5634 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 5635 | ||
| 5636 | if ((start & 0x04) == chr_page) | |
| 5637 | bank |= 0x100; | |
| 5638 | ||
| 5639 | chr1_x(machine, start, bank, source); | |
| 5640 | } | |
| 5641 | ||
| 5642 | static WRITE8_HANDLER( kay_pp_w ) | |
| 5643 | { | |
| 5644 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5645 | LOG_MMC(("kay_pp_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5646 | ||
| 5647 | switch (offset & 0x6003) | |
| 5648 | { | |
| 5649 | case 0x0000: | |
| 5650 | txrom_w(space, offset, data); | |
| 5651 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5652 | break; | |
| 5653 | ||
| 5654 | case 0x0001: | |
| 5655 | state->m_mmc_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3) | |
| 5656 | | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5); | |
| 5657 | if (!state->m_mmc_reg[7]) | |
| 5658 | kay_pp_update_regs(space->machine()); | |
| 5659 | txrom_w(space, offset, data); | |
| 5660 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5661 | break; | |
| 5662 | ||
| 5663 | case 0x0003: | |
| 5664 | state->m_mmc_reg[5] = data; | |
| 5665 | kay_pp_update_regs(space->machine()); | |
| 5666 | txrom_w(space, 0x0000, data); | |
| 5667 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5668 | break; | |
| 5669 | ||
| 5670 | default: | |
| 5671 | txrom_w(space, offset, data); | |
| 5672 | break; | |
| 5673 | } | |
| 5674 | } | |
| 5675 | ||
| 5676 | /************************************************************* | |
| 5677 | ||
| 5678 | Bootleg Board by Kasing | |
| 5679 | ||
| 5680 | Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2, | |
| 5681 | Shisen Mahjong 2 | |
| 5682 | ||
| 5683 | MMC3 clone | |
| 5684 | ||
| 5685 | iNES: mapper 115 | |
| 5686 | ||
| 5687 | In MESS: Supported | |
| 5688 | ||
| 5689 | *************************************************************/ | |
| 5690 | ||
| 5691 | static void kasing_prg_cb( running_machine &machine, int start, int bank ) | |
| 5692 | { | |
| 5693 | nes_state *state = machine.driver_data<nes_state>(); | |
| 5694 | if (BIT(state->m_mmc_reg[0], 7)) | |
| 5695 | prg32(machine, state->m_mmc_reg[0] >> 1); | |
| 5696 | else | |
| 5697 | prg8_x(machine, start, bank); | |
| 5698 | } | |
| 5699 | ||
| 5700 | static WRITE8_HANDLER( kasing_m_w ) | |
| 5701 | { | |
| 5702 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5703 | LOG_MMC(("kasing_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5704 | ||
| 5705 | switch (offset & 0x01) | |
| 5706 | { | |
| 5707 | case 0x00: | |
| 5708 | state->m_mmc_reg[0] = data; | |
| 5709 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 5710 | break; | |
| 5711 | case 0x01: | |
| 5712 | state->m_mmc_chr_base = (data & 0x01) ? 0x100 : 0x000; | |
| 5713 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 5714 | break; | |
| 5715 | } | |
| 5716 | } | |
| 5717 | ||
| 5718 | /************************************************************* | |
| 5719 | ||
| 5720 | Bootleg Board by Magic Series | |
| 5721 | ||
| 5722 | Games: Magic Dragon | |
| 5723 | ||
| 5724 | Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8 | |
| 5725 | banks | |
| 5726 | ||
| 5727 | iNES: mapper 107 | |
| 5728 | ||
| 5729 | In MESS: Supported. | |
| 5730 | ||
| 5731 | *************************************************************/ | |
| 5732 | ||
| 5733 | static WRITE8_HANDLER( magics_md_w ) | |
| 5734 | { | |
| 5735 | LOG_MMC(("magics_md_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5736 | ||
| 5737 | prg32(space->machine(), data >> 1); | |
| 5738 | chr8(space->machine(), data, CHRROM); | |
| 5739 | } | |
| 5740 | ||
| 5741 | /************************************************************* | |
| 5742 | ||
| 5743 | Bootleg Board by Nanjing | |
| 5744 | ||
| 5745 | Games: A lot of pirate originals | |
| 5746 | ||
| 5747 | iNES: mapper 163 | |
| 5748 | ||
| 5749 | In MESS: Unsupported. | |
| 5750 | ||
| 5751 | *************************************************************/ | |
| 5752 | ||
| 5753 | static void nanjing_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 5754 | { | |
| 5755 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 5756 | ||
| 5757 | if (BIT(state->m_mmc_reg[0], 7)) | |
| 5758 | { | |
| 5759 | if (scanline == 127) | |
| 5760 | { | |
| 5761 | chr4_0(device->machine(), 1, CHRRAM); | |
| 5762 | chr4_4(device->machine(), 1, CHRRAM); | |
| 5763 | } | |
| 5764 | ||
| 5765 | if (scanline == 239) | |
| 5766 | { | |
| 5767 | chr4_0(device->machine(), 0, CHRRAM); | |
| 5768 | chr4_4(device->machine(), 0, CHRRAM); | |
| 5769 | } | |
| 5770 | } | |
| 5771 | ||
| 5772 | } | |
| 5773 | ||
| 5774 | static WRITE8_HANDLER( nanjing_l_w ) | |
| 5775 | { | |
| 5776 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5777 | LOG_MMC(("nanjing_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5778 | ||
| 5779 | offset += 0x100; | |
| 5780 | ||
| 5781 | if (offset < 0x1000) | |
| 5782 | return; | |
| 5783 | ||
| 5784 | if (offset == 0x1100) // 0x5100 | |
| 5785 | { | |
| 5786 | if (data == 6) | |
| 5787 | prg32(space->machine(), 3); | |
| 5788 | return; | |
| 5789 | } | |
| 5790 | ||
| 5791 | if (offset == 0x1101) // 0x5101 | |
| 5792 | { | |
| 5793 | UINT8 temp = state->m_mmc_count; | |
| 5794 | state->m_mmc_count = data; | |
| 5795 | ||
| 5796 | if (temp & !data) | |
| 5797 | state->m_mmc_latch2 ^= 0xff; | |
| 5798 | } | |
| 5799 | ||
| 5800 | switch (offset & 0x300) | |
| 5801 | { | |
| 5802 | case 0x000: | |
| 5803 | case 0x200: | |
| 5804 | state->m_mmc_reg[BIT(offset, 9)] = data; | |
| 5805 | if (!BIT(state->m_mmc_reg[0], 7) && ppu2c0x_get_current_scanline(state->m_ppu) <= 127) | |
| 5806 | chr8(space->machine(), 0, CHRRAM); | |
| 5807 | break; | |
| 5808 | case 0x300: | |
| 5809 | state->m_mmc_latch1 = data; | |
| 5810 | break; | |
| 5811 | } | |
| 5812 | ||
| 5813 | prg32(space->machine(), (state->m_mmc_reg[0] & 0x0f) | ((state->m_mmc_reg[1] & 0x0f) << 4)); | |
| 5814 | } | |
| 5815 | ||
| 5816 | static READ8_HANDLER( nanjing_l_r ) | |
| 5817 | { | |
| 5818 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5819 | UINT8 value = 0; | |
| 5820 | LOG_MMC(("nanjing_l_r, offset: %04x\n", offset)); | |
| 5821 | ||
| 5822 | offset += 0x100; | |
| 5823 | ||
| 5824 | if (offset < 0x1000) | |
| 5825 | return 0; | |
| 5826 | ||
| 5827 | switch (offset & 0x700) | |
| 5828 | { | |
| 5829 | case 0x100: | |
| 5830 | value = state->m_mmc_latch1; | |
| 5831 | break; | |
| 5832 | case 0x500: | |
| 5833 | value = state->m_mmc_latch2 & state->m_mmc_latch1; | |
| 5834 | break; | |
| 5835 | case 0x000: | |
| 5836 | case 0x200: | |
| 5837 | case 0x300: | |
| 5838 | case 0x400: | |
| 5839 | case 0x600: | |
| 5840 | case 0x700: | |
| 5841 | value = 4; | |
| 5842 | break; | |
| 5843 | } | |
| 5844 | return value; | |
| 5845 | } | |
| 5846 | ||
| 5847 | /************************************************************* | |
| 5848 | ||
| 5849 | Bootleg Board by Nitra | |
| 5850 | ||
| 5851 | Games: Time Diver Avenger | |
| 5852 | ||
| 5853 | This acts basically like a MMC3 with different use of write | |
| 5854 | address. | |
| 5855 | ||
| 5856 | iNES: mapper 250 | |
| 5857 | ||
| 5858 | In MESS: Supported. | |
| 5859 | ||
| 5860 | *************************************************************/ | |
| 5861 | ||
| 5862 | static WRITE8_HANDLER( nitra_w ) | |
| 5863 | { | |
| 5864 | LOG_MMC(("nitra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5865 | ||
| 5866 | txrom_w(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff); | |
| 5867 | } | |
| 5868 | ||
| 5869 | /************************************************************* | |
| 5870 | ||
| 5871 | NTDEC ASDER Bootleg Board | |
| 5872 | ||
| 5873 | Games: Cobra Mission, Fighting Hero III, Huang Di, Master | |
| 5874 | Shooter | |
| 5875 | ||
| 5876 | iNES: mapper 112 | |
| 5877 | ||
| 5878 | In MESS: Supported. | |
| 5879 | ||
| 5880 | *************************************************************/ | |
| 5881 | ||
| 5882 | static WRITE8_HANDLER( ntdec_asder_w ) | |
| 5883 | { | |
| 5884 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 5885 | LOG_MMC(("ntdec_asder_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5886 | ||
| 5887 | switch (offset) | |
| 5888 | { | |
| 5889 | case 0x0000: | |
| 5890 | state->m_mmc_latch1 = data & 0x07; | |
| 5891 | break; | |
| 5892 | case 0x2000: | |
| 5893 | switch (state->m_mmc_latch1) | |
| 5894 | { | |
| 5895 | case 0: | |
| 5896 | prg8_89(space->machine(), data); | |
| 5897 | break; | |
| 5898 | case 1: | |
| 5899 | prg8_ab(space->machine(), data); | |
| 5900 | break; | |
| 5901 | case 2: | |
| 5902 | data &= 0xfe; | |
| 5903 | chr1_0(space->machine(), data, CHRROM); | |
| 5904 | chr1_1(space->machine(), data + 1, CHRROM); | |
| 5905 | break; | |
| 5906 | case 3: | |
| 5907 | data &= 0xfe; | |
| 5908 | chr1_2(space->machine(), data, CHRROM); | |
| 5909 | chr1_3(space->machine(), data + 1, CHRROM); | |
| 5910 | break; | |
| 5911 | case 4: | |
| 5912 | chr1_4(space->machine(), data, CHRROM); | |
| 5913 | break; | |
| 5914 | case 5: | |
| 5915 | chr1_5(space->machine(), data, CHRROM); | |
| 5916 | break; | |
| 5917 | case 6: | |
| 5918 | chr1_6(space->machine(), data, CHRROM); | |
| 5919 | break; | |
| 5920 | case 7: | |
| 5921 | chr1_7(space->machine(), data, CHRROM); | |
| 5922 | break; | |
| 5923 | } | |
| 5924 | break; | |
| 5925 | case 0x6000: | |
| 5926 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 5927 | break; | |
| 5928 | } | |
| 5929 | } | |
| 5930 | ||
| 5931 | /************************************************************* | |
| 5932 | ||
| 5933 | Bootleg Board by NTDEC for Fighting Hero | |
| 5934 | ||
| 5935 | Games: Fighting Hero | |
| 5936 | ||
| 5937 | Very simple mapper: writes to 0x6000-0x7fff swap PRG and | |
| 5938 | CHR banks. | |
| 5939 | ||
| 5940 | iNES: mapper 193 | |
| 5941 | ||
| 5942 | In MESS: Supported. | |
| 5943 | ||
| 5944 | *************************************************************/ | |
| 5945 | ||
| 5946 | static WRITE8_HANDLER( ntdec_fh_m_w ) | |
| 5947 | { | |
| 5948 | LOG_MMC(("ntdec_fh_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5949 | ||
| 5950 | switch (offset & 0x03) | |
| 5951 | { | |
| 5952 | case 0: | |
| 5953 | chr4_0(space->machine(), data >> 2, CHRROM); | |
| 5954 | break; | |
| 5955 | case 1: | |
| 5956 | chr2_4(space->machine(), data >> 1, CHRROM); | |
| 5957 | break; | |
| 5958 | case 2: | |
| 5959 | chr2_6(space->machine(), data >> 1 , CHRROM); | |
| 5960 | break; | |
| 5961 | case 3: | |
| 5962 | prg8_89(space->machine(), data); | |
| 5963 | break; | |
| 5964 | } | |
| 5965 | } | |
| 5966 | ||
| 5967 | /************************************************************* | |
| 5968 | ||
| 5969 | Open Corp DAOU306 board | |
| 5970 | ||
| 5971 | Games: Metal Force (K) | |
| 5972 | ||
| 5973 | iNES: mapper 156 | |
| 5974 | ||
| 5975 | In MESS: Supported. | |
| 5976 | ||
| 5977 | *************************************************************/ | |
| 5978 | ||
| 5979 | static WRITE8_HANDLER( daou306_w ) | |
| 5980 | { | |
| 5981 | LOG_MMC(("daou306_w, offset: %04x, data: %02x\n", offset, data)); | |
| 5982 | ||
| 5983 | switch (offset) | |
| 5984 | { | |
| 5985 | case 0x4000: | |
| 5986 | chr1_0(space->machine(), data, CHRROM); | |
| 5987 | break; | |
| 5988 | case 0x4001: | |
| 5989 | chr1_1(space->machine(), data, CHRROM); | |
| 5990 | break; | |
| 5991 | case 0x4002: | |
| 5992 | chr1_2(space->machine(), data, CHRROM); | |
| 5993 | break; | |
| 5994 | case 0x4003: | |
| 5995 | chr1_3(space->machine(), data, CHRROM); | |
| 5996 | break; | |
| 5997 | case 0x4008: | |
| 5998 | chr1_4(space->machine(), data, CHRROM); | |
| 5999 | break; | |
| 6000 | case 0x4009: | |
| 6001 | chr1_5(space->machine(), data, CHRROM); | |
| 6002 | break; | |
| 6003 | case 0x400a: | |
| 6004 | chr1_6(space->machine(), data, CHRROM); | |
| 6005 | break; | |
| 6006 | case 0x400b: | |
| 6007 | chr1_7(space->machine(), data, CHRROM); | |
| 6008 | break; | |
| 6009 | case 0x4010: | |
| 6010 | prg16_89ab(space->machine(), data); | |
| 6011 | break; | |
| 6012 | } | |
| 6013 | } | |
| 6014 | ||
| 6015 | /************************************************************* | |
| 6016 | ||
| 6017 | RCM GS2015 Board | |
| 6018 | ||
| 6019 | Games: Bonza, Magic Jewelry 2 | |
| 6020 | ||
| 6021 | Very simple mapper: writes to 0x8000-0xffff sets prg32 | |
| 6022 | to offset and chr8 to offset>>1 (when chrrom is present) | |
| 6023 | ||
| 6024 | iNES: mapper 216 | |
| 6025 | ||
| 6026 | In MESS: Supported. | |
| 6027 | ||
| 6028 | *************************************************************/ | |
| 6029 | ||
| 6030 | static WRITE8_HANDLER( gs2015_w ) | |
| 6031 | { | |
| 6032 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6033 | LOG_MMC(("gs2015_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6034 | ||
| 6035 | prg32(space->machine(), offset); | |
| 6036 | chr8(space->machine(), offset >> 1, state->m_mmc_chr_source); | |
| 6037 | } | |
| 6038 | ||
| 6039 | /************************************************************* | |
| 6040 | ||
| 6041 | Bootleg Board by RCM for Tetris Family | |
| 6042 | ||
| 6043 | Games: Tetris Family 9 in 1, 20 in 1 | |
| 6044 | ||
| 6045 | Simple Mapper: prg/chr/nt are swapped depending on the offset | |
| 6046 | of writes in 0x8000-0xffff. offset&0x80 set NT mirroring, | |
| 6047 | when (offset&0x30) is 0,3 prg32 is set; when it is 1,2 | |
| 6048 | two 16k prg banks are set. See below for the values used in | |
| 6049 | these banks. | |
| 6050 | ||
| 6051 | iNES: mapper 61 | |
| 6052 | ||
| 6053 | In MESS: Supported. | |
| 6054 | ||
| 6055 | *************************************************************/ | |
| 6056 | ||
| 6057 | static WRITE8_HANDLER( rcm_tf_w ) | |
| 6058 | { | |
| 6059 | LOG_MMC(("rcm_tf_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6060 | ||
| 6061 | switch (offset & 0x30) | |
| 6062 | { | |
| 6063 | case 0x00: | |
| 6064 | case 0x30: | |
| 6065 | prg32(space->machine(), offset & 0x0f); | |
| 6066 | break; | |
| 6067 | case 0x10: | |
| 6068 | case 0x20: | |
| 6069 | prg16_89ab(space->machine(), ((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); | |
| 6070 | prg16_cdef(space->machine(), ((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); | |
| 6071 | break; | |
| 6072 | } | |
| 6073 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6074 | } | |
| 6075 | ||
| 6076 | /************************************************************* | |
| 6077 | ||
| 6078 | Bootleg Board by Rex Soft | |
| 6079 | ||
| 6080 | Games: Dragon Ball Z 5, Dragon Ball Z Super | |
| 6081 | ||
| 6082 | MMC3 clone | |
| 6083 | ||
| 6084 | iNES: mapper 12 | |
| 6085 | ||
| 6086 | In MESS: Supported | |
| 6087 | ||
| 6088 | *************************************************************/ | |
| 6089 | ||
| 6090 | static WRITE8_HANDLER( rex_dbz_l_w ) | |
| 6091 | { | |
| 6092 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6093 | LOG_MMC(("rex_dbz_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6094 | ||
| 6095 | state->m_mmc_reg[0] = data; | |
| 6096 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6097 | } | |
| 6098 | ||
| 6099 | /* we would need to use this read handler in 0x6000-0x7fff as well */ | |
| 6100 | static READ8_HANDLER( rex_dbz_l_r ) | |
| 6101 | { | |
| 6102 | LOG_MMC(("rex_dbz_l_r, offset: %04x\n", offset)); | |
| 6103 | return 0x01; | |
| 6104 | } | |
| 6105 | ||
| 6106 | static void rex_dbz_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 6107 | { | |
| 6108 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6109 | int shift = (start < 4) ? 8 : 4; | |
| 6110 | ||
| 6111 | bank |= ((state->m_mmc_reg[0] << shift) & 0x100); | |
| 6112 | chr1_x(machine, start, bank, source); | |
| 6113 | } | |
| 6114 | ||
| 6115 | /************************************************************* | |
| 6116 | ||
| 6117 | Rex Soft SL1632 Board | |
| 6118 | ||
| 6119 | Games: Samurai Spirits | |
| 6120 | ||
| 6121 | MMC3 clone | |
| 6122 | ||
| 6123 | iNES: mapper 14 | |
| 6124 | ||
| 6125 | In MESS: Supported | |
| 6126 | ||
| 6127 | *************************************************************/ | |
| 6128 | ||
| 6129 | static void rex_sl1632_set_prg( running_machine &machine, int prg_base, int prg_mask ) | |
| 6130 | { | |
| 6131 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6132 | ||
| 6133 | if (state->m_mmc_reg[0] & 0x02) | |
| 6134 | { | |
| 6135 | mmc3_set_prg(machine, prg_base, prg_mask); | |
| 6136 | } | |
| 6137 | else | |
| 6138 | { | |
| 6139 | prg8_89(machine, state->m_mmc_extra_bank[0]); | |
| 6140 | prg8_ab(machine, state->m_mmc_extra_bank[1]); | |
| 6141 | prg8_cd(machine, state->m_mmc_extra_bank[2]); | |
| 6142 | prg8_ef(machine, state->m_mmc_extra_bank[3]); | |
| 6143 | } | |
| 6144 | } | |
| 6145 | ||
| 6146 | static void rex_sl1632_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask ) | |
| 6147 | { | |
| 6148 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6149 | static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1}; | |
| 6150 | UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5; | |
| 6151 | UINT8 bank[8]; | |
| 6152 | UINT8 chr_base2[8]; | |
| 6153 | int i; | |
| 6154 | ||
| 6155 | if (state->m_mmc_reg[0] & 0x02) | |
| 6156 | { | |
| 6157 | for(i = 0; i < 8; i++) | |
| 6158 | { | |
| 6159 | bank[i] = state->m_mmc_vrom_bank[i]; | |
| 6160 | chr_base2[i] = chr_base | ((state->m_mmc_reg[0] << conv_table[i]) & 0x100); | |
| 6161 | } | |
| 6162 | } | |
| 6163 | else | |
| 6164 | { | |
| 6165 | for(i = 0; i < 8; i++) | |
| 6166 | { | |
| 6167 | bank[i] = state->m_mmc_extra_bank[i + 4]; // first 4 state->m_mmc_extra_banks are PRG | |
| 6168 | chr_base2[i] = chr_base; | |
| 6169 | } | |
| 6170 | } | |
| 6171 | ||
| 6172 | chr1_x(machine, chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr); | |
| 6173 | chr1_x(machine, chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr); | |
| 6174 | chr1_x(machine, chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr); | |
| 6175 | chr1_x(machine, chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr); | |
| 6176 | chr1_x(machine, chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr); | |
| 6177 | chr1_x(machine, chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr); | |
| 6178 | chr1_x(machine, chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr); | |
| 6179 | chr1_x(machine, chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr); | |
| 6180 | } | |
| 6181 | ||
| 6182 | static WRITE8_HANDLER( rex_sl1632_w ) | |
| 6183 | { | |
| 6184 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6185 | UINT8 map14_helper1, map14_helper2, mmc_helper, cmd; | |
| 6186 | LOG_MMC(("rex_sl1632_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6187 | ||
| 6188 | if (offset == 0x2131) | |
| 6189 | { | |
| 6190 | state->m_mmc_reg[0] = data; | |
| 6191 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6192 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6193 | ||
| 6194 | if (!(state->m_mmc_reg[0] & 0x02)) | |
| 6195 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6196 | } | |
| 6197 | ||
| 6198 | if (state->m_mmc_reg[0] & 0x02) | |
| 6199 | { | |
| 6200 | switch (offset & 0x6001) | |
| 6201 | { | |
| 6202 | case 0x0000: | |
| 6203 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 6204 | state->m_mmc3_latch = data; | |
| 6205 | ||
| 6206 | /* Has PRG Mode changed? */ | |
| 6207 | if (mmc_helper & 0x40) | |
| 6208 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6209 | ||
| 6210 | /* Has CHR Mode changed? */ | |
| 6211 | if (mmc_helper & 0x80) | |
| 6212 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6213 | break; | |
| 6214 | ||
| 6215 | case 0x0001: | |
| 6216 | cmd = state->m_mmc3_latch & 0x07; | |
| 6217 | switch (cmd) | |
| 6218 | { | |
| 6219 | case 0: case 1: // these have to be changed due to the different way rex_sl1632_set_chr works (it handles 1k banks)! | |
| 6220 | state->m_mmc_vrom_bank[2 * cmd] = data; | |
| 6221 | state->m_mmc_vrom_bank[2 * cmd + 1] = data; | |
| 6222 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6223 | break; | |
| 6224 | case 2: case 3: case 4: case 5: | |
| 6225 | state->m_mmc_vrom_bank[cmd + 2] = data; | |
| 6226 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6227 | break; | |
| 6228 | case 6: | |
| 6229 | case 7: | |
| 6230 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 6231 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6232 | break; | |
| 6233 | } | |
| 6234 | break; | |
| 6235 | ||
| 6236 | case 0x2000: | |
| 6237 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 6238 | break; | |
| 6239 | ||
| 6240 | default: | |
| 6241 | txrom_w(space, offset, data); | |
| 6242 | break; | |
| 6243 | } | |
| 6244 | } | |
| 6245 | else if (offset >= 0x3000 && offset <= 0x6003 ) | |
| 6246 | { | |
| 6247 | map14_helper1 = (offset & 0x01) << 2; | |
| 6248 | offset = ((offset & 0x02) | (offset >> 10)) >> 1; | |
| 6249 | map14_helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 state->m_mmc_extra_banks are for PRG! | |
| 6250 | state->m_mmc_extra_bank[map14_helper2] = (state->m_mmc_extra_bank[map14_helper2] & (0xf0 >> map14_helper1)) | ((data & 0x0f) << map14_helper1); | |
| 6251 | rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6252 | } | |
| 6253 | else | |
| 6254 | { | |
| 6255 | switch (offset & 0x7003) | |
| 6256 | { | |
| 6257 | case 0x0000: | |
| 6258 | case 0x2000: | |
| 6259 | state->m_mmc_extra_bank[offset >> 13] = data; | |
| 6260 | rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6261 | break; | |
| 6262 | ||
| 6263 | case 0x1000: | |
| 6264 | state->m_mmc_reg[1] = data; | |
| 6265 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6266 | break; | |
| 6267 | } | |
| 6268 | } | |
| 6269 | } | |
| 6270 | ||
| 6271 | /************************************************************* | |
| 6272 | ||
| 6273 | Rumblestation Board | |
| 6274 | ||
| 6275 | Games: Rumblestation 15 in 1 | |
| 6276 | ||
| 6277 | iNES: mapper 46 | |
| 6278 | ||
| 6279 | In MESS: Supported. | |
| 6280 | ||
| 6281 | *************************************************************/ | |
| 6282 | ||
| 6283 | static WRITE8_HANDLER( rumblestation_m_w ) | |
| 6284 | { | |
| 6285 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6286 | LOG_MMC(("rumblestation_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6287 | ||
| 6288 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x01) | ((data & 0x0f) << 1); | |
| 6289 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x07) | ((data & 0xf0) >> 1); | |
| 6290 | prg32(space->machine(), state->m_mmc_prg_bank[0]); | |
| 6291 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6292 | } | |
| 6293 | ||
| 6294 | static WRITE8_HANDLER( rumblestation_w ) | |
| 6295 | { | |
| 6296 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6297 | LOG_MMC(("rumblestation_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6298 | ||
| 6299 | state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & ~0x01) | (data & 0x01); | |
| 6300 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x07) | ((data & 0x70) >> 4); | |
| 6301 | prg32(space->machine(), state->m_mmc_prg_bank[0]); | |
| 6302 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6303 | } | |
| 6304 | ||
| 6305 | /************************************************************* | |
| 6306 | ||
| 6307 | Sachen 74x374 bootleg boards | |
| 6308 | ||
| 6309 | Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy, | |
| 6310 | Olympic IQ, Poker II, Tasac [150], Poker III [243] | |
| 6311 | ||
| 6312 | iNES: mappers 150 & 243 | |
| 6313 | ||
| 6314 | *************************************************************/ | |
| 6315 | ||
| 6316 | static void sachen_set_mirror( running_machine &machine, UINT8 nt ) // used by mappers 137, 138, 139, 141 | |
| 6317 | { | |
| 6318 | switch (nt) | |
| 6319 | { | |
| 6320 | case 0: | |
| 6321 | case 1: | |
| 6322 | set_nt_mirroring(machine, nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6323 | break; | |
| 6324 | case 2: | |
| 6325 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 6326 | set_nt_page(machine, 1, CIRAM, 1, 1); | |
| 6327 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 6328 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 6329 | break; | |
| 6330 | case 3: | |
| 6331 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 6332 | break; | |
| 6333 | default: | |
| 6334 | LOG_MMC(("Mapper set NT to invalid value %02x", nt)); | |
| 6335 | break; | |
| 6336 | } | |
| 6337 | } | |
| 6338 | ||
| 6339 | static WRITE8_HANDLER( sachen_74x374_l_w ) | |
| 6340 | { | |
| 6341 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6342 | LOG_MMC(("sachen_74x374_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6343 | ||
| 6344 | /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6345 | if (!(offset & 0x100)) | |
| 6346 | { | |
| 6347 | if (!(offset & 0x01)) | |
| 6348 | state->m_mmc_latch1 = data & 0x07; | |
| 6349 | else | |
| 6350 | { | |
| 6351 | switch (state->m_mmc_latch1) | |
| 6352 | { | |
| 6353 | case 0x02: | |
| 6354 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08); | |
| 6355 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6356 | prg32(space->machine(), data & 0x01); | |
| 6357 | break; | |
| 6358 | case 0x04: | |
| 6359 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x04) | ((data << 2) & 0x04); | |
| 6360 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6361 | break; | |
| 6362 | case 0x05: | |
| 6363 | prg32(space->machine(), data & 0x07); | |
| 6364 | break; | |
| 6365 | case 0x06: | |
| 6366 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x03) | ((data << 0) & 0x03); | |
| 6367 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6368 | break; | |
| 6369 | case 0x07: | |
| 6370 | sachen_set_mirror(space->machine(), (data >> 1) & 0x03); | |
| 6371 | break; | |
| 6372 | default: | |
| 6373 | break; | |
| 6374 | } | |
| 6375 | } | |
| 6376 | } | |
| 6377 | } | |
| 6378 | ||
| 6379 | static READ8_HANDLER( sachen_74x374_l_r ) | |
| 6380 | { | |
| 6381 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6382 | LOG_MMC(("sachen_74x374_l_r, offset: %04x", offset)); | |
| 6383 | ||
| 6384 | /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6385 | if (!(offset & 0x100)) | |
| 6386 | return (~state->m_mmc_latch1 & 0x3f) /* ^ dips*/; // we would need to check the Dips here | |
| 6387 | else | |
| 6388 | return 0; | |
| 6389 | } | |
| 6390 | ||
| 6391 | static WRITE8_HANDLER( sachen_74x374a_l_w ) | |
| 6392 | { | |
| 6393 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6394 | LOG_MMC(("sachen_74x374a_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6395 | ||
| 6396 | /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6397 | if (!(offset & 0x100)) | |
| 6398 | { | |
| 6399 | if (!(offset & 0x01)) | |
| 6400 | state->m_mmc_latch1 = data; | |
| 6401 | else | |
| 6402 | { | |
| 6403 | switch (state->m_mmc_latch1 & 0x07) | |
| 6404 | { | |
| 6405 | case 0x00: | |
| 6406 | prg32(space->machine(), 0); | |
| 6407 | chr8(space->machine(), 3, CHRROM); | |
| 6408 | break; | |
| 6409 | case 0x02: | |
| 6410 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08); | |
| 6411 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6412 | break; | |
| 6413 | case 0x04: | |
| 6414 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x01) | ((data << 0) & 0x01); | |
| 6415 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6416 | break; | |
| 6417 | case 0x05: | |
| 6418 | prg32(space->machine(), data & 0x01); | |
| 6419 | break; | |
| 6420 | case 0x06: | |
| 6421 | state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x06) | ((data << 1) & 0x06); | |
| 6422 | chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM); | |
| 6423 | break; | |
| 6424 | case 0x07: | |
| 6425 | sachen_set_mirror(space->machine(), BIT(data, 0)); | |
| 6426 | break; | |
| 6427 | default: | |
| 6428 | break; | |
| 6429 | } | |
| 6430 | } | |
| 6431 | } | |
| 6432 | } | |
| 6433 | ||
| 6434 | /************************************************************* | |
| 6435 | ||
| 6436 | Sachen S8259 bootleg boards | |
| 6437 | ||
| 6438 | iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D) | |
| 6439 | ||
| 6440 | *************************************************************/ | |
| 6441 | ||
| 6442 | static void common_s8259_write_handler( address_space *space, offs_t offset, UINT8 data, int board ) | |
| 6443 | { | |
| 6444 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6445 | UINT8 bank_helper1, bank_helper2, shift, add1, add2, add3; | |
| 6446 | ||
| 6447 | /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6448 | if (!(offset & 0x100)) | |
| 6449 | { | |
| 6450 | if (!(offset & 0x01)) | |
| 6451 | state->m_mmc_latch1 = data & 0x07; | |
| 6452 | else | |
| 6453 | { | |
| 6454 | state->m_sachen_reg[state->m_mmc_latch1] = data; | |
| 6455 | ||
| 6456 | switch (state->m_mmc_latch1) | |
| 6457 | { | |
| 6458 | case 0x05: | |
| 6459 | prg32(space->machine(), data); | |
| 6460 | break; | |
| 6461 | case 0x07: | |
| 6462 | sachen_set_mirror(space->machine(), BIT(data, 0) ? 0 : (data >> 1) & 0x03); | |
| 6463 | break; | |
| 6464 | default: | |
| 6465 | if (board == SACHEN_8259D) | |
| 6466 | { | |
| 6467 | if (state->m_mmc_chr_source == CHRROM) | |
| 6468 | { | |
| 6469 | chr1_0(space->machine(), (state->m_sachen_reg[0] & 0x07), CHRROM); | |
| 6470 | chr1_1(space->machine(), (state->m_sachen_reg[1] & 0x07) | (state->m_sachen_reg[4] << 4 & 0x10), CHRROM); | |
| 6471 | chr1_2(space->machine(), (state->m_sachen_reg[2] & 0x07) | (state->m_sachen_reg[4] << 3 & 0x10), CHRROM); | |
| 6472 | chr1_3(space->machine(), (state->m_sachen_reg[3] & 0x07) | (state->m_sachen_reg[4] << 2 & 0x10) | (state->m_sachen_reg[6] << 3 & 0x08), CHRROM); | |
| 6473 | } | |
| 6474 | } | |
| 6475 | else | |
| 6476 | { | |
| 6477 | bank_helper1 = state->m_sachen_reg[7] & 0x01; | |
| 6478 | bank_helper2 = (state->m_sachen_reg[4] & 0x07) << 3; | |
| 6479 | shift = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 2 : 0; | |
| 6480 | add1 = (board == SACHEN_8259B) ? 0 : 1; | |
| 6481 | add2 = (board == SACHEN_8259C) ? 2 : 0; | |
| 6482 | add3 = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 3 : 0; | |
| 6483 | ||
| 6484 | if (state->m_mmc_chr_source == CHRROM) | |
| 6485 | { | |
| 6486 | chr2_0(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << shift, CHRROM); | |
| 6487 | chr2_2(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << shift | add1, CHRROM); | |
| 6488 | chr2_4(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << shift | add2, CHRROM); | |
| 6489 | chr2_6(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << shift | add3, CHRROM); | |
| 6490 | } | |
| 6491 | } | |
| 6492 | break; | |
| 6493 | } | |
| 6494 | } | |
| 6495 | } | |
| 6496 | } | |
| 6497 | ||
| 6498 | static WRITE8_HANDLER( s8259_l_w ) | |
| 6499 | { | |
| 6500 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6501 | LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", state->m_pcb_id, offset, data)); | |
| 6502 | ||
| 6503 | common_s8259_write_handler(space, offset, data, state->m_pcb_id); | |
| 6504 | } | |
| 6505 | ||
| 6506 | static WRITE8_HANDLER( s8259_m_w ) | |
| 6507 | { | |
| 6508 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6509 | LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", state->m_pcb_id, offset, data)); | |
| 6510 | ||
| 6511 | common_s8259_write_handler(space, (offset + 0x100) & 0xfff, data, state->m_pcb_id); | |
| 6512 | } | |
| 6513 | ||
| 6514 | ||
| 6515 | /************************************************************* | |
| 6516 | ||
| 6517 | Sachen SA009 bootleg boards | |
| 6518 | ||
| 6519 | Games: Pipe 5 | |
| 6520 | ||
| 6521 | iNES: mapper 160 | |
| 6522 | ||
| 6523 | In MESS: Supported. | |
| 6524 | ||
| 6525 | *************************************************************/ | |
| 6526 | ||
| 6527 | static WRITE8_HANDLER( sa009_l_w ) | |
| 6528 | { | |
| 6529 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6530 | LOG_MMC(("sa009_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6531 | ||
| 6532 | chr8(space->machine(), data, state->m_mmc_chr_source); | |
| 6533 | } | |
| 6534 | ||
| 6535 | /************************************************************* | |
| 6536 | ||
| 6537 | Sachen SA0036 bootleg boards | |
| 6538 | ||
| 6539 | Games: Taiwan Mahjong 16 | |
| 6540 | ||
| 6541 | iNES: mapper 149 | |
| 6542 | ||
| 6543 | In MESS: Supported. | |
| 6544 | ||
| 6545 | *************************************************************/ | |
| 6546 | ||
| 6547 | static WRITE8_HANDLER( sa0036_w ) | |
| 6548 | { | |
| 6549 | LOG_MMC(("sa0036_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6550 | ||
| 6551 | chr8(space->machine(), data >> 7, CHRROM); | |
| 6552 | } | |
| 6553 | ||
| 6554 | /************************************************************* | |
| 6555 | ||
| 6556 | Sachen SA0037 bootleg boards | |
| 6557 | ||
| 6558 | Games: Mahjong World, Shisen Mahjong | |
| 6559 | ||
| 6560 | iNES: mapper 148 | |
| 6561 | ||
| 6562 | In MESS: Supported. | |
| 6563 | ||
| 6564 | *************************************************************/ | |
| 6565 | ||
| 6566 | static WRITE8_HANDLER( sa0037_w ) | |
| 6567 | { | |
| 6568 | LOG_MMC(("sa0037_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6569 | ||
| 6570 | prg32(space->machine(), data >> 3); | |
| 6571 | chr8(space->machine(), data, CHRROM); | |
| 6572 | } | |
| 6573 | ||
| 6574 | /************************************************************* | |
| 6575 | ||
| 6576 | Sachen SA72007 bootleg boards | |
| 6577 | ||
| 6578 | Games: Sidewinder | |
| 6579 | ||
| 6580 | iNES: mapper 145 | |
| 6581 | ||
| 6582 | In MESS: Supported. | |
| 6583 | ||
| 6584 | *************************************************************/ | |
| 6585 | ||
| 6586 | static WRITE8_HANDLER( sa72007_l_w ) | |
| 6587 | { | |
| 6588 | LOG_MMC(("sa72007_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6589 | ||
| 6590 | /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6591 | if (!(offset & 0x100)) | |
| 6592 | chr8(space->machine(), data >> 7, CHRROM); | |
| 6593 | } | |
| 6594 | ||
| 6595 | /************************************************************* | |
| 6596 | ||
| 6597 | Sachen SA72008 bootleg boards | |
| 6598 | ||
| 6599 | Games: Jovial Race, Qi Wang | |
| 6600 | ||
| 6601 | iNES: mapper 133 | |
| 6602 | ||
| 6603 | In MESS: Supported. | |
| 6604 | ||
| 6605 | *************************************************************/ | |
| 6606 | ||
| 6607 | static WRITE8_HANDLER( sa72008_l_w ) | |
| 6608 | { | |
| 6609 | LOG_MMC(("sa72008_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6610 | ||
| 6611 | prg32(space->machine(), data >> 2); | |
| 6612 | chr8(space->machine(), data, CHRROM); | |
| 6613 | } | |
| 6614 | ||
| 6615 | /************************************************************* | |
| 6616 | ||
| 6617 | Sachen TCA-01 bootleg boards | |
| 6618 | ||
| 6619 | iNES: mapper 143 | |
| 6620 | ||
| 6621 | Games: Dancing Blocks, Magic Mathematic | |
| 6622 | ||
| 6623 | In MESS: Supported. | |
| 6624 | ||
| 6625 | *************************************************************/ | |
| 6626 | ||
| 6627 | static READ8_HANDLER( tca01_l_r ) | |
| 6628 | { | |
| 6629 | LOG_MMC(("tca01_l_r, offset: %04x\n", offset)); | |
| 6630 | ||
| 6631 | /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ | |
| 6632 | if (!(offset & 0x100)) | |
| 6633 | return (~offset & 0x3f) | 0x40; | |
| 6634 | else | |
| 6635 | return 0x00; | |
| 6636 | } | |
| 6637 | ||
| 6638 | /************************************************************* | |
| 6639 | ||
| 6640 | Sachen TCU-01 bootleg boards | |
| 6641 | ||
| 6642 | Games: Challenge of the Dragon, Chinese Kungfu | |
| 6643 | ||
| 6644 | iNES: mapper 147 | |
| 6645 | ||
| 6646 | In MESS: Supported. | |
| 6647 | ||
| 6648 | *************************************************************/ | |
| 6649 | ||
| 6650 | static WRITE8_HANDLER( tcu01_l_w ) | |
| 6651 | { | |
| 6652 | LOG_MMC(("tcu01_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6653 | ||
| 6654 | if ((offset & 0x103) == 0x002) | |
| 6655 | { | |
| 6656 | prg32(space->machine(), ((data >> 6) & 0x02) | ((data >> 2) & 0x01)); | |
| 6657 | chr8(space->machine(), data >> 3, CHRROM); | |
| 6658 | } | |
| 6659 | } | |
| 6660 | ||
| 6661 | static WRITE8_HANDLER( tcu01_m_w ) | |
| 6662 | { | |
| 6663 | LOG_MMC(("tcu01_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6664 | ||
| 6665 | tcu01_l_w(space, (offset + 0x100) & 0xfff, data); | |
| 6666 | } | |
| 6667 | ||
| 6668 | static WRITE8_HANDLER( tcu01_w ) | |
| 6669 | { | |
| 6670 | LOG_MMC(("tcu01_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6671 | ||
| 6672 | tcu01_l_w(space, (offset + 0x100) & 0xfff, data); | |
| 6673 | } | |
| 6674 | ||
| 6675 | /************************************************************* | |
| 6676 | ||
| 6677 | Sachen TCU-02 bootleg boards | |
| 6678 | ||
| 6679 | Games: Mei Loi Siu Ji | |
| 6680 | ||
| 6681 | iNES: mapper 136 | |
| 6682 | ||
| 6683 | In MESS: Supported. | |
| 6684 | ||
| 6685 | *************************************************************/ | |
| 6686 | ||
| 6687 | static WRITE8_HANDLER( tcu02_l_w ) | |
| 6688 | { | |
| 6689 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6690 | LOG_MMC(("tcu02_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6691 | ||
| 6692 | if ((offset & 0x103) == 0x002) | |
| 6693 | { | |
| 6694 | state->m_mmc_latch1 = (data & 0x30) | ((data + 3) & 0x0f); | |
| 6695 | chr8(space->machine(), state->m_mmc_latch1, CHRROM); | |
| 6696 | } | |
| 6697 | } | |
| 6698 | ||
| 6699 | static READ8_HANDLER( tcu02_l_r ) | |
| 6700 | { | |
| 6701 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6702 | LOG_MMC(("tcu02_l_r, offset: %04x\n", offset)); | |
| 6703 | ||
| 6704 | if ((offset & 0x103) == 0x000) | |
| 6705 | return state->m_mmc_latch1 | 0x40; | |
| 6706 | else | |
| 6707 | return 0x00; | |
| 6708 | } | |
| 6709 | ||
| 6710 | ||
| 6711 | /************************************************************* | |
| 6712 | ||
| 6713 | Subor bootleg board Type 0 | |
| 6714 | ||
| 6715 | iNES: mapper 167 | |
| 6716 | ||
| 6717 | *************************************************************/ | |
| 6718 | ||
| 6719 | static WRITE8_HANDLER( subor0_w ) | |
| 6720 | { | |
| 6721 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6722 | UINT8 subor_helper1, subor_helper2; | |
| 6723 | LOG_MMC(("subor0_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6724 | ||
| 6725 | state->m_subor_reg[(offset >> 13) & 0x03] = data; | |
| 6726 | subor_helper1 = ((state->m_subor_reg[0] ^ state->m_subor_reg[1]) << 1) & 0x20; | |
| 6727 | subor_helper2 = ((state->m_subor_reg[2] ^ state->m_subor_reg[3]) << 0) & 0x1f; | |
| 6728 | ||
| 6729 | if (state->m_subor_reg[1] & 0x08) | |
| 6730 | { | |
| 6731 | subor_helper1 += subor_helper2 & 0xfe; | |
| 6732 | subor_helper2 = subor_helper1; | |
| 6733 | subor_helper1 += 1; | |
| 6734 | } | |
| 6735 | else if (state->m_subor_reg[1] & 0x04) | |
| 6736 | { | |
| 6737 | subor_helper2 += subor_helper1; | |
| 6738 | subor_helper1 = 0x1f; | |
| 6739 | } | |
| 6740 | else | |
| 6741 | { | |
| 6742 | subor_helper1 += subor_helper2; | |
| 6743 | subor_helper2 = 0x20; | |
| 6744 | } | |
| 6745 | ||
| 6746 | prg16_89ab(space->machine(), subor_helper1); | |
| 6747 | prg16_cdef(space->machine(), subor_helper2); | |
| 6748 | } | |
| 6749 | ||
| 6750 | /************************************************************* | |
| 6751 | ||
| 6752 | Subor bootleg board Type 1 | |
| 6753 | ||
| 6754 | iNES: mapper 166 | |
| 6755 | ||
| 6756 | *************************************************************/ | |
| 6757 | ||
| 6758 | static WRITE8_HANDLER( subor1_w ) | |
| 6759 | { | |
| 6760 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6761 | UINT8 subor_helper1, subor_helper2; | |
| 6762 | LOG_MMC(("subor1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6763 | ||
| 6764 | state->m_subor_reg[(offset >> 13) & 0x03] = data; | |
| 6765 | subor_helper1 = ((state->m_subor_reg[0] ^ state->m_subor_reg[1]) << 1) & 0x20; | |
| 6766 | subor_helper2 = ((state->m_subor_reg[2] ^ state->m_subor_reg[3]) << 0) & 0x1f; | |
| 6767 | ||
| 6768 | if (state->m_subor_reg[1] & 0x08) | |
| 6769 | { | |
| 6770 | subor_helper1 += subor_helper2 & 0xfe; | |
| 6771 | subor_helper2 = subor_helper1; | |
| 6772 | subor_helper2 += 1; | |
| 6773 | } | |
| 6774 | else if (state->m_subor_reg[1] & 0x04) | |
| 6775 | { | |
| 6776 | subor_helper2 += subor_helper1; | |
| 6777 | subor_helper1 = 0x1f; | |
| 6778 | } | |
| 6779 | else | |
| 6780 | { | |
| 6781 | subor_helper1 += subor_helper2; | |
| 6782 | subor_helper2 = 0x07; | |
| 6783 | } | |
| 6784 | ||
| 6785 | prg16_89ab(space->machine(), subor_helper1); | |
| 6786 | prg16_cdef(space->machine(), subor_helper2); | |
| 6787 | } | |
| 6788 | ||
| 6789 | /************************************************************* | |
| 6790 | ||
| 6791 | Bootleg Board by Super Game | |
| 6792 | ||
| 6793 | Games: Boogerman, Mortal Kombat III | |
| 6794 | ||
| 6795 | MMC3 clone. Also, it probably needs a hack to support both | |
| 6796 | variants (Boogerman & MK3). | |
| 6797 | ||
| 6798 | iNES: mapper 215 | |
| 6799 | ||
| 6800 | In MESS: Preliminary support. | |
| 6801 | ||
| 6802 | *************************************************************/ | |
| 6803 | ||
| 6804 | static void sgame_boog_prg_cb( running_machine &machine, int start, int bank ) | |
| 6805 | { | |
| 6806 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6807 | if (!(state->m_mmc_reg[0] & 0x80)) // if this is != 0 we should never even arrive here | |
| 6808 | { | |
| 6809 | if (state->m_mmc_reg[1] & 0x08) | |
| 6810 | bank = (bank & 0x1f) | 0x20; | |
| 6811 | else | |
| 6812 | bank = (bank & 0x0f) | (state->m_mmc_reg[1] & 0x10); | |
| 6813 | ||
| 6814 | prg8_x(machine, start, bank); | |
| 6815 | } | |
| 6816 | } | |
| 6817 | ||
| 6818 | static void sgame_boog_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 6819 | { | |
| 6820 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6821 | ||
| 6822 | if ((state->m_mmc_reg[1] & 0x04)) | |
| 6823 | bank |= 0x100; | |
| 6824 | else | |
| 6825 | bank = (bank & 0x7f) | ((state->m_mmc_reg[1] & 0x10) << 3); | |
| 6826 | ||
| 6827 | chr1_x(machine, start, bank, source); | |
| 6828 | } | |
| 6829 | ||
| 6830 | static void sgame_boog_set_prg( running_machine &machine ) | |
| 6831 | { | |
| 6832 | nes_state *state = machine.driver_data<nes_state>(); | |
| 6833 | if (state->m_mmc_reg[0] & 0x80) | |
| 6834 | { | |
| 6835 | prg16_89ab(machine, (state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10)); | |
| 6836 | prg16_cdef(machine, (state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10)); | |
| 6837 | } | |
| 6838 | else | |
| 6839 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6840 | } | |
| 6841 | ||
| 6842 | static WRITE8_HANDLER( sgame_boog_l_w ) | |
| 6843 | { | |
| 6844 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6845 | LOG_MMC(("sgame_boog_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6846 | offset += 0x100; | |
| 6847 | ||
| 6848 | if (offset == 0x1000) | |
| 6849 | { | |
| 6850 | state->m_mmc_reg[0] = data; | |
| 6851 | sgame_boog_set_prg(space->machine()); | |
| 6852 | } | |
| 6853 | else if (offset == 0x1001) | |
| 6854 | { | |
| 6855 | state->m_mmc_reg[1] = data; | |
| 6856 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6857 | } | |
| 6858 | else if (offset == 0x1007) | |
| 6859 | { | |
| 6860 | state->m_mmc3_latch = 0; | |
| 6861 | state->m_mmc_reg[2] = data; | |
| 6862 | sgame_boog_set_prg(space->machine()); | |
| 6863 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6864 | } | |
| 6865 | } | |
| 6866 | ||
| 6867 | static WRITE8_HANDLER( sgame_boog_m_w ) | |
| 6868 | { | |
| 6869 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6870 | LOG_MMC(("sgame_boog_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6871 | ||
| 6872 | if (offset == 0x0000) | |
| 6873 | { | |
| 6874 | state->m_mmc_reg[0] = data; | |
| 6875 | sgame_boog_set_prg(space->machine()); | |
| 6876 | } | |
| 6877 | else if (offset == 0x0001) | |
| 6878 | { | |
| 6879 | state->m_mmc_reg[1] = data; | |
| 6880 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6881 | } | |
| 6882 | else if (offset == 0x0007) | |
| 6883 | { | |
| 6884 | state->m_mmc3_latch = 0; | |
| 6885 | state->m_mmc_reg[2] = data; | |
| 6886 | sgame_boog_set_prg(space->machine()); | |
| 6887 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 6888 | } | |
| 6889 | } | |
| 6890 | ||
| 6891 | static WRITE8_HANDLER( sgame_boog_w ) | |
| 6892 | { | |
| 6893 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6894 | static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4}; | |
| 6895 | LOG_MMC(("sgame_boog_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6896 | ||
| 6897 | switch (offset & 0x6001) | |
| 6898 | { | |
| 6899 | case 0x0000: | |
| 6900 | if (!state->m_mmc_reg[2]) | |
| 6901 | txrom_w(space, 0x0000, data); | |
| 6902 | break; | |
| 6903 | ||
| 6904 | case 0x0001: | |
| 6905 | if (!state->m_mmc_reg[2]) | |
| 6906 | txrom_w(space, 0x0001, data); | |
| 6907 | else if (state->m_mmc_reg[3] && ((state->m_mmc_reg[0] & 0x80) == 0 || (state->m_mmc_latch1 & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter! | |
| 6908 | { | |
| 6909 | state->m_mmc_reg[3] = 0; | |
| 6910 | txrom_w(space, 0x0001, data); | |
| 6911 | } | |
| 6912 | break; | |
| 6913 | ||
| 6914 | case 0x2000: | |
| 6915 | if (!state->m_mmc_reg[2]) | |
| 6916 | txrom_w(space, 0x2000, data); | |
| 6917 | else | |
| 6918 | { | |
| 6919 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 6920 | state->m_mmc_reg[3] = 1; | |
| 6921 | txrom_w(space, 0x0000, data); | |
| 6922 | break; | |
| 6923 | } | |
| 6924 | break; | |
| 6925 | ||
| 6926 | case 0x4000: | |
| 6927 | if (!state->m_mmc_reg[2]) | |
| 6928 | txrom_w(space, 0x4000, data); | |
| 6929 | else | |
| 6930 | set_nt_mirroring(space->machine(), ((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6931 | break; | |
| 6932 | ||
| 6933 | case 0x4001: | |
| 6934 | if (!state->m_mmc_reg[2]) | |
| 6935 | txrom_w(space, 0x4001, data); | |
| 6936 | else | |
| 6937 | txrom_w(space, 0x6001, data); | |
| 6938 | break; | |
| 6939 | ||
| 6940 | case 0x6001: | |
| 6941 | if (!state->m_mmc_reg[2]) | |
| 6942 | txrom_w(space, 0x6001, data); | |
| 6943 | else | |
| 6944 | { | |
| 6945 | txrom_w(space, 0x4000, data); | |
| 6946 | txrom_w(space, 0x4001, data); | |
| 6947 | } | |
| 6948 | break; | |
| 6949 | ||
| 6950 | default: | |
| 6951 | txrom_w(space, offset, data); | |
| 6952 | break; | |
| 6953 | } | |
| 6954 | } | |
| 6955 | ||
| 6956 | /************************************************************* | |
| 6957 | ||
| 6958 | Bootleg Board by Super Game | |
| 6959 | ||
| 6960 | Games: The Lion King | |
| 6961 | ||
| 6962 | MMC3 clone. | |
| 6963 | ||
| 6964 | iNES: mapper 114 | |
| 6965 | ||
| 6966 | In MESS: Supported. | |
| 6967 | ||
| 6968 | *************************************************************/ | |
| 6969 | ||
| 6970 | static WRITE8_HANDLER( sgame_lion_m_w ) | |
| 6971 | { | |
| 6972 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6973 | LOG_MMC(("sgame_lion_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6974 | ||
| 6975 | state->m_map114_reg = data; | |
| 6976 | ||
| 6977 | if (state->m_map114_reg & 0x80) | |
| 6978 | { | |
| 6979 | prg16_89ab(space->machine(), data & 0x1f); | |
| 6980 | prg16_cdef(space->machine(), data & 0x1f); | |
| 6981 | } | |
| 6982 | else | |
| 6983 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 6984 | ||
| 6985 | } | |
| 6986 | ||
| 6987 | static WRITE8_HANDLER( sgame_lion_w ) | |
| 6988 | { | |
| 6989 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 6990 | static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; | |
| 6991 | LOG_MMC(("sgame_lion_w, offset: %04x, data: %02x\n", offset, data)); | |
| 6992 | ||
| 6993 | if (offset < 0x6000) | |
| 6994 | { | |
| 6995 | switch (offset & 0x6000) | |
| 6996 | { | |
| 6997 | case 0x0000: | |
| 6998 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 6999 | break; | |
| 7000 | case 0x2000: | |
| 7001 | state->m_map114_reg_enabled = 1; | |
| 7002 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 7003 | txrom_w(space, 0x0000, data); | |
| 7004 | break; | |
| 7005 | case 0x4000: | |
| 7006 | if (state->m_map114_reg_enabled && (state->m_map114_reg & 0x80) == 0) | |
| 7007 | { | |
| 7008 | state->m_map114_reg_enabled = 0; | |
| 7009 | txrom_w(space, 0x0001, data); | |
| 7010 | } | |
| 7011 | break; | |
| 7012 | } | |
| 7013 | } | |
| 7014 | else | |
| 7015 | { | |
| 7016 | switch (offset & 0x03) | |
| 7017 | { | |
| 7018 | case 0x02: | |
| 7019 | txrom_w(space, 0x6000, data); | |
| 7020 | break; | |
| 7021 | case 0x03: | |
| 7022 | txrom_w(space, 0x6001, data); | |
| 7023 | txrom_w(space, 0x4000, data); | |
| 7024 | txrom_w(space, 0x4001, data); | |
| 7025 | break; | |
| 7026 | } | |
| 7027 | } | |
| 7028 | } | |
| 7029 | ||
| 7030 | /************************************************************* | |
| 7031 | ||
| 7032 | Tengen 800008 Board | |
| 7033 | ||
| 7034 | iNES: mapper 3? | |
| 7035 | ||
| 7036 | In MESS: Supported. | |
| 7037 | ||
| 7038 | *************************************************************/ | |
| 7039 | ||
| 7040 | static WRITE8_HANDLER( tengen_800008_w ) | |
| 7041 | { | |
| 7042 | LOG_MMC(("tengen_800008_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7043 | ||
| 7044 | prg32(space->machine(), data >> 3); | |
| 7045 | chr8(space->machine(), data, CHRROM); | |
| 7046 | } | |
| 7047 | ||
| 7048 | /************************************************************* | |
| 7049 | ||
| 7050 | Tengen 800032 Board | |
| 7051 | ||
| 7052 | Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls | |
| 7053 | & Croosbones, Xybots | |
| 7054 | ||
| 7055 | iNES: mapper 64 | |
| 7056 | ||
| 7057 | In MESS: Partially Supported. | |
| 7058 | ||
| 7059 | *************************************************************/ | |
| 7060 | ||
| 7061 | static void tengen_800032_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 7062 | { | |
| 7063 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 7064 | if (!state->m_IRQ_mode) // we are in scanline mode! | |
| 7065 | { | |
| 7066 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 7067 | { | |
| 7068 | if (!state->m_IRQ_reset) | |
| 7069 | { | |
| 7070 | if (!state->m_IRQ_count) | |
| 7071 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 7072 | else | |
| 7073 | { | |
| 7074 | state->m_IRQ_count--; | |
| 7075 | if (state->m_IRQ_enable && !blanked && !state->m_IRQ_count) | |
| 7076 | { | |
| 7077 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 7078 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 7079 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 7080 | } | |
| 7081 | } | |
| 7082 | } | |
| 7083 | else | |
| 7084 | { | |
| 7085 | state->m_IRQ_reset = 0; | |
| 7086 | state->m_IRQ_count = state->m_IRQ_count_latch + 1; | |
| 7087 | } | |
| 7088 | } | |
| 7089 | } | |
| 7090 | /* otherwise, we are in CPU cycles mode --> decrement count of 114 every scanline | |
| 7091 | --> in the meanwhile anything can have happened to IRQ_reset and we would not know | |
| 7092 | --> Skulls and Crossbones does not show anything!! */ | |
| 7093 | else | |
| 7094 | { | |
| 7095 | // if (!state->m_IRQ_reset) | |
| 7096 | { | |
| 7097 | if (state->m_IRQ_count <= 114) | |
| 7098 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 7099 | else | |
| 7100 | { | |
| 7101 | state->m_IRQ_count -= 114; | |
| 7102 | if (state->m_IRQ_enable && !blanked && (state->m_IRQ_count <= 114)) | |
| 7103 | { | |
| 7104 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 7105 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 7106 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 7107 | } | |
| 7108 | } | |
| 7109 | } | |
| 7110 | // else | |
| 7111 | // { | |
| 7112 | // state->m_IRQ_reset = 0; | |
| 7113 | // state->m_IRQ_count = state->m_IRQ_count_latch + 1; | |
| 7114 | // } | |
| 7115 | } | |
| 7116 | } | |
| 7117 | ||
| 7118 | static void tengen_800032_set_prg( running_machine &machine ) | |
| 7119 | { | |
| 7120 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7121 | UINT8 prg_mode = state->m_mmc_latch1 & 0x40; | |
| 7122 | ||
| 7123 | prg8_89(machine, state->m_mmc_prg_bank[prg_mode ? 2: 0]); | |
| 7124 | prg8_ab(machine, state->m_mmc_prg_bank[prg_mode ? 0: 1]); | |
| 7125 | prg8_cd(machine, state->m_mmc_prg_bank[prg_mode ? 1: 2]); | |
| 7126 | } | |
| 7127 | ||
| 7128 | static void tengen_800032_set_chr( running_machine &machine ) | |
| 7129 | { | |
| 7130 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7131 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 7132 | ||
| 7133 | if (state->m_mmc_latch1 & 0x20) | |
| 7134 | { | |
| 7135 | chr1_x(machine, 0 ^ chr_page, state->m_mmc_vrom_bank[0], CHRROM); | |
| 7136 | chr1_x(machine, 1 ^ chr_page, state->m_mmc_vrom_bank[8], CHRROM); | |
| 7137 | chr1_x(machine, 2 ^ chr_page, state->m_mmc_vrom_bank[1], CHRROM); | |
| 7138 | chr1_x(machine, 3 ^ chr_page, state->m_mmc_vrom_bank[9], CHRROM); | |
| 7139 | } | |
| 7140 | else | |
| 7141 | { | |
| 7142 | chr1_x(machine, 0 ^ chr_page, state->m_mmc_vrom_bank[0] & ~0x01, CHRROM); | |
| 7143 | chr1_x(machine, 1 ^ chr_page, state->m_mmc_vrom_bank[0] | 0x01, CHRROM); | |
| 7144 | chr1_x(machine, 2 ^ chr_page, state->m_mmc_vrom_bank[1] & ~0x01, CHRROM); | |
| 7145 | chr1_x(machine, 3 ^ chr_page, state->m_mmc_vrom_bank[1] | 0x01, CHRROM); | |
| 7146 | } | |
| 7147 | ||
| 7148 | chr1_x(machine, 4 ^ chr_page, state->m_mmc_vrom_bank[2], CHRROM); | |
| 7149 | chr1_x(machine, 5 ^ chr_page, state->m_mmc_vrom_bank[3], CHRROM); | |
| 7150 | chr1_x(machine, 6 ^ chr_page, state->m_mmc_vrom_bank[4], CHRROM); | |
| 7151 | chr1_x(machine, 7 ^ chr_page, state->m_mmc_vrom_bank[5], CHRROM); | |
| 7152 | } | |
| 7153 | ||
| 7154 | static WRITE8_HANDLER( tengen_800032_w ) | |
| 7155 | { | |
| 7156 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7157 | UINT8 map64_helper, cmd; | |
| 7158 | LOG_MMC(("tengen_800032_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7159 | ||
| 7160 | switch (offset & 0x6001) | |
| 7161 | { | |
| 7162 | case 0x0000: | |
| 7163 | map64_helper = state->m_mmc_latch1 ^ data; | |
| 7164 | state->m_mmc_latch1 = data; | |
| 7165 | ||
| 7166 | /* Has PRG Mode changed? */ | |
| 7167 | if (map64_helper & 0x40) | |
| 7168 | tengen_800032_set_prg(space->machine()); | |
| 7169 | ||
| 7170 | /* Has CHR Mode changed? */ | |
| 7171 | if (map64_helper & 0xa0) | |
| 7172 | tengen_800032_set_chr(space->machine()); | |
| 7173 | break; | |
| 7174 | ||
| 7175 | case 0x0001: | |
| 7176 | cmd = state->m_mmc_latch1 & 0x0f; | |
| 7177 | switch (cmd) | |
| 7178 | { | |
| 7179 | case 0: case 1: | |
| 7180 | case 2: case 3: | |
| 7181 | case 4: case 5: | |
| 7182 | state->m_mmc_vrom_bank[cmd] = data; | |
| 7183 | tengen_800032_set_chr(space->machine()); | |
| 7184 | break; | |
| 7185 | case 6: case 7: | |
| 7186 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 7187 | tengen_800032_set_prg(space->machine()); | |
| 7188 | break; | |
| 7189 | case 8: case 9: | |
| 7190 | state->m_mmc_vrom_bank[cmd - 2] = data; | |
| 7191 | tengen_800032_set_chr(space->machine()); | |
| 7192 | break; | |
| 7193 | case 0x0f: | |
| 7194 | state->m_mmc_prg_bank[2] = data; | |
| 7195 | tengen_800032_set_prg(space->machine()); | |
| 7196 | break; | |
| 7197 | } | |
| 7198 | break; | |
| 7199 | ||
| 7200 | case 0x2000: | |
| 7201 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 7202 | break; | |
| 7203 | ||
| 7204 | case 0x4000: | |
| 7205 | state->m_IRQ_count_latch = data; | |
| 7206 | break; | |
| 7207 | ||
| 7208 | case 0x4001: /* $c001 - IRQ scanline latch */ | |
| 7209 | state->m_IRQ_mode = data & 0x01; | |
| 7210 | state->m_IRQ_reset = 1; | |
| 7211 | break; | |
| 7212 | ||
| 7213 | case 0x6000: | |
| 7214 | state->m_IRQ_enable = 0; | |
| 7215 | break; | |
| 7216 | ||
| 7217 | case 0x6001: | |
| 7218 | state->m_IRQ_enable = 1; | |
| 7219 | break; | |
| 7220 | ||
| 7221 | default: | |
| 7222 | LOG_MMC(("Mapper 64 write. addr: %04x value: %02x\n", offset + 0x8000, data)); | |
| 7223 | break; | |
| 7224 | } | |
| 7225 | } | |
| 7226 | ||
| 7227 | /************************************************************* | |
| 7228 | ||
| 7229 | Tengen 800037 Board | |
| 7230 | ||
| 7231 | Games: Alien Syndrome | |
| 7232 | ||
| 7233 | iNES: mapper 158 | |
| 7234 | ||
| 7235 | In MESS: Very preliminary support. | |
| 7236 | ||
| 7237 | *************************************************************/ | |
| 7238 | ||
| 7239 | // probably wrong... | |
| 7240 | static void tengen_800037_set_mirror( running_machine &machine ) | |
| 7241 | { | |
| 7242 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7243 | UINT8 nt_mode = state->m_mmc_latch1 & 0x80; | |
| 7244 | ||
| 7245 | set_nt_page(machine, 0, ROM, state->m_mmc_vrom_bank[nt_mode ? 2 : 0], 0); | |
| 7246 | set_nt_page(machine, 1, ROM, state->m_mmc_vrom_bank[nt_mode ? 3 : 0], 0); | |
| 7247 | set_nt_page(machine, 2, ROM, state->m_mmc_vrom_bank[nt_mode ? 4 : 1], 0); | |
| 7248 | set_nt_page(machine, 3, ROM, state->m_mmc_vrom_bank[nt_mode ? 5 : 1], 0); | |
| 7249 | } | |
| 7250 | ||
| 7251 | static WRITE8_HANDLER( tengen_800037_w ) | |
| 7252 | { | |
| 7253 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7254 | UINT8 map158_helper, cmd; | |
| 7255 | LOG_MMC(("tengen_800037_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7256 | ||
| 7257 | switch (offset & 0x6001) | |
| 7258 | { | |
| 7259 | case 0x0000: | |
| 7260 | map158_helper = state->m_mmc_latch1 ^ data; | |
| 7261 | state->m_mmc_latch1 = data; | |
| 7262 | ||
| 7263 | /* Has PRG Mode changed? */ | |
| 7264 | if (map158_helper & 0x40) | |
| 7265 | tengen_800032_set_prg(space->machine()); | |
| 7266 | ||
| 7267 | /* Has CHR Mode changed? */ | |
| 7268 | if (map158_helper & 0xa0) | |
| 7269 | { | |
| 7270 | tengen_800032_set_chr(space->machine()); | |
| 7271 | tengen_800037_set_mirror(space->machine()); | |
| 7272 | } | |
| 7273 | break; | |
| 7274 | ||
| 7275 | case 0x0001: | |
| 7276 | cmd = state->m_mmc_latch1 & 0x0f; | |
| 7277 | switch (cmd) | |
| 7278 | { | |
| 7279 | case 0: case 1: | |
| 7280 | case 2: case 3: | |
| 7281 | case 4: case 5: | |
| 7282 | state->m_mmc_vrom_bank[cmd] = data; | |
| 7283 | tengen_800032_set_chr(space->machine()); | |
| 7284 | tengen_800037_set_mirror(space->machine()); | |
| 7285 | break; | |
| 7286 | case 6: case 7: | |
| 7287 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 7288 | tengen_800032_set_prg(space->machine()); | |
| 7289 | break; | |
| 7290 | case 8: case 9: | |
| 7291 | state->m_mmc_vrom_bank[cmd - 2] = data; | |
| 7292 | tengen_800032_set_chr(space->machine()); | |
| 7293 | tengen_800037_set_mirror(space->machine()); | |
| 7294 | break; | |
| 7295 | case 0x0f: | |
| 7296 | state->m_mmc_prg_bank[2] = data; | |
| 7297 | tengen_800032_set_prg(space->machine()); | |
| 7298 | break; | |
| 7299 | } | |
| 7300 | break; | |
| 7301 | ||
| 7302 | case 0x2000: | |
| 7303 | break; | |
| 7304 | ||
| 7305 | default: | |
| 7306 | tengen_800032_w(space, offset, data); | |
| 7307 | break; | |
| 7308 | } | |
| 7309 | } | |
| 7310 | ||
| 7311 | /************************************************************* | |
| 7312 | ||
| 7313 | Bootleg Board 22211 by TXC (Type A) | |
| 7314 | ||
| 7315 | Games: Creatom | |
| 7316 | ||
| 7317 | Info from NEStopia: this mapper features write to four | |
| 7318 | registers (0x4100-0x4103). The third one is used to select | |
| 7319 | PRG and CHR banks. | |
| 7320 | ||
| 7321 | iNES: mapper 132 | |
| 7322 | ||
| 7323 | In MESS: Supported. | |
| 7324 | ||
| 7325 | *************************************************************/ | |
| 7326 | ||
| 7327 | static WRITE8_HANDLER( txc_22211_l_w ) | |
| 7328 | { | |
| 7329 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7330 | LOG_MMC(("txc_22211_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7331 | ||
| 7332 | if (offset < 4) | |
| 7333 | state->m_txc_reg[offset & 0x03] = data; | |
| 7334 | } | |
| 7335 | ||
| 7336 | static READ8_HANDLER( txc_22211_l_r ) | |
| 7337 | { | |
| 7338 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7339 | LOG_MMC(("txc_22211_l_r, offset: %04x\n", offset)); | |
| 7340 | ||
| 7341 | if (offset == 0x0000) | |
| 7342 | return (state->m_txc_reg[1] ^ state->m_txc_reg[2]) | 0x40; | |
| 7343 | else | |
| 7344 | return 0x00; | |
| 7345 | } | |
| 7346 | ||
| 7347 | static WRITE8_HANDLER( txc_22211_w ) | |
| 7348 | { | |
| 7349 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7350 | LOG_MMC(("txc_22211_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7351 | ||
| 7352 | prg32(space->machine(), state->m_txc_reg[2] >> 2); | |
| 7353 | chr8(space->machine(), state->m_txc_reg[2], CHRROM); | |
| 7354 | } | |
| 7355 | ||
| 7356 | /************************************************************* | |
| 7357 | ||
| 7358 | Bootleg Board 22211 by TXC (Type B) | |
| 7359 | ||
| 7360 | Games: 1991 Du Ma Racing | |
| 7361 | ||
| 7362 | This mapper is basically the same as Type A. Only difference is | |
| 7363 | in the way CHR banks are selected (see below) | |
| 7364 | ||
| 7365 | iNES: mapper 172 | |
| 7366 | ||
| 7367 | In MESS: Supported. | |
| 7368 | ||
| 7369 | *************************************************************/ | |
| 7370 | ||
| 7371 | static WRITE8_HANDLER( txc_22211b_w ) | |
| 7372 | { | |
| 7373 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7374 | LOG_MMC(("txc_22211b_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7375 | ||
| 7376 | prg32(space->machine(), state->m_txc_reg[2] >> 2); | |
| 7377 | chr8(space->machine(), (((data ^ state->m_txc_reg[2]) >> 3) & 0x02) | (((data ^ state->m_txc_reg[2]) >> 5) & 0x01), CHRROM); | |
| 7378 | } | |
| 7379 | ||
| 7380 | /************************************************************* | |
| 7381 | ||
| 7382 | Bootleg Board 22211 by TXC (Type C) | |
| 7383 | ||
| 7384 | Games: Mahjong Block, Xiao Ma Li | |
| 7385 | ||
| 7386 | This mapper is basically the same as 132 too. Only difference is | |
| 7387 | in 0x4100 reads which expect also bit 0 to be set | |
| 7388 | ||
| 7389 | iNES: mapper 172 | |
| 7390 | ||
| 7391 | In MESS: Supported. | |
| 7392 | ||
| 7393 | *************************************************************/ | |
| 7394 | ||
| 7395 | static READ8_HANDLER( txc_22211c_l_r ) | |
| 7396 | { | |
| 7397 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7398 | LOG_MMC(("txc_22211c_l_r, offset: %04x\n", offset)); | |
| 7399 | ||
| 7400 | if (offset == 0x0000) | |
| 7401 | return (state->m_txc_reg[1] ^ state->m_txc_reg[2]) | 0x41; | |
| 7402 | else | |
| 7403 | return 0x00; | |
| 7404 | } | |
| 7405 | ||
| 7406 | /************************************************************* | |
| 7407 | ||
| 7408 | Bootleg Board 'Thunder Warrior' by TXC | |
| 7409 | ||
| 7410 | Games: Master Fighter II, Master Fighter 3, Thunder Warrior | |
| 7411 | ||
| 7412 | MMC3 clone | |
| 7413 | ||
| 7414 | iNES: mapper 189 | |
| 7415 | ||
| 7416 | In MESS: Supported. | |
| 7417 | ||
| 7418 | *************************************************************/ | |
| 7419 | ||
| 7420 | static WRITE8_HANDLER( txc_tw_l_w ) | |
| 7421 | { | |
| 7422 | LOG_MMC(("txctw_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7423 | ||
| 7424 | prg32(space->machine(), (data >> 4) | data); | |
| 7425 | } | |
| 7426 | ||
| 7427 | static WRITE8_HANDLER( txc_tw_m_w ) | |
| 7428 | { | |
| 7429 | LOG_MMC(("txctw_m_w, offset: %04x, data: %04x\n", offset, data)); | |
| 7430 | ||
| 7431 | txc_tw_l_w(space, offset & 0xff, data); // offset does not really count for this mapper | |
| 7432 | } | |
| 7433 | ||
| 7434 | /* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ | |
| 7435 | static void txc_tw_prg_cb( running_machine &machine, int start, int bank ) | |
| 7436 | { | |
| 7437 | return; | |
| 7438 | } | |
| 7439 | ||
| 7440 | /************************************************************* | |
| 7441 | ||
| 7442 | Bootleg Board 'Strike Wolf' by TXC | |
| 7443 | ||
| 7444 | Games: Strike Wolf (also Policeman?? according to Nestopia) | |
| 7445 | ||
| 7446 | iNES: mapper 36 | |
| 7447 | ||
| 7448 | Known Boards: Bootleg Board by TXC | |
| 7449 | ||
| 7450 | In MESS: Supported. | |
| 7451 | ||
| 7452 | *************************************************************/ | |
| 7453 | ||
| 7454 | static WRITE8_HANDLER( txc_strikewolf_w ) | |
| 7455 | { | |
| 7456 | LOG_MMC(("txc_strikewolf_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7457 | ||
| 7458 | if ((offset >= 0x400) && (offset < 0x7fff)) | |
| 7459 | { | |
| 7460 | prg32(space->machine(), data >> 4); | |
| 7461 | chr8(space->machine(), data & 0x0f, CHRROM); | |
| 7462 | } | |
| 7463 | } | |
| 7464 | ||
| 7465 | /************************************************************* | |
| 7466 | ||
| 7467 | Bootleg Board MXMDHTWO by TXC | |
| 7468 | ||
| 7469 | Games: Commandos, Journey to the West, Ma Bu Mi Zhen & | |
| 7470 | Qu Wei Cheng Yu Wu, Si Lu Chuan Qi | |
| 7471 | ||
| 7472 | Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank. | |
| 7473 | Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct. | |
| 7474 | ||
| 7475 | iNES: mapper 241 | |
| 7476 | ||
| 7477 | In MESS: Supported. | |
| 7478 | ||
| 7479 | *************************************************************/ | |
| 7480 | ||
| 7481 | static READ8_HANDLER( txc_mxmdhtwo_l_r ) | |
| 7482 | { | |
| 7483 | return 0x50; | |
| 7484 | } | |
| 7485 | ||
| 7486 | static WRITE8_HANDLER( txc_mxmdhtwo_w ) | |
| 7487 | { | |
| 7488 | LOG_MMC(("txc_mxmdhtwo_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7489 | ||
| 7490 | prg32(space->machine(), data); | |
| 7491 | } | |
| 7492 | ||
| 7493 | /************************************************************* | |
| 7494 | ||
| 7495 | Waixing Board Type A | |
| 7496 | ||
| 7497 | Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi, | |
| 7498 | Jia A Fung Yun, Wei Luo Chuan Qi | |
| 7499 | ||
| 7500 | This mapper is quite similar to MMC3, but with two differences: | |
| 7501 | mirroring is not the same, and when VROM banks 8,9 are accessed | |
| 7502 | they point to CHRRAM and not CHRROM. | |
| 7503 | ||
| 7504 | iNES: mapper 74 | |
| 7505 | ||
| 7506 | In MESS: Supported | |
| 7507 | ||
| 7508 | *************************************************************/ | |
| 7509 | ||
| 7510 | /* MIRROR_LOW and MIRROR_HIGH are swapped! */ | |
| 7511 | static void waixing_set_mirror( running_machine &machine, UINT8 nt ) | |
| 7512 | { | |
| 7513 | switch (nt) | |
| 7514 | { | |
| 7515 | case 0: | |
| 7516 | case 1: | |
| 7517 | set_nt_mirroring(machine, nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 7518 | break; | |
| 7519 | case 2: | |
| 7520 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 7521 | break; | |
| 7522 | case 3: | |
| 7523 | set_nt_mirroring(machine, PPU_MIRROR_HIGH); | |
| 7524 | break; | |
| 7525 | default: | |
| 7526 | LOG_MMC(("Mapper set NT to invalid value %02x", nt)); | |
| 7527 | break; | |
| 7528 | } | |
| 7529 | } | |
| 7530 | ||
| 7531 | /* Luo Ke Ren X only works with this */ | |
| 7532 | static void waixing_a_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7533 | { | |
| 7534 | int chr_src = (bank <= 9) ? CHRRAM : CHRROM; | |
| 7535 | chr1_x(machine, start, bank, chr_src); | |
| 7536 | } | |
| 7537 | ||
| 7538 | /* Ji Jia Zhan Shi only works with this */ | |
| 7539 | static void waixing_a1_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7540 | { | |
| 7541 | int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM; | |
| 7542 | chr1_x(machine, start, bank, chr_src); | |
| 7543 | } | |
| 7544 | ||
| 7545 | static WRITE8_HANDLER( waixing_a_w ) | |
| 7546 | { | |
| 7547 | LOG_MMC(("waixing_a_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7548 | ||
| 7549 | switch (offset & 0x6001) | |
| 7550 | { | |
| 7551 | case 0x2000: | |
| 7552 | waixing_set_mirror(space->machine(), data); //maybe data & 0x03? | |
| 7553 | break; | |
| 7554 | ||
| 7555 | case 0x2001: | |
| 7556 | break; | |
| 7557 | ||
| 7558 | default: | |
| 7559 | txrom_w(space, offset, data); | |
| 7560 | break; | |
| 7561 | } | |
| 7562 | } | |
| 7563 | ||
| 7564 | /************************************************************* | |
| 7565 | ||
| 7566 | Waixing Board Type B | |
| 7567 | ||
| 7568 | Games: Sugoro Quest (C) | |
| 7569 | ||
| 7570 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7571 | in the sense that it is the same board except for the | |
| 7572 | CHRRAM pages. | |
| 7573 | ||
| 7574 | iNES: mapper 191 | |
| 7575 | ||
| 7576 | In MESS: Supported. | |
| 7577 | ||
| 7578 | *************************************************************/ | |
| 7579 | ||
| 7580 | static void waixing_b_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7581 | { | |
| 7582 | int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM; | |
| 7583 | chr1_x(machine, start, bank, chr_src); | |
| 7584 | } | |
| 7585 | ||
| 7586 | /************************************************************* | |
| 7587 | ||
| 7588 | Waixing Board Type C | |
| 7589 | ||
| 7590 | Games: Ying Lie Qun Xia Zhuan, Young Chivalry | |
| 7591 | ||
| 7592 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7593 | in the sense that it is the same board except for the | |
| 7594 | CHRRAM pages. | |
| 7595 | ||
| 7596 | iNES: mapper 192 | |
| 7597 | ||
| 7598 | In MESS: Supported. | |
| 7599 | ||
| 7600 | *************************************************************/ | |
| 7601 | ||
| 7602 | static void waixing_c_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7603 | { | |
| 7604 | int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM; | |
| 7605 | chr1_x(machine, start, bank, chr_src); | |
| 7606 | } | |
| 7607 | ||
| 7608 | /************************************************************* | |
| 7609 | ||
| 7610 | Waixing Board Type D | |
| 7611 | ||
| 7612 | Games: Super Robot Taisen (C) | |
| 7613 | ||
| 7614 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7615 | in the sense that it is the same board except for the | |
| 7616 | CHRRAM pages. | |
| 7617 | ||
| 7618 | iNES: mapper 194 | |
| 7619 | ||
| 7620 | In MESS: Supported. | |
| 7621 | ||
| 7622 | *************************************************************/ | |
| 7623 | ||
| 7624 | static void waixing_d_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7625 | { | |
| 7626 | int chr_src = (bank < 0x02) ? CHRRAM : CHRROM; | |
| 7627 | chr1_x(machine, start, bank, chr_src); | |
| 7628 | } | |
| 7629 | ||
| 7630 | /************************************************************* | |
| 7631 | ||
| 7632 | Waixing Board Type E | |
| 7633 | ||
| 7634 | Games: Captain Tsubasa Vol. II (C), Chaos World, God | |
| 7635 | Slayer (C), Zu Qiu Xiao Jiang | |
| 7636 | ||
| 7637 | MMC3 clone. This is a minor modification of Mapper 74, | |
| 7638 | in the sense that it is the same board except for the | |
| 7639 | CHRRAM pages. | |
| 7640 | ||
| 7641 | iNES: mapper 195 | |
| 7642 | ||
| 7643 | In MESS: Supported. | |
| 7644 | ||
| 7645 | *************************************************************/ | |
| 7646 | ||
| 7647 | static void waixing_e_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7648 | { | |
| 7649 | int chr_src = (bank < 0x04) ? CHRRAM : CHRROM; | |
| 7650 | chr1_x(machine, start, bank, chr_src); | |
| 7651 | } | |
| 7652 | ||
| 7653 | /************************************************************* | |
| 7654 | ||
| 7655 | Waixing Board Type F | |
| 7656 | ||
| 7657 | Games: Tenchi wo Kurau II (C) | |
| 7658 | ||
| 7659 | MMC3 clone. | |
| 7660 | ||
| 7661 | iNES: mapper 198 | |
| 7662 | ||
| 7663 | In MESS: Preliminary support. | |
| 7664 | ||
| 7665 | *************************************************************/ | |
| 7666 | ||
| 7667 | static WRITE8_HANDLER( waixing_f_w ) | |
| 7668 | { | |
| 7669 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7670 | UINT8 cmd; | |
| 7671 | LOG_MMC(("waixing_f_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7672 | ||
| 7673 | switch (offset & 0x6001) | |
| 7674 | { | |
| 7675 | case 0x0001: | |
| 7676 | cmd = state->m_mmc_latch1 & 0x07; | |
| 7677 | if (cmd >= 6) | |
| 7678 | { | |
| 7679 | state->m_mmc_prg_bank[cmd - 6] = data & ((data > 0x3f) ? 0x4f : 0x3f); | |
| 7680 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7681 | } | |
| 7682 | else | |
| 7683 | waixing_a_w(space, offset, data); | |
| 7684 | break; | |
| 7685 | ||
| 7686 | default: | |
| 7687 | waixing_a_w(space, offset, data); | |
| 7688 | break; | |
| 7689 | } | |
| 7690 | } | |
| 7691 | ||
| 7692 | /************************************************************* | |
| 7693 | ||
| 7694 | Waixing Board Type G | |
| 7695 | ||
| 7696 | Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon | |
| 7697 | Ball Z II (C) | |
| 7698 | ||
| 7699 | MMC3 clone | |
| 7700 | ||
| 7701 | iNES: mapper 199 | |
| 7702 | ||
| 7703 | In MESS: Supported. | |
| 7704 | ||
| 7705 | *************************************************************/ | |
| 7706 | ||
| 7707 | static void waixing_g_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7708 | { | |
| 7709 | int chr_src = (bank < 0x08) ? CHRRAM : CHRROM; | |
| 7710 | chr1_x(machine, start, bank, chr_src); | |
| 7711 | } | |
| 7712 | ||
| 7713 | static void waixing_g_set_chr( running_machine &machine, int chr_base, int chr_mask ) | |
| 7714 | { | |
| 7715 | nes_state *state = machine.driver_data<nes_state>(); | |
| 7716 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 7717 | ||
| 7718 | state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | (state->m_mmc_vrom_bank[0] & chr_mask), state->m_mmc_chr_source); | |
| 7719 | state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | (state->m_mmc_vrom_bank[6] & chr_mask), state->m_mmc_chr_source); | |
| 7720 | state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), state->m_mmc_chr_source); | |
| 7721 | state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | (state->m_mmc_vrom_bank[7] & chr_mask), state->m_mmc_chr_source); | |
| 7722 | state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), state->m_mmc_chr_source); | |
| 7723 | state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), state->m_mmc_chr_source); | |
| 7724 | state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), state->m_mmc_chr_source); | |
| 7725 | state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), state->m_mmc_chr_source); | |
| 7726 | } | |
| 7727 | ||
| 7728 | static WRITE8_HANDLER( waixing_g_w ) | |
| 7729 | { | |
| 7730 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7731 | UINT8 MMC3_helper, cmd; | |
| 7732 | LOG_MMC(("waixing_g_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7733 | ||
| 7734 | switch (offset & 0x6001) | |
| 7735 | { | |
| 7736 | case 0x0000: | |
| 7737 | MMC3_helper = state->m_mmc_latch1 ^ data; | |
| 7738 | state->m_mmc_latch1 = data; | |
| 7739 | ||
| 7740 | /* Has PRG Mode changed? */ | |
| 7741 | if (MMC3_helper & 0x40) | |
| 7742 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7743 | ||
| 7744 | /* Has CHR Mode changed? */ | |
| 7745 | if (MMC3_helper & 0x80) | |
| 7746 | waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 7747 | break; | |
| 7748 | ||
| 7749 | case 0x0001: | |
| 7750 | cmd = state->m_mmc_latch1 & 0x0f; | |
| 7751 | switch (cmd) | |
| 7752 | { | |
| 7753 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 7754 | case 2: case 3: case 4: case 5: | |
| 7755 | state->m_mmc_vrom_bank[cmd] = data; | |
| 7756 | waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 7757 | break; | |
| 7758 | case 6: | |
| 7759 | case 7: | |
| 7760 | case 8: | |
| 7761 | case 9: | |
| 7762 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 7763 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7764 | break; | |
| 7765 | case 0x0a: case 0x0b: | |
| 7766 | state->m_mmc_vrom_bank[cmd - 4] = data; | |
| 7767 | waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 7768 | break; | |
| 7769 | } | |
| 7770 | break; | |
| 7771 | ||
| 7772 | default: | |
| 7773 | waixing_a_w(space, offset, data); | |
| 7774 | break; | |
| 7775 | } | |
| 7776 | } | |
| 7777 | ||
| 7778 | /************************************************************* | |
| 7779 | ||
| 7780 | Waixing Board Type H | |
| 7781 | ||
| 7782 | Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E | |
| 7783 | Long - Dragon Quest VII | |
| 7784 | ||
| 7785 | MMC3 clone. More info to come. | |
| 7786 | ||
| 7787 | iNES: mapper 245 | |
| 7788 | ||
| 7789 | In MESS: Supported. | |
| 7790 | ||
| 7791 | *************************************************************/ | |
| 7792 | ||
| 7793 | static void waixing_h_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 7794 | { | |
| 7795 | if (source == CHRROM) | |
| 7796 | chr1_x(machine, start, bank, source); | |
| 7797 | } | |
| 7798 | ||
| 7799 | static WRITE8_HANDLER( waixing_h_w ) | |
| 7800 | { | |
| 7801 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7802 | UINT8 cmd; | |
| 7803 | LOG_MMC(("waixing_h_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7804 | ||
| 7805 | switch (offset & 0x6001) | |
| 7806 | { | |
| 7807 | case 0x0001: | |
| 7808 | cmd = state->m_mmc3_latch & 0x07; | |
| 7809 | switch (cmd) | |
| 7810 | { | |
| 7811 | case 0: // in this case we set prg_base in addition to state->m_mmc_vrom_bank! | |
| 7812 | state->m_mmc_prg_base = (data << 5) & 0x40; | |
| 7813 | state->m_mmc_prg_mask = 0x3f; | |
| 7814 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 7815 | txrom_w(space, offset, data); | |
| 7816 | default: | |
| 7817 | txrom_w(space, offset, data); | |
| 7818 | break; | |
| 7819 | } | |
| 7820 | break; | |
| 7821 | ||
| 7822 | case 0x2001: | |
| 7823 | break; | |
| 7824 | ||
| 7825 | default: | |
| 7826 | txrom_w(space, offset, data); | |
| 7827 | break; | |
| 7828 | } | |
| 7829 | } | |
| 7830 | ||
| 7831 | /************************************************************* | |
| 7832 | ||
| 7833 | Waixing San Guo Zhi Board | |
| 7834 | ||
| 7835 | Games: San Guo Zhi | |
| 7836 | ||
| 7837 | This board uses Konami IRQ | |
| 7838 | ||
| 7839 | iNES: mapper 252 | |
| 7840 | ||
| 7841 | In MESS: Unsupported. | |
| 7842 | ||
| 7843 | *************************************************************/ | |
| 7844 | ||
| 7845 | static WRITE8_HANDLER( waixing_sgz_w ) | |
| 7846 | { | |
| 7847 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7848 | UINT8 mmc_helper, bank; | |
| 7849 | LOG_MMC(("waixing_sgz_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7850 | ||
| 7851 | switch (offset & 0x7000) | |
| 7852 | { | |
| 7853 | case 0x0000: | |
| 7854 | prg8_89(space->machine(), data); | |
| 7855 | break; | |
| 7856 | case 0x2000: | |
| 7857 | prg8_ab(space->machine(), data); | |
| 7858 | break; | |
| 7859 | case 0x3000: | |
| 7860 | case 0x4000: | |
| 7861 | case 0x5000: | |
| 7862 | case 0x6000: | |
| 7863 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3); | |
| 7864 | mmc_helper = offset & 0x04; | |
| 7865 | if (mmc_helper) | |
| 7866 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); | |
| 7867 | else | |
| 7868 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 7869 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 7870 | break; | |
| 7871 | case 0x7000: | |
| 7872 | switch (offset & 0x0c) | |
| 7873 | { | |
| 7874 | case 0x00: | |
| 7875 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f); | |
| 7876 | break; | |
| 7877 | case 0x04: | |
| 7878 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4); | |
| 7879 | break; | |
| 7880 | case 0x08: | |
| 7881 | state->m_IRQ_enable = data & 0x02; | |
| 7882 | state->m_IRQ_enable_latch = data & 0x01; | |
| 7883 | if (data & 0x02) | |
| 7884 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 7885 | break; | |
| 7886 | case 0x0c: | |
| 7887 | state->m_IRQ_enable = state->m_IRQ_enable_latch; | |
| 7888 | break; | |
| 7889 | } | |
| 7890 | break; | |
| 7891 | } | |
| 7892 | } | |
| 7893 | ||
| 7894 | ||
| 7895 | /************************************************************* | |
| 7896 | ||
| 7897 | Waixing San Guo Zhong Lie Zhuan Board | |
| 7898 | ||
| 7899 | Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing | |
| 7900 | Ji Zheng Ba | |
| 7901 | ||
| 7902 | iNES: mapper 178 | |
| 7903 | ||
| 7904 | In MESS: Supported. | |
| 7905 | ||
| 7906 | *************************************************************/ | |
| 7907 | ||
| 7908 | static WRITE8_HANDLER( waixing_sgzlz_l_w ) | |
| 7909 | { | |
| 7910 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7911 | LOG_MMC(("waixing_sgzlz_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7912 | ||
| 7913 | switch (offset) | |
| 7914 | { | |
| 7915 | case 0x700: | |
| 7916 | set_nt_mirroring(space->machine(), data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 7917 | break; | |
| 7918 | case 0x701: | |
| 7919 | state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x0c) | ((data >> 1) & 0x03); | |
| 7920 | prg32(space->machine(), state->m_mmc_latch1); | |
| 7921 | break; | |
| 7922 | case 0x702: | |
| 7923 | state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x03) | ((data << 2) & 0x0c); | |
| 7924 | break; | |
| 7925 | } | |
| 7926 | } | |
| 7927 | ||
| 7928 | /************************************************************* | |
| 7929 | ||
| 7930 | Waixing Final Fantasy V Board | |
| 7931 | ||
| 7932 | Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket | |
| 7933 | Monster Red | |
| 7934 | ||
| 7935 | iNES: mapper 164 | |
| 7936 | ||
| 7937 | In MESS: Supported. | |
| 7938 | ||
| 7939 | *************************************************************/ | |
| 7940 | ||
| 7941 | static WRITE8_HANDLER( waixing_ffv_l_w ) | |
| 7942 | { | |
| 7943 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 7944 | UINT8 mmc_helper; | |
| 7945 | LOG_MMC(("waixing_ffv_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7946 | offset += 0x100; /* the checks work better on addresses */ | |
| 7947 | ||
| 7948 | if (0x1000 == (offset & 0x1200)) | |
| 7949 | { | |
| 7950 | state->m_mmc_reg[BIT(offset, 8)] = data; | |
| 7951 | mmc_helper = BIT(state->m_mmc_reg[1], 0) << 5; | |
| 7952 | switch (state->m_mmc_reg[0] & 0x70) | |
| 7953 | { | |
| 7954 | case 0x00: | |
| 7955 | case 0x20: | |
| 7956 | case 0x40: | |
| 7957 | case 0x60: | |
| 7958 | prg16_89ab(space->machine(), mmc_helper | ((state->m_mmc_reg[0] >> 1) & 0x10) | (state->m_mmc_reg[0] & 0x0f)); | |
| 7959 | prg16_cdef(space->machine(), mmc_helper & 0x1f); | |
| 7960 | break; | |
| 7961 | case 0x50: | |
| 7962 | prg32(space->machine(), (mmc_helper >> 1) | (state->m_mmc_reg[0] & 0x0f)); | |
| 7963 | break; | |
| 7964 | case 0x70: | |
| 7965 | prg16_89ab(space->machine(), mmc_helper | ((state->m_mmc_reg[0] << 1) & 0x10) | (state->m_mmc_reg[0] & 0x0f)); | |
| 7966 | prg16_cdef(space->machine(), mmc_helper & 0x1f); | |
| 7967 | break; | |
| 7968 | } | |
| 7969 | } | |
| 7970 | } | |
| 7971 | ||
| 7972 | /************************************************************* | |
| 7973 | ||
| 7974 | Waixing Zhan Shi Board | |
| 7975 | ||
| 7976 | Games: Wai Xing Zhan Shi | |
| 7977 | ||
| 7978 | Simple mapper: writes to 0x8000-0xffff sets prg32 banks to | |
| 7979 | (offset>>3)&f. written data&3 sets the mirroring (with | |
| 7980 | switched high/low compared to the standard one). | |
| 7981 | ||
| 7982 | A crc check is required to support Dragon Quest VIII (which | |
| 7983 | uses a slightly different board) | |
| 7984 | ||
| 7985 | iNES: mapper 242 | |
| 7986 | ||
| 7987 | In MESS: Supported. | |
| 7988 | ||
| 7989 | *************************************************************/ | |
| 7990 | ||
| 7991 | static WRITE8_HANDLER( waixing_zs_w ) | |
| 7992 | { | |
| 7993 | LOG_MMC(("waixing_zs_w, offset: %04x, data: %02x\n", offset, data)); | |
| 7994 | ||
| 7995 | prg32(space->machine(), offset >> 3); | |
| 7996 | ||
| 7997 | switch (data & 0x03) | |
| 7998 | { | |
| 7999 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 8000 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 8001 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 8002 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 8003 | } | |
| 8004 | } | |
| 8005 | ||
| 8006 | /************************************************************* | |
| 8007 | ||
| 8008 | Waixing Dragon Quest VIII Board | |
| 8009 | ||
| 8010 | Games: Dragon Quest VIII | |
| 8011 | ||
| 8012 | Simple mapper: writes to 0x8000-0xffff sets prg32 banks to | |
| 8013 | (offset>>3)&f. | |
| 8014 | ||
| 8015 | iNES: mapper 242 | |
| 8016 | ||
| 8017 | In MESS: Supported. | |
| 8018 | ||
| 8019 | *************************************************************/ | |
| 8020 | ||
| 8021 | static WRITE8_HANDLER( waixing_dq8_w ) | |
| 8022 | { | |
| 8023 | LOG_MMC(("waixing_dq8_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8024 | ||
| 8025 | prg32(space->machine(), offset >> 3); | |
| 8026 | } | |
| 8027 | ||
| 8028 | ||
| 8029 | /************************************************************* | |
| 8030 | ||
| 8031 | Waixing PS2 board | |
| 8032 | ||
| 8033 | Games: Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R) | |
| 8034 | ||
| 8035 | iNES: mapper 15 | |
| 8036 | ||
| 8037 | In MESS: Supported | |
| 8038 | ||
| 8039 | *************************************************************/ | |
| 8040 | ||
| 8041 | static WRITE8_HANDLER( waixing_ps2_w ) | |
| 8042 | { | |
| 8043 | UINT8 map15_flip = (data & 0x80) >> 7; | |
| 8044 | UINT8 map15_helper = (data & 0x7f) << 1; | |
| 8045 | ||
| 8046 | LOG_MMC(("waixing_ps2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8047 | ||
| 8048 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8049 | ||
| 8050 | switch (offset & 0x0fff) | |
| 8051 | { | |
| 8052 | case 0x000: | |
| 8053 | prg8_89(space->machine(), (map15_helper + 0) ^ map15_flip); | |
| 8054 | prg8_ab(space->machine(), (map15_helper + 1) ^ map15_flip); | |
| 8055 | prg8_cd(space->machine(), (map15_helper + 2) ^ map15_flip); | |
| 8056 | prg8_ef(space->machine(), (map15_helper + 3) ^ map15_flip); | |
| 8057 | break; | |
| 8058 | case 0x001: | |
| 8059 | map15_helper |= map15_flip; | |
| 8060 | prg8_89(space->machine(), map15_helper); | |
| 8061 | prg8_ab(space->machine(), map15_helper + 1); | |
| 8062 | prg8_cd(space->machine(), map15_helper + 1); | |
| 8063 | prg8_ef(space->machine(), map15_helper + 1); | |
| 8064 | break; | |
| 8065 | case 0x002: | |
| 8066 | map15_helper |= map15_flip; | |
| 8067 | prg8_89(space->machine(), map15_helper); | |
| 8068 | prg8_ab(space->machine(), map15_helper); | |
| 8069 | prg8_cd(space->machine(), map15_helper); | |
| 8070 | prg8_ef(space->machine(), map15_helper); | |
| 8071 | break; | |
| 8072 | case 0x003: | |
| 8073 | map15_helper |= map15_flip; | |
| 8074 | prg8_89(space->machine(), map15_helper); | |
| 8075 | prg8_ab(space->machine(), map15_helper + 1); | |
| 8076 | prg8_cd(space->machine(), map15_helper); | |
| 8077 | prg8_ef(space->machine(), map15_helper + 1); | |
| 8078 | break; | |
| 8079 | } | |
| 8080 | } | |
| 8081 | ||
| 8082 | /************************************************************* | |
| 8083 | ||
| 8084 | Waixing Board with Security Chip | |
| 8085 | ||
| 8086 | Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo, | |
| 8087 | Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan | |
| 8088 | ||
| 8089 | MMC3 clone | |
| 8090 | ||
| 8091 | iNES: mapper 249 | |
| 8092 | ||
| 8093 | In MESS: Partially Supported. | |
| 8094 | ||
| 8095 | *************************************************************/ | |
| 8096 | ||
| 8097 | static void waixing_sec_prg_cb( running_machine &machine, int start, int bank ) | |
| 8098 | { | |
| 8099 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8100 | ||
| 8101 | if (state->m_mmc_reg[0]) | |
| 8102 | bank = ((bank & 0x01)) | ((bank >> 3) & 0x02) | ((bank >> 1) & 0x04) | ((bank << 2) & 0x18); | |
| 8103 | ||
| 8104 | prg8_x(machine, start, bank); | |
| 8105 | } | |
| 8106 | ||
| 8107 | static void waixing_sec_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8108 | { | |
| 8109 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8110 | ||
| 8111 | if (state->m_mmc_reg[0]) | |
| 8112 | bank = ((bank & 0x03)) | ((bank >> 1) & 0x04) | ((bank >> 4) & 0x08) | | |
| 8113 | ((bank >> 2) & 0x10) | ((bank << 3) & 0x20) | ((bank << 2) & 0xc0); | |
| 8114 | ||
| 8115 | chr1_x(machine, start, bank, source); | |
| 8116 | } | |
| 8117 | ||
| 8118 | static WRITE8_HANDLER( waixing_sec_l_w ) | |
| 8119 | { | |
| 8120 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8121 | LOG_MMC(("waixing_sec_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8122 | ||
| 8123 | offset += 0x100; | |
| 8124 | ||
| 8125 | if (offset == 0x1000) | |
| 8126 | { | |
| 8127 | state->m_mmc_reg[0] = data & 0x02; | |
| 8128 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8129 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8130 | } | |
| 8131 | } | |
| 8132 | ||
| 8133 | /************************************************************* | |
| 8134 | ||
| 8135 | Waixing SH2 Board | |
| 8136 | ||
| 8137 | Games: Fire Emblem (C) and Fire Emblem Gaiden (C) | |
| 8138 | ||
| 8139 | MMC3 clone with different access to CHR | |
| 8140 | ||
| 8141 | iNES: mapper 165 | |
| 8142 | ||
| 8143 | In MESS: Partially Supported. | |
| 8144 | ||
| 8145 | *************************************************************/ | |
| 8146 | ||
| 8147 | static void waixing_sh2_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8148 | { | |
| 8149 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8150 | ||
| 8151 | chr4_0(machine, state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM); | |
| 8152 | chr4_4(machine, state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM); | |
| 8153 | } | |
| 8154 | ||
| 8155 | READ8_HANDLER( waixing_sh2_chr_r ) | |
| 8156 | { | |
| 8157 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8158 | int bank = offset >> 10; | |
| 8159 | UINT8 val = state->m_chr_map[bank].access[offset & 0x3ff]; // this would be usual return value | |
| 8160 | int chr_helper; | |
| 8161 | ||
| 8162 | switch (offset & 0xff8) | |
| 8163 | { | |
| 8164 | case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break; | |
| 8165 | case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break; | |
| 8166 | default: return val; | |
| 8167 | } | |
| 8168 | ||
| 8169 | state->m_mmc_reg[offset >> 12] = chr_helper; | |
| 8170 | if (offset & 0x1000) | |
| 8171 | chr4_4(space->machine(), state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM); | |
| 8172 | else | |
| 8173 | chr4_0(space->machine(), state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM); | |
| 8174 | ||
| 8175 | return val; | |
| 8176 | } | |
| 8177 | ||
| 8178 | /************************************************************* | |
| 8179 | ||
| 8180 | Board UNL-8237 | |
| 8181 | ||
| 8182 | Games: Pocahontas 2 | |
| 8183 | ||
| 8184 | MMC3 clone | |
| 8185 | ||
| 8186 | In MESS: Supported | |
| 8187 | ||
| 8188 | *************************************************************/ | |
| 8189 | ||
| 8190 | static void unl_8237_prg_cb( running_machine &machine, int start, int bank ) | |
| 8191 | { | |
| 8192 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8193 | ||
| 8194 | if (!(state->m_mmc_reg[0] & 0x80)) | |
| 8195 | prg8_x(machine, start, bank); | |
| 8196 | } | |
| 8197 | ||
| 8198 | static void unl_8237_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8199 | { | |
| 8200 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8201 | bank |= ((state->m_mmc_reg[1] << 6) & 0x100); | |
| 8202 | ||
| 8203 | chr1_x(machine, start, bank, source); | |
| 8204 | } | |
| 8205 | ||
| 8206 | static WRITE8_HANDLER( unl_8237_l_w ) | |
| 8207 | { | |
| 8208 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8209 | LOG_MMC(("unl_8237_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 8210 | offset += 0x100; | |
| 8211 | ||
| 8212 | if (offset == 0x1000) | |
| 8213 | { | |
| 8214 | state->m_mmc_reg[0] = data; | |
| 8215 | if (state->m_mmc_reg[0] & 0x80) | |
| 8216 | { | |
| 8217 | if (state->m_mmc_reg[0] & 0x20) | |
| 8218 | prg32(space->machine(), (state->m_mmc_reg[0] & 0x0f) >> 1); | |
| 8219 | else | |
| 8220 | { | |
| 8221 | prg16_89ab(space->machine(), state->m_mmc_reg[0] & 0x1f); | |
| 8222 | prg16_cdef(space->machine(), state->m_mmc_reg[0] & 0x1f); | |
| 8223 | } | |
| 8224 | } | |
| 8225 | else | |
| 8226 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8227 | } | |
| 8228 | ||
| 8229 | if (offset == 0x1001) | |
| 8230 | { | |
| 8231 | state->m_mmc_reg[1] = data; | |
| 8232 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8233 | } | |
| 8234 | } | |
| 8235 | ||
| 8236 | static WRITE8_HANDLER( unl_8237_w ) | |
| 8237 | { | |
| 8238 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8239 | static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5}; | |
| 8240 | LOG_MMC(("unl_8237_w offset: %04x, data: %02x\n", offset, data)); | |
| 8241 | ||
| 8242 | switch (offset & 0x7000) | |
| 8243 | { | |
| 8244 | case 0x0000: | |
| 8245 | case 0x1000: | |
| 8246 | set_nt_mirroring(space->machine(), (data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8247 | break; | |
| 8248 | ||
| 8249 | case 0x2000: | |
| 8250 | case 0x3000: | |
| 8251 | state->m_mmc_reg[2] = 1; | |
| 8252 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 8253 | txrom_w(space, 0x0000, data); | |
| 8254 | break; | |
| 8255 | ||
| 8256 | case 0x4000: | |
| 8257 | case 0x5000: | |
| 8258 | if (state->m_mmc_reg[2]) | |
| 8259 | { | |
| 8260 | state->m_mmc_reg[2] = 0; | |
| 8261 | txrom_w(space, 0x0001, data); | |
| 8262 | } | |
| 8263 | break; | |
| 8264 | ||
| 8265 | case 0x6000: | |
| 8266 | break; | |
| 8267 | ||
| 8268 | case 0x7000: | |
| 8269 | txrom_w(space, 0x6001, data); | |
| 8270 | txrom_w(space, 0x4000, data); | |
| 8271 | txrom_w(space, 0x4001, data); | |
| 8272 | break; | |
| 8273 | } | |
| 8274 | } | |
| 8275 | ||
| 8276 | /************************************************************* | |
| 8277 | ||
| 8278 | Board UNL-AX5705 | |
| 8279 | ||
| 8280 | Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack) | |
| 8281 | ||
| 8282 | In MESS: Supported | |
| 8283 | ||
| 8284 | *************************************************************/ | |
| 8285 | ||
| 8286 | static void unl_ax5705_set_prg( running_machine &machine ) | |
| 8287 | { | |
| 8288 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8289 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 8290 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 8291 | } | |
| 8292 | ||
| 8293 | static WRITE8_HANDLER( unl_ax5705_w ) | |
| 8294 | { | |
| 8295 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8296 | UINT8 bank; | |
| 8297 | LOG_MMC(("unl_ax5705_w offset: %04x, data: %02x\n", offset, data)); | |
| 8298 | ||
| 8299 | switch (offset & 0x700f) | |
| 8300 | { | |
| 8301 | case 0x0000: | |
| 8302 | state->m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); | |
| 8303 | unl_ax5705_set_prg(space->machine()); | |
| 8304 | break; | |
| 8305 | case 0x0008: | |
| 8306 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8307 | break; | |
| 8308 | case 0x2000: | |
| 8309 | state->m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); | |
| 8310 | unl_ax5705_set_prg(space->machine()); | |
| 8311 | break; | |
| 8312 | /* CHR banks 0, 1, 4, 5 */ | |
| 8313 | case 0x2008: | |
| 8314 | case 0x200a: | |
| 8315 | case 0x4008: | |
| 8316 | case 0x400a: | |
| 8317 | bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8318 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 8319 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8320 | break; | |
| 8321 | case 0x2009: | |
| 8322 | case 0x200b: | |
| 8323 | case 0x4009: | |
| 8324 | case 0x400b: | |
| 8325 | bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8326 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); | |
| 8327 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8328 | break; | |
| 8329 | /* CHR banks 2, 3, 6, 7 */ | |
| 8330 | case 0x4000: | |
| 8331 | case 0x4002: | |
| 8332 | case 0x6000: | |
| 8333 | case 0x6002: | |
| 8334 | bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8335 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 8336 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8337 | break; | |
| 8338 | case 0x4001: | |
| 8339 | case 0x4003: | |
| 8340 | case 0x6001: | |
| 8341 | case 0x6003: | |
| 8342 | bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); | |
| 8343 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); | |
| 8344 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM); | |
| 8345 | break; | |
| 8346 | } | |
| 8347 | } | |
| 8348 | ||
| 8349 | /************************************************************* | |
| 8350 | ||
| 8351 | Board UNL-CC-21 | |
| 8352 | ||
| 8353 | Games: Mi Hun Che | |
| 8354 | ||
| 8355 | In MESS: Supported | |
| 8356 | ||
| 8357 | *************************************************************/ | |
| 8358 | ||
| 8359 | static WRITE8_HANDLER( unl_cc21_w ) | |
| 8360 | { | |
| 8361 | LOG_MMC(("unl_cc21_w offset: %04x, data: %02x\n", offset, data)); | |
| 8362 | ||
| 8363 | set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 8364 | chr8(space->machine(), (offset & 0x01), CHRROM); | |
| 8365 | } | |
| 8366 | ||
| 8367 | /************************************************************* | |
| 8368 | ||
| 8369 | Board UNL-KOF97 | |
| 8370 | ||
| 8371 | Games: King of Fighters 97 (Rex Soft) | |
| 8372 | ||
| 8373 | MMC3 clone | |
| 8374 | ||
| 8375 | In MESS: Not working | |
| 8376 | ||
| 8377 | *************************************************************/ | |
| 8378 | ||
| 8379 | static UINT8 unl_kof97_unscramble( UINT8 data ) | |
| 8380 | { | |
| 8381 | return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20); | |
| 8382 | } | |
| 8383 | ||
| 8384 | static WRITE8_HANDLER( unl_kof97_w ) | |
| 8385 | { | |
| 8386 | LOG_MMC(("unl_kof97_w offset: %04x, data: %02x\n", offset, data)); | |
| 8387 | ||
| 8388 | /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */ | |
| 8389 | if (offset == 0x1000) | |
| 8390 | { | |
| 8391 | data = unl_kof97_unscramble(data); | |
| 8392 | txrom_w(space, 0x0001, data); | |
| 8393 | } | |
| 8394 | else if (offset == 0x2000) | |
| 8395 | { | |
| 8396 | data = unl_kof97_unscramble(data); | |
| 8397 | txrom_w(space, 0x0000, data); | |
| 8398 | } | |
| 8399 | else if (offset == 0x5000) | |
| 8400 | { | |
| 8401 | data = unl_kof97_unscramble(data); | |
| 8402 | txrom_w(space, 0x4001, data); | |
| 8403 | } | |
| 8404 | else if (offset == 0x7000) | |
| 8405 | { | |
| 8406 | data = unl_kof97_unscramble(data); | |
| 8407 | txrom_w(space, 0x6001, data); | |
| 8408 | } | |
| 8409 | else /* Other addresses behaves like MMC3, up to unscrambling data */ | |
| 8410 | { | |
| 8411 | switch (offset & 0x6001) | |
| 8412 | { | |
| 8413 | case 0x0000: | |
| 8414 | case 0x0001: | |
| 8415 | case 0x4000: | |
| 8416 | case 0x4001: | |
| 8417 | case 0x6000: | |
| 8418 | case 0x6001: | |
| 8419 | case 0x2000: /* are these ever called?!? */ | |
| 8420 | case 0x2001: | |
| 8421 | data = unl_kof97_unscramble(data); | |
| 8422 | txrom_w(space, offset, data); | |
| 8423 | break; | |
| 8424 | } | |
| 8425 | } | |
| 8426 | } | |
| 8427 | ||
| 8428 | /************************************************************* | |
| 8429 | ||
| 8430 | Board UNL-T-230 | |
| 8431 | ||
| 8432 | Games: Dragon Ball Z IV (Unl) | |
| 8433 | ||
| 8434 | In MESS: Supported | |
| 8435 | ||
| 8436 | *************************************************************/ | |
| 8437 | ||
| 8438 | static WRITE8_HANDLER( unl_t230_w ) | |
| 8439 | { | |
| 8440 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8441 | UINT8 bank; | |
| 8442 | LOG_MMC(("unl_t230_w offset: %04x, data: %02x\n", offset, data)); | |
| 8443 | ||
| 8444 | switch (offset & 0x700c) | |
| 8445 | { | |
| 8446 | case 0x0000: | |
| 8447 | break; | |
| 8448 | case 0x2000: | |
| 8449 | prg16_89ab(space->machine(), data); | |
| 8450 | break; | |
| 8451 | ||
| 8452 | // the part below works like VRC-2. how was the original board wired up? | |
| 8453 | // was there a VRC2? if so, we can use VRC-2 and add proper pin settings to xml! | |
| 8454 | case 0x1000: | |
| 8455 | case 0x1004: | |
| 8456 | case 0x1008: | |
| 8457 | case 0x100c: | |
| 8458 | switch (data & 0x03) | |
| 8459 | { | |
| 8460 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 8461 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 8462 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 8463 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 8464 | } | |
| 8465 | break; | |
| 8466 | ||
| 8467 | case 0x3000: | |
| 8468 | case 0x3004: | |
| 8469 | case 0x3008: | |
| 8470 | case 0x300c: | |
| 8471 | case 0x4000: | |
| 8472 | case 0x4004: | |
| 8473 | case 0x4008: | |
| 8474 | case 0x400c: | |
| 8475 | case 0x5000: | |
| 8476 | case 0x5004: | |
| 8477 | case 0x5008: | |
| 8478 | case 0x500c: | |
| 8479 | case 0x6000: | |
| 8480 | case 0x6004: | |
| 8481 | case 0x6008: | |
| 8482 | case 0x600c: | |
| 8483 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 2); | |
| 8484 | if (offset & 0x0004) | |
| 8485 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | (data << 4); | |
| 8486 | else | |
| 8487 | state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); | |
| 8488 | ||
| 8489 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], state->m_mmc_chr_source); | |
| 8490 | break; | |
| 8491 | case 0x7000: | |
| 8492 | state->m_IRQ_count_latch &= ~0x0f; | |
| 8493 | state->m_IRQ_count_latch |= data & 0x0f; | |
| 8494 | break; | |
| 8495 | case 0x7004: | |
| 8496 | state->m_IRQ_count_latch &= ~0xf0; | |
| 8497 | state->m_IRQ_count_latch |= (data << 4) & 0xf0; | |
| 8498 | break; | |
| 8499 | case 0x7008: | |
| 8500 | state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode | |
| 8501 | state->m_IRQ_enable = data & 0x02; | |
| 8502 | state->m_IRQ_enable_latch = data & 0x01; | |
| 8503 | if (data & 0x02) | |
| 8504 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 8505 | break; | |
| 8506 | ||
| 8507 | default: | |
| 8508 | logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data); | |
| 8509 | break; | |
| 8510 | } | |
| 8511 | } | |
| 8512 | ||
| 8513 | /************************************************************* | |
| 8514 | ||
| 8515 | Bootleg Board for KOF96 | |
| 8516 | ||
| 8517 | Games: The King of Fighters 96, Sonic 3D Blast 6, Street | |
| 8518 | Fighter Zero 2 | |
| 8519 | ||
| 8520 | MMC3 clone | |
| 8521 | ||
| 8522 | iNES: mapper 187 | |
| 8523 | ||
| 8524 | In MESS: Preliminary Support. | |
| 8525 | ||
| 8526 | *************************************************************/ | |
| 8527 | ||
| 8528 | static void kof96_prg_cb( running_machine &machine, int start, int bank ) | |
| 8529 | { | |
| 8530 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8531 | ||
| 8532 | if (!(state->m_mmc_reg[0] & 0x80)) | |
| 8533 | prg8_x(machine, start, bank); | |
| 8534 | } | |
| 8535 | ||
| 8536 | static void kof96_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 8537 | { | |
| 8538 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8539 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 8540 | ||
| 8541 | if ((start & 0x04) == chr_page) | |
| 8542 | bank |= 0x100; | |
| 8543 | ||
| 8544 | chr1_x(machine, start, bank, source); | |
| 8545 | } | |
| 8546 | ||
| 8547 | static WRITE8_HANDLER( kof96_l_w ) | |
| 8548 | { | |
| 8549 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8550 | UINT8 new_bank; | |
| 8551 | LOG_MMC(("kof96_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8552 | offset += 0x100; | |
| 8553 | ||
| 8554 | if (offset == 0x1000) | |
| 8555 | { | |
| 8556 | state->m_mmc_reg[0] = data; | |
| 8557 | ||
| 8558 | if (state->m_mmc_reg[0] & 0x80) | |
| 8559 | { | |
| 8560 | new_bank = (state->m_mmc_reg[0] & 0x1f); | |
| 8561 | ||
| 8562 | if (state->m_mmc_reg[0] & 0x20) | |
| 8563 | prg32(space->machine(), new_bank >> 2); | |
| 8564 | else | |
| 8565 | { | |
| 8566 | prg16_89ab(space->machine(), new_bank); | |
| 8567 | prg16_cdef(space->machine(), new_bank); | |
| 8568 | } | |
| 8569 | } | |
| 8570 | else | |
| 8571 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8572 | } | |
| 8573 | ||
| 8574 | if (offset >= 0x1000) | |
| 8575 | { | |
| 8576 | switch (data & 0x03) | |
| 8577 | { | |
| 8578 | case 0x00: | |
| 8579 | case 0x01: | |
| 8580 | state->m_mmc_reg[1] = 0x83; | |
| 8581 | break; | |
| 8582 | case 0x02: | |
| 8583 | state->m_mmc_reg[1] = 0x42; | |
| 8584 | break; | |
| 8585 | case 0x03: | |
| 8586 | state->m_mmc_reg[1] = 0x00; | |
| 8587 | break; | |
| 8588 | } | |
| 8589 | ||
| 8590 | } | |
| 8591 | ||
| 8592 | if (!state->m_mmc_reg[3] && offset > 0x1000) | |
| 8593 | { | |
| 8594 | state->m_mmc_reg[3] = 1; | |
| 8595 | space->write_byte(0x4017, 0x40); | |
| 8596 | } | |
| 8597 | } | |
| 8598 | ||
| 8599 | static READ8_HANDLER( kof96_l_r ) | |
| 8600 | { | |
| 8601 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8602 | LOG_MMC(("kof96_l_r, offset: %04x\n", offset)); | |
| 8603 | offset += 0x100; | |
| 8604 | ||
| 8605 | if (!(offset < 0x1000)) | |
| 8606 | return state->m_mmc_reg[1]; | |
| 8607 | else | |
| 8608 | return 0; | |
| 8609 | } | |
| 8610 | ||
| 8611 | static WRITE8_HANDLER( kof96_w ) | |
| 8612 | { | |
| 8613 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8614 | LOG_MMC(("kof96_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8615 | ||
| 8616 | switch (offset & 0x6003) | |
| 8617 | { | |
| 8618 | case 0x0000: | |
| 8619 | state->m_mmc_reg[2] = 1; | |
| 8620 | txrom_w(space, 0x0000, data); | |
| 8621 | break; | |
| 8622 | ||
| 8623 | case 0x0001: | |
| 8624 | if (state->m_mmc_reg[2]) | |
| 8625 | txrom_w(space, 0x0001, data); | |
| 8626 | break; | |
| 8627 | ||
| 8628 | case 0x0002: | |
| 8629 | break; | |
| 8630 | ||
| 8631 | case 0x0003: | |
| 8632 | state->m_mmc_reg[2] = 0; | |
| 8633 | ||
| 8634 | if (data == 0x28) | |
| 8635 | prg8_cd(space->machine(), 0x17); | |
| 8636 | else if (data == 0x2a) | |
| 8637 | prg8_ab(space->machine(), 0x0f); | |
| 8638 | break; | |
| 8639 | ||
| 8640 | default: | |
| 8641 | txrom_w(space, offset, data); | |
| 8642 | break; | |
| 8643 | } | |
| 8644 | } | |
| 8645 | ||
| 8646 | /************************************************************* | |
| 8647 | ||
| 8648 | Bootleg Board for MK2 | |
| 8649 | ||
| 8650 | Games: Mortal Kombat II, Street Fighter III, Super Mario | |
| 8651 | Kart Rider | |
| 8652 | ||
| 8653 | This board uses an IRQ system very similar to MMC3. We indeed | |
| 8654 | use mapper4_irq, but there is some small glitch! | |
| 8655 | ||
| 8656 | iNES: mapper 91 | |
| 8657 | ||
| 8658 | In MESS: Supported. | |
| 8659 | ||
| 8660 | *************************************************************/ | |
| 8661 | ||
| 8662 | static WRITE8_HANDLER( mk2_m_w ) | |
| 8663 | { | |
| 8664 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8665 | LOG_MMC(("mk2_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8666 | ||
| 8667 | switch (offset & 0x1000) | |
| 8668 | { | |
| 8669 | case 0x0000: | |
| 8670 | switch (offset & 0x03) | |
| 8671 | { | |
| 8672 | case 0x00: chr2_0(space->machine(), data, CHRROM); break; | |
| 8673 | case 0x01: chr2_2(space->machine(), data, CHRROM); break; | |
| 8674 | case 0x02: chr2_4(space->machine(), data, CHRROM); break; | |
| 8675 | case 0x03: chr2_6(space->machine(), data, CHRROM); break; | |
| 8676 | } | |
| 8677 | break; | |
| 8678 | case 0x1000: | |
| 8679 | switch (offset & 0x03) | |
| 8680 | { | |
| 8681 | case 0x00: prg8_89(space->machine(), data); break; | |
| 8682 | case 0x01: prg8_ab(space->machine(), data); break; | |
| 8683 | case 0x02: state->m_IRQ_enable = 0; state->m_IRQ_count = 0; break; | |
| 8684 | case 0x03: state->m_IRQ_enable = 1; state->m_IRQ_count = 7; break; | |
| 8685 | } | |
| 8686 | break; | |
| 8687 | default: | |
| 8688 | logerror("mk2_m_w uncaught addr: %04x value: %02x\n", offset + 0x6000, data); | |
| 8689 | break; | |
| 8690 | } | |
| 8691 | } | |
| 8692 | ||
| 8693 | /************************************************************* | |
| 8694 | ||
| 8695 | Bootleg Board N625092 | |
| 8696 | ||
| 8697 | Games: 400 in 1, 700 in 1, 1000 in 1 | |
| 8698 | ||
| 8699 | iNES: mapper 221 | |
| 8700 | ||
| 8701 | In MESS: Supported. | |
| 8702 | ||
| 8703 | *************************************************************/ | |
| 8704 | ||
| 8705 | static void n625092_set_prg( running_machine &machine, UINT8 reg1, UINT8 reg2 ) | |
| 8706 | { | |
| 8707 | UINT8 map221_helper1, map221_helper2; | |
| 8708 | ||
| 8709 | map221_helper1 = !(reg1 & 0x01) ? reg2 : | |
| 8710 | (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00; | |
| 8711 | map221_helper2 = !(reg1 & 0x01) ? reg2 : | |
| 8712 | (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01; | |
| 8713 | ||
| 8714 | prg16_89ab(machine, map221_helper1 | ((reg1 & 0x70) >> 1)); | |
| 8715 | prg16_cdef(machine, map221_helper2 | ((reg1 & 0x70) >> 1)); | |
| 8716 | } | |
| 8717 | ||
| 8718 | static WRITE8_HANDLER( n625092_w ) | |
| 8719 | { | |
| 8720 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8721 | LOG_MMC(("n625092_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8722 | ||
| 8723 | if (offset < 0x4000) | |
| 8724 | { | |
| 8725 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8726 | offset = (offset >> 1) & 0xff; | |
| 8727 | ||
| 8728 | if (state->m_mmc_latch1 != offset) | |
| 8729 | { | |
| 8730 | state->m_mmc_latch1 = offset; | |
| 8731 | n625092_set_prg(space->machine(), state->m_mmc_latch1, state->m_mmc_latch2); | |
| 8732 | } | |
| 8733 | } | |
| 8734 | else | |
| 8735 | { | |
| 8736 | offset &= 0x07; | |
| 8737 | ||
| 8738 | if (state->m_mmc_latch2 != offset) | |
| 8739 | { | |
| 8740 | state->m_mmc_latch2 = offset; | |
| 8741 | n625092_set_prg(space->machine(), state->m_mmc_latch1, state->m_mmc_latch2); | |
| 8742 | } | |
| 8743 | } | |
| 8744 | } | |
| 8745 | ||
| 8746 | /************************************************************* | |
| 8747 | ||
| 8748 | SC-127 Board | |
| 8749 | ||
| 8750 | Games: Wario World II (Kirby Hack) | |
| 8751 | ||
| 8752 | iNES: mapper 35 | |
| 8753 | ||
| 8754 | In MESS: Supported | |
| 8755 | ||
| 8756 | *************************************************************/ | |
| 8757 | ||
| 8758 | static void sc127_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 8759 | { | |
| 8760 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 8761 | ||
| 8762 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && state->m_IRQ_enable) | |
| 8763 | { | |
| 8764 | state->m_IRQ_count--; | |
| 8765 | ||
| 8766 | if (!blanked && (state->m_IRQ_count == 0)) | |
| 8767 | { | |
| 8768 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 8769 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 8770 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 8771 | state->m_IRQ_enable = 0; | |
| 8772 | } | |
| 8773 | } | |
| 8774 | } | |
| 8775 | ||
| 8776 | static WRITE8_HANDLER( sc127_w ) | |
| 8777 | { | |
| 8778 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8779 | LOG_MMC(("sc127_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8780 | ||
| 8781 | switch (offset) | |
| 8782 | { | |
| 8783 | case 0x0000: | |
| 8784 | prg8_89(space->machine(), data); | |
| 8785 | break; | |
| 8786 | case 0x0001: | |
| 8787 | prg8_ab(space->machine(), data); | |
| 8788 | break; | |
| 8789 | case 0x0002: | |
| 8790 | // state->m_mmc_prg_bank[offset & 0x02] = data; | |
| 8791 | prg8_cd(space->machine(), data); | |
| 8792 | break; | |
| 8793 | case 0x1000: | |
| 8794 | case 0x1001: | |
| 8795 | case 0x1002: | |
| 8796 | case 0x1003: | |
| 8797 | case 0x1004: | |
| 8798 | case 0x1005: | |
| 8799 | case 0x1006: | |
| 8800 | case 0x1007: | |
| 8801 | // state->m_mmc_vrom_bank[offset & 0x07] = data; | |
| 8802 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 8803 | break; | |
| 8804 | case 0x4002: | |
| 8805 | state->m_IRQ_enable = 0; | |
| 8806 | break; | |
| 8807 | case 0x4003: | |
| 8808 | state->m_IRQ_enable = 1; | |
| 8809 | break; | |
| 8810 | case 0x4005: | |
| 8811 | state->m_IRQ_count = data; | |
| 8812 | break; | |
| 8813 | case 0x5001: | |
| 8814 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8815 | break; | |
| 8816 | } | |
| 8817 | } | |
| 8818 | ||
| 8819 | /************************************************************* | |
| 8820 | ||
| 8821 | Bootleg Board SMB2J | |
| 8822 | ||
| 8823 | Games: Super Mario Bros. 2 Pirate (LF36) | |
| 8824 | ||
| 8825 | iNES: mapper 43 | |
| 8826 | ||
| 8827 | In MESS: Supported? The only image I found is not working | |
| 8828 | (not even in NEStopia). | |
| 8829 | ||
| 8830 | *************************************************************/ | |
| 8831 | ||
| 8832 | static WRITE8_HANDLER( smb2j_w ) | |
| 8833 | { | |
| 8834 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8835 | int bank = (((offset >> 8) & 0x03) * 0x20) + (offset & 0x1f); | |
| 8836 | ||
| 8837 | LOG_MMC(("smb2j_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8838 | ||
| 8839 | set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 8840 | ||
| 8841 | if (offset & 0x0800) | |
| 8842 | { | |
| 8843 | if (offset & 0x1000) | |
| 8844 | { | |
| 8845 | if (bank * 2 >= state->m_prg_chunks) | |
| 8846 | { | |
| 8847 | memory_set_bankptr(space->machine(), "bank3", state->m_wram); | |
| 8848 | memory_set_bankptr(space->machine(), "bank4", state->m_wram); | |
| 8849 | } | |
| 8850 | else | |
| 8851 | { | |
| 8852 | LOG_MMC(("smb2j_w, selecting upper 16KB bank of #%02x\n", bank)); | |
| 8853 | prg16_cdef(space->machine(), 2 * bank + 1); | |
| 8854 | } | |
| 8855 | } | |
| 8856 | else | |
| 8857 | { | |
| 8858 | if (bank * 2 >= state->m_prg_chunks) | |
| 8859 | { | |
| 8860 | memory_set_bankptr(space->machine(), "bank1", state->m_wram); | |
| 8861 | memory_set_bankptr(space->machine(), "bank2", state->m_wram); | |
| 8862 | } | |
| 8863 | else | |
| 8864 | { | |
| 8865 | LOG_MMC(("smb2j_w, selecting lower 16KB bank of #%02x\n", bank)); | |
| 8866 | prg16_89ab(space->machine(), 2 * bank); | |
| 8867 | } | |
| 8868 | } | |
| 8869 | } | |
| 8870 | else | |
| 8871 | { | |
| 8872 | if (bank * 2 >= state->m_prg_chunks) | |
| 8873 | { | |
| 8874 | memory_set_bankptr(space->machine(), "bank1", state->m_wram); | |
| 8875 | memory_set_bankptr(space->machine(), "bank2", state->m_wram); | |
| 8876 | memory_set_bankptr(space->machine(), "bank3", state->m_wram); | |
| 8877 | memory_set_bankptr(space->machine(), "bank4", state->m_wram); | |
| 8878 | } | |
| 8879 | else | |
| 8880 | { | |
| 8881 | LOG_MMC(("smb2j_w, selecting 32KB bank #%02x\n", bank)); | |
| 8882 | prg32(space->machine(), bank); | |
| 8883 | } | |
| 8884 | } | |
| 8885 | } | |
| 8886 | ||
| 8887 | /************************************************************* | |
| 8888 | ||
| 8889 | BTL-SMB2B | |
| 8890 | ||
| 8891 | Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) | |
| 8892 | ||
| 8893 | This was marked as Alt. Levels. is it true? | |
| 8894 | ||
| 8895 | iNES: mapper 50 | |
| 8896 | ||
| 8897 | In MESS: Supported. | |
| 8898 | ||
| 8899 | *************************************************************/ | |
| 8900 | ||
| 8901 | static void smb2jb_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 8902 | { | |
| 8903 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 8904 | if (state->m_IRQ_enable) | |
| 8905 | { | |
| 8906 | if (state->m_IRQ_count < 0x1000) | |
| 8907 | { | |
| 8908 | if ((0x1000 - state->m_IRQ_count) <= 114) | |
| 8909 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 8910 | else | |
| 8911 | state->m_IRQ_count += 114; | |
| 8912 | } | |
| 8913 | else | |
| 8914 | state->m_IRQ_count += 114; | |
| 8915 | ||
| 8916 | state->m_IRQ_count &= 0xffff; // according to docs is 16bit counter -> it wraps only after 0xffff | |
| 8917 | } | |
| 8918 | } | |
| 8919 | ||
| 8920 | static WRITE8_HANDLER( smb2jb_l_w ) | |
| 8921 | { | |
| 8922 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8923 | UINT8 prg; | |
| 8924 | LOG_MMC(("smb2jb_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8925 | offset += 0x100; | |
| 8926 | ||
| 8927 | switch (offset & 0x160) | |
| 8928 | { | |
| 8929 | case 0x020: | |
| 8930 | prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); | |
| 8931 | prg8_cd(space->machine(), prg); | |
| 8932 | break; | |
| 8933 | case 0x120: | |
| 8934 | state->m_IRQ_enable = data & 0x01; | |
| 8935 | break; | |
| 8936 | } | |
| 8937 | } | |
| 8938 | ||
| 8939 | /* This goes to 0x4020-0x403f */ | |
| 8940 | WRITE8_HANDLER( smb2jb_extra_w ) | |
| 8941 | { | |
| 8942 | UINT8 prg; | |
| 8943 | LOG_MMC(("smb2jb_extra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8944 | ||
| 8945 | prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); | |
| 8946 | prg8_cd(space->machine(), prg); | |
| 8947 | } | |
| 8948 | ||
| 8949 | /************************************************************* | |
| 8950 | ||
| 8951 | Bootleg Board for Super Fighter III | |
| 8952 | ||
| 8953 | MMC3 clone | |
| 8954 | ||
| 8955 | iNES: mapper 197 | |
| 8956 | ||
| 8957 | In MESS: Supported. | |
| 8958 | ||
| 8959 | *************************************************************/ | |
| 8960 | ||
| 8961 | static void unl_sf3_set_chr( running_machine &machine, UINT8 chr_source, int chr_base, int chr_mask ) | |
| 8962 | { | |
| 8963 | nes_state *state = machine.driver_data<nes_state>(); | |
| 8964 | chr4_0(machine, chr_base | ((state->m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source); | |
| 8965 | chr2_4(machine, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), chr_source); | |
| 8966 | chr2_6(machine, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr_source); | |
| 8967 | } | |
| 8968 | ||
| 8969 | static WRITE8_HANDLER( unl_sf3_w ) | |
| 8970 | { | |
| 8971 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 8972 | UINT8 mmc_helper, cmd; | |
| 8973 | LOG_MMC(("unl_sf3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 8974 | ||
| 8975 | switch (offset & 0x6001) | |
| 8976 | { | |
| 8977 | case 0x0000: | |
| 8978 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 8979 | state->m_mmc3_latch = data; | |
| 8980 | ||
| 8981 | /* Has PRG Mode changed? */ | |
| 8982 | if (mmc_helper & 0x40) | |
| 8983 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 8984 | ||
| 8985 | /* Has CHR Mode changed? */ | |
| 8986 | if (mmc_helper & 0x80) | |
| 8987 | unl_sf3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8988 | break; | |
| 8989 | ||
| 8990 | case 0x0001: | |
| 8991 | cmd = state->m_mmc3_latch & 0x0f; | |
| 8992 | switch (cmd) | |
| 8993 | { | |
| 8994 | case 0: case 2: case 4: | |
| 8995 | state->m_mmc_vrom_bank[cmd >> 1] = data; | |
| 8996 | unl_sf3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 8997 | break; | |
| 8998 | case 6: | |
| 8999 | case 7: | |
| 9000 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 9001 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9002 | break; | |
| 9003 | } | |
| 9004 | break; | |
| 9005 | ||
| 9006 | default: | |
| 9007 | txrom_w(space, offset, data); | |
| 9008 | break; | |
| 9009 | } | |
| 9010 | } | |
| 9011 | ||
| 9012 | /************************************************************* | |
| 9013 | ||
| 9014 | Bootleg Board for Xiao Zhuan Yuan | |
| 9015 | ||
| 9016 | Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan | |
| 9017 | ||
| 9018 | Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1), | |
| 9019 | while writes to 0x5ff2 set chr8 | |
| 9020 | ||
| 9021 | iNES: mapper 176 | |
| 9022 | ||
| 9023 | In MESS: Supported. | |
| 9024 | ||
| 9025 | *************************************************************/ | |
| 9026 | ||
| 9027 | static WRITE8_HANDLER( unl_xzy_l_w ) | |
| 9028 | { | |
| 9029 | LOG_MMC(("unl_xzy_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9030 | ||
| 9031 | switch (offset) | |
| 9032 | { | |
| 9033 | case 0x1ef1: /* 0x5ff1 */ | |
| 9034 | prg32(space->machine(), data >> 1); | |
| 9035 | break; | |
| 9036 | case 0x1ef2: /* 0x5ff2 */ | |
| 9037 | chr8(space->machine(), data, CHRROM); | |
| 9038 | break; | |
| 9039 | } | |
| 9040 | } | |
| 9041 | ||
| 9042 | /************************************************************* | |
| 9043 | ||
| 9044 | Board UNL-RACERMATE | |
| 9045 | ||
| 9046 | In MESS: *VERY* preliminary support. Also, it seems that this | |
| 9047 | board saves to battery the CHRRAM!!! | |
| 9048 | ||
| 9049 | *************************************************************/ | |
| 9050 | ||
| 9051 | static void racmate_update_banks( running_machine &machine ) | |
| 9052 | { | |
| 9053 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9054 | chr4_4(machine, state->m_mmc_latch1 & 0x0f, state->m_mmc_chr_source); | |
| 9055 | prg16_89ab(machine, state->m_mmc_latch1 >> 1); | |
| 9056 | } | |
| 9057 | ||
| 9058 | static WRITE8_HANDLER( unl_racmate_w ) | |
| 9059 | { | |
| 9060 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9061 | LOG_MMC(("unl_racmate_w offset: %04x, data: %02x\n", offset, data)); | |
| 9062 | ||
| 9063 | if (offset == 0x3000) | |
| 9064 | { | |
| 9065 | state->m_mmc_latch1 = data; | |
| 9066 | racmate_update_banks(space->machine()); | |
| 9067 | } | |
| 9068 | } | |
| 9069 | ||
| 9070 | /************************************************************* | |
| 9071 | ||
| 9072 | BOOTLEG CART VERSIONS OF FDS GAMES | |
| 9073 | ||
| 9074 | *************************************************************/ | |
| 9075 | ||
| 9076 | /************************************************************* | |
| 9077 | ||
| 9078 | BTL-SUPERBROS11 | |
| 9079 | ||
| 9080 | Games: Super Mario Bros. 11, Super Mario Bros. 17 | |
| 9081 | ||
| 9082 | This acts basically like a MMC3 with different use of write | |
| 9083 | address. | |
| 9084 | ||
| 9085 | iNES: mapper 196 | |
| 9086 | ||
| 9087 | In MESS: Supported. | |
| 9088 | ||
| 9089 | *************************************************************/ | |
| 9090 | ||
| 9091 | static WRITE8_HANDLER( btl_smb11_w ) | |
| 9092 | { | |
| 9093 | LOG_MMC(("btl_smb11_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9094 | ||
| 9095 | txrom_w(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data); | |
| 9096 | } | |
| 9097 | ||
| 9098 | /************************************************************* | |
| 9099 | ||
| 9100 | BTL-MARIOBABY | |
| 9101 | ||
| 9102 | Games: Mario Baby, Ai Senshi Nicol | |
| 9103 | ||
| 9104 | iNES: mapper 42 | |
| 9105 | ||
| 9106 | In MESS: Supported. | |
| 9107 | ||
| 9108 | *************************************************************/ | |
| 9109 | ||
| 9110 | // is the code fine for ai senshi nicol?!? | |
| 9111 | static WRITE8_HANDLER( btl_mariobaby_w ) | |
| 9112 | { | |
| 9113 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9114 | LOG_MMC(("btl_mariobaby_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9115 | ||
| 9116 | if (offset >= 0x7000) | |
| 9117 | { | |
| 9118 | switch (offset & 0x03) | |
| 9119 | { | |
| 9120 | case 0x00: | |
| 9121 | prg8_67(space->machine(), data); | |
| 9122 | break; | |
| 9123 | case 0x01: | |
| 9124 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9125 | break; | |
| 9126 | case 0x02: | |
| 9127 | /* Check if IRQ is being enabled */ | |
| 9128 | if (!state->m_IRQ_enable && (data & 0x02)) | |
| 9129 | { | |
| 9130 | state->m_IRQ_enable = 1; | |
| 9131 | state->m_irq_timer->adjust(downcast<cpu_device *>(state->m_maincpu)->cycles_to_attotime(24576)); | |
| 9132 | } | |
| 9133 | if (!(data & 0x02)) | |
| 9134 | { | |
| 9135 | state->m_IRQ_enable = 0; | |
| 9136 | state->m_irq_timer->adjust(attotime::never); | |
| 9137 | } | |
| 9138 | break; | |
| 9139 | } | |
| 9140 | } | |
| 9141 | } | |
| 9142 | ||
| 9143 | /************************************************************* | |
| 9144 | ||
| 9145 | BTL-SMB2A | |
| 9146 | ||
| 9147 | Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) | |
| 9148 | ||
| 9149 | iNES: mapper 40 | |
| 9150 | ||
| 9151 | In MESS: Supported. | |
| 9152 | ||
| 9153 | *************************************************************/ | |
| 9154 | ||
| 9155 | static void btl_smb2a_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 9156 | { | |
| 9157 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 9158 | ||
| 9159 | if (state->m_IRQ_enable) | |
| 9160 | { | |
| 9161 | if ((0xfff - state->m_IRQ_count) <= 114) | |
| 9162 | { | |
| 9163 | state->m_IRQ_count = (state->m_IRQ_count + 1) & 0xfff; | |
| 9164 | state->m_IRQ_enable = 0; | |
| 9165 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 9166 | } | |
| 9167 | else | |
| 9168 | state->m_IRQ_count += 114; | |
| 9169 | } | |
| 9170 | } | |
| 9171 | ||
| 9172 | static WRITE8_HANDLER( btl_smb2a_w ) | |
| 9173 | { | |
| 9174 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9175 | LOG_MMC(("btl_smb2a_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9176 | ||
| 9177 | switch (offset & 0x6000) | |
| 9178 | { | |
| 9179 | case 0x0000: | |
| 9180 | state->m_IRQ_enable = 0; | |
| 9181 | state->m_IRQ_count = 0; | |
| 9182 | break; | |
| 9183 | case 0x2000: | |
| 9184 | state->m_IRQ_enable = 1; | |
| 9185 | break; | |
| 9186 | case 0x6000: | |
| 9187 | prg8_cd(space->machine(), data); | |
| 9188 | break; | |
| 9189 | } | |
| 9190 | } | |
| 9191 | ||
| 9192 | /************************************************************* | |
| 9193 | ||
| 9194 | WHIRLWIND-2706 | |
| 9195 | ||
| 9196 | Games: Meikyuu Jiin Dababa (FDS conversion) | |
| 9197 | ||
| 9198 | iNES: mapper 108 | |
| 9199 | ||
| 9200 | In MESS: Supported. | |
| 9201 | ||
| 9202 | *************************************************************/ | |
| 9203 | ||
| 9204 | static WRITE8_HANDLER( whirl2706_w ) | |
| 9205 | { | |
| 9206 | LOG_MMC(("whirl2706_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9207 | prg8_67(space->machine(), data); | |
| 9208 | } | |
| 9209 | ||
| 9210 | /************************************************************* | |
| 9211 | ||
| 9212 | Bootleg Board used for FDS conversion | |
| 9213 | ||
| 9214 | Games: Tobidase Daisakusen (FDS conversion) | |
| 9215 | ||
| 9216 | iNES: mapper 120 | |
| 9217 | ||
| 9218 | In MESS: Partially Supported. | |
| 9219 | ||
| 9220 | *************************************************************/ | |
| 9221 | ||
| 9222 | static WRITE8_HANDLER( btl_tobi_l_w ) | |
| 9223 | { | |
| 9224 | LOG_MMC(("btl_tobi_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9225 | offset += 0x100; | |
| 9226 | ||
| 9227 | if ((offset & 0x43c0) == 0x41c0) | |
| 9228 | prg8_67(space->machine(), data & 0x07); | |
| 9229 | } | |
| 9230 | ||
| 9231 | /************************************************************* | |
| 9232 | ||
| 9233 | BTL-SMB3 | |
| 9234 | ||
| 9235 | Games: Super Mario Bros. 3 Pirate | |
| 9236 | ||
| 9237 | iNES: mapper 106 | |
| 9238 | ||
| 9239 | In MESS: Supported. | |
| 9240 | ||
| 9241 | *************************************************************/ | |
| 9242 | ||
| 9243 | static void btl_smb3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 9244 | { | |
| 9245 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 9246 | ||
| 9247 | if (state->m_IRQ_enable) | |
| 9248 | { | |
| 9249 | if ((0xffff - state->m_IRQ_count) < 114) | |
| 9250 | { | |
| 9251 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 9252 | state->m_IRQ_enable = 0; | |
| 9253 | } | |
| 9254 | ||
| 9255 | state->m_IRQ_count = (state->m_IRQ_count + 114) & 0xffff; | |
| 9256 | } | |
| 9257 | } | |
| 9258 | ||
| 9259 | static WRITE8_HANDLER( btl_smb3_w ) | |
| 9260 | { | |
| 9261 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9262 | LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9263 | switch (offset & 0x0f) | |
| 9264 | { | |
| 9265 | case 0x00: | |
| 9266 | case 0x02: | |
| 9267 | chr1_x(space->machine(), offset & 0x07, data & 0xfe, CHRROM); | |
| 9268 | break; | |
| 9269 | case 0x01: | |
| 9270 | case 0x03: | |
| 9271 | chr1_x(space->machine(), offset & 0x07, data | 0x01, CHRROM); | |
| 9272 | break; | |
| 9273 | case 0x04: case 0x05: | |
| 9274 | case 0x06: case 0x07: | |
| 9275 | chr1_x(space->machine(), offset & 0x07, data, CHRROM); | |
| 9276 | break; | |
| 9277 | case 0x08: | |
| 9278 | prg8_89(space->machine(), data | 0x10); | |
| 9279 | break; | |
| 9280 | case 0x09: | |
| 9281 | prg8_ab(space->machine(), data); | |
| 9282 | break; | |
| 9283 | case 0x0a: | |
| 9284 | prg8_cd(space->machine(), data); | |
| 9285 | break; | |
| 9286 | case 0x0b: | |
| 9287 | prg8_ef(space->machine(), data | 0x10); | |
| 9288 | break; | |
| 9289 | case 0x0c: | |
| 9290 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9291 | break; | |
| 9292 | case 0x0d: | |
| 9293 | state->m_IRQ_count = 0; | |
| 9294 | state->m_IRQ_enable = 0; | |
| 9295 | break; | |
| 9296 | case 0x0e: | |
| 9297 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 9298 | break; | |
| 9299 | case 0x0f: | |
| 9300 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 9301 | state->m_IRQ_enable = 1; | |
| 9302 | break; | |
| 9303 | } | |
| 9304 | } | |
| 9305 | ||
| 9306 | /************************************************************* | |
| 9307 | ||
| 9308 | BTL-DRAGONNINJA | |
| 9309 | ||
| 9310 | Games: Dragon Ninja (Bootleg), Super Mario Bros. 8 | |
| 9311 | ||
| 9312 | iNES: mapper 222 | |
| 9313 | ||
| 9314 | In MESS: Unsupported. | |
| 9315 | ||
| 9316 | *************************************************************/ | |
| 9317 | ||
| 9318 | /* Scanline based IRQ ? */ | |
| 9319 | static void btl_dn_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 9320 | { | |
| 9321 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 9322 | if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) | |
| 9323 | { | |
| 9324 | if (!state->m_IRQ_count || ++state->m_IRQ_count < 240) | |
| 9325 | return; | |
| 9326 | ||
| 9327 | state->m_IRQ_count = 0; | |
| 9328 | LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, | |
| 9329 | device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos())); | |
| 9330 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 9331 | } | |
| 9332 | } | |
| 9333 | ||
| 9334 | static WRITE8_HANDLER( btl_dn_w ) | |
| 9335 | { | |
| 9336 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9337 | UINT8 bank; | |
| 9338 | LOG_MMC(("btl_dn_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9339 | ||
| 9340 | switch (offset & 0x7003) | |
| 9341 | { | |
| 9342 | case 0x0000: | |
| 9343 | prg8_89(space->machine(), data); | |
| 9344 | break; | |
| 9345 | case 0x1000: | |
| 9346 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9347 | break; | |
| 9348 | case 0x2000: | |
| 9349 | prg8_ab(space->machine(), data); | |
| 9350 | break; | |
| 9351 | case 0x3000: | |
| 9352 | case 0x3002: | |
| 9353 | case 0x4000: | |
| 9354 | case 0x4002: | |
| 9355 | case 0x5000: | |
| 9356 | case 0x5002: | |
| 9357 | case 0x6000: | |
| 9358 | case 0x6002: | |
| 9359 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 3); | |
| 9360 | chr1_x(space->machine(), bank, data, CHRROM); | |
| 9361 | break; | |
| 9362 | case 0x7000: | |
| 9363 | state->m_IRQ_count = data; | |
| 9364 | break; | |
| 9365 | } | |
| 9366 | } | |
| 9367 | ||
| 9368 | /************************************************************* | |
| 9369 | ||
| 9370 | BTL-PIKACHUY2K | |
| 9371 | ||
| 9372 | Games: Pikachu Y2k | |
| 9373 | ||
| 9374 | iNES: mapper 254 | |
| 9375 | ||
| 9376 | In MESS: | |
| 9377 | ||
| 9378 | *************************************************************/ | |
| 9379 | ||
| 9380 | static WRITE8_HANDLER( btl_pika_y2k_w ) | |
| 9381 | { | |
| 9382 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9383 | LOG_MMC(("btl_pika_y2k_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9384 | ||
| 9385 | switch (offset & 0x6001) | |
| 9386 | { | |
| 9387 | case 0x2001: | |
| 9388 | state->m_mmc_latch2 = data; | |
| 9389 | break; | |
| 9390 | ||
| 9391 | case 0x2000: | |
| 9392 | state->m_mmc_reg[0] = 0; | |
| 9393 | default: | |
| 9394 | txrom_w(space, offset, data); | |
| 9395 | break; | |
| 9396 | } | |
| 9397 | } | |
| 9398 | ||
| 9399 | // strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000 | |
| 9400 | static WRITE8_HANDLER( btl_pika_y2k_m_w ) | |
| 9401 | { | |
| 9402 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9403 | LOG_MMC(("btl_pika_y2k_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9404 | ||
| 9405 | state->m_wram[offset] = data; | |
| 9406 | } | |
| 9407 | ||
| 9408 | static READ8_HANDLER( btl_pika_y2k_m_r ) | |
| 9409 | { | |
| 9410 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9411 | LOG_MMC(("btl_pika_y2k_m_r, offset: %04x\n", offset)); | |
| 9412 | ||
| 9413 | return state->m_wram[offset] ^ (state->m_mmc_latch2 & state->m_mmc_reg[0]); | |
| 9414 | } | |
| 9415 | ||
| 9416 | /************************************************************* | |
| 9417 | ||
| 9418 | MULTICART | |
| 9419 | ||
| 9420 | *************************************************************/ | |
| 9421 | ||
| 9422 | /************************************************************* | |
| 9423 | ||
| 9424 | Board BMC-FK23C | |
| 9425 | ||
| 9426 | In MESS: partially supported (still to sort initial banking | |
| 9427 | for many games) | |
| 9428 | ||
| 9429 | *************************************************************/ | |
| 9430 | ||
| 9431 | #if 0 | |
| 9432 | static void fk23c_prg_cb( running_machine &machine, int start, int bank ) | |
| 9433 | { | |
| 9434 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9435 | ||
| 9436 | if (((state->m_mmc_reg[0] & 0x07) - 3) > 1 && (!(state->m_mmc_reg[3] & 0x02) || start < 2)) | |
| 9437 | { | |
| 9438 | if (state->m_mmc_reg[0] & 0x03) | |
| 9439 | bank = (bank & (0x3f >> (state->m_mmc_reg[0] & 0x03))) | (state->m_mmc_reg[1] << 1); | |
| 9440 | ||
| 9441 | prg8_x(machine, start, bank); | |
| 9442 | } | |
| 9443 | } | |
| 9444 | ||
| 9445 | static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 9446 | { | |
| 9447 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9448 | ||
| 9449 | if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3))) | |
| 9450 | chr1_x(machine, start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source); | |
| 9451 | } | |
| 9452 | ||
| 9453 | #endif | |
| 9454 | ||
| 9455 | static void fk23c_prg_cb( running_machine &machine, int start, int bank ) | |
| 9456 | { | |
| 9457 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9458 | UINT8 mask = (0x3f >> (state->m_mmc_reg[0] & 0x03)); | |
| 9459 | ||
| 9460 | if ((state->m_mmc_reg[0] & 0x07) < 3) | |
| 9461 | { | |
| 9462 | if (!(state->m_mmc_reg[0] & 0x03)) | |
| 9463 | bank = (bank & mask) | ((state->m_mmc_reg[1] & (0x7f ^ mask)) << 1); | |
| 9464 | ||
| 9465 | prg8_x(machine, start, bank); | |
| 9466 | } | |
| 9467 | } | |
| 9468 | ||
| 9469 | static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 9470 | { | |
| 9471 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9472 | ||
| 9473 | if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3))) | |
| 9474 | chr1_x(machine, start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source); | |
| 9475 | } | |
| 9476 | ||
| 9477 | static void fk23c_set_prg( running_machine &machine ) | |
| 9478 | { | |
| 9479 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9480 | ||
| 9481 | if ((state->m_mmc_reg[0] & 0x07) == 4) | |
| 9482 | prg32(machine, (state->m_mmc_reg[1] & 0x7f) >> 1); | |
| 9483 | else if ((state->m_mmc_reg[0] & 0x07) == 3) | |
| 9484 | { | |
| 9485 | prg16_89ab(machine, state->m_mmc_reg[1] & 0x7f); | |
| 9486 | prg16_cdef(machine, state->m_mmc_reg[1] & 0x7f); | |
| 9487 | } | |
| 9488 | else | |
| 9489 | { | |
| 9490 | if (state->m_mmc_reg[3] & 0x02) | |
| 9491 | { | |
| 9492 | prg8_cd(machine, state->m_mmc_reg[4]); | |
| 9493 | prg8_ef(machine, state->m_mmc_reg[5]); | |
| 9494 | } | |
| 9495 | ||
| 9496 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9497 | } | |
| 9498 | } | |
| 9499 | ||
| 9500 | static void fk23c_set_chr( running_machine &machine ) | |
| 9501 | { | |
| 9502 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9503 | ||
| 9504 | if (state->m_mmc_reg[0] & 0x40) | |
| 9505 | chr8(machine, state->m_mmc_reg[2] | state->m_mmc_cmd1, state->m_mmc_chr_source); | |
| 9506 | else | |
| 9507 | { | |
| 9508 | if (state->m_mmc_reg[3] & 0x02) | |
| 9509 | { | |
| 9510 | int base = (state->m_mmc_reg[2] & 0x7f) << 3; | |
| 9511 | chr1_x(machine, 1, base | state->m_mmc_reg[6], state->m_mmc_chr_source); | |
| 9512 | chr1_x(machine, 3, base | state->m_mmc_reg[7], state->m_mmc_chr_source); | |
| 9513 | } | |
| 9514 | ||
| 9515 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 9516 | } | |
| 9517 | } | |
| 9518 | ||
| 9519 | static WRITE8_HANDLER( fk23c_l_w ) | |
| 9520 | { | |
| 9521 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9522 | LOG_MMC(("fk23c_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9523 | offset += 0x100; | |
| 9524 | ||
| 9525 | if (offset >= 0x1000) | |
| 9526 | { | |
| 9527 | if (offset & (1 << 4)) // here it should be (4 + state->m_mmc_dipsetting) | |
| 9528 | { | |
| 9529 | state->m_mmc_reg[offset & 0x03] = data; | |
| 9530 | ||
| 9531 | fk23c_set_prg(space->machine()); | |
| 9532 | fk23c_set_chr(space->machine()); | |
| 9533 | } | |
| 9534 | } | |
| 9535 | } | |
| 9536 | ||
| 9537 | static WRITE8_HANDLER( fk23c_w ) | |
| 9538 | { | |
| 9539 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9540 | LOG_MMC(("fk23c_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9541 | ||
| 9542 | if (state->m_mmc_reg[0] & 0x40) | |
| 9543 | { | |
| 9544 | if (state->m_mmc_reg[0] & 0x30) | |
| 9545 | state->m_mmc_cmd1 = 0; | |
| 9546 | else | |
| 9547 | { | |
| 9548 | state->m_mmc_cmd1 = data & 0x03; | |
| 9549 | fk23c_set_chr(space->machine()); | |
| 9550 | } | |
| 9551 | } | |
| 9552 | else | |
| 9553 | { | |
| 9554 | switch (offset & 0x6001) | |
| 9555 | { | |
| 9556 | case 0x0001: | |
| 9557 | if ((state->m_mmc_reg[3] & 0x02) && (state->m_mmc3_latch & 0x08)) | |
| 9558 | { | |
| 9559 | state->m_mmc_reg[4 | (state->m_mmc3_latch & 0x03)] = data; | |
| 9560 | fk23c_set_prg(space->machine()); | |
| 9561 | fk23c_set_chr(space->machine()); | |
| 9562 | } | |
| 9563 | else | |
| 9564 | txrom_w(space, offset, data); | |
| 9565 | break; | |
| 9566 | ||
| 9567 | case 0x2000: | |
| 9568 | set_nt_mirroring(space->machine(), data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9569 | break; | |
| 9570 | ||
| 9571 | default: | |
| 9572 | txrom_w(space, offset, data); | |
| 9573 | break; | |
| 9574 | } | |
| 9575 | } | |
| 9576 | } | |
| 9577 | ||
| 9578 | ||
| 9579 | /************************************************************* | |
| 9580 | ||
| 9581 | Board BMC-64IN1NOREPEAT | |
| 9582 | ||
| 9583 | Games: 64-in-1 Y2K | |
| 9584 | ||
| 9585 | In MESS: Supported | |
| 9586 | ||
| 9587 | *************************************************************/ | |
| 9588 | ||
| 9589 | static void bmc_64in1nr_set_prg( running_machine &machine ) | |
| 9590 | { | |
| 9591 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9592 | UINT8 helper1 = (state->m_mmc_reg[1] & 0x1f); | |
| 9593 | UINT8 helper2 = (helper1 << 1) | ((state->m_mmc_reg[1] & 0x40) >> 6); | |
| 9594 | ||
| 9595 | if (state->m_mmc_reg[0] & 0x80) | |
| 9596 | { | |
| 9597 | if (state->m_mmc_reg[1] & 0x80) | |
| 9598 | prg32(machine, helper1); | |
| 9599 | else | |
| 9600 | { | |
| 9601 | prg16_89ab(machine, helper2); | |
| 9602 | prg16_cdef(machine, helper2); | |
| 9603 | } | |
| 9604 | } | |
| 9605 | else | |
| 9606 | prg16_cdef(machine, helper2); | |
| 9607 | } | |
| 9608 | ||
| 9609 | static WRITE8_HANDLER( bmc_64in1nr_l_w ) | |
| 9610 | { | |
| 9611 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9612 | LOG_MMC(("bmc_64in1nr_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 9613 | offset += 0x100; | |
| 9614 | ||
| 9615 | switch (offset) | |
| 9616 | { | |
| 9617 | case 0x1000: | |
| 9618 | case 0x1001: | |
| 9619 | case 0x1002: | |
| 9620 | case 0x1003: | |
| 9621 | state->m_mmc_reg[offset & 0x03] = data; | |
| 9622 | bmc_64in1nr_set_prg(space->machine()); | |
| 9623 | chr8(space->machine(), ((state->m_mmc_reg[0] >> 1) & 0x03) | (state->m_mmc_reg[2] << 2), CHRROM); | |
| 9624 | break; | |
| 9625 | } | |
| 9626 | if (offset == 0x1000) /* reg[0] also sets mirroring */ | |
| 9627 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9628 | } | |
| 9629 | ||
| 9630 | static WRITE8_HANDLER( bmc_64in1nr_w ) | |
| 9631 | { | |
| 9632 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9633 | LOG_MMC(("bmc_64in1nr_w offset: %04x, data: %02x\n", offset, data)); | |
| 9634 | ||
| 9635 | state->m_mmc_reg[3] = data; // reg[3] is currently unused?!? | |
| 9636 | } | |
| 9637 | ||
| 9638 | /************************************************************* | |
| 9639 | ||
| 9640 | Board BMC-190IN1 | |
| 9641 | ||
| 9642 | Games: 190-in-1 | |
| 9643 | ||
| 9644 | In MESS: Supported | |
| 9645 | ||
| 9646 | *************************************************************/ | |
| 9647 | ||
| 9648 | static WRITE8_HANDLER( bmc_190in1_w ) | |
| 9649 | { | |
| 9650 | LOG_MMC(("bmc_190in1_w offset: %04x, data: %02x\n", offset, data)); | |
| 9651 | ||
| 9652 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9653 | offset >>= 2; | |
| 9654 | prg16_89ab(space->machine(), offset); | |
| 9655 | prg16_cdef(space->machine(), offset); | |
| 9656 | chr8(space->machine(), offset, CHRROM); | |
| 9657 | } | |
| 9658 | ||
| 9659 | /************************************************************* | |
| 9660 | ||
| 9661 | Board BMC-A65AS | |
| 9662 | ||
| 9663 | Games: 3-in-1 (N068) | |
| 9664 | ||
| 9665 | In MESS: Supported | |
| 9666 | ||
| 9667 | *************************************************************/ | |
| 9668 | ||
| 9669 | static WRITE8_HANDLER( bmc_a65as_w ) | |
| 9670 | { | |
| 9671 | UINT8 helper = (data & 0x30) >> 1; | |
| 9672 | LOG_MMC(("bmc_a65as_w offset: %04x, data: %02x\n", offset, data)); | |
| 9673 | ||
| 9674 | if (data & 0x80) | |
| 9675 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 9676 | else | |
| 9677 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9678 | ||
| 9679 | if (data & 0x40) | |
| 9680 | prg32(space->machine(), data >> 1); | |
| 9681 | else | |
| 9682 | { | |
| 9683 | prg16_89ab(space->machine(), helper | (data & 0x07)); | |
| 9684 | prg16_cdef(space->machine(), helper | 0x07); | |
| 9685 | } | |
| 9686 | } | |
| 9687 | ||
| 9688 | /************************************************************* | |
| 9689 | ||
| 9690 | Board BMC-GS2004 | |
| 9691 | ||
| 9692 | Games: Tetris Family 6-in-1 | |
| 9693 | ||
| 9694 | In MESS: Preliminary Support. It also misses WRAM handling | |
| 9695 | (we need reads from 0x6000-0x7fff) | |
| 9696 | ||
| 9697 | *************************************************************/ | |
| 9698 | ||
| 9699 | static WRITE8_HANDLER( bmc_gs2004_w ) | |
| 9700 | { | |
| 9701 | LOG_MMC(("bmc_gs2004_w offset: %04x, data: %02x\n", offset, data)); | |
| 9702 | ||
| 9703 | prg32(space->machine(), data); | |
| 9704 | } | |
| 9705 | ||
| 9706 | /************************************************************* | |
| 9707 | ||
| 9708 | Board BMC-GS2013 | |
| 9709 | ||
| 9710 | Games: Tetris Family 12-in-1 | |
| 9711 | ||
| 9712 | In MESS: Preliminary Support. It also misses WRAM handling | |
| 9713 | (we need reads from 0x6000-0x7fff) | |
| 9714 | ||
| 9715 | *************************************************************/ | |
| 9716 | ||
| 9717 | static WRITE8_HANDLER( bmc_gs2013_w ) | |
| 9718 | { | |
| 9719 | LOG_MMC(("bmc_gs2013_w offset: %04x, data: %02x\n", offset, data)); | |
| 9720 | ||
| 9721 | if (data & 0x08) | |
| 9722 | prg32(space->machine(), data & 0x09); | |
| 9723 | else | |
| 9724 | prg32(space->machine(), data & 0x07); | |
| 9725 | } | |
| 9726 | ||
| 9727 | /************************************************************* | |
| 9728 | ||
| 9729 | Board BMC-SUPER24IN1SC03 | |
| 9730 | ||
| 9731 | Games: Super 24-in-1 | |
| 9732 | ||
| 9733 | In MESS: Partially Supported | |
| 9734 | ||
| 9735 | *************************************************************/ | |
| 9736 | ||
| 9737 | static void bmc_s24in1sc03_prg_cb( running_machine &machine, int start, int bank ) | |
| 9738 | { | |
| 9739 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9740 | static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00}; | |
| 9741 | int prg_base = state->m_mmc_reg[1] << 1; | |
| 9742 | int prg_mask = masks[state->m_mmc_reg[0] & 0x07]; | |
| 9743 | ||
| 9744 | bank = prg_base | (bank & prg_mask); | |
| 9745 | prg8_x(machine, start, bank); | |
| 9746 | } | |
| 9747 | ||
| 9748 | static void bmc_s24in1sc03_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 9749 | { | |
| 9750 | nes_state *state = machine.driver_data<nes_state>(); | |
| 9751 | UINT8 chr = BIT(state->m_mmc_reg[0], 5) ? CHRRAM : CHRROM; | |
| 9752 | int chr_base = (state->m_mmc_reg[2] << 3) & 0xf00; | |
| 9753 | ||
| 9754 | chr1_x(machine, start, chr_base | bank, chr); | |
| 9755 | } | |
| 9756 | ||
| 9757 | static WRITE8_HANDLER( bmc_s24in1sc03_l_w ) | |
| 9758 | { | |
| 9759 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9760 | LOG_MMC(("bmc_s24in1sc03_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 9761 | offset += 0x100; | |
| 9762 | ||
| 9763 | if (offset == 0x1ff0) | |
| 9764 | { | |
| 9765 | state->m_mmc_reg[0] = data; | |
| 9766 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 9767 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9768 | } | |
| 9769 | ||
| 9770 | if (offset == 0x1ff1) | |
| 9771 | { | |
| 9772 | state->m_mmc_reg[1] = data; | |
| 9773 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 9774 | } | |
| 9775 | ||
| 9776 | if (offset == 0x1ff2) | |
| 9777 | { | |
| 9778 | state->m_mmc_reg[2] = data; | |
| 9779 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 9780 | } | |
| 9781 | } | |
| 9782 | ||
| 9783 | /************************************************************* | |
| 9784 | ||
| 9785 | Board BMC-T-262 | |
| 9786 | ||
| 9787 | Games: 4-in-1 (D-010), 8-in-1 (A-020) | |
| 9788 | ||
| 9789 | In MESS: Supported | |
| 9790 | ||
| 9791 | *************************************************************/ | |
| 9792 | ||
| 9793 | static WRITE8_HANDLER( bmc_t262_w ) | |
| 9794 | { | |
| 9795 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9796 | UINT8 mmc_helper; | |
| 9797 | LOG_MMC(("bmc_t262_w offset: %04x, data: %02x\n", offset, data)); | |
| 9798 | ||
| 9799 | if (state->m_mmc_latch2 || offset == 0) | |
| 9800 | { | |
| 9801 | state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x38) | (data & 0x07); | |
| 9802 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 9803 | } | |
| 9804 | else | |
| 9805 | { | |
| 9806 | state->m_mmc_latch2 = 1; | |
| 9807 | set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9808 | mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18); | |
| 9809 | state->m_mmc_latch1 = mmc_helper | (state->m_mmc_latch1 & 0x07); | |
| 9810 | prg16_89ab(space->machine(), state->m_mmc_latch1); | |
| 9811 | prg16_cdef(space->machine(), mmc_helper | 0x07); | |
| 9812 | } | |
| 9813 | } | |
| 9814 | ||
| 9815 | /************************************************************* | |
| 9816 | ||
| 9817 | Board BMC-WS | |
| 9818 | ||
| 9819 | Games: Super 40-in-1 | |
| 9820 | ||
| 9821 | In MESS: Partially Supported (some games, like Galaxian, have | |
| 9822 | issues) | |
| 9823 | ||
| 9824 | *************************************************************/ | |
| 9825 | ||
| 9826 | static WRITE8_HANDLER( bmc_ws_m_w ) | |
| 9827 | { | |
| 9828 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9829 | UINT8 mmc_helper; | |
| 9830 | LOG_MMC(("bmc_ws_m_w offset: %04x, data: %02x\n", offset, data)); | |
| 9831 | ||
| 9832 | if (offset < 0x1000) | |
| 9833 | { | |
| 9834 | switch (offset & 0x01) | |
| 9835 | { | |
| 9836 | case 0: | |
| 9837 | if (!state->m_mmc_latch1) | |
| 9838 | { | |
| 9839 | state->m_mmc_latch1 = data & 0x20; | |
| 9840 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9841 | mmc_helper = (~data & 0x08) >> 3; | |
| 9842 | prg16_89ab(space->machine(), data & ~mmc_helper); | |
| 9843 | prg16_cdef(space->machine(), data | mmc_helper); | |
| 9844 | } | |
| 9845 | break; | |
| 9846 | case 1: | |
| 9847 | if (!state->m_mmc_latch1) | |
| 9848 | { | |
| 9849 | chr8(space->machine(), data, CHRROM); | |
| 9850 | } | |
| 9851 | break; | |
| 9852 | } | |
| 9853 | } | |
| 9854 | } | |
| 9855 | ||
| 9856 | /************************************************************* | |
| 9857 | ||
| 9858 | BMC-NOVELDIAMOND and BMC-999999in1 | |
| 9859 | ||
| 9860 | Unknown Bootleg Multigame Board | |
| 9861 | Games: I only found 'Novel Diamond 999999-in-1.unf' using | |
| 9862 | this mapper (hence the code is used for BMC_NOVELDIAMOND | |
| 9863 | board). The code is included here in case a mapper 54 | |
| 9864 | dump arises. | |
| 9865 | ||
| 9866 | iNES: mappers 54 and 213 | |
| 9867 | ||
| 9868 | In MESS: Partial Support. | |
| 9869 | ||
| 9870 | *************************************************************/ | |
| 9871 | ||
| 9872 | // Are this correct or should they work the same? | |
| 9873 | static WRITE8_HANDLER( novel1_w ) | |
| 9874 | { | |
| 9875 | LOG_MMC(("novel1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9876 | ||
| 9877 | prg32(space->machine(), offset & 0x03); | |
| 9878 | chr8(space->machine(), offset & 0x07, CHRROM); | |
| 9879 | } | |
| 9880 | ||
| 9881 | static WRITE8_HANDLER( novel2_w ) | |
| 9882 | { | |
| 9883 | LOG_MMC(("novel2_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9884 | ||
| 9885 | prg32(space->machine(), offset >> 1); | |
| 9886 | chr8(space->machine(), offset >> 3, CHRROM); | |
| 9887 | } | |
| 9888 | ||
| 9889 | /************************************************************* | |
| 9890 | ||
| 9891 | Board BMC-GKA | |
| 9892 | ||
| 9893 | Unknown Bootleg Multigame Board | |
| 9894 | Games: 6 in 1, 54 in 1, 106 in 1 | |
| 9895 | ||
| 9896 | iNES: mapper 57 | |
| 9897 | ||
| 9898 | In MESS: Supported. | |
| 9899 | ||
| 9900 | *************************************************************/ | |
| 9901 | ||
| 9902 | static WRITE8_HANDLER( bmc_gka_w ) | |
| 9903 | { | |
| 9904 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9905 | LOG_MMC(("bmc_gka_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9906 | ||
| 9907 | if (offset & 0x0800) | |
| 9908 | state->m_mmc_latch2 = data; | |
| 9909 | else | |
| 9910 | state->m_mmc_latch1 = data; | |
| 9911 | ||
| 9912 | if (state->m_mmc_latch2 & 0x80) | |
| 9913 | prg32(space->machine(), 2 | (state->m_mmc_latch2 >> 6)); | |
| 9914 | else | |
| 9915 | { | |
| 9916 | prg16_89ab(space->machine(), (state->m_mmc_latch2 >> 5) & 0x03); | |
| 9917 | prg16_cdef(space->machine(), (state->m_mmc_latch2 >> 5) & 0x03); | |
| 9918 | } | |
| 9919 | ||
| 9920 | set_nt_mirroring(space->machine(), (state->m_mmc_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9921 | ||
| 9922 | chr8(space->machine(), (state->m_mmc_latch1 & 0x03) | (state->m_mmc_latch2 & 0x07) | ((state->m_mmc_latch2 & 0x10) >> 1), CHRROM); | |
| 9923 | } | |
| 9924 | ||
| 9925 | ||
| 9926 | /************************************************************* | |
| 9927 | ||
| 9928 | Board UNL-STUDYNGAME | |
| 9929 | ||
| 9930 | Games: Study n Game 32 in 1 | |
| 9931 | ||
| 9932 | iNES: mapper 39 | |
| 9933 | ||
| 9934 | In MESS: Partially Supported (problems with PRG bankswitch, | |
| 9935 | only keyboard exercise work). | |
| 9936 | ||
| 9937 | *************************************************************/ | |
| 9938 | ||
| 9939 | static WRITE8_HANDLER( sng32_w ) | |
| 9940 | { | |
| 9941 | LOG_MMC(("sng32_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9942 | prg32(space->machine(), data); | |
| 9943 | } | |
| 9944 | ||
| 9945 | /************************************************************* | |
| 9946 | ||
| 9947 | Board BMC-GKB | |
| 9948 | ||
| 9949 | Unknown Bootleg Multigame Board | |
| 9950 | Games: 68 in 1, 73 in 1, 98 in 1 | |
| 9951 | ||
| 9952 | iNES: mapper 58 | |
| 9953 | ||
| 9954 | In MESS: Supported. | |
| 9955 | ||
| 9956 | *************************************************************/ | |
| 9957 | ||
| 9958 | static WRITE8_HANDLER( bmc_gkb_w ) | |
| 9959 | { | |
| 9960 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 9961 | UINT8 bank = (offset & 0x40) ? 0 : 1; | |
| 9962 | LOG_MMC(("bmc_gkb_w, offset: %04x, data: %02x\n", offset, data)); | |
| 9963 | ||
| 9964 | prg16_89ab(space->machine(), offset & ~bank); | |
| 9965 | prg16_cdef(space->machine(), offset | bank); | |
| 9966 | chr8(space->machine(), offset >> 3, state->m_mmc_chr_source); | |
| 9967 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 9968 | } | |
| 9969 | ||
| 9970 | /************************************************************* | |
| 9971 | ||
| 9972 | BMC-SUPER-700IN1 | |
| 9973 | ||
| 9974 | Unknown Bootleg Multigame Board | |
| 9975 | Games: Super 700 in 1 | |
| 9976 | ||
| 9977 | iNES: mapper 62 | |
| 9978 | ||
| 9979 | In MESS: Supported. | |
| 9980 | ||
| 9981 | *************************************************************/ | |
| 9982 | ||
| 9983 | static WRITE8_HANDLER( bmc_super700in1_w ) | |
| 9984 | { | |
| 9985 | LOG_MMC(("bmc_super700in1_w, offset :%04x, data: %02x\n", offset, data)); | |
| 9986 | ||
| 9987 | chr8(space->machine(), ((offset & 0x1f) << 2) | (data & 0x03), CHRROM); | |
| 9988 | ||
| 9989 | if (offset & 0x20) | |
| 9990 | { | |
| 9991 | prg16_89ab(space->machine(), (offset & 0x40) | ((offset >> 8) & 0x3f)); | |
| 9992 | prg16_cdef(space->machine(), (offset & 0x40) | ((offset >> 8) & 0x3f)); | |
| 9993 | } | |
| 9994 | else | |
| 9995 | { | |
| 9996 | prg32(space->machine(), ((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1); | |
| 9997 | } | |
| 9998 | ||
| 9999 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10000 | } | |
| 10001 | ||
| 10002 | /************************************************************* | |
| 10003 | ||
| 10004 | BMC-36IN1 | |
| 10005 | ||
| 10006 | Unknown Bootleg Multigame Board | |
| 10007 | Games: 36 in 1, 1200 in 1 | |
| 10008 | ||
| 10009 | iNES: mapper 200 | |
| 10010 | ||
| 10011 | In MESS: Supported. | |
| 10012 | ||
| 10013 | *************************************************************/ | |
| 10014 | ||
| 10015 | static WRITE8_HANDLER( bmc_36in1_w ) | |
| 10016 | { | |
| 10017 | LOG_MMC(("bmc_36in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10018 | ||
| 10019 | prg16_89ab(space->machine(), offset & 0x07); | |
| 10020 | prg16_cdef(space->machine(), offset & 0x07); | |
| 10021 | chr8(space->machine(), offset & 0x07, CHRROM); | |
| 10022 | ||
| 10023 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10024 | } | |
| 10025 | ||
| 10026 | /************************************************************* | |
| 10027 | ||
| 10028 | BMC-21IN1 | |
| 10029 | ||
| 10030 | Unknown Bootleg Multigame Board | |
| 10031 | Games: 8 in 1, 21 in 1 | |
| 10032 | ||
| 10033 | iNES: mapper 201 | |
| 10034 | ||
| 10035 | In MESS: Supported. | |
| 10036 | ||
| 10037 | *************************************************************/ | |
| 10038 | ||
| 10039 | static WRITE8_HANDLER( bmc_21in1_w ) | |
| 10040 | { | |
| 10041 | LOG_MMC(("bmc_21in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10042 | ||
| 10043 | prg32(space->machine(), offset & 0x03); | |
| 10044 | chr8(space->machine(), offset & 0x03, CHRROM); | |
| 10045 | } | |
| 10046 | ||
| 10047 | /************************************************************* | |
| 10048 | ||
| 10049 | BMC-150IN1 | |
| 10050 | ||
| 10051 | Unknown Bootleg Multigame Board | |
| 10052 | Games: 150 in 1 | |
| 10053 | ||
| 10054 | iNES: mapper 202 | |
| 10055 | ||
| 10056 | In MESS: Supported. | |
| 10057 | ||
| 10058 | *************************************************************/ | |
| 10059 | ||
| 10060 | static WRITE8_HANDLER( bmc_150in1_w ) | |
| 10061 | { | |
| 10062 | int bank = (offset >> 1) & 0x07; | |
| 10063 | ||
| 10064 | LOG_MMC(("bmc_150in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10065 | ||
| 10066 | prg16_89ab(space->machine(), bank); | |
| 10067 | prg16_cdef(space->machine(), bank + (((bank & 0x06) == 0x06) ? 1 : 0)); | |
| 10068 | chr8(space->machine(), bank, CHRROM); | |
| 10069 | ||
| 10070 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); | |
| 10071 | } | |
| 10072 | ||
| 10073 | /************************************************************* | |
| 10074 | ||
| 10075 | BMC-35IN1 | |
| 10076 | ||
| 10077 | Unknown Bootleg Multigame Board | |
| 10078 | Games: 35 in 1 | |
| 10079 | ||
| 10080 | iNES: mapper 203 | |
| 10081 | ||
| 10082 | In MESS: Supported. | |
| 10083 | ||
| 10084 | *************************************************************/ | |
| 10085 | ||
| 10086 | static WRITE8_HANDLER( bmc_35in1_w ) | |
| 10087 | { | |
| 10088 | LOG_MMC(("bmc_35in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10089 | ||
| 10090 | prg16_89ab(space->machine(), (data >> 2) & 0x03); | |
| 10091 | prg16_cdef(space->machine(), (data >> 2) & 0x03); | |
| 10092 | chr8(space->machine(), data & 0x03, CHRROM); | |
| 10093 | } | |
| 10094 | ||
| 10095 | /************************************************************* | |
| 10096 | ||
| 10097 | BMC-64IN1 | |
| 10098 | ||
| 10099 | Unknown Bootleg Multigame Board | |
| 10100 | Games: 64 in 1 | |
| 10101 | ||
| 10102 | iNES: mapper 204 | |
| 10103 | ||
| 10104 | In MESS: Supported. | |
| 10105 | ||
| 10106 | *************************************************************/ | |
| 10107 | ||
| 10108 | static WRITE8_HANDLER( bmc_64in1_w ) | |
| 10109 | { | |
| 10110 | int bank = (offset >> 1) & (offset >> 2) & 0x01; | |
| 10111 | ||
| 10112 | LOG_MMC(("bmc_64in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10113 | ||
| 10114 | prg16_89ab(space->machine(), offset & ~bank); | |
| 10115 | prg16_cdef(space->machine(), offset | bank); | |
| 10116 | chr8(space->machine(), offset & ~bank, CHRROM); | |
| 10117 | ||
| 10118 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); | |
| 10119 | } | |
| 10120 | ||
| 10121 | /************************************************************* | |
| 10122 | ||
| 10123 | BMC-15IN1 | |
| 10124 | ||
| 10125 | Unknown Bootleg Multigame Board | |
| 10126 | Games: 3 in 1, 15 in 1 | |
| 10127 | ||
| 10128 | iNES: mapper 205, MMC3 clone | |
| 10129 | ||
| 10130 | In MESS: Supported. | |
| 10131 | ||
| 10132 | *************************************************************/ | |
| 10133 | ||
| 10134 | static WRITE8_HANDLER( bmc_15in1_m_w ) | |
| 10135 | { | |
| 10136 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10137 | LOG_MMC(("bmc_15in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10138 | ||
| 10139 | if (offset & 0x0800) | |
| 10140 | { | |
| 10141 | state->m_mmc_prg_base = (data & 0x03) << 4; | |
| 10142 | state->m_mmc_prg_mask = (data & 0x02) ? 0x0f : 0x1f; | |
| 10143 | state->m_mmc_chr_base = (data & 0x03) << 7; | |
| 10144 | state->m_mmc_chr_mask = (data & 0x02) ? 0x7f : 0xff; | |
| 10145 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10146 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10147 | } | |
| 10148 | } | |
| 10149 | ||
| 10150 | /************************************************************* | |
| 10151 | ||
| 10152 | BMC-SUPERHIK_300IN1 | |
| 10153 | ||
| 10154 | Unknown Bootleg Multigame Board | |
| 10155 | Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1 | |
| 10156 | ||
| 10157 | iNES: mapper 212 | |
| 10158 | ||
| 10159 | In MESS: Supported. | |
| 10160 | ||
| 10161 | *************************************************************/ | |
| 10162 | ||
| 10163 | static WRITE8_HANDLER( bmc_hik300_w ) | |
| 10164 | { | |
| 10165 | LOG_MMC(("bmc_hik300_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10166 | ||
| 10167 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10168 | chr8(space->machine(), offset, CHRROM); | |
| 10169 | ||
| 10170 | if (offset < 0x4000) | |
| 10171 | { | |
| 10172 | prg16_89ab(space->machine(), offset); | |
| 10173 | prg16_cdef(space->machine(), offset); | |
| 10174 | } | |
| 10175 | else | |
| 10176 | prg32(space->machine(), offset >> 1); | |
| 10177 | } | |
| 10178 | ||
| 10179 | /************************************************************* | |
| 10180 | ||
| 10181 | BMC-SUPERGUN-20IN1 | |
| 10182 | ||
| 10183 | Unknown Bootleg Multigame Board | |
| 10184 | Games: Super Gun 20 in 1 | |
| 10185 | ||
| 10186 | iNES: mapper 214 | |
| 10187 | ||
| 10188 | In MESS: Supported. | |
| 10189 | ||
| 10190 | *************************************************************/ | |
| 10191 | ||
| 10192 | static WRITE8_HANDLER( supergun20in1_w ) | |
| 10193 | { | |
| 10194 | LOG_MMC(("supergun20in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10195 | ||
| 10196 | prg16_89ab(space->machine(), offset >> 2); | |
| 10197 | prg16_cdef(space->machine(), offset >> 2); | |
| 10198 | chr8(space->machine(), offset, CHRROM); | |
| 10199 | } | |
| 10200 | ||
| 10201 | /************************************************************* | |
| 10202 | ||
| 10203 | BMC-72IN1 | |
| 10204 | ||
| 10205 | Unknown Bootleg Multigame Board | |
| 10206 | Games: 72 in 1, 115 in 1 and other multigame carts | |
| 10207 | ||
| 10208 | iNES: mapper 225 | |
| 10209 | ||
| 10210 | In MESS: Supported. | |
| 10211 | ||
| 10212 | *************************************************************/ | |
| 10213 | ||
| 10214 | static WRITE8_HANDLER( bmc_72in1_w ) | |
| 10215 | { | |
| 10216 | int hi_bank; | |
| 10217 | int size_16; | |
| 10218 | int bank; | |
| 10219 | ||
| 10220 | LOG_MMC(("bmc_72in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10221 | ||
| 10222 | chr8(space->machine(), offset, CHRROM); | |
| 10223 | set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10224 | ||
| 10225 | hi_bank = offset & 0x40; | |
| 10226 | size_16 = offset & 0x1000; | |
| 10227 | bank = (offset & 0xf80) >> 7; | |
| 10228 | if (size_16) | |
| 10229 | { | |
| 10230 | bank <<= 1; | |
| 10231 | if (hi_bank) | |
| 10232 | bank ++; | |
| 10233 | ||
| 10234 | prg16_89ab(space->machine(), bank); | |
| 10235 | prg16_cdef(space->machine(), bank); | |
| 10236 | } | |
| 10237 | else | |
| 10238 | prg32(space->machine(), bank); | |
| 10239 | } | |
| 10240 | ||
| 10241 | /************************************************************* | |
| 10242 | ||
| 10243 | BMC-76IN1 | |
| 10244 | ||
| 10245 | Unknown Bootleg Multigame Board | |
| 10246 | Games: 76 in 1, Super 42 in 1 | |
| 10247 | ||
| 10248 | iNES: mapper 226 | |
| 10249 | ||
| 10250 | In MESS: Supported. | |
| 10251 | ||
| 10252 | *************************************************************/ | |
| 10253 | ||
| 10254 | // does this work for super42in1 as well?!? | |
| 10255 | static WRITE8_HANDLER( bmc_76in1_w ) | |
| 10256 | { | |
| 10257 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10258 | int hi_bank; | |
| 10259 | int size_16; | |
| 10260 | int bank; | |
| 10261 | ||
| 10262 | LOG_MMC(("bmc_76in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10263 | ||
| 10264 | if (offset & 0x01) | |
| 10265 | state->m_mmc_latch2 = data; | |
| 10266 | else | |
| 10267 | state->m_mmc_latch1 = data; | |
| 10268 | ||
| 10269 | set_nt_mirroring(space->machine(), BIT(state->m_mmc_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10270 | ||
| 10271 | hi_bank = state->m_mmc_latch1 & 0x01; | |
| 10272 | size_16 = state->m_mmc_latch1 & 0x20; | |
| 10273 | bank = ((state->m_mmc_latch1 & 0x1e) >> 1) | ((state->m_mmc_latch1 & 0x80) >> 3) | ((state->m_mmc_latch2 & 0x01) << 5); | |
| 10274 | ||
| 10275 | if (size_16) | |
| 10276 | { | |
| 10277 | bank <<= 1; | |
| 10278 | if (hi_bank) | |
| 10279 | bank ++; | |
| 10280 | ||
| 10281 | prg16_89ab(space->machine(), bank); | |
| 10282 | prg16_cdef(space->machine(), bank); | |
| 10283 | } | |
| 10284 | else | |
| 10285 | prg32(space->machine(), bank); | |
| 10286 | } | |
| 10287 | ||
| 10288 | /************************************************************* | |
| 10289 | ||
| 10290 | BMC-1200IN1 | |
| 10291 | ||
| 10292 | Unknown Bootleg Multigame Board | |
| 10293 | Games: 1200 in 1, 295 in 1, 76 in 1 | |
| 10294 | ||
| 10295 | iNES: mapper 227 | |
| 10296 | ||
| 10297 | In MESS: Supported. | |
| 10298 | ||
| 10299 | *************************************************************/ | |
| 10300 | ||
| 10301 | static WRITE8_HANDLER( bmc_1200in1_w ) | |
| 10302 | { | |
| 10303 | int hi_bank; | |
| 10304 | int size_32; | |
| 10305 | int bank; | |
| 10306 | ||
| 10307 | LOG_MMC(("bmc_1200in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10308 | ||
| 10309 | hi_bank = offset & 0x04; | |
| 10310 | size_32 = offset & 0x01; | |
| 10311 | bank = ((offset & 0x78) >> 3) | ((offset & 0x0100) >> 4); | |
| 10312 | if (!size_32) | |
| 10313 | { | |
| 10314 | bank <<= 1; | |
| 10315 | if (hi_bank) | |
| 10316 | bank ++; | |
| 10317 | ||
| 10318 | prg16_89ab(space->machine(), bank); | |
| 10319 | prg16_cdef(space->machine(), bank); | |
| 10320 | } | |
| 10321 | else | |
| 10322 | prg32(space->machine(), bank); | |
| 10323 | ||
| 10324 | if (!(offset & 0x80)) | |
| 10325 | { | |
| 10326 | if (offset & 0x200) | |
| 10327 | prg16_cdef(space->machine(), ((bank << 1) & 0x38) + 7); | |
| 10328 | else | |
| 10329 | prg16_cdef(space->machine(), ((bank << 1) & 0x38)); | |
| 10330 | } | |
| 10331 | ||
| 10332 | set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10333 | } | |
| 10334 | ||
| 10335 | /************************************************************* | |
| 10336 | ||
| 10337 | BMC-31IN1 | |
| 10338 | ||
| 10339 | Unknown Bootleg Multigame Board | |
| 10340 | Games: 31 in 1 | |
| 10341 | ||
| 10342 | iNES: mapper 229 | |
| 10343 | ||
| 10344 | In MESS: Supported. | |
| 10345 | ||
| 10346 | *************************************************************/ | |
| 10347 | ||
| 10348 | static WRITE8_HANDLER( bmc_31in1_w ) | |
| 10349 | { | |
| 10350 | LOG_MMC(("bmc_31in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10351 | ||
| 10352 | set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10353 | chr8(space->machine(), offset, CHRROM); | |
| 10354 | ||
| 10355 | if ((offset & 0x1e) == 0) | |
| 10356 | { | |
| 10357 | prg16_89ab(space->machine(), 0); | |
| 10358 | prg16_89ab(space->machine(), 1); | |
| 10359 | } | |
| 10360 | else | |
| 10361 | { | |
| 10362 | prg16_89ab(space->machine(), offset & 0x1f); | |
| 10363 | prg16_89ab(space->machine(), offset & 0x1f); | |
| 10364 | } | |
| 10365 | } | |
| 10366 | ||
| 10367 | /************************************************************* | |
| 10368 | ||
| 10369 | BMC-22GAMES | |
| 10370 | ||
| 10371 | Unknown Bootleg Multigame Board | |
| 10372 | Games: 22 in 1 | |
| 10373 | ||
| 10374 | iNES: mapper 230 | |
| 10375 | ||
| 10376 | In MESS: Partially Supported. It would need a reset | |
| 10377 | to work (not possible yet) | |
| 10378 | ||
| 10379 | *************************************************************/ | |
| 10380 | ||
| 10381 | static WRITE8_HANDLER( bmc_22g_w ) | |
| 10382 | { | |
| 10383 | LOG_MMC(("bmc_22g_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10384 | ||
| 10385 | if (1) // this should flip at reset | |
| 10386 | { | |
| 10387 | prg16_89ab(space->machine(), data & 0x07); | |
| 10388 | } | |
| 10389 | else | |
| 10390 | { | |
| 10391 | if (data & 0x20) | |
| 10392 | { | |
| 10393 | prg16_89ab(space->machine(), (data & 0x1f) + 8); | |
| 10394 | prg16_cdef(space->machine(), (data & 0x1f) + 8); | |
| 10395 | } | |
| 10396 | else | |
| 10397 | { | |
| 10398 | prg16_89ab(space->machine(), (data & 0x1f) + 8); | |
| 10399 | prg16_cdef(space->machine(), (data & 0x1f) + 9); | |
| 10400 | } | |
| 10401 | set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 10402 | } | |
| 10403 | } | |
| 10404 | ||
| 10405 | /************************************************************* | |
| 10406 | ||
| 10407 | BMC-20IN1 | |
| 10408 | ||
| 10409 | Unknown Bootleg Multigame Board | |
| 10410 | Games: 20 in 1 | |
| 10411 | ||
| 10412 | iNES: mapper 231 | |
| 10413 | ||
| 10414 | In MESS: Supported. | |
| 10415 | ||
| 10416 | *************************************************************/ | |
| 10417 | ||
| 10418 | static WRITE8_HANDLER( bmc_20in1_w ) | |
| 10419 | { | |
| 10420 | LOG_MMC(("bmc_20in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10421 | ||
| 10422 | set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10423 | ||
| 10424 | prg16_89ab(space->machine(), (offset & 0x1e)); | |
| 10425 | prg16_cdef(space->machine(), (offset & 0x1e) | ((offset & 0x20) ? 1 : 0)); | |
| 10426 | } | |
| 10427 | ||
| 10428 | /************************************************************* | |
| 10429 | ||
| 10430 | BMC-110IN1 | |
| 10431 | ||
| 10432 | Known Boards: Unknown Bootleg Board | |
| 10433 | Games: 110 in 1 | |
| 10434 | ||
| 10435 | iNES: mapper 255 | |
| 10436 | ||
| 10437 | In MESS: Preliminary support. | |
| 10438 | ||
| 10439 | *************************************************************/ | |
| 10440 | ||
| 10441 | static WRITE8_HANDLER( bmc_110in1_w ) | |
| 10442 | { | |
| 10443 | UINT8 map255_helper1 = (offset >> 12) ? 0 : 1; | |
| 10444 | UINT8 map255_helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f); | |
| 10445 | ||
| 10446 | LOG_MMC(("bmc_110in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10447 | ||
| 10448 | set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10449 | prg16_89ab(space->machine(), map255_helper1 & ~map255_helper2); | |
| 10450 | prg16_cdef(space->machine(), map255_helper1 | map255_helper2); | |
| 10451 | chr8(space->machine(), ((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM); | |
| 10452 | } | |
| 10453 | ||
| 10454 | /************************************************************* | |
| 10455 | ||
| 10456 | BMC-SUPERBIG-7IN1 | |
| 10457 | ||
| 10458 | Known Boards: Unknown Multigame Bootleg Board | |
| 10459 | Games: Kunio 8 in 1, Super Big 7 in 1 | |
| 10460 | ||
| 10461 | iNES: mapper 44 | |
| 10462 | ||
| 10463 | In MESS: Supported. It also uses mmc3_irq. | |
| 10464 | ||
| 10465 | *************************************************************/ | |
| 10466 | ||
| 10467 | static WRITE8_HANDLER( bmc_sbig7_w ) | |
| 10468 | { | |
| 10469 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10470 | UINT8 page; | |
| 10471 | LOG_MMC(("bmc_sbig7_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10472 | ||
| 10473 | switch (offset & 0x6001) | |
| 10474 | { | |
| 10475 | case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */ | |
| 10476 | page = (data & 0x07); | |
| 10477 | if (page > 6) | |
| 10478 | page = 6; | |
| 10479 | ||
| 10480 | state->m_mmc_prg_base = page << 4; | |
| 10481 | state->m_mmc_prg_mask = (page > 5) ? 0x1f : 0x0f; | |
| 10482 | state->m_mmc_chr_base = page << 7; | |
| 10483 | state->m_mmc_chr_mask = (page > 5) ? 0xff : 0x7f; | |
| 10484 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10485 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10486 | break; | |
| 10487 | ||
| 10488 | default: | |
| 10489 | txrom_w(space, offset, data); | |
| 10490 | break; | |
| 10491 | } | |
| 10492 | } | |
| 10493 | ||
| 10494 | /************************************************************* | |
| 10495 | ||
| 10496 | BMC-HIK8IN1 | |
| 10497 | ||
| 10498 | Known Boards: Unknown Multigame Bootleg Board | |
| 10499 | Games: Street Fighter V, various multigame carts | |
| 10500 | ||
| 10501 | iNES: mapper 45 | |
| 10502 | ||
| 10503 | In MESS: Supported. It also uses mmc3_irq. | |
| 10504 | ||
| 10505 | *************************************************************/ | |
| 10506 | ||
| 10507 | static WRITE8_HANDLER( bmc_hik8_m_w ) | |
| 10508 | { | |
| 10509 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10510 | LOG_MMC(("bmc_hik8_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10511 | ||
| 10512 | /* This bit is the "register lock". Once register are locked, writes go to WRAM | |
| 10513 | and there is no way to unlock them (except by resetting the machine) */ | |
| 10514 | if ((state->m_mmc_reg[3] & 0x40) && state->m_wram != NULL) | |
| 10515 | state->m_wram[offset] = data; | |
| 10516 | else | |
| 10517 | { | |
| 10518 | state->m_mmc_reg[state->m_mmc_count] = data; | |
| 10519 | state->m_mmc_count = (state->m_mmc_count + 1) & 0x03; | |
| 10520 | ||
| 10521 | if (!state->m_mmc_count) | |
| 10522 | { | |
| 10523 | LOG_MMC(("bmc_hik8_m_w, command completed %02x %02x %02x %02x\n", state->m_mmc_reg[3], | |
| 10524 | state->m_mmc_reg[2], state->m_mmc_reg[1], state->m_mmc_reg[0])); | |
| 10525 | ||
| 10526 | state->m_mmc_prg_base = state->m_mmc_reg[1]; | |
| 10527 | state->m_mmc_prg_mask = 0x3f ^ (state->m_mmc_reg[3] & 0x3f); | |
| 10528 | state->m_mmc_chr_base = ((state->m_mmc_reg[2] & 0xf0) << 4) | state->m_mmc_reg[0]; | |
| 10529 | if (BIT(state->m_mmc_reg[2], 3)) | |
| 10530 | state->m_mmc_chr_mask = (1 << ((state->m_mmc_reg[2] & 7) + 1)) - 1; | |
| 10531 | else if (state->m_mmc_reg[2]) | |
| 10532 | state->m_mmc_chr_mask = 0; | |
| 10533 | else | |
| 10534 | state->m_mmc_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking | |
| 10535 | ||
| 10536 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10537 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10538 | } | |
| 10539 | } | |
| 10540 | } | |
| 10541 | ||
| 10542 | /************************************************************* | |
| 10543 | ||
| 10544 | BMC-SUPERHIK-4IN1 | |
| 10545 | ||
| 10546 | Known Boards: Unknown Multigame Bootleg Board | |
| 10547 | Games: Super HIK 4 in 1 | |
| 10548 | ||
| 10549 | iNES: mapper 49 | |
| 10550 | ||
| 10551 | In MESS: Supported. It also uses mmc3_irq. | |
| 10552 | ||
| 10553 | *************************************************************/ | |
| 10554 | ||
| 10555 | static WRITE8_HANDLER( bmc_hik4in1_m_w ) | |
| 10556 | { | |
| 10557 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10558 | LOG_MMC(("bmc_hik4in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10559 | ||
| 10560 | /* mid writes only work when WRAM is enabled. not sure if I should | |
| 10561 | change the condition to state->m_mmc_latch2==0x80 (i.e. what is the effect of | |
| 10562 | the read-only bit?) */ | |
| 10563 | if (state->m_mmc3_wram_protect & 0x80) | |
| 10564 | { | |
| 10565 | if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */ | |
| 10566 | { | |
| 10567 | state->m_mmc_prg_base = (data & 0xc0) >> 2; | |
| 10568 | state->m_mmc_prg_mask = 0x0f; | |
| 10569 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10570 | } | |
| 10571 | else | |
| 10572 | prg32(space->machine(), (data & 0x30) >> 4); | |
| 10573 | ||
| 10574 | state->m_mmc_chr_base = (data & 0xc0) << 1; | |
| 10575 | state->m_mmc_chr_mask = 0x7f; | |
| 10576 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10577 | } | |
| 10578 | } | |
| 10579 | ||
| 10580 | /************************************************************* | |
| 10581 | ||
| 10582 | BMC-BALLGAMES-11IN1 | |
| 10583 | ||
| 10584 | Known Boards: Unknown Multigame Bootleg Board | |
| 10585 | Games: 11 in 1 Ball Games | |
| 10586 | ||
| 10587 | iNES: mapper 51 | |
| 10588 | ||
| 10589 | In MESS: Partially Supported. | |
| 10590 | ||
| 10591 | *************************************************************/ | |
| 10592 | ||
| 10593 | static void bmc_ball11_set_banks( running_machine &machine ) | |
| 10594 | { | |
| 10595 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10596 | set_nt_mirroring(machine, (state->m_mmc_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10597 | ||
| 10598 | if (state->m_mmc_reg[0] & 0x01) | |
| 10599 | { | |
| 10600 | prg32(machine, state->m_mmc_reg[1]); | |
| 10601 | } | |
| 10602 | else | |
| 10603 | { | |
| 10604 | prg16_89ab(machine, (state->m_mmc_reg[1] << 1) | (state->m_mmc_reg[0] >> 1)); | |
| 10605 | prg16_cdef(machine, (state->m_mmc_reg[1] << 1) | 0x07); | |
| 10606 | } | |
| 10607 | } | |
| 10608 | ||
| 10609 | static WRITE8_HANDLER( bmc_ball11_m_w ) | |
| 10610 | { | |
| 10611 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10612 | ||
| 10613 | LOG_MMC(("bmc_ball11_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10614 | ||
| 10615 | state->m_mmc_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02); | |
| 10616 | bmc_ball11_set_banks(space->machine()); | |
| 10617 | } | |
| 10618 | ||
| 10619 | static WRITE8_HANDLER( bmc_ball11_w ) | |
| 10620 | { | |
| 10621 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10622 | ||
| 10623 | LOG_MMC(("bmc_ball11_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10624 | ||
| 10625 | switch (offset & 0x6000) | |
| 10626 | { | |
| 10627 | case 0x4000: // here we also update reg[0] upper bit | |
| 10628 | state->m_mmc_reg[0] = (state->m_mmc_reg[0] & 0x01) | ((data >> 3) & 0x02); | |
| 10629 | case 0x0000: | |
| 10630 | case 0x2000: | |
| 10631 | case 0x6000: | |
| 10632 | state->m_mmc_reg[1] = data & 0x0f; | |
| 10633 | bmc_ball11_set_banks(space->machine()); | |
| 10634 | break; | |
| 10635 | } | |
| 10636 | } | |
| 10637 | ||
| 10638 | /************************************************************* | |
| 10639 | ||
| 10640 | BMC-MARIOPARTY-7IN1 | |
| 10641 | ||
| 10642 | Known Boards: Unknown Multigame Bootleg Board | |
| 10643 | Games: Mario 7 in 1 | |
| 10644 | ||
| 10645 | MMC3 clone | |
| 10646 | ||
| 10647 | iNES: mapper 52 | |
| 10648 | ||
| 10649 | In MESS: Supported. | |
| 10650 | ||
| 10651 | *************************************************************/ | |
| 10652 | ||
| 10653 | static WRITE8_HANDLER( bmc_mario7in1_m_w ) | |
| 10654 | { | |
| 10655 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10656 | UINT8 map52_helper1, map52_helper2; | |
| 10657 | LOG_MMC(("bmc_mario7in1_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10658 | ||
| 10659 | /* mid writes only work when WRAM is enabled. not sure if I should | |
| 10660 | change the condition to state->m_mmc_latch2==0x80 (i.e. what is the effect of | |
| 10661 | the read-only bit?) and it only can happen once! */ | |
| 10662 | if ((state->m_mmc3_wram_protect & 0x80) && !state->m_map52_reg_written) | |
| 10663 | { | |
| 10664 | map52_helper1 = (data & 0x08); | |
| 10665 | map52_helper2 = (data & 0x40); | |
| 10666 | ||
| 10667 | state->m_mmc_prg_base = map52_helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); | |
| 10668 | state->m_mmc_prg_mask = map52_helper1 ? 0x0f : 0x1f; | |
| 10669 | state->m_mmc_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (map52_helper2 ? ((data & 0x10) << 3) : 0); | |
| 10670 | state->m_mmc_chr_mask = map52_helper2 ? 0x7f : 0xff; | |
| 10671 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10672 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10673 | ||
| 10674 | state->m_map52_reg_written = 1; | |
| 10675 | } | |
| 10676 | else | |
| 10677 | state->m_wram[offset] = data; | |
| 10678 | } | |
| 10679 | ||
| 10680 | /************************************************************* | |
| 10681 | ||
| 10682 | BMC-GOLDENCARD-6IN1 | |
| 10683 | ||
| 10684 | Known Boards: Unknown Bootleg Multigame Board | |
| 10685 | Games: Golden Card 6 in 1 | |
| 10686 | ||
| 10687 | MMC3 clone | |
| 10688 | ||
| 10689 | iNES: mapper 217 | |
| 10690 | ||
| 10691 | In MESS: Supported. | |
| 10692 | ||
| 10693 | *************************************************************/ | |
| 10694 | ||
| 10695 | // remove mask & base parameters! | |
| 10696 | static void bmc_gc6in1_set_prg( running_machine &machine, int prg_base, int prg_mask ) | |
| 10697 | { | |
| 10698 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10699 | state->m_mmc_prg_base = (state->m_mmc_reg[1] & 0x08) ? 0 : (state->m_mmc_reg[1] & 0x10); | |
| 10700 | state->m_mmc_prg_mask = (state->m_mmc_reg[1] & 0x08) ? 0x1f : 0x0f; | |
| 10701 | ||
| 10702 | state->m_mmc_prg_base |= ((state->m_mmc_reg[1] & 0x03) << 5); | |
| 10703 | ||
| 10704 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10705 | } | |
| 10706 | ||
| 10707 | static void bmc_gc6in1_set_chr( running_machine &machine, UINT8 chr ) | |
| 10708 | { | |
| 10709 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10710 | UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5; | |
| 10711 | int chr_base = (state->m_mmc_reg[1] & 0x08) ? 0x00 : ((state->m_mmc_reg[1] & 0x10) << 3); | |
| 10712 | int chr_mask = (state->m_mmc_reg[1] & 0x08) ? 0xff : 0x7f; | |
| 10713 | ||
| 10714 | chr_base |= ((state->m_mmc_reg[1] & 0x03) << 8); | |
| 10715 | ||
| 10716 | chr1_x(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); | |
| 10717 | chr1_x(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); | |
| 10718 | chr1_x(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); | |
| 10719 | chr1_x(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); | |
| 10720 | chr1_x(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr); | |
| 10721 | chr1_x(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr); | |
| 10722 | chr1_x(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr); | |
| 10723 | chr1_x(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr); | |
| 10724 | } | |
| 10725 | ||
| 10726 | static WRITE8_HANDLER( bmc_gc6in1_l_w ) | |
| 10727 | { | |
| 10728 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10729 | UINT8 bank; | |
| 10730 | LOG_MMC(("bmc_gc6in1_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10731 | offset += 0x100; | |
| 10732 | ||
| 10733 | if (offset == 0x1000) | |
| 10734 | { | |
| 10735 | state->m_mmc_reg[0] = data; | |
| 10736 | if (data & 0x80) | |
| 10737 | { | |
| 10738 | bank = (data & 0x0f) | ((state->m_mmc_reg[1] & 0x03) << 4); | |
| 10739 | prg16_89ab(space->machine(), bank); | |
| 10740 | prg16_cdef(space->machine(), bank); | |
| 10741 | } | |
| 10742 | else | |
| 10743 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10744 | } | |
| 10745 | else if (offset == 0x1001) | |
| 10746 | { | |
| 10747 | state->m_mmc_reg[1] = data; | |
| 10748 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10749 | } | |
| 10750 | else if (offset == 0x1007) | |
| 10751 | { | |
| 10752 | state->m_mmc_reg[2] = data; | |
| 10753 | } | |
| 10754 | } | |
| 10755 | ||
| 10756 | static WRITE8_HANDLER( bmc_gc6in1_w ) | |
| 10757 | { | |
| 10758 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10759 | UINT8 mmc_helper, cmd; | |
| 10760 | static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1}; | |
| 10761 | LOG_MMC(("bmc_gc6in1_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10762 | ||
| 10763 | if (!state->m_mmc_reg[2]) // in this case we act like MMC3, only with alt prg/chr handlers | |
| 10764 | { | |
| 10765 | switch (offset & 0x6001) | |
| 10766 | { | |
| 10767 | case 0x0000: | |
| 10768 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 10769 | state->m_mmc3_latch = data; | |
| 10770 | ||
| 10771 | /* Has PRG Mode changed? */ | |
| 10772 | if (mmc_helper & 0x40) | |
| 10773 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10774 | ||
| 10775 | /* Has CHR Mode changed? */ | |
| 10776 | if (mmc_helper & 0x80) | |
| 10777 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10778 | break; | |
| 10779 | ||
| 10780 | case 0x0001: | |
| 10781 | cmd = state->m_mmc3_latch & 0x07; | |
| 10782 | switch (cmd) | |
| 10783 | { | |
| 10784 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 10785 | case 2: case 3: case 4: case 5: | |
| 10786 | state->m_mmc_vrom_bank[cmd] = data; | |
| 10787 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10788 | break; | |
| 10789 | case 6: | |
| 10790 | case 7: | |
| 10791 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 10792 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10793 | break; | |
| 10794 | } | |
| 10795 | break; | |
| 10796 | ||
| 10797 | default: | |
| 10798 | txrom_w(space, offset, data); | |
| 10799 | break; | |
| 10800 | } | |
| 10801 | } | |
| 10802 | else | |
| 10803 | { | |
| 10804 | switch (offset & 0x6001) | |
| 10805 | { | |
| 10806 | case 0x0000: | |
| 10807 | txrom_w(space, 0x4000, data); | |
| 10808 | break; | |
| 10809 | ||
| 10810 | case 0x0001: | |
| 10811 | data = (data & 0xc0) | conv_table[data & 0x07]; | |
| 10812 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 10813 | state->m_mmc3_latch = data; | |
| 10814 | ||
| 10815 | /* Has PRG Mode changed? */ | |
| 10816 | if (mmc_helper & 0x40) | |
| 10817 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10818 | ||
| 10819 | /* Has CHR Mode changed? */ | |
| 10820 | if (mmc_helper & 0x80) | |
| 10821 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10822 | ||
| 10823 | state->m_mmc_reg[3] = 1; | |
| 10824 | break; | |
| 10825 | ||
| 10826 | case 0x2000: | |
| 10827 | cmd = state->m_mmc3_latch & 0x07; | |
| 10828 | if (state->m_mmc_reg[3]) | |
| 10829 | { | |
| 10830 | state->m_mmc_reg[3] = 0; | |
| 10831 | switch (cmd) | |
| 10832 | { | |
| 10833 | case 0: case 1: // these do not need to be separated: we take care of them in set_chr! | |
| 10834 | case 2: case 3: case 4: case 5: | |
| 10835 | state->m_mmc_vrom_bank[cmd] = data; | |
| 10836 | bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source); | |
| 10837 | break; | |
| 10838 | case 6: | |
| 10839 | case 7: | |
| 10840 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 10841 | bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10842 | break; | |
| 10843 | } | |
| 10844 | } | |
| 10845 | break; | |
| 10846 | ||
| 10847 | ||
| 10848 | case 0x2001: | |
| 10849 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10850 | break; | |
| 10851 | ||
| 10852 | default: | |
| 10853 | txrom_w(space, offset, data); | |
| 10854 | break; | |
| 10855 | } | |
| 10856 | } | |
| 10857 | } | |
| 10858 | ||
| 10859 | /************************************************************* | |
| 10860 | ||
| 10861 | BMC-FAMILY-4646B | |
| 10862 | ||
| 10863 | Known Boards: Unknown Multigame Bootleg Board (4646B) | |
| 10864 | Games: 2 in 1 - Family Kid & Aladdin 4 | |
| 10865 | ||
| 10866 | MMC3 clone | |
| 10867 | ||
| 10868 | iNES: mapper 134 | |
| 10869 | ||
| 10870 | In MESS: Supported. | |
| 10871 | ||
| 10872 | *************************************************************/ | |
| 10873 | ||
| 10874 | static WRITE8_HANDLER( bmc_family4646_m_w ) | |
| 10875 | { | |
| 10876 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10877 | LOG_MMC(("bmc_family4646_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10878 | ||
| 10879 | if (offset == 0x01) | |
| 10880 | { | |
| 10881 | state->m_mmc_prg_base = (data & 0x02) << 4; | |
| 10882 | state->m_mmc_prg_mask = 0x1f; | |
| 10883 | state->m_mmc_chr_base = (data & 0x20) << 3; | |
| 10884 | state->m_mmc_chr_mask = 0xff; | |
| 10885 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 10886 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 10887 | } | |
| 10888 | } | |
| 10889 | ||
| 10890 | /************************************************************* | |
| 10891 | ||
| 10892 | BMC-VT5201 | |
| 10893 | ||
| 10894 | *************************************************************/ | |
| 10895 | ||
| 10896 | static WRITE8_HANDLER( bmc_vt5201_w ) | |
| 10897 | { | |
| 10898 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10899 | LOG_MMC(("bmc_vt5201_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10900 | ||
| 10901 | state->m_mmc_latch1 = BIT(offset, 8); | |
| 10902 | ||
| 10903 | // not sure about this mirroring bit!! | |
| 10904 | // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian! | |
| 10905 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10906 | if (BIT(offset, 7)) | |
| 10907 | { | |
| 10908 | prg16_89ab(space->machine(), (offset >> 4) & 0x07); | |
| 10909 | prg16_cdef(space->machine(), (offset >> 4) & 0x07); | |
| 10910 | } | |
| 10911 | else | |
| 10912 | prg32(space->machine(), (offset >> 5) & 0x03); | |
| 10913 | chr8(space->machine(), offset, CHRROM); | |
| 10914 | } | |
| 10915 | ||
| 10916 | static READ8_HANDLER( bmc_vt5201_r ) | |
| 10917 | { | |
| 10918 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10919 | LOG_MMC(("bmc_vt5201_r, offset: %04x\n", offset)); | |
| 10920 | // state->m_mmc_dipsetting = input_port_read(space->machine(), "CARTDIPS"); | |
| 10921 | ||
| 10922 | if (state->m_mmc_latch1) | |
| 10923 | return state->m_mmc_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs) | |
| 10924 | else | |
| 10925 | return mmc_hi_access_rom(space->machine(), offset); | |
| 10926 | } | |
| 10927 | ||
| 10928 | /************************************************************* | |
| 10929 | ||
| 10930 | BMC-BS-5 | |
| 10931 | ||
| 10932 | Games: a few 4 in 1 multicarts | |
| 10933 | ||
| 10934 | *************************************************************/ | |
| 10935 | ||
| 10936 | static void bmc_bs5_update_banks( running_machine &machine ) | |
| 10937 | { | |
| 10938 | nes_state *state = machine.driver_data<nes_state>(); | |
| 10939 | ||
| 10940 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 10941 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 10942 | prg8_cd(machine, state->m_mmc_prg_bank[2]); | |
| 10943 | prg8_ef(machine, state->m_mmc_prg_bank[3]); | |
| 10944 | chr2_0(machine, state->m_mmc_vrom_bank[0], CHRROM); | |
| 10945 | chr2_2(machine, state->m_mmc_vrom_bank[1], CHRROM); | |
| 10946 | chr2_4(machine, state->m_mmc_vrom_bank[2], CHRROM); | |
| 10947 | chr2_6(machine, state->m_mmc_vrom_bank[3], CHRROM); | |
| 10948 | } | |
| 10949 | ||
| 10950 | static WRITE8_HANDLER( bmc_bs5_w ) | |
| 10951 | { | |
| 10952 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 10953 | UINT8 bs5_helper = (offset & 0xc00) >> 10; | |
| 10954 | LOG_MMC(("bmc_bs5_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10955 | // state->m_mmc_dipsetting = input_port_read(space->machine(), "CARTDIPS"); | |
| 10956 | ||
| 10957 | switch (offset & 0x7000) | |
| 10958 | { | |
| 10959 | case 0x0000: | |
| 10960 | state->m_mmc_vrom_bank[bs5_helper] = offset & 0x1f; | |
| 10961 | break; | |
| 10962 | case 0x2000: | |
| 10963 | if (BIT(offset, state->m_mmc_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs | |
| 10964 | state->m_mmc_prg_bank[bs5_helper] = offset & 0x0f; | |
| 10965 | break; | |
| 10966 | } | |
| 10967 | bmc_bs5_update_banks(space->machine()); | |
| 10968 | } | |
| 10969 | ||
| 10970 | /************************************************************* | |
| 10971 | ||
| 10972 | BMC-810544-C-A1 | |
| 10973 | ||
| 10974 | Games: 200-in-1 Elfland | |
| 10975 | ||
| 10976 | *************************************************************/ | |
| 10977 | ||
| 10978 | static WRITE8_HANDLER( bmc_810544_w ) | |
| 10979 | { | |
| 10980 | UINT8 bank = (offset >> 7); | |
| 10981 | LOG_MMC(("bmc_810544_w, offset: %04x, data: %02x\n", offset, data)); | |
| 10982 | ||
| 10983 | if (!BIT(offset, 6)) | |
| 10984 | { | |
| 10985 | prg16_89ab(space->machine(), (bank << 1) | BIT(offset, 5)); | |
| 10986 | prg16_cdef(space->machine(), (bank << 1) | BIT(offset, 5)); | |
| 10987 | } | |
| 10988 | else | |
| 10989 | prg32(space->machine(), bank); | |
| 10990 | ||
| 10991 | set_nt_mirroring(space->machine(), BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 10992 | ||
| 10993 | chr8(space->machine(), offset & 0x0f, CHRROM); | |
| 10994 | } | |
| 10995 | ||
| 10996 | /************************************************************* | |
| 10997 | ||
| 10998 | BMC-NTD-03 | |
| 10999 | ||
| 11000 | *************************************************************/ | |
| 11001 | ||
| 11002 | static WRITE8_HANDLER( bmc_ntd03_w ) | |
| 11003 | { | |
| 11004 | UINT8 pbank, cbank; | |
| 11005 | LOG_MMC(("bmc_ntd03_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11006 | ||
| 11007 | pbank = (offset >> 10) & 0x1e; | |
| 11008 | cbank = ((offset & 0x300) >> 5) | (offset & 0x07); | |
| 11009 | ||
| 11010 | if (BIT(offset, 7)) | |
| 11011 | { | |
| 11012 | prg16_89ab(space->machine(), pbank | BIT(offset, 6)); | |
| 11013 | prg16_cdef(space->machine(), pbank | BIT(offset, 6)); | |
| 11014 | } | |
| 11015 | else | |
| 11016 | prg32(space->machine(), pbank >> 1); | |
| 11017 | ||
| 11018 | set_nt_mirroring(space->machine(), BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 11019 | ||
| 11020 | chr8(space->machine(), cbank, CHRROM); | |
| 11021 | } | |
| 11022 | ||
| 11023 | /************************************************************* | |
| 11024 | ||
| 11025 | BMC-GHOSTBUSTERS63IN1 | |
| 11026 | ||
| 11027 | in MESS: only preliminar support | |
| 11028 | ||
| 11029 | *************************************************************/ | |
| 11030 | ||
| 11031 | static void bmc_gb63_update( running_machine &machine ) | |
| 11032 | { | |
| 11033 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11034 | ||
| 11035 | set_nt_mirroring(machine, BIT(state->m_mmc_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); | |
| 11036 | ||
| 11037 | if (BIT(state->m_mmc_reg[0], 5)) | |
| 11038 | { | |
| 11039 | prg16_89ab(machine, state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1! | |
| 11040 | prg16_cdef(machine, state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1! | |
| 11041 | } | |
| 11042 | else | |
| 11043 | prg32(machine, (state->m_mmc_reg[0] & 0x1f) >> 1); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1! | |
| 11044 | ||
| 11045 | if (BIT(state->m_mmc_reg[1], 2)) | |
| 11046 | chr8(machine, 0, CHRRAM); | |
| 11047 | // else | |
| 11048 | // chr8(machine, 0, CHRROM); | |
| 11049 | } | |
| 11050 | ||
| 11051 | static WRITE8_HANDLER( bmc_gb63_w ) | |
| 11052 | { | |
| 11053 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11054 | LOG_MMC(("bmc_gb63_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11055 | ||
| 11056 | state->m_mmc_reg[offset & 1] = data; | |
| 11057 | state->m_mmc_latch1 = BIT(state->m_mmc_reg[0], 7) | (BIT(state->m_mmc_reg[1], 0) << 1); | |
| 11058 | ||
| 11059 | } | |
| 11060 | ||
| 11061 | static READ8_HANDLER( bmc_gb63_r ) | |
| 11062 | { | |
| 11063 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11064 | LOG_MMC(("bmc_gb63_r, offset: %04x\n", offset)); | |
| 11065 | // state->m_mmc_dipsetting = input_port_read(space->machine(), "CARTDIPS"); | |
| 11066 | ||
| 11067 | if (state->m_mmc_latch1 == 1) | |
| 11068 | return 0xff; // open bus | |
| 11069 | else | |
| 11070 | return mmc_hi_access_rom(space->machine(), offset); | |
| 11071 | } | |
| 11072 | ||
| 11073 | /************************************************************* | |
| 11074 | ||
| 11075 | UNL-EDU2000 | |
| 11076 | ||
| 11077 | *************************************************************/ | |
| 11078 | ||
| 11079 | static WRITE8_HANDLER( edu2k_w ) | |
| 11080 | { | |
| 11081 | LOG_MMC(("edu2k_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11082 | ||
| 11083 | prg32(space->machine(), data & 0x1f); | |
| 11084 | wram_bank(space->machine(), (data & 0xc0) >> 6, NES_WRAM); | |
| 11085 | } | |
| 11086 | ||
| 11087 | /************************************************************* | |
| 11088 | ||
| 11089 | UNL-H2288 | |
| 11090 | ||
| 11091 | *************************************************************/ | |
| 11092 | ||
| 11093 | static void h2288_prg_cb( running_machine &machine, int start, int bank ) | |
| 11094 | { | |
| 11095 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11096 | ||
| 11097 | if (!(state->m_mmc_reg[0] & 0x40)) | |
| 11098 | prg8_x(machine, start, bank); | |
| 11099 | } | |
| 11100 | ||
| 11101 | static WRITE8_HANDLER( h2288_l_w ) | |
| 11102 | { | |
| 11103 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11104 | LOG_MMC(("h2288_l_w offset: %04x, data: %02x\n", offset, data)); | |
| 11105 | offset += 0x100; | |
| 11106 | ||
| 11107 | if (offset >= 0x1800) | |
| 11108 | { | |
| 11109 | state->m_mmc_reg[offset & 1] = data; | |
| 11110 | if (state->m_mmc_reg[0] & 0x40) | |
| 11111 | { | |
| 11112 | UINT8 helper1 = (state->m_mmc_reg[0] & 0x05) | ((state->m_mmc_reg[0] >> 2) & 0x0a); | |
| 11113 | UINT8 helper2 = BIT(state->m_mmc_reg[0], 1); | |
| 11114 | prg16_89ab(space->machine(), helper1 & ~helper2); | |
| 11115 | prg16_cdef(space->machine(), helper1 | helper2); | |
| 11116 | } | |
| 11117 | else | |
| 11118 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11119 | } | |
| 11120 | } | |
| 11121 | ||
| 11122 | static READ8_HANDLER( h2288_l_r ) | |
| 11123 | { | |
| 11124 | LOG_MMC(("h2288_l_r offset: %04x\n", offset)); | |
| 11125 | offset += 0x100; | |
| 11126 | ||
| 11127 | if (offset >= 0x1000) | |
| 11128 | { | |
| 11129 | int helper = offset >> 8; | |
| 11130 | if (offset & 1) | |
| 11131 | return helper | 0x01; | |
| 11132 | else | |
| 11133 | return helper ^ 0x01; | |
| 11134 | } | |
| 11135 | ||
| 11136 | return 0; | |
| 11137 | } | |
| 11138 | ||
| 11139 | static WRITE8_HANDLER( h2288_w ) | |
| 11140 | { | |
| 11141 | static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; | |
| 11142 | LOG_MMC(("h2288_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11143 | ||
| 11144 | switch (offset & 0x6001) | |
| 11145 | { | |
| 11146 | case 0x0000: | |
| 11147 | txrom_w(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07]); | |
| 11148 | break; | |
| 11149 | ||
| 11150 | default: | |
| 11151 | txrom_w(space, offset, data); | |
| 11152 | break; | |
| 11153 | } | |
| 11154 | } | |
| 11155 | ||
| 11156 | /************************************************************* | |
| 11157 | ||
| 11158 | UNL-SHJY3 | |
| 11159 | ||
| 11160 | *************************************************************/ | |
| 11161 | ||
| 11162 | /* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */ | |
| 11163 | static void shjy3_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 11164 | { | |
| 11165 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 11166 | if (state->m_IRQ_enable & 0x02) | |
| 11167 | { | |
| 11168 | if (state->m_IRQ_count == 0xff) | |
| 11169 | { | |
| 11170 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 11171 | state->m_IRQ_enable = state->m_IRQ_enable | ((state->m_IRQ_enable & 0x01) << 1); | |
| 11172 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 11173 | } | |
| 11174 | else | |
| 11175 | state->m_IRQ_count++; | |
| 11176 | } | |
| 11177 | } | |
| 11178 | ||
| 11179 | static void shjy3_update( running_machine &machine ) | |
| 11180 | { | |
| 11181 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11182 | int i; | |
| 11183 | ||
| 11184 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 11185 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 11186 | ||
| 11187 | for (i = 0; i < 8; i++) | |
| 11188 | { | |
| 11189 | UINT8 chr_bank = state->m_mmc_vrom_bank[i] | (state->m_mmc_extra_bank[i] << 4); | |
| 11190 | if (state->m_mmc_vrom_bank[i] == 0xc8) | |
| 11191 | { | |
| 11192 | state->m_mmc_latch1 = 0; | |
| 11193 | continue; | |
| 11194 | } | |
| 11195 | else if (state->m_mmc_vrom_bank[i] == 0x88) | |
| 11196 | { | |
| 11197 | state->m_mmc_latch1 = 1; | |
| 11198 | continue; | |
| 11199 | } | |
| 11200 | if ((state->m_mmc_vrom_bank[i] == 4 || state->m_mmc_vrom_bank[i] == 5) && !state->m_mmc_latch1) | |
| 11201 | chr1_x(machine, i, chr_bank & 1, CHRRAM); | |
| 11202 | else | |
| 11203 | chr1_x(machine, i, chr_bank, CHRROM); | |
| 11204 | } | |
| 11205 | } | |
| 11206 | ||
| 11207 | static WRITE8_HANDLER( shjy3_w ) | |
| 11208 | { | |
| 11209 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11210 | UINT8 mmc_helper, shift; | |
| 11211 | LOG_MMC(("shjy3_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11212 | ||
| 11213 | if (offset >= 0x3000 && offset <= 0x600c) | |
| 11214 | { | |
| 11215 | mmc_helper = ((offset & 8) | (offset >> 8)) >> 3; | |
| 11216 | mmc_helper += 2; | |
| 11217 | mmc_helper &= 7; | |
| 11218 | shift = offset & 4; | |
| 11219 | ||
| 11220 | state->m_mmc_vrom_bank[mmc_helper] = (state->m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift); | |
| 11221 | if (shift) | |
| 11222 | state->m_mmc_extra_bank[mmc_helper] = data >> 4; | |
| 11223 | } | |
| 11224 | else | |
| 11225 | { | |
| 11226 | switch (offset) | |
| 11227 | { | |
| 11228 | case 0x0010: | |
| 11229 | state->m_mmc_prg_bank[0] = data; | |
| 11230 | break; | |
| 11231 | case 0x2010: | |
| 11232 | state->m_mmc_prg_bank[1] = data; | |
| 11233 | break; | |
| 11234 | case 0x1400: | |
| 11235 | switch (data & 0x03) | |
| 11236 | { | |
| 11237 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 11238 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 11239 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 11240 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 11241 | } | |
| 11242 | break; | |
| 11243 | case 0x7000: | |
| 11244 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f); | |
| 11245 | break; | |
| 11246 | case 0x7004: | |
| 11247 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4); | |
| 11248 | break; | |
| 11249 | case 0x7008: | |
| 11250 | state->m_IRQ_enable = data & 0x03; | |
| 11251 | if (state->m_IRQ_enable & 0x02) | |
| 11252 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 11253 | break; | |
| 11254 | } | |
| 11255 | } | |
| 11256 | shjy3_update(space->machine()); | |
| 11257 | } | |
| 11258 | ||
| 11259 | /************************************************************* | |
| 11260 | ||
| 11261 | UNL-603-5052 | |
| 11262 | ||
| 11263 | MMC3 + protection access in 0x4020 - 0x7fff | |
| 11264 | ||
| 11265 | in MESS: Partial support | |
| 11266 | ||
| 11267 | *************************************************************/ | |
| 11268 | ||
| 11269 | WRITE8_HANDLER( unl_6035052_extra_w ) | |
| 11270 | { | |
| 11271 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11272 | LOG_MMC(("unl_6035052_extra_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11273 | state->m_mmc_latch1 = data & 0x03; | |
| 11274 | if (state->m_mmc_latch1 == 1) | |
| 11275 | state->m_mmc_latch1 = 2; | |
| 11276 | } | |
| 11277 | ||
| 11278 | READ8_HANDLER( unl_6035052_extra_r ) | |
| 11279 | { | |
| 11280 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11281 | LOG_MMC(("unl_6035052_extra_r, offset: %04x\n", offset)); | |
| 11282 | return state->m_mmc_latch1; | |
| 11283 | } | |
| 11284 | ||
| 11285 | ||
| 11286 | /************************************************************* | |
| 11287 | ||
| 11288 | BMC-POWERJOY | |
| 11289 | ||
| 11290 | *************************************************************/ | |
| 11291 | ||
| 11292 | static void pjoy84_prg_cb( running_machine &machine, int start, int bank ) | |
| 11293 | { | |
| 11294 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11295 | UINT8 flip = (state->m_mmc3_latch & 0x40) ? 2 : 0; | |
| 11296 | ||
| 11297 | if (!(state->m_mmc_reg[3] & 0x03)) | |
| 11298 | prg8_x(machine, start, bank); | |
| 11299 | else if (start == flip) | |
| 11300 | { | |
| 11301 | if ((state->m_mmc_reg[3] & 0x03) == 0x03) | |
| 11302 | prg32(machine, bank >> 2); | |
| 11303 | else | |
| 11304 | { | |
| 11305 | prg16_89ab(machine, bank >> 1); | |
| 11306 | prg16_cdef(machine, bank >> 1); | |
| 11307 | } | |
| 11308 | } | |
| 11309 | } | |
| 11310 | ||
| 11311 | static void pjoy84_chr_cb( running_machine &machine, int start, int bank, int source ) | |
| 11312 | { | |
| 11313 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11314 | ||
| 11315 | if (!(state->m_mmc_reg[3] & 0x10)) | |
| 11316 | chr1_x(machine, start, bank, source); | |
| 11317 | } | |
| 11318 | ||
| 11319 | INLINE void pjoy84_set_base_mask( running_machine &machine ) | |
| 11320 | { | |
| 11321 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11322 | ||
| 11323 | state->m_mmc_prg_base = ((state->m_mmc_reg[0] & (0x06 | BIT(state->m_mmc_reg[0], 6))) << 4) | | |
| 11324 | (BIT(state->m_mmc_reg[0], 4) << 7); | |
| 11325 | ||
| 11326 | state->m_mmc_chr_base = ((~state->m_mmc_reg[0] << 0) & 0x080 & state->m_mmc_reg[2]) | | |
| 11327 | ((state->m_mmc_reg[0] << 4) & 0x080 & state->m_mmc_reg[0]) | | |
| 11328 | ((state->m_mmc_reg[0] << 3) & 0x100) | | |
| 11329 | ((state->m_mmc_reg[0] << 5) & 0x200); | |
| 11330 | ||
| 11331 | state->m_mmc_prg_mask = BIT(state->m_mmc_reg[0], 6) ? 0x0f : 0x1f; | |
| 11332 | state->m_mmc_chr_mask = BIT(state->m_mmc_reg[0], 7) ? 0x7f : 0xff; | |
| 11333 | } | |
| 11334 | ||
| 11335 | static WRITE8_HANDLER( pjoy84_m_w ) | |
| 11336 | { | |
| 11337 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11338 | LOG_MMC(("pjoy84_m_w offset: %04x, data: %02x\n", offset, data)); | |
| 11339 | ||
| 11340 | switch (offset & 0x03) | |
| 11341 | { | |
| 11342 | case 0x00: | |
| 11343 | case 0x03: | |
| 11344 | if (state->m_mmc_reg[3] & 0x80) | |
| 11345 | return; // else we act as if offset & 3 = 1,2 | |
| 11346 | case 0x01: | |
| 11347 | case 0x02: | |
| 11348 | state->m_mmc_reg[offset & 0x03] = data; | |
| 11349 | pjoy84_set_base_mask(space->machine()); | |
| 11350 | if (state->m_mmc_reg[3] & 0x10) | |
| 11351 | chr8(space->machine(), (state->m_mmc_chr_base >> 3) | (state->m_mmc_reg[2] & 0x0f), state->m_mmc_chr_source); | |
| 11352 | else | |
| 11353 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11354 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11355 | break; | |
| 11356 | } | |
| 11357 | } | |
| 11358 | ||
| 11359 | /************************************************************* | |
| 11360 | ||
| 11361 | SOMERI TEAM | |
| 11362 | ||
| 11363 | iNES: mapper 116 | |
| 11364 | ||
| 11365 | Emulation note about regs in MESS: currently, | |
| 11366 | - state->m_mmc_cmd1 represent the board mode | |
| 11367 | - state->m_mmc_reg[n] for n=0,1,2,3 represent the MMC1 regs | |
| 11368 | - state->m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks | |
| 11369 | - state->m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks | |
| 11370 | - state->m_mmc_prg_bank[n] for n=4,5 represent the VRC2 PRG banks | |
| 11371 | - state->m_mmc_vrom_bank[n] for n=6,...,13 represent the VRC2 CHR banks | |
| 11372 | ||
| 11373 | In MESS: Preliminary support | |
| 11374 | ||
| 11375 | *************************************************************/ | |
| 11376 | ||
| 11377 | // MMC1 Mode emulation | |
| 11378 | static void someri_mmc1_set_prg( running_machine &machine ) | |
| 11379 | { | |
| 11380 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11381 | UINT8 prg_mode = state->m_mmc_reg[0] & 0x0c; | |
| 11382 | UINT8 prg_offset = state->m_mmc_reg[1] & 0x10; | |
| 11383 | ||
| 11384 | switch (prg_mode) | |
| 11385 | { | |
| 11386 | case 0x00: | |
| 11387 | case 0x04: | |
| 11388 | prg32(machine, (prg_offset + state->m_mmc_reg[3]) >> 1); | |
| 11389 | break; | |
| 11390 | case 0x08: | |
| 11391 | prg16_89ab(machine, prg_offset + 0); | |
| 11392 | prg16_cdef(machine, prg_offset + state->m_mmc_reg[3]); | |
| 11393 | break; | |
| 11394 | case 0x0c: | |
| 11395 | prg16_89ab(machine, prg_offset + state->m_mmc_reg[3]); | |
| 11396 | prg16_cdef(machine, prg_offset + 0x0f); | |
| 11397 | break; | |
| 11398 | } | |
| 11399 | } | |
| 11400 | ||
| 11401 | static void someri_mmc1_set_chr( running_machine &machine ) | |
| 11402 | { | |
| 11403 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11404 | UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4); | |
| 11405 | ||
| 11406 | if (chr_mode) | |
| 11407 | { | |
| 11408 | chr4_0(machine, state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source); | |
| 11409 | chr4_4(machine, state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source); | |
| 11410 | } | |
| 11411 | else | |
| 11412 | chr8(machine, (state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source); | |
| 11413 | } | |
| 11414 | ||
| 11415 | static WRITE8_HANDLER( someri_mmc1_w ) | |
| 11416 | { | |
| 11417 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11418 | ||
| 11419 | assert(state->m_mmc_cmd1 == 2); | |
| 11420 | ||
| 11421 | if (data & 0x80) | |
| 11422 | { | |
| 11423 | state->m_mmc1_count = 0; | |
| 11424 | state->m_mmc1_latch = 0; | |
| 11425 | ||
| 11426 | state->m_mmc_reg[0] |= 0x0c; | |
| 11427 | someri_mmc1_set_prg(space->machine()); | |
| 11428 | return; | |
| 11429 | } | |
| 11430 | ||
| 11431 | if (state->m_mmc1_count < 5) | |
| 11432 | { | |
| 11433 | if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0; | |
| 11434 | state->m_mmc1_latch >>= 1; | |
| 11435 | state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; | |
| 11436 | state->m_mmc1_count++; | |
| 11437 | } | |
| 11438 | ||
| 11439 | if (state->m_mmc1_count == 5) | |
| 11440 | { | |
| 11441 | switch (offset & 0x6000) | |
| 11442 | { | |
| 11443 | case 0x0000: | |
| 11444 | state->m_mmc_reg[0] = state->m_mmc1_latch; | |
| 11445 | switch (state->m_mmc_reg[0] & 0x03) | |
| 11446 | { | |
| 11447 | case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 11448 | case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 11449 | case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 11450 | case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 11451 | } | |
| 11452 | someri_mmc1_set_chr(space->machine()); | |
| 11453 | someri_mmc1_set_prg(space->machine()); | |
| 11454 | break; | |
| 11455 | case 0x2000: | |
| 11456 | state->m_mmc_reg[1] = state->m_mmc1_latch; | |
| 11457 | someri_mmc1_set_chr(space->machine()); | |
| 11458 | someri_mmc1_set_prg(space->machine()); | |
| 11459 | break; | |
| 11460 | case 0x4000: | |
| 11461 | state->m_mmc_reg[2] = state->m_mmc1_latch; | |
| 11462 | someri_mmc1_set_chr(space->machine()); | |
| 11463 | break; | |
| 11464 | case 0x6000: | |
| 11465 | state->m_mmc_reg[3] = state->m_mmc1_latch; | |
| 11466 | someri_mmc1_set_prg(space->machine()); | |
| 11467 | break; | |
| 11468 | } | |
| 11469 | ||
| 11470 | state->m_mmc1_count = 0; | |
| 11471 | } | |
| 11472 | } | |
| 11473 | ||
| 11474 | // MMC3 Mode emulation | |
| 11475 | static WRITE8_HANDLER( someri_mmc3_w ) | |
| 11476 | { | |
| 11477 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11478 | UINT8 mmc_helper, cmd; | |
| 11479 | ||
| 11480 | assert(state->m_mmc_cmd1 == 1); | |
| 11481 | switch (offset & 0x6001) | |
| 11482 | { | |
| 11483 | case 0x0000: | |
| 11484 | mmc_helper = state->m_mmc3_latch ^ data; | |
| 11485 | state->m_mmc3_latch = data; | |
| 11486 | ||
| 11487 | if (mmc_helper & 0x40) | |
| 11488 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11489 | ||
| 11490 | if (mmc_helper & 0x80) | |
| 11491 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11492 | break; | |
| 11493 | ||
| 11494 | case 0x0001: | |
| 11495 | cmd = state->m_mmc3_latch & 0x07; | |
| 11496 | switch (cmd) | |
| 11497 | { | |
| 11498 | case 0: case 1: | |
| 11499 | case 2: case 3: case 4: case 5: | |
| 11500 | state->m_mmc_vrom_bank[cmd] = data; | |
| 11501 | mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11502 | break; | |
| 11503 | case 6: | |
| 11504 | case 7: | |
| 11505 | state->m_mmc_prg_bank[cmd - 6] = data; | |
| 11506 | mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11507 | break; | |
| 11508 | } | |
| 11509 | break; | |
| 11510 | ||
| 11511 | case 0x2000: | |
| 11512 | set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 11513 | break; | |
| 11514 | case 0x2001: break; | |
| 11515 | case 0x4000: state->m_IRQ_count_latch = data; break; | |
| 11516 | case 0x4001: state->m_IRQ_count = 0; break; | |
| 11517 | case 0x6000: state->m_IRQ_enable = 0; break; | |
| 11518 | case 0x6001: state->m_IRQ_enable = 1; break; | |
| 11519 | } | |
| 11520 | } | |
| 11521 | ||
| 11522 | // VRC2 Mode emulation | |
| 11523 | static WRITE8_HANDLER( someri_vrc2_w ) | |
| 11524 | { | |
| 11525 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11526 | UINT8 bank, shift; | |
| 11527 | ||
| 11528 | assert(state->m_mmc_cmd1 == 0); | |
| 11529 | ||
| 11530 | if (offset < 0x1000) | |
| 11531 | { | |
| 11532 | state->m_mmc_prg_bank[4] = data; | |
| 11533 | prg8_89(space->machine(), state->m_mmc_prg_bank[4]); | |
| 11534 | } | |
| 11535 | else if (offset < 0x2000) | |
| 11536 | { | |
| 11537 | switch (data & 0x03) | |
| 11538 | { | |
| 11539 | case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break; | |
| 11540 | case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break; | |
| 11541 | case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break; | |
| 11542 | case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break; | |
| 11543 | } | |
| 11544 | } | |
| 11545 | else if (offset < 0x3000) | |
| 11546 | { | |
| 11547 | state->m_mmc_prg_bank[5] = data; | |
| 11548 | prg8_ab(space->machine(), state->m_mmc_prg_bank[5]); | |
| 11549 | } | |
| 11550 | else if (offset < 0x7000) | |
| 11551 | { | |
| 11552 | bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); | |
| 11553 | shift = BIT(offset, 2) * 4; | |
| 11554 | data = (data & 0x0f) << shift; | |
| 11555 | state->m_mmc_vrom_bank[6 + bank] = data | state->m_mmc_chr_base; | |
| 11556 | chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[6 + bank], CHRROM); | |
| 11557 | } | |
| 11558 | } | |
| 11559 | ||
| 11560 | static WRITE8_HANDLER( someri_w ) | |
| 11561 | { | |
| 11562 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11563 | LOG_MMC(("someri_w mode %d, offset: %04x, data: %02x\n", state->m_mmc_cmd1, offset, data)); | |
| 11564 | ||
| 11565 | switch (state->m_mmc_cmd1) | |
| 11566 | { | |
| 11567 | case 0x00: someri_vrc2_w(space, offset, data); break; | |
| 11568 | case 0x01: someri_mmc3_w(space, offset, data); break; | |
| 11569 | case 0x02: someri_mmc1_w(space, offset, data); break; | |
| 11570 | } | |
| 11571 | } | |
| 11572 | ||
| 11573 | static void someri_mode_update( running_machine &machine ) | |
| 11574 | { | |
| 11575 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11576 | int i; | |
| 11577 | ||
| 11578 | switch (state->m_mmc_cmd1) | |
| 11579 | { | |
| 11580 | case 0x00: | |
| 11581 | prg8_89(machine, state->m_mmc_prg_bank[4]); | |
| 11582 | prg8_ab(machine, state->m_mmc_prg_bank[5]); | |
| 11583 | for (i = 0; i < 8; i++) | |
| 11584 | chr1_x(machine, i, state->m_mmc_vrom_bank[6 + i], CHRROM); | |
| 11585 | break; | |
| 11586 | case 0x01: | |
| 11587 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 11588 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 11589 | break; | |
| 11590 | case 0x02: | |
| 11591 | someri_mmc1_set_prg(machine); | |
| 11592 | someri_mmc1_set_chr(machine); | |
| 11593 | break; | |
| 11594 | } | |
| 11595 | } | |
| 11596 | ||
| 11597 | static WRITE8_HANDLER( someri_l_w ) | |
| 11598 | { | |
| 11599 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11600 | LOG_MMC(("someri_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11601 | offset += 0x100; | |
| 11602 | ||
| 11603 | if (offset & 0x100) | |
| 11604 | { | |
| 11605 | state->m_mmc_cmd1 = data & 0x03; | |
| 11606 | state->m_mmc_chr_base = ((state->m_mmc_cmd1 & 0x04) << 6); | |
| 11607 | if (state->m_mmc_cmd1 != 1) | |
| 11608 | state->m_IRQ_enable = 0; | |
| 11609 | someri_mode_update(space->machine()); | |
| 11610 | } | |
| 11611 | } | |
| 11612 | ||
| 11613 | #ifdef UNUSED_FUNCTION | |
| 11614 | /************************************************************* | |
| 11615 | ||
| 11616 | FUJIYA Board - mapper 170 according to NEStopia | |
| 11617 | ||
| 11618 | Which games are supposed to use this? | |
| 11619 | ||
| 11620 | *************************************************************/ | |
| 11621 | ||
| 11622 | static WRITE8_HANDLER( fujiya_m_w ) | |
| 11623 | { | |
| 11624 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11625 | LOG_MMC(("fujiya_m_w, offset: %04x, data: %02x\n", offset, data)); | |
| 11626 | offset += 0x6000; | |
| 11627 | ||
| 11628 | if (offset == 0x6502 || offset == 0x7000) | |
| 11629 | state->m_mmc_latch1 = (data & 0x40) << 1; | |
| 11630 | } | |
| 11631 | ||
| 11632 | static READ8_HANDLER( fujiya_m_r ) | |
| 11633 | { | |
| 11634 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 11635 | LOG_MMC(("fujiya_m_r, offset: %04x\n", offset)); | |
| 11636 | offset += 0x6000; | |
| 11637 | ||
| 11638 | if (offset == 0x7001 || offset == 0x7777) | |
| 11639 | return state->m_mmc_latch1 | ((offset >> 8) & 0x7f); | |
| 11640 | ||
| 11641 | return 0; | |
| 11642 | } | |
| 11643 | #endif | |
| 11644 | ||
| 11645 | ||
| 11646 | ||
| 11647 | ||
| 11648 | typedef void (*nes_ppu_latch)(device_t *device, offs_t offset); | |
| 11649 | ||
| 11650 | struct nes_memory_accessor | |
| 11651 | { | |
| 11652 | write8_space_func write; | |
| 11653 | const char *write_name; | |
| 11654 | read8_space_func read; | |
| 11655 | const char *read_name; | |
| 11656 | }; | |
| 11657 | ||
| 11658 | typedef struct _nes_pcb_intf nes_pcb_intf; | |
| 11659 | struct _nes_pcb_intf | |
| 11660 | { | |
| 11661 | int mmc_pcb; | |
| 11662 | nes_memory_accessor mmc_l; /* $4100-$5fff read/write routines */ | |
| 11663 | nes_memory_accessor mmc_m; /* $6000-$7fff read/write routines */ | |
| 11664 | nes_memory_accessor mmc_h; /* $8000-$ffff read/write routines */ | |
| 11665 | nes_ppu_latch mmc_ppu_latch; | |
| 11666 | ppu2c0x_scanline_cb mmc_scanline; | |
| 11667 | ppu2c0x_hblank_cb mmc_hblank; | |
| 11668 | }; | |
| 11669 | ||
| 11670 | #define NES_NOACCESS \ | |
| 11671 | {FUNC_NULL, FUNC_NULL} | |
| 11672 | ||
| 11673 | #define NES_READONLY(a) \ | |
| 11674 | {FUNC_NULL, FUNC(a)} | |
| 11675 | ||
| 11676 | #define NES_WRITEONLY(a) \ | |
| 11677 | {FUNC(a), FUNC_NULL} | |
| 11678 | ||
| 11679 | static WRITE8_HANDLER( dummy_l_w ) | |
| 11680 | { | |
| 11681 | logerror("write access, offset: %04x, data: %02x\n", offset + 0x4100, data); | |
| 11682 | } | |
| 11683 | ||
| 11684 | static WRITE8_HANDLER( dummy_m_w ) | |
| 11685 | { | |
| 11686 | logerror("write access, offset: %04x, data: %02x\n", offset + 0x6000, data); | |
| 11687 | } | |
| 11688 | ||
| 11689 | static WRITE8_HANDLER( dummy_w ) | |
| 11690 | { | |
| 11691 | logerror("write access, offset: %04x, data: %02x\n", offset + 0x8000, data); | |
| 11692 | } | |
| 11693 | ||
| 11694 | static READ8_HANDLER( dummy_l_r ) | |
| 11695 | { | |
| 11696 | logerror("read access, offset: %04x\n", offset + 0x4100); | |
| 11697 | return 0x00; | |
| 11698 | } | |
| 11699 | ||
| 11700 | static READ8_HANDLER( dummy_m_r ) | |
| 11701 | { | |
| 11702 | logerror("read access, offset: %04x\n", offset + 0x6000); | |
| 11703 | return 0x00; | |
| 11704 | } | |
| 11705 | ||
| 11706 | static READ8_HANDLER( dummy_r ) | |
| 11707 | { | |
| 11708 | logerror("read access, offset: %04x\n", offset + 0x8000); | |
| 11709 | return 0x00; | |
| 11710 | } | |
| 11711 | ||
| 11712 | static const nes_pcb_intf nes_intf_list[] = | |
| 11713 | { | |
| 11714 | { STD_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11715 | { HVC_FAMBASIC, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11716 | { GG_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11717 | { STD_UXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(uxrom_w), NULL, NULL, NULL }, | |
| 11718 | { STD_UN1ROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(un1rom_w), NULL, NULL, NULL }, | |
| 11719 | { STD_CPROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cprom_w), NULL, NULL, NULL }, | |
| 11720 | { STD_CNROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cnrom_w), NULL, NULL, NULL }, | |
| 11721 | { BANDAI_PT554, NES_NOACCESS, NES_WRITEONLY(bandai_pt554_m_w), NES_WRITEONLY(cnrom_w), NULL, NULL, NULL }, | |
| 11722 | { STD_AXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(axrom_w), NULL, NULL, NULL }, | |
| 11723 | { STD_PXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(pxrom_w), mmc2_latch, NULL, NULL }, | |
| 11724 | { STD_FXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(fxrom_w), mmc2_latch, NULL, NULL }, | |
| 11725 | { STD_BXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bxrom_w), NULL, NULL, NULL }, | |
| 11726 | { STD_GXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gxrom_w), NULL, NULL, NULL }, | |
| 11727 | { STD_MXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gxrom_w), NULL, NULL, NULL }, | |
| 11728 | { STD_NXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntbrom_w), NULL, NULL, NULL }, | |
| 11729 | { SUNSOFT_DCS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntbrom_w), NULL, NULL, NULL }, | |
| 11730 | { STD_JXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jxrom_w), NULL, NULL, jxrom_irq }, | |
| 11731 | { STD_SXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11732 | { STD_SOROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11733 | { STD_SXROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11734 | { STD_SOROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL }, | |
| 11735 | { STD_TXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11736 | { STD_TVROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11737 | { STD_TKROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11738 | { STD_HKROM, NES_NOACCESS, {FUNC(hkrom_m_w), FUNC(hkrom_m_r)}, NES_WRITEONLY(hkrom_w), NULL, NULL, mmc3_irq }, | |
| 11739 | { STD_TQROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tqrom_w), NULL, NULL, mmc3_irq }, | |
| 11740 | { STD_TXSROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txsrom_w), NULL, NULL, mmc3_irq }, | |
| 11741 | { STD_DXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL }, | |
| 11742 | { STD_DRROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL }, | |
| 11743 | { NAMCOT_34X3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL }, | |
| 11744 | { NAMCOT_3425, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3425_w), NULL, NULL, NULL }, | |
| 11745 | { NAMCOT_3446, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3446_w), NULL, NULL, NULL }, | |
| 11746 | { NAMCOT_3453, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3453_w), NULL, NULL, NULL }, | |
| 11747 | { STD_EXROM, {FUNC(exrom_l_w), FUNC(exrom_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, mmc5_irq }, | |
| 11748 | { NES_QJ, NES_NOACCESS, NES_WRITEONLY(qj_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11749 | { PAL_ZZ, NES_NOACCESS, NES_WRITEONLY(zz_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11750 | { UXROM_CC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(uxrom_cc_w), NULL, NULL, NULL }, | |
| 11751 | // | |
| 11752 | { DIS_74X139X74, NES_NOACCESS, NES_WRITEONLY(dis_74x139x74_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11753 | { DIS_74X377, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dis_74x377_w), NULL, NULL, NULL }, | |
| 11754 | { DIS_74X161X161X32, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dis_74x161x161x32_w), NULL, NULL, NULL }, | |
| 11755 | { DIS_74X161X138, NES_NOACCESS, NES_WRITEONLY(dis_74x161x138_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11756 | { BANDAI_LZ93, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11757 | { BANDAI_LZ93EX, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11758 | { BANDAI_FCG, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11759 | { BANDAI_DATACH, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq }, | |
| 11760 | { BANDAI_JUMP2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(fjump2_w), NULL, NULL, bandai_lz_irq }, | |
| 11761 | { BANDAI_KARAOKE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bandai_ks_w), NULL, NULL, NULL }, | |
| 11762 | { BANDAI_OEKAKIDS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bandai_ok_w), NULL, NULL, NULL }, | |
| 11763 | { IREM_G101, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(g101_w), NULL, NULL, NULL }, | |
| 11764 | { IREM_LROG017, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(lrog017_w), NULL, NULL, NULL }, | |
| 11765 | { IREM_H3001, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(h3001_w), NULL, NULL, h3001_irq }, | |
| 11766 | { IREM_TAM_S1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tam_s1_w), NULL, NULL, NULL }, | |
| 11767 | { IREM_HOLYDIV, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(irem_hd_w), NULL, NULL, NULL }, | |
| 11768 | { JALECO_SS88006, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ss88006_w), NULL, NULL, ss88006_irq }, | |
| 11769 | { JALECO_JF11, NES_NOACCESS, NES_WRITEONLY(jf11_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11770 | { JALECO_JF13, NES_NOACCESS, NES_WRITEONLY(jf13_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11771 | { JALECO_JF16, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf16_w), NULL, NULL, NULL }, | |
| 11772 | { JALECO_JF17, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf17_w), NULL, NULL, NULL }, | |
| 11773 | { JALECO_JF19, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf19_w), NULL, NULL, NULL }, | |
| 11774 | { KONAMI_VRC1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc1_w), NULL, NULL, NULL }, | |
| 11775 | { KONAMI_VRC2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc2_w), NULL, NULL, NULL }, | |
| 11776 | { KONAMI_VRC3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc3_w), NULL, NULL, konami_irq }, | |
| 11777 | { KONAMI_VRC4, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc4_w), NULL, NULL, konami_irq }, | |
| 11778 | { KONAMI_VRC6, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc6_w), NULL, NULL, konami_irq }, | |
| 11779 | { KONAMI_VRC7, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc7_w), NULL, NULL, konami_irq }, | |
| 11780 | { NAMCOT_163, {FUNC(namcot163_l_w), FUNC(namcot163_l_r) }, NES_NOACCESS, NES_WRITEONLY(namcot163_w), NULL, NULL, namcot_irq }, | |
| 11781 | { SUNSOFT_1, NES_NOACCESS, NES_WRITEONLY(sunsoft1_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11782 | { SUNSOFT_2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sunsoft2_w), NULL, NULL, NULL }, | |
| 11783 | { SUNSOFT_3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sunsoft3_w), NULL, NULL, sunsoft3_irq }, | |
| 11784 | { TAITO_TC0190FMC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tc0190fmc_w), NULL, NULL, NULL }, | |
| 11785 | { TAITO_TC0190FMCP, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tc0190fmc_p16_w), NULL, NULL, mmc3_irq }, | |
| 11786 | { TAITO_X1_005, NES_NOACCESS, {FUNC(x1005_m_w), FUNC(x1005_m_r)}, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11787 | { TAITO_X1_005_A, NES_NOACCESS, {FUNC(x1005a_m_w), FUNC(x1005_m_r)}, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11788 | { TAITO_X1_017, NES_NOACCESS, {FUNC(x1017_m_w), FUNC(x1017_m_r)}, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11789 | // | |
| 11790 | { AGCI_50282, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(agci_50282_w), NULL, NULL, NULL }, | |
| 11791 | { ACTENT_ACT52, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ae_act52_w), NULL, NULL, NULL }, | |
| 11792 | { AVE_NINA01, NES_NOACCESS, NES_WRITEONLY(nina01_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11793 | { AVE_NINA06, NES_WRITEONLY(nina06_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11794 | { CNE_DECATHLON, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cne_decathl_w), NULL, NULL, NULL }, | |
| 11795 | { CNE_FSB, NES_NOACCESS, NES_WRITEONLY(cne_fsb_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11796 | { CNE_SHLZ, NES_WRITEONLY(cne_shlz_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11797 | { CALTRON_6IN1, NES_NOACCESS, NES_WRITEONLY(caltron6in1_m_w), NES_WRITEONLY(caltron6in1_w), NULL, NULL, NULL }, | |
| 11798 | { CAMERICA_BF9093, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bf9093_w), NULL, NULL, NULL }, | |
| 11799 | { CAMERICA_BF9097, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bf9093_w), NULL, NULL, NULL }, | |
| 11800 | { CAMERICA_BF9096, NES_NOACCESS, NES_WRITEONLY(bf9096_w), NES_WRITEONLY(bf9096_w), NULL, NULL, NULL }, | |
| 11801 | { CAMERICA_GOLDENFIVE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(golden5_w), NULL, NULL, NULL }, | |
| 11802 | { CONY_BOARD, {FUNC(cony_l_w), FUNC(cony_l_r)}, NES_NOACCESS, NES_WRITEONLY(cony_w), NULL, NULL, sunsoft3_irq }, | |
| 11803 | { DREAMTECH_BOARD, NES_WRITEONLY(dreamtech_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11804 | { FUTUREMEDIA_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(futuremedia_w), NULL, NULL, futuremedia_irq }, | |
| 11805 | { FUKUTAKE_BOARD, {FUNC(fukutake_l_w), FUNC(fukutake_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11806 | { GOUDER_37017, {FUNC(gouder_sf4_l_w), FUNC(gouder_sf4_l_r)}, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11807 | { HENGEDIANZI_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(henggedianzi_w), NULL, NULL, NULL }, | |
| 11808 | { HENGEDIANZI_XJZB, NES_WRITEONLY(heng_xjzb_l_w), NES_NOACCESS, NES_WRITEONLY(heng_xjzb_w), NULL, NULL, NULL }, | |
| 11809 | { HES6IN1_BOARD, NES_WRITEONLY(hes6in1_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11810 | { HES_BOARD, NES_WRITEONLY(hes_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11811 | { HOSENKAN_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(hosenkan_w), NULL, NULL, mmc3_irq }, | |
| 11812 | { KAISER_KS7058, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7058_w), NULL, NULL, NULL }, | |
| 11813 | { KAISER_KS7022, NES_NOACCESS, NES_NOACCESS, {FUNC(ks7022_w), FUNC(ks7022_r)}, NULL, NULL, NULL }, | |
| 11814 | { KAISER_KS7032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7032_w), NULL, NULL, ks7032_irq }, | |
| 11815 | { KAISER_KS202, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks202_w), NULL, NULL, ks7032_irq }, | |
| 11816 | { KAISER_KS7017, NES_WRITEONLY(ks7017_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, mmc_fds_irq }, | |
| 11817 | { KAY_PANDAPRINCE, {FUNC(kay_pp_l_w), FUNC(kay_pp_l_r)}, NES_NOACCESS, NES_WRITEONLY(kay_pp_w), NULL, NULL, mmc3_irq }, | |
| 11818 | { KASING_BOARD, NES_NOACCESS, NES_WRITEONLY(kasing_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11819 | { SACHEN_74LS374, {FUNC(sachen_74x374_l_w), FUNC(sachen_74x374_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11820 | { SACHEN_74LS374_A, NES_WRITEONLY(sachen_74x374a_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11821 | { SACHEN_8259A, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11822 | { SACHEN_8259B, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11823 | { SACHEN_8259C, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11824 | { SACHEN_8259D, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11825 | { SACHEN_SA009, NES_WRITEONLY(sa009_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11826 | { SACHEN_SA0036, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sa0036_w), NULL, NULL, NULL }, | |
| 11827 | { SACHEN_SA0037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sa0037_w), NULL, NULL, NULL }, | |
| 11828 | { SACHEN_SA72007, NES_WRITEONLY(sa72007_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11829 | { SACHEN_SA72008, NES_WRITEONLY(sa72008_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11830 | { SACHEN_TCA01, NES_READONLY(tca01_l_r), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11831 | { SACHEN_TCU01, NES_WRITEONLY(tcu01_l_w), NES_WRITEONLY(tcu01_m_w), NES_WRITEONLY(tcu01_w), NULL, NULL, NULL }, | |
| 11832 | { SACHEN_TCU02, {FUNC(tcu02_l_w), FUNC(tcu02_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11833 | { SUBOR_TYPE0, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(subor0_w), NULL, NULL, NULL }, | |
| 11834 | { SUBOR_TYPE1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(subor1_w), NULL, NULL, NULL }, | |
| 11835 | { MAGICSERIES_MD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(magics_md_w), NULL, NULL, NULL }, | |
| 11836 | { NANJING_BOARD, {FUNC(nanjing_l_w), FUNC(nanjing_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, nanjing_irq }, | |
| 11837 | { NITRA_TDA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nitra_w), NULL, NULL, mmc3_irq }, | |
| 11838 | { NTDEC_ASDER, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntdec_asder_w), NULL, NULL, NULL }, | |
| 11839 | { NTDEC_FIGHTINGHERO, NES_NOACCESS, NES_WRITEONLY(ntdec_fh_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11840 | { OPENCORP_DAOU306, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(daou306_w), NULL, NULL, NULL }, | |
| 11841 | { RCM_GS2015, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gs2015_w), NULL, NULL, NULL }, | |
| 11842 | { RCM_TETRISFAMILY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(rcm_tf_w), NULL, NULL, NULL }, | |
| 11843 | { REXSOFT_DBZ5, {FUNC(rex_dbz_l_w), FUNC(rex_dbz_l_r)}, NES_READONLY(rex_dbz_l_r), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11844 | { REXSOFT_SL1632, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(rex_sl1632_w), NULL, NULL, mmc3_irq }, | |
| 11845 | { RUMBLESTATION_BOARD, NES_NOACCESS, NES_WRITEONLY(rumblestation_m_w), NES_WRITEONLY(rumblestation_w), NULL, NULL, NULL }, | |
| 11846 | { SOMERI_SL12, NES_WRITEONLY(someri_l_w), NES_NOACCESS, NES_WRITEONLY(someri_w), NULL, NULL, mmc3_irq }, | |
| 11847 | { SUPERGAME_BOOGERMAN, NES_WRITEONLY(sgame_boog_l_w), NES_WRITEONLY(sgame_boog_m_w), NES_WRITEONLY(sgame_boog_w), NULL, NULL, mmc3_irq }, | |
| 11848 | { SUPERGAME_LIONKING, NES_NOACCESS, NES_WRITEONLY(sgame_lion_m_w), NES_WRITEONLY(sgame_lion_w), NULL, NULL, mmc3_irq }, | |
| 11849 | { TENGEN_800008, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800008_w), NULL, NULL, NULL }, | |
| 11850 | { TENGEN_800032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800032_w), NULL, NULL, tengen_800032_irq }, | |
| 11851 | { TENGEN_800037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800037_w), NULL, NULL, tengen_800032_irq }, | |
| 11852 | { TXC_22211A, {FUNC(txc_22211_l_w), FUNC(txc_22211_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211_w), NULL, NULL, NULL }, | |
| 11853 | { TXC_22211B, {FUNC(txc_22211_l_w), FUNC(txc_22211_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211b_w), NULL, NULL, NULL }, | |
| 11854 | { TXC_22211C, {FUNC(txc_22211_l_w), FUNC(txc_22211c_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211_w), NULL, NULL, NULL }, | |
| 11855 | { TXC_TW, NES_WRITEONLY(txc_tw_l_w), NES_WRITEONLY(txc_tw_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11856 | { TXC_STRIKEWOLF, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txc_strikewolf_w), NULL, NULL, NULL }, | |
| 11857 | { TXC_MXMDHTWO, NES_READONLY(txc_mxmdhtwo_l_r), NES_NOACCESS, NES_WRITEONLY(txc_mxmdhtwo_w), NULL, NULL, NULL }, | |
| 11858 | { WAIXING_TYPE_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11859 | { WAIXING_TYPE_A_1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11860 | { WAIXING_TYPE_B, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11861 | { WAIXING_TYPE_C, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11862 | { WAIXING_TYPE_D, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11863 | { WAIXING_TYPE_E, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq }, | |
| 11864 | { WAIXING_TYPE_F, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_f_w), NULL, NULL, mmc3_irq }, | |
| 11865 | { WAIXING_TYPE_G, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_g_w), NULL, NULL, mmc3_irq }, | |
| 11866 | { WAIXING_TYPE_H, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_h_w), NULL, NULL, mmc3_irq }, | |
| 11867 | { WAIXING_TYPE_I, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff | |
| 11868 | { WAIXING_TYPE_J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff | |
| 11869 | { WAIXING_SGZ, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_sgz_w), NULL, NULL, konami_irq }, | |
| 11870 | { WAIXING_SGZLZ, NES_WRITEONLY(waixing_sgzlz_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11871 | { WAIXING_FFV, NES_WRITEONLY(waixing_ffv_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11872 | { WAIXING_ZS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_zs_w), NULL, NULL, NULL }, | |
| 11873 | { WAIXING_DQ8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_dq8_w), NULL, NULL, NULL }, | |
| 11874 | { WAIXING_SECURITY, NES_WRITEONLY(waixing_sec_l_w), NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11875 | { WAIXING_SH2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff | |
| 11876 | { WAIXING_PS2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_ps2_w), NULL, NULL, NULL }, | |
| 11877 | { UNL_8237, NES_WRITEONLY(unl_8237_l_w), NES_NOACCESS, NES_WRITEONLY(unl_8237_w), NULL, NULL, mmc3_irq }, | |
| 11878 | { UNL_AX5705, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_ax5705_w), NULL, NULL, NULL }, | |
| 11879 | { UNL_CC21, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_cc21_w), NULL, NULL, NULL }, | |
| 11880 | { UNL_KOF97, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_kof97_w), NULL, NULL, mmc3_irq }, | |
| 11881 | { UNL_T230, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_t230_w), NULL, NULL, konami_irq }, | |
| 11882 | { UNL_KOF96, {FUNC(kof96_l_w), FUNC(kof96_l_r)}, NES_NOACCESS, NES_WRITEONLY(kof96_w), NULL, NULL, mmc3_irq }, | |
| 11883 | { UNL_MK2, NES_NOACCESS, NES_WRITEONLY(mk2_m_w), NES_NOACCESS, NULL, NULL, mmc3_irq }, | |
| 11884 | { UNL_N625092, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(n625092_w), NULL, NULL, NULL }, | |
| 11885 | { UNL_SC127, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sc127_w), NULL, NULL, sc127_irq }, | |
| 11886 | { UNL_SMB2J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(smb2j_w), NULL, NULL, NULL }, | |
| 11887 | { UNL_SUPERFIGHTER3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_sf3_w), NULL, NULL, mmc3_irq }, | |
| 11888 | { UNL_XZY, NES_WRITEONLY(unl_xzy_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11889 | { UNL_RACERMATE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_racmate_w), NULL, NULL, NULL }, | |
| 11890 | { UNL_STUDYNGAME, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sng32_w), NULL, NULL, NULL }, | |
| 11891 | { UNL_603_5052, {FUNC(unl_6035052_extra_w), FUNC(unl_6035052_extra_r)}, {FUNC(unl_6035052_extra_w), FUNC(unl_6035052_extra_r)}, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11892 | { UNL_EDU2K, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(edu2k_w), NULL, NULL, NULL }, | |
| 11893 | { UNL_SHJY3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(shjy3_w), NULL, NULL, shjy3_irq }, | |
| 11894 | { UNL_H2288, {FUNC(h2288_l_w), FUNC(h2288_l_r)}, NES_NOACCESS, NES_WRITEONLY(h2288_w), NULL, NULL, mmc3_irq }, | |
| 11895 | // | |
| 11896 | { BTL_AISENSHINICOL, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_mariobaby_w), NULL, NULL, NULL }, | |
| 11897 | { BTL_DRAGONNINJA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_dn_w), NULL, NULL, btl_dn_irq }, | |
| 11898 | { BTL_MARIOBABY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_mariobaby_w), NULL, NULL, NULL }, | |
| 11899 | { BTL_SMB2A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb2a_w), NULL, NULL, btl_smb2a_irq }, | |
| 11900 | { BTL_SMB2B, NES_WRITEONLY(smb2jb_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, smb2jb_irq }, | |
| 11901 | { BTL_SMB3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb3_w), NULL, NULL, btl_smb3_irq }, | |
| 11902 | { BTL_SUPERBROS11, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb11_w), NULL, NULL, mmc3_irq }, | |
| 11903 | { BTL_TOBIDASE, NES_WRITEONLY(btl_tobi_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11904 | { BTL_PIKACHUY2K, NES_NOACCESS, {FUNC(btl_pika_y2k_m_w), FUNC(btl_pika_y2k_m_r)}, NES_WRITEONLY(btl_pika_y2k_w), NULL, NULL, mmc3_irq }, | |
| 11905 | { WHIRLWIND_2706, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(whirl2706_w), NULL, NULL, NULL }, | |
| 11906 | // | |
| 11907 | { BMC_190IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_190in1_w), NULL, NULL, NULL }, | |
| 11908 | { BMC_A65AS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_a65as_w), NULL, NULL, NULL }, | |
| 11909 | { BMC_GS2004, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gs2004_w), NULL, NULL, NULL }, | |
| 11910 | { BMC_GS2013, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gs2013_w), NULL, NULL, NULL }, | |
| 11911 | { BMC_NOVELDIAMOND, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(novel1_w), NULL, NULL, NULL }, | |
| 11912 | { BMC_9999999IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(novel2_w), NULL, NULL, NULL }, | |
| 11913 | { BMC_T262, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_t262_w), NULL, NULL, NULL }, | |
| 11914 | { BMC_WS, NES_NOACCESS, NES_WRITEONLY(bmc_ws_m_w), NES_NOACCESS, NULL, NULL, NULL }, | |
| 11915 | { BMC_GKA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gka_w), NULL, NULL, NULL }, | |
| 11916 | { BMC_GKB, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gkb_w), NULL, NULL, NULL }, | |
| 11917 | { BMC_SUPER_700IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_super700in1_w), NULL, NULL, NULL }, | |
| 11918 | { BMC_36IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_36in1_w), NULL, NULL, NULL }, | |
| 11919 | { BMC_21IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_21in1_w), NULL, NULL, NULL }, | |
| 11920 | { BMC_150IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_150in1_w), NULL, NULL, NULL }, | |
| 11921 | { BMC_35IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_35in1_w), NULL, NULL, NULL }, | |
| 11922 | { BMC_64IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_64in1_w), NULL, NULL, NULL }, | |
| 11923 | { BMC_SUPERHIK_300IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_hik300_w), NULL, NULL, NULL }, | |
| 11924 | { BMC_SUPERGUN_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(supergun20in1_w), NULL, NULL, NULL }, | |
| 11925 | { BMC_72IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_72in1_w), NULL, NULL, NULL }, | |
| 11926 | { BMC_76IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_76in1_w), NULL, NULL, NULL }, | |
| 11927 | { BMC_SUPER_42IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_76in1_w), NULL, NULL, NULL }, | |
| 11928 | { BMC_1200IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_1200in1_w), NULL, NULL, NULL }, | |
| 11929 | { BMC_31IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_31in1_w), NULL, NULL, NULL }, | |
| 11930 | { BMC_22GAMES, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_22g_w), NULL, NULL, NULL }, | |
| 11931 | { BMC_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_20in1_w), NULL, NULL, NULL }, | |
| 11932 | { BMC_110IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_110in1_w), NULL, NULL, NULL }, | |
| 11933 | { BMC_64IN1NR, NES_WRITEONLY(bmc_64in1nr_l_w), NES_NOACCESS, NES_WRITEONLY(bmc_64in1nr_w), NULL, NULL, NULL }, | |
| 11934 | { BMC_S24IN1SC03, NES_WRITEONLY(bmc_s24in1sc03_l_w), NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11935 | { BMC_HIK8IN1, NES_NOACCESS, NES_WRITEONLY(bmc_hik8_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11936 | { BMC_SUPERHIK_4IN1, NES_NOACCESS, NES_WRITEONLY(bmc_hik4in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11937 | { BMC_SUPERBIG_7IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_sbig7_w), NULL, NULL, mmc3_irq }, | |
| 11938 | { BMC_MARIOPARTY_7IN1, NES_NOACCESS, NES_WRITEONLY(bmc_mario7in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11939 | { BMC_FAMILY_4646B, NES_NOACCESS, NES_WRITEONLY(bmc_family4646_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11940 | { BMC_15IN1, NES_NOACCESS, NES_WRITEONLY(bmc_15in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11941 | { BMC_BALLGAMES_11IN1, NES_NOACCESS, NES_WRITEONLY(bmc_ball11_m_w), NES_WRITEONLY(bmc_ball11_w), NULL, NULL, NULL }, | |
| 11942 | { BMC_GOLDENCARD_6IN1, NES_WRITEONLY(bmc_gc6in1_l_w), NES_NOACCESS, NES_WRITEONLY(bmc_gc6in1_w), NULL, NULL, mmc3_irq }, | |
| 11943 | { BMC_VT5201, NES_NOACCESS, NES_NOACCESS, {FUNC(bmc_vt5201_w), FUNC(bmc_vt5201_r)}, NULL, NULL, NULL }, | |
| 11944 | { BMC_BENSHENG_BS5, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_bs5_w), NULL, NULL, NULL }, | |
| 11945 | { BMC_810544, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_810544_w), NULL, NULL, NULL }, | |
| 11946 | { BMC_NTD_03, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_ntd03_w), NULL, NULL, NULL }, | |
| 11947 | { BMC_G63IN1, NES_NOACCESS, NES_NOACCESS, {FUNC(bmc_gb63_w), FUNC(bmc_gb63_r)}, NULL, NULL, NULL }, | |
| 11948 | { BMC_FK23C, NES_WRITEONLY(fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(fk23c_w), NULL, NULL, mmc3_irq }, | |
| 11949 | { BMC_FK23CA, NES_WRITEONLY(fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(fk23c_w), NULL, NULL, mmc3_irq }, | |
| 11950 | { BMC_PJOY84, NES_NOACCESS, NES_WRITEONLY(pjoy84_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, | |
| 11951 | // | |
| 11952 | { FFE_MAPPER6, NES_WRITEONLY(mapper6_l_w), NES_NOACCESS, NES_WRITEONLY(mapper6_w), NULL, NULL, ffe_irq }, | |
| 11953 | { FFE_MAPPER8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(mapper8_w), NULL, NULL, NULL }, | |
| 11954 | { FFE_MAPPER17, NES_WRITEONLY(mapper17_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, ffe_irq }, | |
| 11955 | // for debug and development | |
| 11956 | { UNKNOWN_BOARD, {FUNC(dummy_l_w), FUNC(dummy_l_r)}, {FUNC(dummy_m_w), FUNC(dummy_m_r)}, {FUNC(dummy_w), FUNC(dummy_r)}, NULL, NULL, NULL }, | |
| 11957 | // | |
| 11958 | { UNSUPPORTED_BOARD, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL }, | |
| 11959 | // | |
| 11960 | }; | |
| 11961 | ||
| 11962 | const nes_pcb_intf *nes_pcb_intf_lookup( int pcb_id ) | |
| 11963 | { | |
| 11964 | int i; | |
| 11965 | for (i = 0; i < ARRAY_LENGTH(nes_intf_list); i++) | |
| 11966 | { | |
| 11967 | if (nes_intf_list[i].mmc_pcb == pcb_id) | |
| 11968 | return &nes_intf_list[i]; | |
| 11969 | } | |
| 11970 | return NULL; | |
| 11971 | } | |
| 11972 | ||
| 11973 | void pcb_handlers_setup( running_machine &machine ) | |
| 11974 | { | |
| 11975 | nes_state *state = machine.driver_data<nes_state>(); | |
| 11976 | const nes_pcb_intf *intf = nes_pcb_intf_lookup(state->m_pcb_id); | |
| 11977 | device_t *ppu = machine.device("ppu"); | |
| 11978 | ||
| 11979 | if (intf == NULL) | |
| 11980 | fatalerror("Missing PCB interface\n"); | |
| 11981 | ||
| 11982 | if (intf) | |
| 11983 | { | |
| 11984 | state->m_mmc_write_low = intf->mmc_l.write; | |
| 11985 | state->m_mmc_write_low_name = intf->mmc_l.write_name; | |
| 11986 | state->m_mmc_write_mid = intf->mmc_m.write; | |
| 11987 | state->m_mmc_write_mid_name = intf->mmc_m.write_name; | |
| 11988 | state->m_mmc_write = intf->mmc_h.write; | |
| 11989 | state->m_mmc_write_name = intf->mmc_h.write_name; | |
| 11990 | state->m_mmc_read_low = intf->mmc_l.read; | |
| 11991 | state->m_mmc_read_low_name = intf->mmc_l.read_name; | |
| 11992 | state->m_mmc_read_mid = intf->mmc_m.read; // in progress | |
| 11993 | state->m_mmc_read_mid_name = intf->mmc_m.read_name; | |
| 11994 | state->m_mmc_read = intf->mmc_h.read; // in progress | |
| 11995 | state->m_mmc_read_name = intf->mmc_h.read_name; | |
| 11996 | ppu2c0x_set_latch(ppu, intf->mmc_ppu_latch); | |
| 11997 | } | |
| 11998 | else | |
| 11999 | { | |
| 12000 | logerror("PCB %d is not yet supported, defaulting to no mapper.\n", state->m_pcb_id); | |
| 12001 | state->m_mmc_write_low = NULL; | |
| 12002 | state->m_mmc_write_mid = NULL; | |
| 12003 | state->m_mmc_write = NULL; | |
| 12004 | state->m_mmc_read_low = NULL; | |
| 12005 | state->m_mmc_read_mid = NULL; // in progress | |
| 12006 | state->m_mmc_read = NULL; // in progress | |
| 12007 | ppu2c0x_set_latch(ppu, NULL); | |
| 12008 | } | |
| 12009 | ||
| 12010 | state->m_mmc3_prg_cb = prg8_x; | |
| 12011 | state->m_mmc3_chr_cb = chr1_x; | |
| 12012 | ||
| 12013 | switch (state->m_pcb_id) | |
| 12014 | { | |
| 12015 | case STD_TXSROM: | |
| 12016 | state->m_mmc3_chr_cb = txsrom_chr_cb; | |
| 12017 | break; | |
| 12018 | case GOUDER_37017: | |
| 12019 | state->m_mmc3_prg_cb = gouder_sf4_prg_cb; | |
| 12020 | break; | |
| 12021 | case KASING_BOARD: | |
| 12022 | state->m_mmc3_prg_cb = kasing_prg_cb; | |
| 12023 | break; | |
| 12024 | case REXSOFT_DBZ5: | |
| 12025 | state->m_mmc3_chr_cb = rex_dbz_chr_cb; | |
| 12026 | break; | |
| 12027 | case TXC_TW: | |
| 12028 | state->m_mmc3_prg_cb = txc_tw_prg_cb; | |
| 12029 | break; | |
| 12030 | case WAIXING_TYPE_A: | |
| 12031 | state->m_mmc3_chr_cb = waixing_a_chr_cb; | |
| 12032 | break; | |
| 12033 | case WAIXING_TYPE_A_1: | |
| 12034 | state->m_mmc3_chr_cb = waixing_a1_chr_cb; | |
| 12035 | break; | |
| 12036 | case WAIXING_TYPE_B: | |
| 12037 | state->m_mmc3_chr_cb = waixing_b_chr_cb; | |
| 12038 | break; | |
| 12039 | case WAIXING_TYPE_C: | |
| 12040 | state->m_mmc3_chr_cb = waixing_c_chr_cb; | |
| 12041 | break; | |
| 12042 | case WAIXING_TYPE_D: | |
| 12043 | state->m_mmc3_chr_cb = waixing_d_chr_cb; | |
| 12044 | break; | |
| 12045 | case WAIXING_TYPE_E: | |
| 12046 | state->m_mmc3_chr_cb = waixing_e_chr_cb; | |
| 12047 | break; | |
| 12048 | case WAIXING_TYPE_G: | |
| 12049 | state->m_mmc3_chr_cb = waixing_g_chr_cb; | |
| 12050 | break; | |
| 12051 | case WAIXING_TYPE_H: | |
| 12052 | state->m_mmc3_chr_cb = waixing_h_chr_cb; | |
| 12053 | break; | |
| 12054 | case WAIXING_SECURITY: | |
| 12055 | state->m_mmc3_prg_cb = waixing_sec_prg_cb; | |
| 12056 | state->m_mmc3_chr_cb = waixing_sec_chr_cb; | |
| 12057 | break; | |
| 12058 | case WAIXING_SH2: | |
| 12059 | state->m_mmc3_chr_cb = waixing_sh2_chr_cb; | |
| 12060 | break; | |
| 12061 | case UNL_8237: | |
| 12062 | state->m_mmc3_prg_cb = unl_8237_prg_cb; | |
| 12063 | state->m_mmc3_chr_cb = unl_8237_chr_cb; | |
| 12064 | break; | |
| 12065 | case UNL_H2288: | |
| 12066 | state->m_mmc3_prg_cb = h2288_prg_cb; | |
| 12067 | break; | |
| 12068 | case SUPERGAME_BOOGERMAN: | |
| 12069 | state->m_mmc3_prg_cb = sgame_boog_prg_cb; | |
| 12070 | state->m_mmc3_chr_cb = sgame_boog_chr_cb; | |
| 12071 | break; | |
| 12072 | case UNL_KOF96: | |
| 12073 | state->m_mmc3_prg_cb = kof96_prg_cb; | |
| 12074 | state->m_mmc3_chr_cb = kof96_chr_cb; | |
| 12075 | break; | |
| 12076 | case KAY_PANDAPRINCE: | |
| 12077 | state->m_mmc3_prg_cb = kay_pp_prg_cb; | |
| 12078 | state->m_mmc3_chr_cb = kay_pp_chr_cb; | |
| 12079 | break; | |
| 12080 | case BMC_FK23C: | |
| 12081 | state->m_mmc3_prg_cb = fk23c_prg_cb; | |
| 12082 | state->m_mmc3_chr_cb = fk23c_chr_cb; | |
| 12083 | break; | |
| 12084 | case BMC_S24IN1SC03: | |
| 12085 | state->m_mmc3_prg_cb = bmc_s24in1sc03_prg_cb; | |
| 12086 | state->m_mmc3_chr_cb = bmc_s24in1sc03_chr_cb; | |
| 12087 | break; | |
| 12088 | case BMC_PJOY84: | |
| 12089 | state->m_mmc3_prg_cb = pjoy84_prg_cb; | |
| 12090 | state->m_mmc3_chr_cb = pjoy84_chr_cb; | |
| 12091 | break; | |
| 12092 | } | |
| 12093 | } | |
| 12094 | ||
| 12095 | /************************************************************* | |
| 12096 | ||
| 12097 | pcb_initialize | |
| 12098 | ||
| 12099 | Initialize all the necessary registers and quantities for | |
| 12100 | emulation of each board | |
| 12101 | ||
| 12102 | *************************************************************/ | |
| 12103 | ||
| 12104 | /* this is used by many boards (MMC3, MMC6 + most MMC3 pirate clone boards) */ | |
| 12105 | static void mmc3_common_initialize( running_machine &machine, int prg_mask, int chr_mask, int IRQ_type ) | |
| 12106 | { | |
| 12107 | nes_state *state = machine.driver_data<nes_state>(); | |
| 12108 | ||
| 12109 | state->m_mmc3_alt_irq = IRQ_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev... | |
| 12110 | state->m_mmc_prg_bank[0] = state->m_mmc_prg_bank[2] = 0xfe; // prg_bank[2] & prg_bank[3] remain always the same in most MMC3 variants | |
| 12111 | state->m_mmc_prg_bank[1] = state->m_mmc_prg_bank[3] = 0xff; // but some pirate clone mappers change them after writing certain registers | |
| 12112 | state->m_mmc3_latch = 0; | |
| 12113 | state->m_mmc3_wram_protect = 0x80; | |
| 12114 | state->m_mmc_prg_base = state->m_mmc_chr_base = 0; | |
| 12115 | state->m_mmc_prg_mask = prg_mask; | |
| 12116 | state->m_mmc_chr_mask = chr_mask; | |
| 12117 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12118 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12119 | } | |
| 12120 | ||
| 12121 | // WIP code | |
| 12122 | static int pcb_initialize( running_machine &machine, int idx ) | |
| 12123 | { | |
| 12124 | nes_state *state = machine.driver_data<nes_state>(); | |
| 12125 | int err = 0, i; | |
| 12126 | ||
| 12127 | /* basic PRG config */ | |
| 12128 | prg32(machine, 0); | |
| 12129 | ||
| 12130 | /* some boards will not use this, but directly CHRROM (resp. CHRRAM) if the board only has VROM (resp. VRAM) */ | |
| 12131 | state->m_mmc_chr_source = state->m_chr_chunks ? CHRROM : CHRRAM; | |
| 12132 | chr8(machine, 0, state->m_mmc_chr_source); | |
| 12133 | ||
| 12134 | /* Here, we init a few helpers: 4 prg banks and 16 chr banks - some mappers use them */ | |
| 12135 | for (i = 0; i < 4; i++) | |
| 12136 | state->m_mmc_prg_bank[i] = 0; | |
| 12137 | for (i = 0; i < 16; i++) | |
| 12138 | state->m_mmc_vrom_bank[i] = 0; | |
| 12139 | for (i = 0; i < 16; i++) | |
| 12140 | state->m_mmc_extra_bank[i] = 0; | |
| 12141 | ||
| 12142 | state->m_mmc_latch1 = 0; | |
| 12143 | state->m_mmc_latch2 = 0; | |
| 12144 | ||
| 12145 | /* Finally, we init IRQ-related quantities. */ | |
| 12146 | state->m_IRQ_enable = state->m_IRQ_enable_latch = 0; | |
| 12147 | state->m_IRQ_count = state->m_IRQ_count_latch = 0; | |
| 12148 | state->m_IRQ_toggle = 0; | |
| 12149 | ||
| 12150 | switch (idx) | |
| 12151 | { | |
| 12152 | /* many boards only needs PRG to point at first 32k and CHR at first 8k */ | |
| 12153 | case STD_NROM: // mapper 0 | |
| 12154 | case HVC_FAMBASIC: | |
| 12155 | case GG_NROM: | |
| 12156 | case UXROM_CC: // mapper 180 | |
| 12157 | case STD_CNROM: // mapper 3, 185 | |
| 12158 | case BANDAI_PT554: | |
| 12159 | case TENGEN_800008: | |
| 12160 | case STD_BXROM: // mapper 34 | |
| 12161 | case STD_GXROM: // mapper 66 | |
| 12162 | case STD_MXROM: | |
| 12163 | case BANDAI_OEKAKIDS: // mapper 96 | |
| 12164 | case JALECO_JF11: // mapper 140 | |
| 12165 | case JALECO_JF13: // mapper 86 | |
| 12166 | case JALECO_JF19: // mapper 92 | |
| 12167 | case DIS_74X377: // mapper 11 | |
| 12168 | case DIS_74X161X138: // mapper 38 | |
| 12169 | case CALTRON_6IN1: // mapper 41 | |
| 12170 | case TXC_STRIKEWOLF: // mapper 36 | |
| 12171 | case UNL_STUDYNGAME: // mapper 39 | |
| 12172 | case RUMBLESTATION_BOARD: // mapper 46 | |
| 12173 | case BMC_GKB: // mapper 58 | |
| 12174 | case RCM_TETRISFAMILY: // mapper 61 | |
| 12175 | case BMC_SUPER_700IN1: // mapper 62 | |
| 12176 | case MAGICSERIES_MD: // mapper 107 | |
| 12177 | case HES_BOARD: // mapper 113 | |
| 12178 | case HES6IN1_BOARD: // mapper 113 | |
| 12179 | case SACHEN_SA72008: // mapper 133 | |
| 12180 | case SACHEN_TCU02: // mapper 136 | |
| 12181 | case SACHEN_SA72007: // mapper 145 | |
| 12182 | case SACHEN_TCU01: // mapper 147 | |
| 12183 | case SACHEN_SA009: // mapper 160 | |
| 12184 | case SACHEN_SA0037: // mapper 148 | |
| 12185 | case SACHEN_SA0036: // mapper 149 | |
| 12186 | case AGCI_50282: // mapper 144 | |
| 12187 | case KAISER_KS7058: // mapper 171 | |
| 12188 | case HENGEDIANZI_BOARD: // mapper 177 | |
| 12189 | case WAIXING_SGZLZ: // mapper 178 | |
| 12190 | case HENGEDIANZI_XJZB: // mapper 179 | |
| 12191 | case BMC_21IN1: // mapper 201 | |
| 12192 | case BMC_9999999IN1: // mapper 213 | |
| 12193 | case RCM_GS2015: // mapper 216 | |
| 12194 | case BMC_72IN1: // mapper 225 | |
| 12195 | case BMC_76IN1: // mapper 226 | |
| 12196 | case BMC_SUPER_42IN1: // mapper 226 | |
| 12197 | case ACTENT_ACT52: // mapper 228 | |
| 12198 | case CNE_SHLZ: // mapper 240 | |
| 12199 | case TXC_MXMDHTWO: // mapper 241 | |
| 12200 | case WAIXING_ZS: // mapper 242 | |
| 12201 | case WAIXING_DQ8: // mapper 242 | |
| 12202 | case CNE_DECATHLON: // mapper 244 | |
| 12203 | case UNL_CC21: | |
| 12204 | case BMC_VT5201: | |
| 12205 | case BMC_WS: | |
| 12206 | case UNL_EDU2K: | |
| 12207 | break; | |
| 12208 | ||
| 12209 | /* other boards need additional initialization */ | |
| 12210 | case STD_UXROM: // mapper 2 | |
| 12211 | case STD_UN1ROM: // mapper 94 | |
| 12212 | case STD_JXROM: // mapper 69 | |
| 12213 | case SUNSOFT_5B: | |
| 12214 | case SUNSOFT_FME7: | |
| 12215 | case NAMCOT_3425: // mapper 95 | |
| 12216 | case DIS_74X139X74: // mapper 87 | |
| 12217 | case DIS_74X161X161X32: // mapper 152 & 70 | |
| 12218 | case BANDAI_LZ93: // mapper 16, 157 | |
| 12219 | case BANDAI_LZ93EX: // same + EEPROM | |
| 12220 | case BANDAI_DATACH: | |
| 12221 | case BANDAI_FCG: | |
| 12222 | case IREM_HOLYDIV: // mapper 78 | |
| 12223 | case IREM_G101: // mapper 32 | |
| 12224 | case IREM_H3001: // mapper 65 | |
| 12225 | case JALECO_SS88006: // mapper 18 | |
| 12226 | case JALECO_JF16: // mapper 78 | |
| 12227 | case JALECO_JF17: // mapper 72 | |
| 12228 | case KONAMI_VRC1: // mapper 75 | |
| 12229 | case KONAMI_VRC2: | |
| 12230 | case KONAMI_VRC3: // mapper 73 | |
| 12231 | case KONAMI_VRC4: | |
| 12232 | case KONAMI_VRC6: | |
| 12233 | case SUNSOFT_3: // mapper 67 | |
| 12234 | case TAITO_TC0190FMC: // mapper 33 | |
| 12235 | case TAITO_TC0190FMCP: // mapper 48 | |
| 12236 | case TAITO_X1_005: // mapper 80 | |
| 12237 | case TAITO_X1_005_A: // mapper 207 | |
| 12238 | case TAITO_X1_017: // mapper 82 | |
| 12239 | case NTDEC_ASDER: // mapper 112 | |
| 12240 | case FUTUREMEDIA_BOARD: // mapper 117 | |
| 12241 | case BTL_DRAGONNINJA: // mapper 222 | |
| 12242 | case WAIXING_SGZ: // mapper 252 | |
| 12243 | case UNL_T230: | |
| 12244 | case BMC_NTD_03: | |
| 12245 | case KAISER_KS7022: | |
| 12246 | case UNL_SHJY3: | |
| 12247 | case KAISER_KS7017: | |
| 12248 | case KAISER_KS7032: | |
| 12249 | case KAISER_KS202: | |
| 12250 | prg16_89ab(machine, 0); | |
| 12251 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12252 | break; | |
| 12253 | ||
| 12254 | case STD_CPROM: // mapper 13 | |
| 12255 | chr4_0(machine, 0, CHRRAM); | |
| 12256 | chr4_4(machine, 0, CHRRAM); | |
| 12257 | break; | |
| 12258 | case STD_AXROM: // mapper 7 | |
| 12259 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 12260 | break; | |
| 12261 | case STD_SXROM: // mapper 1, 155 | |
| 12262 | case STD_SOROM: | |
| 12263 | case STD_SXROM_A: | |
| 12264 | case STD_SOROM_A: | |
| 12265 | state->m_mmc1_latch = 0; | |
| 12266 | state->m_mmc1_count = 0; | |
| 12267 | state->m_mmc_reg[0] = 0x0f; | |
| 12268 | state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12269 | state->m_mmc1_reg_write_enable = 1; | |
| 12270 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 12271 | mmc1_set_chr(machine); | |
| 12272 | mmc1_set_prg(machine); | |
| 12273 | if (state->m_battery || state->m_wram) | |
| 12274 | wram_bank(machine, 0, (idx == STD_SOROM) ? NES_WRAM : NES_BATTERY); | |
| 12275 | break; | |
| 12276 | case STD_PXROM: // mapper 9 | |
| 12277 | state->m_mmc_reg[0] = state->m_mmc_reg[2] = 0; | |
| 12278 | state->m_mmc_reg[1] = state->m_mmc_reg[3] = 0; | |
| 12279 | state->m_mmc_latch1 = state->m_mmc_latch2 = 0xfe; | |
| 12280 | prg8_89(machine, 0); | |
| 12281 | prg8_ab(machine, (state->m_prg_chunks << 1) - 3); | |
| 12282 | prg8_cd(machine, (state->m_prg_chunks << 1) - 2); | |
| 12283 | prg8_ef(machine, (state->m_prg_chunks << 1) - 1); | |
| 12284 | break; | |
| 12285 | case STD_FXROM: // mapper 10 | |
| 12286 | state->m_mmc_reg[0] = state->m_mmc_reg[2] = 0; | |
| 12287 | state->m_mmc_reg[1] = state->m_mmc_reg[3] = 0; | |
| 12288 | state->m_mmc_latch1 = state->m_mmc_latch2 = 0xfe; | |
| 12289 | prg16_89ab(machine, 0); | |
| 12290 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12291 | break; | |
| 12292 | case STD_TXROM: // mapper 4 | |
| 12293 | case STD_TVROM: | |
| 12294 | case STD_TKROM: | |
| 12295 | case REXSOFT_DBZ5: // mapper 12 | |
| 12296 | case WAIXING_TYPE_A: // mapper 74 | |
| 12297 | case WAIXING_TYPE_A_1: | |
| 12298 | case STD_TXSROM: // mapper 118 | |
| 12299 | case STD_TQROM: // mapper 119 | |
| 12300 | case WAIXING_SH2: // mapper 165 | |
| 12301 | case WAIXING_TYPE_B: // mapper 191 | |
| 12302 | case WAIXING_TYPE_C: // mapper 192 | |
| 12303 | case WAIXING_TYPE_D: // mapper 194 | |
| 12304 | case WAIXING_TYPE_E: // mapper 195 | |
| 12305 | case WAIXING_TYPE_H: // mapper 245 | |
| 12306 | case BTL_SUPERBROS11: // mapper 196 | |
| 12307 | case UNL_H2288: // mapper 123 | |
| 12308 | case UNL_KOF97: | |
| 12309 | case UNL_603_5052: | |
| 12310 | case NITRA_TDA: // mapper 250 | |
| 12311 | if (state->m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring | |
| 12312 | { | |
| 12313 | set_nt_page(machine, 0, CART_NTRAM, 0, 1); | |
| 12314 | set_nt_page(machine, 1, CART_NTRAM, 1, 1); | |
| 12315 | set_nt_page(machine, 2, CART_NTRAM, 2, 1); | |
| 12316 | set_nt_page(machine, 3, CART_NTRAM, 3, 1); | |
| 12317 | } | |
| 12318 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12319 | break; | |
| 12320 | case STD_HKROM: // MMC6 (basically the same as TxROM, but alt IRQ behaviour) | |
| 12321 | mmc3_common_initialize(machine, 0xff, 0xff, 1); | |
| 12322 | state->m_mmc6_reg = 0xf0; | |
| 12323 | state->m_mmc_latch2 = 0; // this is used differently here compared to MMC3 | |
| 12324 | break; | |
| 12325 | case PAL_ZZ: // mapper 37 | |
| 12326 | mmc3_common_initialize(machine, 0x07, 0x7f, 0); | |
| 12327 | break; | |
| 12328 | case NES_QJ: // mapper 47 | |
| 12329 | mmc3_common_initialize(machine, 0x0f, 0x7f, 0); | |
| 12330 | break; | |
| 12331 | case STD_EXROM: // mapper 5 | |
| 12332 | state->m_MMC5_rom_bank_mode = 3; | |
| 12333 | state->m_MMC5_vrom_bank_mode = 0; | |
| 12334 | state->m_MMC5_vram_protect = 0; | |
| 12335 | state->m_mmc5_high_chr = 0; | |
| 12336 | state->m_mmc5_vram_control = 0; | |
| 12337 | state->m_mmc5_split_scr = 0; | |
| 12338 | memset(state->m_MMC5_vrom_bank, 0, ARRAY_LENGTH(state->m_MMC5_vrom_bank)); | |
| 12339 | state->m_mmc5_prg_mode = 3; | |
| 12340 | state->m_mmc5_last_chr_a = 1; | |
| 12341 | state->m_mmc5_prg_regs[0] = 0xfc; | |
| 12342 | state->m_mmc5_prg_regs[1] = 0xfd; | |
| 12343 | state->m_mmc5_prg_regs[2] = 0xfe; | |
| 12344 | state->m_mmc5_prg_regs[3] = 0xff; | |
| 12345 | memset(state->m_mmc5_vrom_regA, ~0, ARRAY_LENGTH(state->m_mmc5_vrom_regA)); | |
| 12346 | memset(state->m_mmc5_vrom_regB, ~0, ARRAY_LENGTH(state->m_mmc5_vrom_regB)); | |
| 12347 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12348 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12349 | break; | |
| 12350 | case STD_NXROM: // mapper 68 | |
| 12351 | case SUNSOFT_DCS: // mapper 68 | |
| 12352 | state->m_mmc_reg[0] = 0; | |
| 12353 | prg16_89ab(machine, 0); | |
| 12354 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12355 | break; | |
| 12356 | case NAMCOT_34X3: // mapper 88 | |
| 12357 | case STD_DXROM: // mapper 206 | |
| 12358 | case STD_DRROM: | |
| 12359 | if (state->m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring | |
| 12360 | { | |
| 12361 | set_nt_page(machine, 0, CART_NTRAM, 0, 1); | |
| 12362 | set_nt_page(machine, 1, CART_NTRAM, 1, 1); | |
| 12363 | set_nt_page(machine, 2, CART_NTRAM, 2, 1); | |
| 12364 | set_nt_page(machine, 3, CART_NTRAM, 3, 1); | |
| 12365 | } | |
| 12366 | case NAMCOT_3453: // mapper 154 | |
| 12367 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12368 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12369 | break; | |
| 12370 | case NAMCOT_3446: // mapper 76 | |
| 12371 | prg8_89(machine, 0); | |
| 12372 | prg8_ab(machine, 1); | |
| 12373 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12374 | chr2_0(machine, 0, CHRROM); | |
| 12375 | chr2_2(machine, 1, CHRROM); | |
| 12376 | chr2_4(machine, 2, CHRROM); | |
| 12377 | chr2_6(machine, 3, CHRROM); | |
| 12378 | break; | |
| 12379 | case BANDAI_JUMP2: // mapper 153 | |
| 12380 | for (i = 0; i < 8; i++) | |
| 12381 | state->m_mmc_reg[i] = 0; | |
| 12382 | prg16_89ab(machine, 0); | |
| 12383 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12384 | fjump2_set_prg(machine); | |
| 12385 | break; | |
| 12386 | case BANDAI_KARAOKE: // mapper 188 | |
| 12387 | prg16_89ab(machine, 0); | |
| 12388 | prg16_cdef(machine, (state->m_prg_chunks - 1) ^ 0x08); | |
| 12389 | break; | |
| 12390 | case IREM_LROG017: // mapper 77 | |
| 12391 | chr2_2(machine, 0, CHRROM); | |
| 12392 | chr2_4(machine, 1, CHRROM); | |
| 12393 | chr2_6(machine, 2, CHRROM); | |
| 12394 | break; | |
| 12395 | case IREM_TAM_S1: // mapper 97 | |
| 12396 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12397 | prg16_cdef(machine, 0); | |
| 12398 | break; | |
| 12399 | case KONAMI_VRC7: // mapper 85 | |
| 12400 | prg8_89(machine, 0); | |
| 12401 | prg8_ab(machine, 0); | |
| 12402 | prg8_cd(machine, 0); | |
| 12403 | prg8_ef(machine, 0xff); | |
| 12404 | break; | |
| 12405 | case NAMCOT_163: // mapper 19 | |
| 12406 | prg16_89ab(machine, 0); | |
| 12407 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12408 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12409 | break; | |
| 12410 | case SUNSOFT_1: // mapper 184 | |
| 12411 | case SUNSOFT_2: // mapper 89 & 93 | |
| 12412 | prg16_89ab(machine, 0); | |
| 12413 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12414 | if (!state->m_hard_mirroring) | |
| 12415 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 12416 | break; | |
| 12417 | ||
| 12418 | // mapper 14 | |
| 12419 | case REXSOFT_SL1632: | |
| 12420 | state->m_mmc_extra_bank[2] = 0xfe; | |
| 12421 | state->m_mmc_extra_bank[3] = 0xff; | |
| 12422 | state->m_mmc_extra_bank[0] = state->m_mmc_extra_bank[1] = state->m_mmc_extra_bank[4] = state->m_mmc_extra_bank[5] = state->m_mmc_extra_bank[6] = 0; | |
| 12423 | state->m_mmc_extra_bank[7] = state->m_mmc_extra_bank[8] = state->m_mmc_extra_bank[9] = state->m_mmc_extra_bank[0xa] = state->m_mmc_extra_bank[0xb] = 0; | |
| 12424 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = 0; | |
| 12425 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12426 | break; | |
| 12427 | // mapper 15 | |
| 12428 | case WAIXING_PS2: | |
| 12429 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12430 | break; | |
| 12431 | ||
| 12432 | // mapper 35 | |
| 12433 | case UNL_SC127: | |
| 12434 | // mapper 42 | |
| 12435 | case BTL_MARIOBABY: | |
| 12436 | case BTL_AISENSHINICOL: | |
| 12437 | prg32(machine, 0xff); | |
| 12438 | break; | |
| 12439 | ||
| 12440 | // mapper 40 | |
| 12441 | case BTL_SMB2A: | |
| 12442 | prg8_67(machine, 0xfe); | |
| 12443 | prg8_89(machine, 0xfc); | |
| 12444 | prg8_ab(machine, 0xfd); | |
| 12445 | prg8_cd(machine, 0xfe); | |
| 12446 | prg8_ef(machine, 0xff); | |
| 12447 | break; | |
| 12448 | ||
| 12449 | // mapper 43 | |
| 12450 | case UNL_SMB2J: | |
| 12451 | if (state->m_battery) | |
| 12452 | memset(state->m_battery_ram, 0x2000, 0xff); | |
| 12453 | else if (state->m_prg_ram) | |
| 12454 | memset(state->m_wram, 0x2000, 0xff); | |
| 12455 | break; | |
| 12456 | // mapper 44 | |
| 12457 | case BMC_SUPERBIG_7IN1: | |
| 12458 | // mapper 49 | |
| 12459 | case BMC_SUPERHIK_4IN1: | |
| 12460 | mmc3_common_initialize(machine, 0x0f, 0x7f, 0); | |
| 12461 | break; | |
| 12462 | // mapper 45 | |
| 12463 | case BMC_HIK8IN1: | |
| 12464 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12465 | mmc3_common_initialize(machine, 0x3f, 0xff, 0); | |
| 12466 | break; | |
| 12467 | ||
| 12468 | // mapper 50 | |
| 12469 | case BTL_SMB2B: | |
| 12470 | prg8_67(machine, 0x0f); | |
| 12471 | prg8_89(machine, 0x08); | |
| 12472 | prg8_ab(machine, 0x09); | |
| 12473 | prg8_cd(machine, 0); | |
| 12474 | prg8_ef(machine, 0x0b); | |
| 12475 | break; | |
| 12476 | // mapper 51 | |
| 12477 | case BMC_BALLGAMES_11IN1: | |
| 12478 | state->m_mmc_reg[0] = 0x01; | |
| 12479 | state->m_mmc_reg[1] = 0x00; | |
| 12480 | bmc_ball11_set_banks(machine); | |
| 12481 | break; | |
| 12482 | // mapper 52 | |
| 12483 | case BMC_MARIOPARTY_7IN1: | |
| 12484 | state->m_map52_reg_written = 0; | |
| 12485 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12486 | break; | |
| 12487 | // mapper 54 | |
| 12488 | case BMC_NOVELDIAMOND: | |
| 12489 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12490 | break; | |
| 12491 | // mapper 57 | |
| 12492 | case BMC_GKA: | |
| 12493 | prg16_89ab(machine, 0); | |
| 12494 | prg16_cdef(machine, 0); | |
| 12495 | break; | |
| 12496 | ||
| 12497 | // mapper 64 | |
| 12498 | case TENGEN_800032: | |
| 12499 | // mapper 158 | |
| 12500 | case TENGEN_800037: | |
| 12501 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12502 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12503 | break; | |
| 12504 | // mapper 71 | |
| 12505 | case CAMERICA_BF9097: | |
| 12506 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 12507 | case CAMERICA_BF9093: | |
| 12508 | prg32(machine, 0xff); | |
| 12509 | break; | |
| 12510 | ||
| 12511 | // mapper 79 (& 146) | |
| 12512 | case AVE_NINA06: | |
| 12513 | set_nt_mirroring(machine, PPU_MIRROR_HORZ); | |
| 12514 | break; | |
| 12515 | ||
| 12516 | // mapper 83 | |
| 12517 | case CONY_BOARD: | |
| 12518 | state->m_mapper83_reg[9] = 0x0f; | |
| 12519 | prg8_cd(machine, 0x1e); | |
| 12520 | prg8_ef(machine, 0x1f); | |
| 12521 | break; | |
| 12522 | ||
| 12523 | // mapper 91 | |
| 12524 | case UNL_MK2: | |
| 12525 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12526 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12527 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12528 | break; | |
| 12529 | ||
| 12530 | // mapper 104 | |
| 12531 | case CAMERICA_GOLDENFIVE: | |
| 12532 | prg16_89ab(machine, 0x00); | |
| 12533 | prg16_cdef(machine, 0x0f); | |
| 12534 | break; | |
| 12535 | // mapper 106 | |
| 12536 | case BTL_SMB3: | |
| 12537 | prg8_89(machine, (state->m_prg_chunks << 1) - 1); | |
| 12538 | prg8_ab(machine, 0); | |
| 12539 | prg8_cd(machine, 0); | |
| 12540 | prg8_ef(machine, (state->m_prg_chunks << 1) - 1); | |
| 12541 | break; | |
| 12542 | ||
| 12543 | // mapper 108 | |
| 12544 | case WHIRLWIND_2706: | |
| 12545 | prg32(machine, 0xff); | |
| 12546 | break; | |
| 12547 | ||
| 12548 | // mapper 114 | |
| 12549 | case SUPERGAME_LIONKING: | |
| 12550 | state->m_map114_reg = state->m_map114_reg_enabled = 0; | |
| 12551 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12552 | break; | |
| 12553 | // mapper 115 | |
| 12554 | case KASING_BOARD: | |
| 12555 | state->m_mmc_reg[0] = 0; | |
| 12556 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12557 | break; | |
| 12558 | // mapper 116 | |
| 12559 | case SOMERI_SL12: | |
| 12560 | state->m_mmc_prg_base = state->m_mmc_chr_base = 0; | |
| 12561 | state->m_mmc_prg_mask = 0xff; | |
| 12562 | state->m_mmc_chr_mask = 0xff; | |
| 12563 | state->m_mmc_cmd1 = 2; // mode | |
| 12564 | state->m_mmc3_latch = 0; | |
| 12565 | state->m_mmc3_wram_protect = 0; | |
| 12566 | // MMC1 regs | |
| 12567 | state->m_mmc1_count = 0; | |
| 12568 | state->m_mmc_reg[0] = 0x0c; | |
| 12569 | state->m_mmc_reg[1] = 0x00; | |
| 12570 | state->m_mmc_reg[2] = 0x00; | |
| 12571 | state->m_mmc_reg[3] = 0x00; | |
| 12572 | // MMC3 regs | |
| 12573 | state->m_mmc_prg_bank[0] = 0x3c; | |
| 12574 | state->m_mmc_prg_bank[1] = 0x3d; | |
| 12575 | state->m_mmc_prg_bank[2] = 0xfe; | |
| 12576 | state->m_mmc_prg_bank[3] = 0xff; | |
| 12577 | state->m_mmc_vrom_bank[0] = 0x00; | |
| 12578 | state->m_mmc_vrom_bank[1] = 0x01; | |
| 12579 | state->m_mmc_vrom_bank[2] = 0x04; | |
| 12580 | state->m_mmc_vrom_bank[3] = 0x05; | |
| 12581 | state->m_mmc_vrom_bank[4] = 0x06; | |
| 12582 | state->m_mmc_vrom_bank[5] = 0x07; | |
| 12583 | // VRC2 regs | |
| 12584 | state->m_mmc_prg_bank[4] = 0x00; | |
| 12585 | state->m_mmc_prg_bank[5] = 0x01; | |
| 12586 | for (i = 0; i < 8; ++i) | |
| 12587 | state->m_mmc_vrom_bank[6 + i] = i; | |
| 12588 | someri_mode_update(machine); | |
| 12589 | break; | |
| 12590 | ||
| 12591 | // mapper 120 | |
| 12592 | case BTL_TOBIDASE: | |
| 12593 | prg32(machine, 2); | |
| 12594 | break; | |
| 12595 | ||
| 12596 | // mapper 121 | |
| 12597 | case KAY_PANDAPRINCE: | |
| 12598 | state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0; | |
| 12599 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12600 | break; | |
| 12601 | ||
| 12602 | // mapper 126 | |
| 12603 | case BMC_PJOY84: | |
| 12604 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12605 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12606 | pjoy84_set_base_mask(machine); | |
| 12607 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12608 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12609 | break; | |
| 12610 | ||
| 12611 | // mapper 132 | |
| 12612 | case TXC_22211A: | |
| 12613 | // mapper 172 | |
| 12614 | case TXC_22211B: | |
| 12615 | // mapper 173 | |
| 12616 | case TXC_22211C: | |
| 12617 | state->m_txc_reg[0] = state->m_txc_reg[1] = state->m_txc_reg[2] = state->m_txc_reg[3] = 0; | |
| 12618 | break; | |
| 12619 | ||
| 12620 | // mapper 134 | |
| 12621 | case BMC_FAMILY_4646B: | |
| 12622 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12623 | break; | |
| 12624 | ||
| 12625 | // mapper 137 | |
| 12626 | case SACHEN_8259D: | |
| 12627 | chr8(machine, state->m_chr_chunks - 1, CHRROM); | |
| 12628 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12629 | break; | |
| 12630 | // mapper 138 | |
| 12631 | case SACHEN_8259B: | |
| 12632 | // mapper 139 | |
| 12633 | case SACHEN_8259C: | |
| 12634 | // mapper 141 | |
| 12635 | case SACHEN_8259A: | |
| 12636 | // mapper 150 | |
| 12637 | case SACHEN_74LS374: | |
| 12638 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12639 | break; | |
| 12640 | // mapper 143 | |
| 12641 | case SACHEN_TCA01: | |
| 12642 | prg16_89ab(machine, 0); | |
| 12643 | prg16_cdef(machine, 1); | |
| 12644 | break; | |
| 12645 | ||
| 12646 | // mapper 156 | |
| 12647 | case OPENCORP_DAOU306: | |
| 12648 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12649 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12650 | set_nt_mirroring(machine, PPU_MIRROR_LOW); | |
| 12651 | break; | |
| 12652 | // mapper 163 | |
| 12653 | case NANJING_BOARD: | |
| 12654 | state->m_mmc_count = 0xff; | |
| 12655 | state->m_mmc_reg[0] = 0xff; | |
| 12656 | state->m_mmc_reg[1] = 0; | |
| 12657 | prg16_89ab(machine, state->m_prg_chunks - 2); | |
| 12658 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12659 | break; | |
| 12660 | // mapper 164 | |
| 12661 | case WAIXING_FFV: | |
| 12662 | prg16_89ab(machine, 0); | |
| 12663 | prg16_cdef(machine, 0x1f); | |
| 12664 | break; | |
| 12665 | // mapper 166 | |
| 12666 | case SUBOR_TYPE1: | |
| 12667 | state->m_subor_reg[0] = state->m_subor_reg[1] = state->m_subor_reg[2] = state->m_subor_reg[3] = 0; | |
| 12668 | prg16_89ab(machine, 0); | |
| 12669 | prg16_cdef(machine, 0x07); | |
| 12670 | break; | |
| 12671 | // mapper 167 | |
| 12672 | case SUBOR_TYPE0: | |
| 12673 | state->m_subor_reg[0] = state->m_subor_reg[1] = state->m_subor_reg[2] = state->m_subor_reg[3] = 0; | |
| 12674 | prg16_89ab(machine, 0); | |
| 12675 | prg16_cdef(machine, 0x20); | |
| 12676 | break; | |
| 12677 | ||
| 12678 | // mapper 176 | |
| 12679 | case UNL_XZY: | |
| 12680 | // mapper 182 | |
| 12681 | case HOSENKAN_BOARD: | |
| 12682 | prg32(machine, (state->m_prg_chunks - 1) >> 1); | |
| 12683 | break; | |
| 12684 | ||
| 12685 | case FUKUTAKE_BOARD: // mapper 186 | |
| 12686 | prg16_89ab(machine, 0); | |
| 12687 | prg16_cdef(machine, 0); | |
| 12688 | break; | |
| 12689 | ||
| 12690 | // mapper 187 | |
| 12691 | case UNL_KOF96: | |
| 12692 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12693 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12694 | break; | |
| 12695 | // mapper 189 | |
| 12696 | case TXC_TW: | |
| 12697 | state->m_mmc_latch1 = 0; | |
| 12698 | state->m_mmc_latch2 = 0x80; | |
| 12699 | state->m_mmc_chr_base = 0; | |
| 12700 | state->m_mmc_chr_mask = 0xff; | |
| 12701 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12702 | break; | |
| 12703 | // mapper 193 | |
| 12704 | case NTDEC_FIGHTINGHERO: | |
| 12705 | prg32(machine, (state->m_prg_chunks - 1) >> 1); | |
| 12706 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12707 | break; | |
| 12708 | // mapper 197 | |
| 12709 | case UNL_SUPERFIGHTER3: | |
| 12710 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12711 | unl_sf3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12712 | break; | |
| 12713 | // mapper 198 | |
| 12714 | case WAIXING_TYPE_F: | |
| 12715 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12716 | state->m_mmc_prg_bank[0] = 0x00; | |
| 12717 | state->m_mmc_prg_bank[1] = 0x01; | |
| 12718 | state->m_mmc_prg_bank[2] = 0x4e; | |
| 12719 | state->m_mmc_prg_bank[3] = 0x4f; | |
| 12720 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12721 | break; | |
| 12722 | // mapper 199 | |
| 12723 | case WAIXING_TYPE_G: | |
| 12724 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12725 | state->m_mmc_prg_bank[0] = 0x00; | |
| 12726 | state->m_mmc_prg_bank[1] = 0x01; | |
| 12727 | state->m_mmc_prg_bank[2] = 0x3e; | |
| 12728 | state->m_mmc_prg_bank[3] = 0x3f; | |
| 12729 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12730 | state->m_mmc_vrom_bank[0] = 0x00; | |
| 12731 | state->m_mmc_vrom_bank[1] = 0x02; | |
| 12732 | state->m_mmc_vrom_bank[2] = 0x04; | |
| 12733 | state->m_mmc_vrom_bank[3] = 0x05; | |
| 12734 | state->m_mmc_vrom_bank[4] = 0x06; | |
| 12735 | state->m_mmc_vrom_bank[5] = 0x07; | |
| 12736 | state->m_mmc_vrom_bank[6] = 0x01; | |
| 12737 | state->m_mmc_vrom_bank[7] = 0x03; | |
| 12738 | waixing_g_set_chr(machine, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12739 | break; | |
| 12740 | ||
| 12741 | // mapper 200 | |
| 12742 | case BMC_36IN1: | |
| 12743 | prg16_89ab(machine, state->m_prg_chunks - 1); | |
| 12744 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12745 | break; | |
| 12746 | ||
| 12747 | // mapper 202 | |
| 12748 | case BMC_150IN1: | |
| 12749 | // mapper 203 | |
| 12750 | case BMC_35IN1: | |
| 12751 | // mapper 204 | |
| 12752 | case BMC_64IN1: | |
| 12753 | // mapper 214 | |
| 12754 | case BMC_SUPERGUN_20IN1: | |
| 12755 | prg16_89ab(machine, 0); | |
| 12756 | prg16_cdef(machine, 0); | |
| 12757 | break; | |
| 12758 | // mapper 205 | |
| 12759 | case BMC_15IN1: | |
| 12760 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12761 | state->m_mmc_prg_base = 0x10; // this board has a diff prg_base | |
| 12762 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12763 | break; | |
| 12764 | ||
| 12765 | // mapper 208 | |
| 12766 | case GOUDER_37017: | |
| 12767 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = state->m_mmc_reg[4] = 0; | |
| 12768 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12769 | break; | |
| 12770 | // mapper 212 | |
| 12771 | case BMC_SUPERHIK_300IN1: | |
| 12772 | chr8(machine, 0xff, CHRROM); | |
| 12773 | prg32(machine, 0xff); | |
| 12774 | break; | |
| 12775 | ||
| 12776 | // mapper 215 | |
| 12777 | case SUPERGAME_BOOGERMAN: | |
| 12778 | state->m_mmc_reg[0] = 0x00; | |
| 12779 | state->m_mmc_reg[1] = 0xff; | |
| 12780 | state->m_mmc_reg[2] = 0x04; | |
| 12781 | state->m_mmc_reg[3] = 0; | |
| 12782 | mmc3_common_initialize(machine, 0x1f, 0xff, 0); | |
| 12783 | sgame_boog_set_prg(machine); | |
| 12784 | mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask); | |
| 12785 | break; | |
| 12786 | ||
| 12787 | // mapper 217 | |
| 12788 | case BMC_GOLDENCARD_6IN1: | |
| 12789 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12790 | state->m_mmc_reg[0] = 0x00; | |
| 12791 | state->m_mmc_reg[1] = 0xff; | |
| 12792 | state->m_mmc_reg[2] = 0x03; | |
| 12793 | state->m_mmc_reg[3] = 0; | |
| 12794 | bmc_gc6in1_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12795 | bmc_gc6in1_set_chr(machine, state->m_mmc_chr_source); | |
| 12796 | break; | |
| 12797 | // mapper 221 | |
| 12798 | case UNL_N625092: | |
| 12799 | prg16_89ab(machine, 0); | |
| 12800 | prg16_cdef(machine, 0); | |
| 12801 | break; | |
| 12802 | ||
| 12803 | // mapper 223? | |
| 12804 | case WAIXING_TYPE_I: | |
| 12805 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12806 | state->m_mmc3_wram_protect = 0; | |
| 12807 | break; | |
| 12808 | ||
| 12809 | // mapper 224? | |
| 12810 | case WAIXING_TYPE_J: | |
| 12811 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12812 | state->m_mmc_prg_bank[0] = 0x01; | |
| 12813 | state->m_mmc_prg_bank[1] = 0x02; | |
| 12814 | state->m_mmc_prg_bank[2] = 0x7e; | |
| 12815 | state->m_mmc_prg_bank[3] = 0x7f; | |
| 12816 | mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask); | |
| 12817 | break; | |
| 12818 | ||
| 12819 | // mapper 227 | |
| 12820 | case BMC_1200IN1: | |
| 12821 | prg16_89ab(machine, 0); | |
| 12822 | prg16_cdef(machine, 0); | |
| 12823 | break; | |
| 12824 | ||
| 12825 | // mapper 229 | |
| 12826 | case BMC_31IN1: | |
| 12827 | prg16_89ab(machine, 0); | |
| 12828 | prg16_cdef(machine, 1); | |
| 12829 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12830 | break; | |
| 12831 | // mapper 230 | |
| 12832 | case BMC_22GAMES: | |
| 12833 | prg16_89ab(machine, 0); | |
| 12834 | prg16_cdef(machine, 7); | |
| 12835 | break; | |
| 12836 | // mapper 231 | |
| 12837 | case BMC_20IN1: | |
| 12838 | prg16_89ab(machine, 0); | |
| 12839 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12840 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12841 | break; | |
| 12842 | // mapper 232 | |
| 12843 | case CAMERICA_BF9096: | |
| 12844 | state->m_mmc_latch1 = 0x18; | |
| 12845 | state->m_mmc_latch2 = 0x00; | |
| 12846 | bf9096_set_prg(machine); | |
| 12847 | break; | |
| 12848 | ||
| 12849 | // mapper 243 | |
| 12850 | case SACHEN_74LS374_A: | |
| 12851 | state->m_mmc_vrom_bank[0] = 3; | |
| 12852 | chr8(machine, 3, CHRROM); | |
| 12853 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12854 | break; | |
| 12855 | ||
| 12856 | // mapper 246 | |
| 12857 | case CNE_FSB: | |
| 12858 | prg32(machine, 0xff); | |
| 12859 | break; | |
| 12860 | // mapper 249 | |
| 12861 | case WAIXING_SECURITY: | |
| 12862 | state->m_mmc_reg[0] = 0; | |
| 12863 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12864 | break; | |
| 12865 | ||
| 12866 | // mapper 254 | |
| 12867 | case BTL_PIKACHUY2K: | |
| 12868 | state->m_mmc_reg[0] = 0xff; | |
| 12869 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12870 | break; | |
| 12871 | ||
| 12872 | // mapper 255 | |
| 12873 | case BMC_110IN1: | |
| 12874 | prg16_89ab(machine, 0); | |
| 12875 | prg16_cdef(machine, 1); | |
| 12876 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12877 | break; | |
| 12878 | ||
| 12879 | // UNIF only | |
| 12880 | case BMC_64IN1NR: | |
| 12881 | state->m_mmc_reg[0] = 0x80; | |
| 12882 | state->m_mmc_reg[1] = 0x43; | |
| 12883 | state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12884 | bmc_64in1nr_set_prg(machine); | |
| 12885 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12886 | break; | |
| 12887 | case BMC_190IN1: | |
| 12888 | prg16_89ab(machine, 0); | |
| 12889 | prg16_cdef(machine, 0); | |
| 12890 | break; | |
| 12891 | case BMC_A65AS: | |
| 12892 | prg16_89ab(machine, 0); | |
| 12893 | prg16_cdef(machine, 7); | |
| 12894 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12895 | break; | |
| 12896 | case BMC_GS2004: | |
| 12897 | case BMC_GS2013: | |
| 12898 | prg32(machine, 0xff); | |
| 12899 | break; | |
| 12900 | case BMC_S24IN1SC03: | |
| 12901 | state->m_mmc_reg[0] = 0x24; | |
| 12902 | state->m_mmc_reg[1] = 0x9f; | |
| 12903 | state->m_mmc_reg[2] = 0; | |
| 12904 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12905 | break; | |
| 12906 | case BMC_T262: | |
| 12907 | state->m_mmc_latch1 = 0; | |
| 12908 | state->m_mmc_latch2 = 0; | |
| 12909 | prg16_89ab(machine, 0); | |
| 12910 | prg16_cdef(machine, 7); | |
| 12911 | break; | |
| 12912 | case DREAMTECH_BOARD: | |
| 12913 | prg16_89ab(machine, 0); | |
| 12914 | prg16_cdef(machine, 8); | |
| 12915 | break; | |
| 12916 | case UNL_8237: | |
| 12917 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = 0; | |
| 12918 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12919 | break; | |
| 12920 | case UNL_AX5705: | |
| 12921 | state->m_mmc_prg_bank[0] = 0; | |
| 12922 | state->m_mmc_prg_bank[1] = 1; | |
| 12923 | prg8_89(machine, state->m_mmc_prg_bank[0]); | |
| 12924 | prg8_ab(machine, state->m_mmc_prg_bank[1]); | |
| 12925 | prg8_cd(machine, 0xfe); | |
| 12926 | prg8_ef(machine, 0xff); | |
| 12927 | break; | |
| 12928 | case UNL_RACERMATE: | |
| 12929 | chr4_0(machine, 0, state->m_mmc_chr_source); | |
| 12930 | chr4_4(machine, 0, state->m_mmc_chr_source); | |
| 12931 | prg16_89ab(machine, 0); | |
| 12932 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12933 | break; | |
| 12934 | ||
| 12935 | case BMC_BENSHENG_BS5: | |
| 12936 | state->m_mmc_prg_bank[0] = 0xff; | |
| 12937 | state->m_mmc_prg_bank[1] = 0xff; | |
| 12938 | state->m_mmc_prg_bank[2] = 0xff; | |
| 12939 | state->m_mmc_prg_bank[3] = 0xff; | |
| 12940 | bmc_bs5_update_banks(machine); | |
| 12941 | break; | |
| 12942 | ||
| 12943 | case BMC_810544: | |
| 12944 | prg16_89ab(machine, 0); | |
| 12945 | prg16_cdef(machine, 0); | |
| 12946 | set_nt_mirroring(machine, PPU_MIRROR_VERT); | |
| 12947 | break; | |
| 12948 | ||
| 12949 | case BMC_G63IN1: | |
| 12950 | bmc_gb63_update(machine); | |
| 12951 | break; | |
| 12952 | ||
| 12953 | case BMC_FK23C: | |
| 12954 | state->m_mmc_reg[0] = 4; | |
| 12955 | state->m_mmc_reg[1] = 0xff; | |
| 12956 | state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12957 | state->m_mmc_reg[4] = state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0xff; | |
| 12958 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12959 | fk23c_set_prg(machine); | |
| 12960 | fk23c_set_chr(machine); | |
| 12961 | break; | |
| 12962 | ||
| 12963 | case BMC_FK23CA: | |
| 12964 | state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0; | |
| 12965 | state->m_mmc_reg[4] = state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0xff; | |
| 12966 | mmc3_common_initialize(machine, 0xff, 0xff, 0); | |
| 12967 | fk23c_set_prg(machine); | |
| 12968 | fk23c_set_chr(machine); | |
| 12969 | break; | |
| 12970 | ||
| 12971 | ||
| 12972 | case FFE_MAPPER6: | |
| 12973 | prg16_89ab(machine, 0); | |
| 12974 | prg16_cdef(machine, 7); | |
| 12975 | break; | |
| 12976 | case FFE_MAPPER8: | |
| 12977 | prg32(machine, 0); | |
| 12978 | break; | |
| 12979 | case FFE_MAPPER17: | |
| 12980 | prg16_89ab(machine, 0); | |
| 12981 | prg16_cdef(machine, state->m_prg_chunks - 1); | |
| 12982 | break; | |
| 12983 | ||
| 12984 | case UNSUPPORTED_BOARD: | |
| 12985 | default: | |
| 12986 | /* Mapper not supported */ | |
| 12987 | err = 2; | |
| 12988 | break; | |
| 12989 | } | |
| 12990 | ||
| 12991 | return err; | |
| 12992 | } | |
| 12993 | ||
| 12994 | /************************************************************* | |
| 12995 | ||
| 12996 | nes_pcb_reset | |
| 12997 | ||
| 12998 | Resets the mmc bankswitch areas to their defaults. | |
| 12999 | It returns a value "err" that indicates if it was | |
| 13000 | successful. Possible values for err are: | |
| 13001 | ||
| 13002 | 0 = success | |
| 13003 | 1 = no pcb found | |
| 13004 | 2 = pcb not supported | |
| 13005 | ||
| 13006 | *************************************************************/ | |
| 13007 | ||
| 13008 | int nes_pcb_reset( running_machine &machine ) | |
| 13009 | { | |
| 13010 | nes_state *state = machine.driver_data<nes_state>(); | |
| 13011 | int err = 0; | |
| 13012 | const nes_pcb_intf *intf = nes_pcb_intf_lookup(state->m_pcb_id); | |
| 13013 | ||
| 13014 | if (intf == NULL) | |
| 13015 | fatalerror("Missing PCB interface\n"); | |
| 13016 | ||
| 13017 | /* Set the mapper irq callback */ | |
| 13018 | ppu2c0x_set_scanline_callback(state->m_ppu, intf ? intf->mmc_scanline : NULL); | |
| 13019 | ppu2c0x_set_hblank_callback(state->m_ppu, intf ? intf->mmc_hblank : NULL); | |
| 13020 | ||
| 13021 | err = pcb_initialize(machine, state->m_pcb_id); | |
| 13022 | ||
| 13023 | return err; | |
| 13024 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Amiga CD-ROM controller emulation | |
| 4 | ||
| 5 | Notes: | |
| 6 | Many thanks to Toni Wilen for all the help and information about the | |
| 7 | DMAC controller. | |
| 8 | ||
| 9 | ***************************************************************************/ | |
| 10 | ||
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | #include "includes/amiga.h" | |
| 14 | #include "amigacd.h" | |
| 15 | #include "machine/6525tpi.h" | |
| 16 | #include "machine/6526cia.h" | |
| 17 | #include "machine/wd33c93.h" | |
| 18 | #include "imagedev/chd_cd.h" | |
| 19 | #include "machine/matsucd.h" | |
| 20 | ||
| 21 | ||
| 22 | #define VERBOSE_DMAC 0 | |
| 23 | ||
| 24 | #define LOG(x) do { if (VERBOSE_DMAC) logerror x; } while (0) | |
| 25 | ||
| 26 | /* constants */ | |
| 27 | #define CD_SECTOR_TIME (1000/((300*1024)/2048)) /* 2X CDROM sector time in msec (300KBps) */ | |
| 28 | ||
| 29 | /*************************************************************************** | |
| 30 | ||
| 31 | DMAC | |
| 32 | ||
| 33 | ***************************************************************************/ | |
| 34 | ||
| 35 | /* | |
| 36 | * value to go into DAWR | |
| 37 | */ | |
| 38 | #define DAWR_ATZSC 3 /* according to A3000T service-manual */ | |
| 39 | ||
| 40 | /* | |
| 41 | * bits defined for CNTR | |
| 42 | */ | |
| 43 | #define CNTR_TCEN (1<<7) /* Terminal Count Enable */ | |
| 44 | #define CNTR_PREST (1<<6) /* Perp Reset (not implemented :-((( ) */ | |
| 45 | #define CNTR_PDMD (1<<5) /* Perp Device Mode Select (1=SCSI,0=XT/AT) */ | |
| 46 | #define CNTR_INTEN (1<<4) /* Interrupt Enable */ | |
| 47 | #define CNTR_DDIR (1<<3) /* Device Direction. 1==rd host, wr to perp */ | |
| 48 | ||
| 49 | /* | |
| 50 | * bits defined for ISTR | |
| 51 | */ | |
| 52 | #define ISTR_INTX (1<<8) /* XT/AT Interrupt pending */ | |
| 53 | #define ISTR_INT_F (1<<7) /* Interrupt Follow */ | |
| 54 | #define ISTR_INTS (1<<6) /* SCSI Peripheral Interrupt */ | |
| 55 | #define ISTR_E_INT (1<<5) /* End-Of-Process Interrupt */ | |
| 56 | #define ISTR_INT_P (1<<4) /* Interrupt Pending */ | |
| 57 | #define ISTR_UE_INT (1<<3) /* Under-Run FIFO Error Interrupt */ | |
| 58 | #define ISTR_OE_INT (1<<2) /* Over-Run FIFO Error Interrupt */ | |
| 59 | #define ISTR_FF_FLG (1<<1) /* FIFO-Full Flag */ | |
| 60 | #define ISTR_FE_FLG (1<<0) /* FIFO-Empty Flag */ | |
| 61 | ||
| 62 | typedef struct | |
| 63 | { | |
| 64 | UINT16 istr; /* Interrupt Status Register (R) */ | |
| 65 | UINT16 cntr; /* Control Register (RW) */ | |
| 66 | UINT32 wtc; /* Word Transfer Count Register (RW) */ | |
| 67 | UINT32 acr; /* Address Count Register (RW) */ | |
| 68 | UINT16 dawr; /* DACK Width Register (W) */ | |
| 69 | emu_timer *dma_timer; | |
| 70 | } _dmac_data; | |
| 71 | ||
| 72 | static _dmac_data dmac_data; | |
| 73 | ||
| 74 | static void check_interrupts( running_machine &machine ) | |
| 75 | { | |
| 76 | /* if interrupts are disabled, bail */ | |
| 77 | if ( (dmac_data.cntr & CNTR_INTEN) == 0 ) | |
| 78 | return; | |
| 79 | ||
| 80 | /* if no interrupts are pending, bail */ | |
| 81 | if ( (dmac_data.istr & ISTR_INT_P) == 0 ) | |
| 82 | return; | |
| 83 | ||
| 84 | /* otherwise, generate the IRQ */ | |
| 85 | amiga_custom_w(machine.device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff); | |
| 86 | } | |
| 87 | ||
| 88 | static TIMER_CALLBACK(dmac_dma_proc) | |
| 89 | { | |
| 90 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 91 | while( dmac_data.wtc > 0 ) | |
| 92 | { | |
| 93 | UINT16 dat16; | |
| 94 | UINT8 dat8; | |
| 95 | ||
| 96 | if ( matsucd_get_next_byte( &dat8 ) < 0 ) | |
| 97 | break; | |
| 98 | ||
| 99 | dat16 = dat8; | |
| 100 | ||
| 101 | if ( matsucd_get_next_byte( &dat8 ) < 0 ) | |
| 102 | break; | |
| 103 | ||
| 104 | dat16 <<= 8; | |
| 105 | dat16 |= dat8; | |
| 106 | ||
| 107 | (*state->m_chip_ram_w)(state, dmac_data.acr, dat16); | |
| 108 | ||
| 109 | dmac_data.acr += 2; | |
| 110 | dmac_data.wtc--; | |
| 111 | } | |
| 112 | ||
| 113 | if ( dmac_data.wtc > 0 ) | |
| 114 | { | |
| 115 | matsucd_read_next_block(); | |
| 116 | dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME )); | |
| 117 | } | |
| 118 | else | |
| 119 | { | |
| 120 | dmac_data.istr |= ISTR_INT_P | ISTR_E_INT; | |
| 121 | check_interrupts( machine ); | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | static READ16_HANDLER( amiga_dmac_r ) | |
| 126 | { | |
| 127 | offset &= 0xff; | |
| 128 | ||
| 129 | switch( offset ) | |
| 130 | { | |
| 131 | case 0x20: | |
| 132 | { | |
| 133 | UINT8 v = dmac_data.istr; | |
| 134 | LOG(( "DMAC: PC=%08x - ISTR Read(%04x)\n", cpu_get_pc(&space->device()), dmac_data.istr )); | |
| 135 | ||
| 136 | dmac_data.istr &= ~0x0f; | |
| 137 | return v; | |
| 138 | } | |
| 139 | break; | |
| 140 | ||
| 141 | case 0x21: | |
| 142 | { | |
| 143 | LOG(( "DMAC: PC=%08x - CNTR Read(%04x)\n", cpu_get_pc(&space->device()), dmac_data.cntr )); | |
| 144 | return dmac_data.cntr; | |
| 145 | } | |
| 146 | break; | |
| 147 | ||
| 148 | case 0x40: /* wtc hi */ | |
| 149 | { | |
| 150 | LOG(( "DMAC: PC=%08x - WTC HI Read\n", cpu_get_pc(&space->device()) )); | |
| 151 | return (dmac_data.wtc >> 16); | |
| 152 | } | |
| 153 | break; | |
| 154 | ||
| 155 | case 0x41: /* wtc lo */ | |
| 156 | { | |
| 157 | LOG(( "DMAC: PC=%08x - WTC LO Read\n", cpu_get_pc(&space->device()) )); | |
| 158 | return dmac_data.wtc; | |
| 159 | } | |
| 160 | break; | |
| 161 | ||
| 162 | case 0x42: /* acr hi */ | |
| 163 | { | |
| 164 | LOG(( "DMAC: PC=%08x - ACR HI Read\n", cpu_get_pc(&space->device()) )); | |
| 165 | return (dmac_data.acr >> 16); | |
| 166 | } | |
| 167 | break; | |
| 168 | ||
| 169 | case 0x43: /* acr lo */ | |
| 170 | { | |
| 171 | LOG(( "DMAC: PC=%08x - ACR LO Read\n", cpu_get_pc(&space->device()) )); | |
| 172 | return dmac_data.acr; | |
| 173 | } | |
| 174 | break; | |
| 175 | ||
| 176 | case 0x48: /* wd33c93 SCSI expansion */ | |
| 177 | case 0x49: | |
| 178 | { | |
| 179 | LOG(( "DMAC: PC=%08x - WD33C93 Read(%d)\n", cpu_get_pc(&space->device()), offset & 1 )); | |
| 180 | return 0x00; /* Not available without SCSI expansion */ | |
| 181 | } | |
| 182 | break; | |
| 183 | ||
| 184 | case 0x50: | |
| 185 | { | |
| 186 | LOG(( "DMAC: PC=%08x - CDROM RESP Read\n", cpu_get_pc(&space->device()) )); | |
| 187 | return matsucd_response_r(space->machine()); | |
| 188 | } | |
| 189 | break; | |
| 190 | ||
| 191 | case 0x51: /* XT IO */ | |
| 192 | case 0x52: | |
| 193 | case 0x53: | |
| 194 | { | |
| 195 | LOG(( "DMAC: PC=%08x - XT IO Read(%d)\n", cpu_get_pc(&space->device()), (offset & 3)-1 )); | |
| 196 | return 0xff; | |
| 197 | } | |
| 198 | break; | |
| 199 | ||
| 200 | case 0x58: /* TPI6525 */ | |
| 201 | case 0x59: | |
| 202 | case 0x5A: | |
| 203 | case 0x5B: | |
| 204 | case 0x5C: | |
| 205 | case 0x5D: | |
| 206 | case 0x5E: | |
| 207 | case 0x5F: | |
| 208 | case 0x60: | |
| 209 | case 0x61: | |
| 210 | case 0x62: | |
| 211 | case 0x63: | |
| 212 | case 0x64: | |
| 213 | case 0x65: | |
| 214 | case 0x66: | |
| 215 | case 0x67: | |
| 216 | { | |
| 217 | device_t *tpi = space->machine().device("tpi6525"); | |
| 218 | LOG(( "DMAC: PC=%08x - TPI6525 Read(%d)\n", cpu_get_pc(&space->device()), (offset - 0x58) )); | |
| 219 | return tpi6525_r(tpi, offset - 0x58); | |
| 220 | } | |
| 221 | break; | |
| 222 | ||
| 223 | case 0x70: /* DMA start strobe */ | |
| 224 | { | |
| 225 | LOG(( "DMAC: PC=%08x - DMA Start Strobe\n", cpu_get_pc(&space->device()) )); | |
| 226 | dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME )); | |
| 227 | } | |
| 228 | break; | |
| 229 | ||
| 230 | case 0x71: /* DMA stop strobe */ | |
| 231 | { | |
| 232 | LOG(( "DMAC: PC=%08x - DMA Stop Strobe\n", cpu_get_pc(&space->device()) )); | |
| 233 | dmac_data.dma_timer->reset( ); | |
| 234 | } | |
| 235 | break; | |
| 236 | ||
| 237 | case 0x72: /* Clear IRQ strobe */ | |
| 238 | { | |
| 239 | LOG(( "DMAC: PC=%08x - IRQ Clear Strobe\n", cpu_get_pc(&space->device()) )); | |
| 240 | dmac_data.istr &= ~ISTR_INT_P; | |
| 241 | } | |
| 242 | break; | |
| 243 | ||
| 244 | case 0x74: /* Flush strobe */ | |
| 245 | { | |
| 246 | LOG(( "DMAC: PC=%08x - Flush Strobe\n", cpu_get_pc(&space->device()) )); | |
| 247 | dmac_data.istr |= ISTR_FE_FLG; | |
| 248 | } | |
| 249 | break; | |
| 250 | ||
| 251 | default: | |
| 252 | logerror( "DMAC-READ: PC=%08x, offset = %02x\n", cpu_get_pc(&space->device()), offset ); | |
| 253 | break; | |
| 254 | } | |
| 255 | ||
| 256 | return 0; | |
| 257 | } | |
| 258 | ||
| 259 | static WRITE16_HANDLER( amiga_dmac_w ) | |
| 260 | { | |
| 261 | offset &= 0xff; | |
| 262 | ||
| 263 | switch( offset ) | |
| 264 | { | |
| 265 | case 0x21: /* control write */ | |
| 266 | { | |
| 267 | LOG(( "DMAC: PC=%08x - CNTR Write(%04x)\n", cpu_get_pc(&space->device()), data )); | |
| 268 | dmac_data.cntr = data; | |
| 269 | check_interrupts(space->machine()); | |
| 270 | } | |
| 271 | break; | |
| 272 | ||
| 273 | case 0x40: /* wtc hi */ | |
| 274 | { | |
| 275 | LOG(( "DMAC: PC=%08x - WTC HI Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 276 | dmac_data.wtc &= 0x0000ffff; | |
| 277 | dmac_data.wtc |= ((UINT32)data) << 16; | |
| 278 | } | |
| 279 | break; | |
| 280 | ||
| 281 | case 0x41: /* wtc lo */ | |
| 282 | { | |
| 283 | LOG(( "DMAC: PC=%08x - WTC LO Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 284 | dmac_data.wtc &= 0xffff0000; | |
| 285 | dmac_data.wtc |= data; | |
| 286 | } | |
| 287 | break; | |
| 288 | ||
| 289 | case 0x42: /* acr hi */ | |
| 290 | { | |
| 291 | LOG(( "DMAC: PC=%08x - ACR HI Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 292 | dmac_data.acr &= 0x0000ffff; | |
| 293 | dmac_data.acr |= ((UINT32)data) << 16; | |
| 294 | } | |
| 295 | break; | |
| 296 | ||
| 297 | case 0x43: /* acr lo */ | |
| 298 | { | |
| 299 | LOG(( "DMAC: PC=%08x - ACR LO Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 300 | dmac_data.acr &= 0xffff0000; | |
| 301 | dmac_data.acr |= data; | |
| 302 | } | |
| 303 | break; | |
| 304 | ||
| 305 | case 0x47: /* dawr */ | |
| 306 | { | |
| 307 | LOG(( "DMAC: PC=%08x - DAWR Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 308 | dmac_data.dawr = data; | |
| 309 | } | |
| 310 | break; | |
| 311 | ||
| 312 | case 0x48: /* wd33c93 SCSI expansion */ | |
| 313 | case 0x49: | |
| 314 | { | |
| 315 | LOG(( "DMAC: PC=%08x - WD33C93 Write(%d) - data = %04x\n", cpu_get_pc(&space->device()), offset & 1, data )); | |
| 316 | /* Not available without SCSI expansion */ | |
| 317 | } | |
| 318 | break; | |
| 319 | ||
| 320 | case 0x50: | |
| 321 | { | |
| 322 | LOG(( "DMAC: PC=%08x - CDROM CMD Write - data = %04x\n", cpu_get_pc(&space->device()), data )); | |
| 323 | matsucd_command_w(space->machine(), data ); | |
| 324 | } | |
| 325 | break; | |
| 326 | ||
| 327 | case 0x58: /* TPI6525 */ | |
| 328 | case 0x59: | |
| 329 | case 0x5A: | |
| 330 | case 0x5B: | |
| 331 | case 0x5C: | |
| 332 | case 0x5D: | |
| 333 | case 0x5E: | |
| 334 | case 0x5F: | |
| 335 | case 0x60: | |
| 336 | case 0x61: | |
| 337 | case 0x62: | |
| 338 | case 0x63: | |
| 339 | case 0x64: | |
| 340 | case 0x65: | |
| 341 | case 0x66: | |
| 342 | case 0x67: | |
| 343 | { | |
| 344 | device_t *tpi = space->machine().device("tpi6525"); | |
| 345 | LOG(( "DMAC: PC=%08x - TPI6525 Write(%d) - data = %04x\n", cpu_get_pc(&space->device()), (offset - 0x58), data )); | |
| 346 | tpi6525_w(tpi, offset - 0x58, data); | |
| 347 | } | |
| 348 | break; | |
| 349 | ||
| 350 | case 0x70: /* DMA start strobe */ | |
| 351 | { | |
| 352 | LOG(( "DMAC: PC=%08x - DMA Start Strobe\n", cpu_get_pc(&space->device()) )); | |
| 353 | dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME )); | |
| 354 | } | |
| 355 | break; | |
| 356 | ||
| 357 | case 0x71: /* DMA stop strobe */ | |
| 358 | { | |
| 359 | LOG(( "DMAC: PC=%08x - DMA Stop Strobe\n", cpu_get_pc(&space->device()) )); | |
| 360 | dmac_data.dma_timer->reset( ); | |
| 361 | } | |
| 362 | break; | |
| 363 | ||
| 364 | case 0x72: /* Clear IRQ strobe */ | |
| 365 | { | |
| 366 | LOG(( "DMAC: PC=%08x - IRQ Clear Strobe\n", cpu_get_pc(&space->device()) )); | |
| 367 | dmac_data.istr &= ~ISTR_INT_P; | |
| 368 | } | |
| 369 | break; | |
| 370 | ||
| 371 | case 0x74: /* Flush Strobe */ | |
| 372 | { | |
| 373 | LOG(( "DMAC: PC=%08x - Flush Strobe\n", cpu_get_pc(&space->device()) )); | |
| 374 | dmac_data.istr |= ISTR_FE_FLG; | |
| 375 | } | |
| 376 | break; | |
| 377 | ||
| 378 | default: | |
| 379 | logerror( "DMAC-WRITE: PC=%08x, offset = %02x, data = %04x\n", cpu_get_pc(&space->device()), offset, data ); | |
| 380 | break; | |
| 381 | } | |
| 382 | } | |
| 383 | ||
| 384 | /*************************************************************************** | |
| 385 | ||
| 386 | Autoconfig | |
| 387 | ||
| 388 | ***************************************************************************/ | |
| 389 | ||
| 390 | static void dmac_install(running_machine &machine, offs_t base) | |
| 391 | { | |
| 392 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 393 | space->install_legacy_read_handler(base, base + 0xFFFF, FUNC(amiga_dmac_r)); | |
| 394 | space->install_legacy_write_handler(base, base + 0xFFFF, FUNC(amiga_dmac_w)); | |
| 395 | } | |
| 396 | ||
| 397 | static void dmac_uninstall(running_machine &machine, offs_t base) | |
| 398 | { | |
| 399 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 400 | space->unmap_readwrite(base, base + 0xFFFF); | |
| 401 | } | |
| 402 | ||
| 403 | static const amiga_autoconfig_device dmac_device = | |
| 404 | { | |
| 405 | 0, /* link into free memory list */ | |
| 406 | 0, /* ROM vector offset valid */ | |
| 407 | 0, /* multiple devices on card */ | |
| 408 | 1, /* number of 64k pages */ | |
| 409 | 3, /* product number (DMAC) */ | |
| 410 | 0, /* prefer 8MB address space */ | |
| 411 | 0, /* can be shut up */ | |
| 412 | 0x0202, /* manufacturers number (Commodore) */ | |
| 413 | 0, /* serial number */ | |
| 414 | 0, /* ROM vector offset */ | |
| 415 | NULL, /* interrupt control read */ | |
| 416 | NULL, /* interrupt control write */ | |
| 417 | dmac_install, /* memory installation */ | |
| 418 | dmac_uninstall /* memory uninstallation */ | |
| 419 | }; | |
| 420 | ||
| 421 | /*************************************************************************** | |
| 422 | ||
| 423 | TPI6525 | |
| 424 | ||
| 425 | ***************************************************************************/ | |
| 426 | ||
| 427 | READ8_DEVICE_HANDLER( amigacd_tpi6525_portc_r ) | |
| 428 | { | |
| 429 | int ret = 0; | |
| 430 | ||
| 431 | if ( (tpi6525_get_ddr_c(device) & 0x04) == 0 ) /* if pin 2 is set to input */ | |
| 432 | { | |
| 433 | ret |= matsucd_stch_r() ? 0x00 : 0x04; /* read status change signal */ | |
| 434 | } | |
| 435 | ||
| 436 | if ( (tpi6525_get_ddr_c(device) & 0x08) == 0 ) /* if pin 3 is set to input */ | |
| 437 | ret |= matsucd_sten_r() ? 0x08 : 0x00; /* read enable signal */ | |
| 438 | ||
| 439 | return ret; | |
| 440 | } | |
| 441 | ||
| 442 | WRITE8_DEVICE_HANDLER( amigacd_tpi6525_portb_w ) | |
| 443 | { | |
| 444 | if ( tpi6525_get_ddr_b(device) & 0x01 ) /* if pin 0 is set to output */ | |
| 445 | matsucd_cmd_w( data & 1 ); /* write to the /CMD signal */ | |
| 446 | ||
| 447 | if ( tpi6525_get_ddr_b(device) & 0x02 ) /* if pin 1 is set to output */ | |
| 448 | matsucd_enable_w( data & 2 ); /* write to the /ENABLE signal */ | |
| 449 | } | |
| 450 | ||
| 451 | static emu_timer *tp6525_delayed_timer; | |
| 452 | ||
| 453 | static TIMER_CALLBACK(tp6525_delayed_irq) | |
| 454 | { | |
| 455 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 456 | (void)param; | |
| 457 | ||
| 458 | if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 ) | |
| 459 | { | |
| 460 | amiga_custom_w(machine.device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff); | |
| 461 | } | |
| 462 | else | |
| 463 | { | |
| 464 | tp6525_delayed_timer->adjust(attotime::from_msec(1)); | |
| 465 | } | |
| 466 | } | |
| 467 | ||
| 468 | static void amigacd_tpi6525_irq_trampoline(device_t *device, int level) | |
| 469 | { | |
| 470 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 471 | LOG(( "TPI6525 Interrupt: level = %d\n", level )); | |
| 472 | ||
| 473 | if ( level ) | |
| 474 | { | |
| 475 | if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 ) | |
| 476 | { | |
| 477 | amiga_custom_w(device->machine().device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff); | |
| 478 | } | |
| 479 | else | |
| 480 | { | |
| 481 | /* we *have to* deliver the irq, so if we can't, delay it and try again later */ | |
| 482 | tp6525_delayed_timer->adjust(attotime::from_msec(1)); | |
| 483 | } | |
| 484 | } | |
| 485 | } | |
| 486 | ||
| 487 | WRITE_LINE_DEVICE_HANDLER( amigacd_tpi6525_irq ) | |
| 488 | { | |
| 489 | amigacd_tpi6525_irq_trampoline(device, state); | |
| 490 | } | |
| 491 | ||
| 492 | static void cdrom_status_enabled( running_machine &machine, int level ) | |
| 493 | { | |
| 494 | device_t *tpi = machine.device("tpi6525"); | |
| 495 | ||
| 496 | /* PC3 on the 6525 */ | |
| 497 | tpi6525_i3_w(tpi, level); | |
| 498 | } | |
| 499 | ||
| 500 | static void cdrom_status_change( running_machine &machine, int level ) | |
| 501 | { | |
| 502 | device_t *tpi = machine.device("tpi6525"); | |
| 503 | ||
| 504 | /* invert */ | |
| 505 | level = level ? 0 : 1; | |
| 506 | ||
| 507 | /* PC2 on the 6525 */ | |
| 508 | tpi6525_i2_w(tpi, level); | |
| 509 | } | |
| 510 | ||
| 511 | static void cdrom_subcode_ready( running_machine &machine, int level ) | |
| 512 | { | |
| 513 | device_t *tpi = machine.device("tpi6525"); | |
| 514 | ||
| 515 | /* PC1 on the 6525 */ | |
| 516 | tpi6525_i1_w(tpi, level); | |
| 517 | } | |
| 518 | ||
| 519 | MACHINE_START( amigacd ) | |
| 520 | { | |
| 521 | /* initialize the dmac */ | |
| 522 | memset( &dmac_data, 0, sizeof( dmac_data ) ); | |
| 523 | ||
| 524 | dmac_data.dma_timer = machine.scheduler().timer_alloc(FUNC(dmac_dma_proc)); | |
| 525 | tp6525_delayed_timer = machine.scheduler().timer_alloc(FUNC(tp6525_delayed_irq)); | |
| 526 | ||
| 527 | /* set up DMAC with autoconfig */ | |
| 528 | amiga_add_autoconfig( machine, &dmac_device ); | |
| 529 | ||
| 530 | matsucd_init( machine.device("cdrom"), "cdda" ); | |
| 531 | } | |
| 532 | ||
| 533 | MACHINE_RESET( amigacd ) | |
| 534 | { | |
| 535 | /* initialize the cdrom */ | |
| 536 | matsucd_set_status_enabled_callback( cdrom_status_enabled ); | |
| 537 | matsucd_set_status_changed_callback( cdrom_status_change ); | |
| 538 | matsucd_set_subcode_ready_callback( cdrom_subcode_ready ); | |
| 539 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | #include "emu.h" | |
| 2 | #include "crsshair.h" | |
| 3 | #include "hash.h" | |
| 4 | #include "cpu/m6502/m6502.h" | |
| 5 | #include "video/ppu2c0x.h" | |
| 6 | #include "includes/nes.h" | |
| 7 | #include "machine/nes_mmc.h" | |
| 8 | #include "imagedev/cartslot.h" | |
| 9 | #include "imagedev/flopdrv.h" | |
| 10 | #include "hashfile.h" | |
| 11 | ||
| 12 | /*************************************************************************** | |
| 13 | CONSTANTS | |
| 14 | ***************************************************************************/ | |
| 15 | ||
| 16 | /* Set to dump info about the inputs to the errorlog */ | |
| 17 | #define LOG_JOY 0 | |
| 18 | ||
| 19 | /* Set to generate prg & chr files when the cart is loaded */ | |
| 20 | #define SPLIT_PRG 0 | |
| 21 | #define SPLIT_CHR 0 | |
| 22 | ||
| 23 | /*************************************************************************** | |
| 24 | FUNCTION PROTOTYPES | |
| 25 | ***************************************************************************/ | |
| 26 | ||
| 27 | static void init_nes_core(running_machine &machine); | |
| 28 | static void nes_machine_stop(running_machine &machine); | |
| 29 | static READ8_HANDLER(nes_fds_r); | |
| 30 | static WRITE8_HANDLER(nes_fds_w); | |
| 31 | static void fds_irq(device_t *device, int scanline, int vblank, int blanked); | |
| 32 | ||
| 33 | /*************************************************************************** | |
| 34 | FUNCTIONS | |
| 35 | ***************************************************************************/ | |
| 36 | ||
| 37 | static void init_nes_core( running_machine &machine ) | |
| 38 | { | |
| 39 | nes_state *state = machine.driver_data<nes_state>(); | |
| 40 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 41 | static const char *const bank_names[] = { "bank1", "bank2", "bank3", "bank4" }; | |
| 42 | int prg_banks = (state->m_prg_chunks == 1) ? (2 * 2) : (state->m_prg_chunks * 2); | |
| 43 | int i; | |
| 44 | ||
| 45 | /* We set these here in case they weren't set in the cart loader */ | |
| 46 | state->m_rom = machine.region("maincpu")->base(); | |
| 47 | state->m_vrom = machine.region("gfx1")->base(); | |
| 48 | state->m_vram = machine.region("gfx2")->base(); | |
| 49 | state->m_ciram = machine.region("gfx3")->base(); | |
| 50 | ||
| 51 | /* Brutal hack put in as a consequence of the new memory system; we really need to fix the NES code */ | |
| 52 | space->install_readwrite_bank(0x0000, 0x07ff, 0, 0x1800, "bank10"); | |
| 53 | ||
| 54 | machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0, 0x1fff, FUNC(nes_chr_r), FUNC(nes_chr_w)); | |
| 55 | machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x2000, 0x3eff, FUNC(nes_nt_r), FUNC(nes_nt_w)); | |
| 56 | ||
| 57 | memory_set_bankptr(machine, "bank10", state->m_rom); | |
| 58 | ||
| 59 | /* If there is Disk Expansion and no cart has been loaded, setup memory accordingly */ | |
| 60 | if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD) | |
| 61 | { | |
| 62 | /* If we are loading a disk we have already filled state->m_fds_data and we don't want to overwrite it, | |
| 63 | if we are loading a cart image identified as mapper 20 (probably wrong mapper...) we need to alloc | |
| 64 | memory for use in nes_fds_r/nes_fds_w. Same goes for allocation of fds_ram (used for bank2) */ | |
| 65 | if (state->m_fds_data == NULL) | |
| 66 | { | |
| 67 | UINT32 size = machine.region("maincpu")->bytes() - 0x10000; | |
| 68 | state->m_fds_data = auto_alloc_array_clear(machine, UINT8, size); | |
| 69 | memcpy(state->m_fds_data, state->m_rom, size); // copy in fds_data the cart PRG | |
| 70 | } | |
| 71 | if (state->m_fds_ram == NULL) | |
| 72 | state->m_fds_ram = auto_alloc_array(machine, UINT8, 0x8000); | |
| 73 | ||
| 74 | space->install_legacy_read_handler(0x4030, 0x403f, FUNC(nes_fds_r)); | |
| 75 | space->install_read_bank(0x6000, 0xdfff, "bank2"); | |
| 76 | space->install_read_bank(0xe000, 0xffff, "bank1"); | |
| 77 | ||
| 78 | space->install_legacy_write_handler(0x4020, 0x402f, FUNC(nes_fds_w)); | |
| 79 | space->install_write_bank(0x6000, 0xdfff, "bank2"); | |
| 80 | ||
| 81 | memory_set_bankptr(machine, "bank1", &state->m_rom[0xe000]); | |
| 82 | memory_set_bankptr(machine, "bank2", state->m_fds_ram); | |
| 83 | return; | |
| 84 | } | |
| 85 | ||
| 86 | /* Set up the mapper callbacks */ | |
| 87 | pcb_handlers_setup(machine); | |
| 88 | ||
| 89 | /* Set up the memory handlers for the mapper */ | |
| 90 | space->install_read_bank(0x8000, 0x9fff, "bank1"); | |
| 91 | space->install_read_bank(0xa000, 0xbfff, "bank2"); | |
| 92 | space->install_read_bank(0xc000, 0xdfff, "bank3"); | |
| 93 | space->install_read_bank(0xe000, 0xffff, "bank4"); | |
| 94 | space->install_readwrite_bank(0x6000, 0x7fff, "bank5"); | |
| 95 | ||
| 96 | /* configure banks 1-4 */ | |
| 97 | for (i = 0; i < 4; i++) | |
| 98 | { | |
| 99 | memory_configure_bank(machine, bank_names[i], 0, prg_banks, machine.region("maincpu")->base() + 0x10000, 0x2000); | |
| 100 | // some mappers (e.g. MMC5) can map PRG RAM in 0x8000-0xffff as well | |
| 101 | if (state->m_prg_ram) | |
| 102 | memory_configure_bank(machine, bank_names[i], prg_banks, state->m_wram_size / 0x2000, state->m_wram, 0x2000); | |
| 103 | // however, at start we point to PRG ROM | |
| 104 | memory_set_bank(machine, bank_names[i], i); | |
| 105 | state->m_prg_bank[i] = i; | |
| 106 | } | |
| 107 | ||
| 108 | /* bank 5 configuration is more delicate, since it can have PRG RAM, PRG ROM or SRAM mapped to it */ | |
| 109 | /* we first map PRG ROM banks, then the battery bank (if a battery is present), and finally PRG RAM (state->m_wram) */ | |
| 110 | memory_configure_bank(machine, "bank5", 0, prg_banks, machine.region("maincpu")->base() + 0x10000, 0x2000); | |
| 111 | state->m_battery_bank5_start = prg_banks; | |
| 112 | state->m_prgram_bank5_start = prg_banks; | |
| 113 | state->m_empty_bank5_start = prg_banks; | |
| 114 | ||
| 115 | /* add battery ram, but only if there's no trainer since they share overlapping memory. */ | |
| 116 | if (state->m_battery && !state->m_trainer) | |
| 117 | { | |
| 118 | UINT32 bank_size = (state->m_battery_size > 0x2000) ? 0x2000 : state->m_battery_size; | |
| 119 | int bank_num = (state->m_battery_size > 0x2000) ? state->m_battery_size / 0x2000 : 1; | |
| 120 | memory_configure_bank(machine, "bank5", prg_banks, bank_num, state->m_battery_ram, bank_size); | |
| 121 | state->m_prgram_bank5_start += bank_num; | |
| 122 | state->m_empty_bank5_start += bank_num; | |
| 123 | } | |
| 124 | /* add prg ram. */ | |
| 125 | if (state->m_prg_ram) | |
| 126 | { | |
| 127 | memory_configure_bank(machine, "bank5", state->m_prgram_bank5_start, state->m_wram_size / 0x2000, state->m_wram, 0x2000); | |
| 128 | state->m_empty_bank5_start += state->m_wram_size / 0x2000; | |
| 129 | } | |
| 130 | ||
| 131 | memory_configure_bank(machine, "bank5", state->m_empty_bank5_start, 1, state->m_rom + 0x6000, 0x2000); | |
| 132 | ||
| 133 | /* if we have any additional PRG RAM, point bank5 to its first bank */ | |
| 134 | if (state->m_battery || state->m_prg_ram) | |
| 135 | state->m_prg_bank[4] = state->m_battery_bank5_start; | |
| 136 | else | |
| 137 | state->m_prg_bank[4] = state->m_empty_bank5_start; // or shall we point to "maincpu" region at 0x6000? point is that we should never access this region if no sram or wram is present! | |
| 138 | ||
| 139 | memory_set_bank(machine, "bank5", state->m_prg_bank[4]); | |
| 140 | ||
| 141 | if (state->m_four_screen_vram) | |
| 142 | { | |
| 143 | state->m_extended_ntram = auto_alloc_array(machine, UINT8, 0x2000); | |
| 144 | state->save_pointer(NAME(state->m_extended_ntram), 0x2000); | |
| 145 | } | |
| 146 | ||
| 147 | // there are still some quirk about writes to bank5... I hope to fix them soon. (mappers 34,45,52,246 have both mid_w and WRAM-->check) | |
| 148 | if (state->m_mmc_write_mid) | |
| 149 | space->install_legacy_write_handler(0x6000, 0x7fff, state->m_mmc_write_mid,state->m_mmc_write_mid_name); | |
| 150 | if (state->m_mmc_write) | |
| 151 | space->install_legacy_write_handler(0x8000, 0xffff, state->m_mmc_write, state->m_mmc_write_name); | |
| 152 | ||
| 153 | // In fact, we also allow single pcbs to overwrite the bank read handlers defined above, | |
| 154 | // because some pcbs (mainly pirate ones) require protection values to be read instead of | |
| 155 | // the expected ROM banks: these handlers, though, must take care of the ROM access as well | |
| 156 | if (state->m_mmc_read_mid) | |
| 157 | space->install_legacy_read_handler(0x6000, 0x7fff, state->m_mmc_read_mid,state->m_mmc_read_mid_name); | |
| 158 | if (state->m_mmc_read) | |
| 159 | space->install_legacy_read_handler(0x8000, 0xffff, state->m_mmc_read,state->m_mmc_read_name); | |
| 160 | ||
| 161 | // install additional handlers | |
| 162 | if (state->m_pcb_id == BTL_SMB2B || state->m_mapper == 50) | |
| 163 | { | |
| 164 | space->install_legacy_write_handler(0x4020, 0x403f, FUNC(smb2jb_extra_w)); | |
| 165 | space->install_legacy_write_handler(0x40a0, 0x40bf, FUNC(smb2jb_extra_w)); | |
| 166 | } | |
| 167 | ||
| 168 | if (state->m_pcb_id == KAISER_KS7017) | |
| 169 | { | |
| 170 | space->install_legacy_read_handler(0x4030, 0x4030, FUNC(ks7017_extra_r)); | |
| 171 | space->install_legacy_write_handler(0x4020, 0x40ff, FUNC(ks7017_extra_w)); | |
| 172 | } | |
| 173 | ||
| 174 | if (state->m_pcb_id == UNL_603_5052) | |
| 175 | { | |
| 176 | space->install_legacy_read_handler(0x4020, 0x40ff, FUNC(unl_6035052_extra_r)); | |
| 177 | space->install_legacy_write_handler(0x4020, 0x40ff, FUNC(unl_6035052_extra_w)); | |
| 178 | } | |
| 179 | ||
| 180 | if (state->m_pcb_id == WAIXING_SH2) | |
| 181 | machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0, 0x1fff, FUNC(waixing_sh2_chr_r)); | |
| 182 | } | |
| 183 | ||
| 184 | // to be probably removed (it does nothing since a long time) | |
| 185 | int nes_ppu_vidaccess( device_t *device, int address, int data ) | |
| 186 | { | |
| 187 | return data; | |
| 188 | } | |
| 189 | ||
| 190 | MACHINE_RESET( nes ) | |
| 191 | { | |
| 192 | nes_state *state = machine.driver_data<nes_state>(); | |
| 193 | ||
| 194 | /* Reset the mapper variables. Will also mark the char-gen ram as dirty */ | |
| 195 | if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD) | |
| 196 | ppu2c0x_set_hblank_callback(state->m_ppu, fds_irq); | |
| 197 | else | |
| 198 | nes_pcb_reset(machine); | |
| 199 | ||
| 200 | /* Reset the serial input ports */ | |
| 201 | state->m_in_0.shift = 0; | |
| 202 | state->m_in_1.shift = 0; | |
| 203 | ||
| 204 | machine.device("maincpu")->reset(); | |
| 205 | } | |
| 206 | ||
| 207 | static TIMER_CALLBACK( nes_irq_callback ) | |
| 208 | { | |
| 209 | nes_state *state = machine.driver_data<nes_state>(); | |
| 210 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 211 | state->m_irq_timer->adjust(attotime::never); | |
| 212 | } | |
| 213 | ||
| 214 | static void nes_banks_restore(nes_state *state) | |
| 215 | { | |
| 216 | memory_set_bank(state->machine(), "bank1", state->m_prg_bank[0]); | |
| 217 | memory_set_bank(state->machine(), "bank2", state->m_prg_bank[1]); | |
| 218 | memory_set_bank(state->machine(), "bank3", state->m_prg_bank[2]); | |
| 219 | memory_set_bank(state->machine(), "bank4", state->m_prg_bank[3]); | |
| 220 | memory_set_bank(state->machine(), "bank5", state->m_prg_bank[4]); | |
| 221 | } | |
| 222 | ||
| 223 | static void nes_state_register( running_machine &machine ) | |
| 224 | { | |
| 225 | nes_state *state = machine.driver_data<nes_state>(); | |
| 226 | ||
| 227 | state->save_item(NAME(state->m_prg_bank)); | |
| 228 | ||
| 229 | state->save_item(NAME(state->m_MMC5_floodtile)); | |
| 230 | state->save_item(NAME(state->m_MMC5_floodattr)); | |
| 231 | state->save_item(NAME(state->m_mmc5_vram_control)); | |
| 232 | ||
| 233 | state->save_item(NAME(state->m_nes_vram_sprite)); | |
| 234 | state->save_item(NAME(state->m_last_frame_flip)); | |
| 235 | ||
| 236 | // shared mapper variables | |
| 237 | state->save_item(NAME(state->m_IRQ_enable)); | |
| 238 | state->save_item(NAME(state->m_IRQ_enable_latch)); | |
| 239 | state->save_item(NAME(state->m_IRQ_count)); | |
| 240 | state->save_item(NAME(state->m_IRQ_count_latch)); | |
| 241 | state->save_item(NAME(state->m_IRQ_toggle)); | |
| 242 | state->save_item(NAME(state->m_IRQ_reset)); | |
| 243 | state->save_item(NAME(state->m_IRQ_status)); | |
| 244 | state->save_item(NAME(state->m_IRQ_mode)); | |
| 245 | state->save_item(NAME(state->m_mult1)); | |
| 246 | state->save_item(NAME(state->m_mult2)); | |
| 247 | state->save_item(NAME(state->m_mmc_chr_source)); | |
| 248 | state->save_item(NAME(state->m_mmc_cmd1)); | |
| 249 | state->save_item(NAME(state->m_mmc_cmd2)); | |
| 250 | state->save_item(NAME(state->m_mmc_count)); | |
| 251 | state->save_item(NAME(state->m_mmc_prg_base)); | |
| 252 | state->save_item(NAME(state->m_mmc_prg_mask)); | |
| 253 | state->save_item(NAME(state->m_mmc_chr_base)); | |
| 254 | state->save_item(NAME(state->m_mmc_chr_mask)); | |
| 255 | state->save_item(NAME(state->m_mmc_prg_bank)); | |
| 256 | state->save_item(NAME(state->m_mmc_vrom_bank)); | |
| 257 | state->save_item(NAME(state->m_mmc_extra_bank)); | |
| 258 | ||
| 259 | state->save_item(NAME(state->m_fds_motor_on)); | |
| 260 | state->save_item(NAME(state->m_fds_door_closed)); | |
| 261 | state->save_item(NAME(state->m_fds_current_side)); | |
| 262 | state->save_item(NAME(state->m_fds_head_position)); | |
| 263 | state->save_item(NAME(state->m_fds_status0)); | |
| 264 | state->save_item(NAME(state->m_fds_read_mode)); | |
| 265 | state->save_item(NAME(state->m_fds_write_reg)); | |
| 266 | state->save_item(NAME(state->m_fds_last_side)); | |
| 267 | state->save_item(NAME(state->m_fds_count)); | |
| 268 | ||
| 269 | state->save_pointer(NAME(state->m_wram), state->m_wram_size); | |
| 270 | if (state->m_battery) | |
| 271 | state->save_pointer(NAME(state->m_battery_ram), state->m_battery_size); | |
| 272 | ||
| 273 | machine.save().register_postload(save_prepost_delegate(FUNC(nes_banks_restore), state)); | |
| 274 | } | |
| 275 | ||
| 276 | MACHINE_START( nes ) | |
| 277 | { | |
| 278 | nes_state *state = machine.driver_data<nes_state>(); | |
| 279 | ||
| 280 | init_nes_core(machine); | |
| 281 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(nes_machine_stop),&machine)); | |
| 282 | ||
| 283 | state->m_maincpu = machine.device("maincpu"); | |
| 284 | state->m_ppu = machine.device("ppu"); | |
| 285 | state->m_sound = machine.device("nessound"); | |
| 286 | state->m_cart = machine.device("cart"); | |
| 287 | ||
| 288 | state->m_irq_timer = machine.scheduler().timer_alloc(FUNC(nes_irq_callback)); | |
| 289 | nes_state_register(machine); | |
| 290 | } | |
| 291 | ||
| 292 | static void nes_machine_stop( running_machine &machine ) | |
| 293 | { | |
| 294 | nes_state *state = machine.driver_data<nes_state>(); | |
| 295 | device_image_interface *image = dynamic_cast<device_image_interface *>(state->m_cart); | |
| 296 | /* Write out the battery file if necessary */ | |
| 297 | if (state->m_battery) | |
| 298 | image->battery_save(state->m_battery_ram, state->m_battery_size); | |
| 299 | ||
| 300 | if (state->m_mapper_bram_size) | |
| 301 | image->battery_save(state->m_mapper_bram, state->m_mapper_bram_size); | |
| 302 | } | |
| 303 | ||
| 304 | ||
| 305 | ||
| 306 | READ8_HANDLER( nes_IN0_r ) | |
| 307 | { | |
| 308 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 309 | int cfg = input_port_read(space->machine(), "CTRLSEL"); | |
| 310 | int ret; | |
| 311 | ||
| 312 | if ((cfg & 0x000f) >= 0x07) // for now we treat the FC keyboard separately from other inputs! | |
| 313 | { | |
| 314 | // here we should have the tape input | |
| 315 | ret = 0; | |
| 316 | } | |
| 317 | else | |
| 318 | { | |
| 319 | /* Some games expect bit 6 to be set because the last entry on the data bus shows up */ | |
| 320 | /* in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there. */ | |
| 321 | ret = 0x40; | |
| 322 | ||
| 323 | ret |= ((state->m_in_0.i0 >> state->m_in_0.shift) & 0x01); | |
| 324 | ||
| 325 | /* zapper */ | |
| 326 | if ((cfg & 0x000f) == 0x0002) | |
| 327 | { | |
| 328 | int x = state->m_in_0.i1; /* read Zapper x-position */ | |
| 329 | int y = state->m_in_0.i2; /* read Zapper y-position */ | |
| 330 | UINT32 pix, color_base; | |
| 331 | ||
| 332 | /* get the pixel at the gun position */ | |
| 333 | pix = ppu2c0x_get_pixel(state->m_ppu, x, y); | |
| 334 | ||
| 335 | /* get the color base from the ppu */ | |
| 336 | color_base = ppu2c0x_get_colorbase(state->m_ppu); | |
| 337 | ||
| 338 | /* look at the screen and see if the cursor is over a bright pixel */ | |
| 339 | if ((pix == color_base + 0x20) || (pix == color_base + 0x30) || | |
| 340 | (pix == color_base + 0x33) || (pix == color_base + 0x34)) | |
| 341 | { | |
| 342 | ret &= ~0x08; /* sprite hit */ | |
| 343 | } | |
| 344 | else | |
| 345 | ret |= 0x08; /* no sprite hit */ | |
| 346 | ||
| 347 | /* If button 1 is pressed, indicate the light gun trigger is pressed */ | |
| 348 | ret |= ((state->m_in_0.i0 & 0x01) << 4); | |
| 349 | } | |
| 350 | ||
| 351 | if (LOG_JOY) | |
| 352 | logerror("joy 0 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, cpu_get_pc(&space->device()), state->m_in_0.shift, state->m_in_0.i0); | |
| 353 | ||
| 354 | state->m_in_0.shift++; | |
| 355 | } | |
| 356 | ||
| 357 | return ret; | |
| 358 | } | |
| 359 | ||
| 360 | // row of the keyboard matrix are read 4-bits at time, and gets returned as bit1->bit4 | |
| 361 | static UINT8 nes_read_fc_keyboard_line( running_machine &machine, UINT8 scan, UINT8 mode ) | |
| 362 | { | |
| 363 | static const char *const fc_keyport_names[] = { "FCKEY0", "FCKEY1", "FCKEY2", "FCKEY3", "FCKEY4", "FCKEY5", "FCKEY6", "FCKEY7", "FCKEY8" }; | |
| 364 | return ((input_port_read(machine, fc_keyport_names[scan]) >> (mode * 4)) & 0x0f) << 1; | |
| 365 | } | |
| 366 | ||
| 367 | static UINT8 nes_read_subor_keyboard_line( running_machine &machine, UINT8 scan, UINT8 mode ) | |
| 368 | { | |
| 369 | static const char *const sub_keyport_names[] = { "SUBKEY0", "SUBKEY1", "SUBKEY2", "SUBKEY3", "SUBKEY4", | |
| 370 | "SUBKEY5", "SUBKEY6", "SUBKEY7", "SUBKEY8", "SUBKEY9", "SUBKEY10", "SUBKEY11", "SUBKEY12" }; | |
| 371 | return ((input_port_read(machine, sub_keyport_names[scan]) >> (mode * 4)) & 0x0f) << 1; | |
| 372 | } | |
| 373 | ||
| 374 | READ8_HANDLER( nes_IN1_r ) | |
| 375 | { | |
| 376 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 377 | int cfg = input_port_read(space->machine(), "CTRLSEL"); | |
| 378 | int ret; | |
| 379 | ||
| 380 | if ((cfg & 0x000f) == 0x07) // for now we treat the FC keyboard separately from other inputs! | |
| 381 | { | |
| 382 | if (state->m_fck_scan < 9) | |
| 383 | ret = ~nes_read_fc_keyboard_line(space->machine(), state->m_fck_scan, state->m_fck_mode) & 0x1e; | |
| 384 | else | |
| 385 | ret = 0x1e; | |
| 386 | } | |
| 387 | else if ((cfg & 0x000f) == 0x08) // for now we treat the Subor keyboard separately from other inputs! | |
| 388 | { | |
| 389 | if (state->m_fck_scan < 12) | |
| 390 | ret = ~nes_read_subor_keyboard_line(space->machine(), state->m_fck_scan, state->m_fck_mode) & 0x1e; | |
| 391 | else | |
| 392 | ret = 0x1e; | |
| 393 | } | |
| 394 | else | |
| 395 | { | |
| 396 | /* Some games expect bit 6 to be set because the last entry on the data bus shows up */ | |
| 397 | /* in the unused upper 3 bits, so typically a read from $4017 leaves 0x40 there. */ | |
| 398 | ret = 0x40; | |
| 399 | ||
| 400 | /* Handle data line 0's serial output */ | |
| 401 | ret |= ((state->m_in_1.i0 >> state->m_in_1.shift) & 0x01); | |
| 402 | ||
| 403 | /* zapper */ | |
| 404 | if ((cfg & 0x00f0) == 0x0030) | |
| 405 | { | |
| 406 | int x = state->m_in_1.i1; /* read Zapper x-position */ | |
| 407 | int y = state->m_in_1.i2; /* read Zapper y-position */ | |
| 408 | UINT32 pix, color_base; | |
| 409 | ||
| 410 | /* get the pixel at the gun position */ | |
| 411 | pix = ppu2c0x_get_pixel(state->m_ppu, x, y); | |
| 412 | ||
| 413 | /* get the color base from the ppu */ | |
| 414 | color_base = ppu2c0x_get_colorbase(state->m_ppu); | |
| 415 | ||
| 416 | /* look at the screen and see if the cursor is over a bright pixel */ | |
| 417 | if ((pix == color_base + 0x20) || (pix == color_base + 0x30) || | |
| 418 | (pix == color_base + 0x33) || (pix == color_base + 0x34)) | |
| 419 | { | |
| 420 | ret &= ~0x08; /* sprite hit */ | |
| 421 | } | |
| 422 | else | |
| 423 | ret |= 0x08; /* no sprite hit */ | |
| 424 | ||
| 425 | /* If button 1 is pressed, indicate the light gun trigger is pressed */ | |
| 426 | ret |= ((state->m_in_1.i0 & 0x01) << 4); | |
| 427 | } | |
| 428 | ||
| 429 | /* arkanoid dial */ | |
| 430 | else if ((cfg & 0x00f0) == 0x0040) | |
| 431 | { | |
| 432 | /* Handle data line 2's serial output */ | |
| 433 | ret |= ((state->m_in_1.i2 >> state->m_in_1.shift) & 0x01) << 3; | |
| 434 | ||
| 435 | /* Handle data line 3's serial output - bits are reversed */ | |
| 436 | /* NPW 27-Nov-2007 - there is no third subscript! commenting out */ | |
| 437 | /* ret |= ((state->m_in_1[3] >> state->m_in_1.shift) & 0x01) << 4; */ | |
| 438 | /* ret |= ((state->m_in_1[3] << state->m_in_1.shift) & 0x80) >> 3; */ | |
| 439 | } | |
| 440 | ||
| 441 | if (LOG_JOY) | |
| 442 | logerror("joy 1 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, cpu_get_pc(&space->device()), state->m_in_1.shift, state->m_in_1.i0); | |
| 443 | ||
| 444 | state->m_in_1.shift++; | |
| 445 | } | |
| 446 | ||
| 447 | return ret; | |
| 448 | } | |
| 449 | ||
| 450 | ||
| 451 | // FIXME: this is getting messier and messier (no pun intended). inputs reading should be simplified and port_categories cleaned up | |
| 452 | // to also emulate the fact that nothing should be in Port 2 if there is a Crazy Climber pad, etc. | |
| 453 | static void nes_read_input_device( running_machine &machine, int cfg, nes_input *vals, int pad_port, int supports_zapper ) | |
| 454 | { | |
| 455 | nes_state *state = machine.driver_data<nes_state>(); | |
| 456 | static const char *const padnames[] = { "PAD1", "PAD2", "PAD3", "PAD4", "CC_LEFT", "CC_RIGHT" }; | |
| 457 | ||
| 458 | vals->i0 = 0; | |
| 459 | vals->i1 = 0; | |
| 460 | vals->i2 = 0; | |
| 461 | ||
| 462 | switch (cfg & 0x0f) | |
| 463 | { | |
| 464 | case 0x01: /* gamepad */ | |
| 465 | if (pad_port >= 0) | |
| 466 | vals->i0 = input_port_read(machine, padnames[pad_port]); | |
| 467 | break; | |
| 468 | ||
| 469 | case 0x02: /* zapper 1 */ | |
| 470 | if (supports_zapper) | |
| 471 | { | |
| 472 | vals->i0 = input_port_read(machine, "ZAPPER1_T"); | |
| 473 | vals->i1 = input_port_read(machine, "ZAPPER1_X"); | |
| 474 | vals->i2 = input_port_read(machine, "ZAPPER1_Y"); | |
| 475 | } | |
| 476 | break; | |
| 477 | ||
| 478 | case 0x03: /* zapper 2 */ | |
| 479 | if (supports_zapper) | |
| 480 | { | |
| 481 | vals->i0 = input_port_read(machine, "ZAPPER2_T"); | |
| 482 | vals->i1 = input_port_read(machine, "ZAPPER2_X"); | |
| 483 | vals->i2 = input_port_read(machine, "ZAPPER2_Y"); | |
| 484 | } | |
| 485 | break; | |
| 486 | ||
| 487 | case 0x04: /* arkanoid paddle */ | |
| 488 | if (pad_port == 1) | |
| 489 | vals->i0 = (UINT8) ((UINT8) input_port_read(machine, "PADDLE") + (UINT8)0x52) ^ 0xff; | |
| 490 | break; | |
| 491 | ||
| 492 | case 0x05: /* crazy climber controller */ | |
| 493 | if (pad_port == 0) | |
| 494 | { | |
| 495 | state->m_in_0.i0 = input_port_read(machine, padnames[4]); | |
| 496 | state->m_in_1.i0 = input_port_read(machine, padnames[5]); | |
| 497 | } | |
| 498 | break; | |
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | ||
| 503 | static TIMER_CALLBACK( lightgun_tick ) | |
| 504 | { | |
| 505 | if ((input_port_read(machine, "CTRLSEL") & 0x000f) == 0x0002) | |
| 506 | { | |
| 507 | /* enable lightpen crosshair */ | |
| 508 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL); | |
| 509 | } | |
| 510 | else | |
| 511 | { | |
| 512 | /* disable lightpen crosshair */ | |
| 513 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE); | |
| 514 | } | |
| 515 | ||
| 516 | if ((input_port_read(machine, "CTRLSEL") & 0x00f0) == 0x0030) | |
| 517 | { | |
| 518 | /* enable lightpen crosshair */ | |
| 519 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL); | |
| 520 | } | |
| 521 | else | |
| 522 | { | |
| 523 | /* disable lightpen crosshair */ | |
| 524 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE); | |
| 525 | } | |
| 526 | } | |
| 527 | ||
| 528 | WRITE8_HANDLER( nes_IN0_w ) | |
| 529 | { | |
| 530 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 531 | int cfg = input_port_read(space->machine(), "CTRLSEL"); | |
| 532 | ||
| 533 | /* Check if lightgun has been chosen as input: if so, enable crosshair */ | |
| 534 | space->machine().scheduler().timer_set(attotime::zero, FUNC(lightgun_tick)); | |
| 535 | ||
| 536 | if ((cfg & 0x000f) >= 0x07) // for now we treat the FC keyboard separately from other inputs! | |
| 537 | { | |
| 538 | // here we should also have the tape output | |
| 539 | ||
| 540 | if (BIT(data, 2)) // keyboard active | |
| 541 | { | |
| 542 | int lines = ((cfg & 0x000f) == 0x04) ? 9 : 12; | |
| 543 | UINT8 out = BIT(data, 1); // scan | |
| 544 | ||
| 545 | if (state->m_fck_mode && !out && ++state->m_fck_scan > lines) | |
| 546 | state->m_fck_scan = 0; | |
| 547 | ||
| 548 | state->m_fck_mode = out; // access lower or upper 4 bits | |
| 549 | ||
| 550 | if (BIT(data, 0)) // reset | |
| 551 | state->m_fck_scan = 0; | |
| 552 | } | |
| 553 | } | |
| 554 | else | |
| 555 | { | |
| 556 | if (data & 0x01) | |
| 557 | return; | |
| 558 | ||
| 559 | if (LOG_JOY) | |
| 560 | logerror("joy 0 bits read: %d\n", state->m_in_0.shift); | |
| 561 | ||
| 562 | /* Toggling bit 0 high then low resets both controllers */ | |
| 563 | state->m_in_0.shift = 0; | |
| 564 | state->m_in_1.shift = 0; | |
| 565 | ||
| 566 | /* Read the input devices */ | |
| 567 | if ((cfg & 0x000f) != 0x06) | |
| 568 | { | |
| 569 | nes_read_input_device(space->machine(), cfg >> 0, &state->m_in_0, 0, TRUE); | |
| 570 | nes_read_input_device(space->machine(), cfg >> 4, &state->m_in_1, 1, TRUE); | |
| 571 | nes_read_input_device(space->machine(), cfg >> 8, &state->m_in_2, 2, FALSE); | |
| 572 | nes_read_input_device(space->machine(), cfg >> 12, &state->m_in_3, 3, FALSE); | |
| 573 | } | |
| 574 | else // crazy climber pad | |
| 575 | { | |
| 576 | nes_read_input_device(space->machine(), 0, &state->m_in_1, 1, TRUE); | |
| 577 | nes_read_input_device(space->machine(), 0, &state->m_in_2, 2, FALSE); | |
| 578 | nes_read_input_device(space->machine(), 0, &state->m_in_3, 3, FALSE); | |
| 579 | nes_read_input_device(space->machine(), cfg >> 0, &state->m_in_0, 0, TRUE); | |
| 580 | } | |
| 581 | ||
| 582 | if (cfg & 0x0f00) | |
| 583 | state->m_in_0.i0 |= (state->m_in_2.i0 << 8) | (0x08 << 16); | |
| 584 | ||
| 585 | if (cfg & 0xf000) | |
| 586 | state->m_in_1.i0 |= (state->m_in_3.i0 << 8) | (0x04 << 16); | |
| 587 | } | |
| 588 | } | |
| 589 | ||
| 590 | ||
| 591 | WRITE8_HANDLER( nes_IN1_w ) | |
| 592 | { | |
| 593 | } | |
| 594 | ||
| 595 | struct nes_cart_lines | |
| 596 | { | |
| 597 | const char *tag; | |
| 598 | int line; | |
| 599 | }; | |
| 600 | ||
| 601 | static const struct nes_cart_lines nes_cart_lines_table[] = | |
| 602 | { | |
| 603 | { "PRG A0", 0 }, | |
| 604 | { "PRG A1", 1 }, | |
| 605 | { "PRG A2", 2 }, | |
| 606 | { "PRG A3", 3 }, | |
| 607 | { "PRG A4", 4 }, | |
| 608 | { "PRG A5", 5 }, | |
| 609 | { "PRG A6", 6 }, | |
| 610 | { "PRG A7", 7 }, | |
| 611 | { "CHR A10", 10 }, | |
| 612 | { "CHR A11", 11 }, | |
| 613 | { "CHR A12", 12 }, | |
| 614 | { "CHR A13", 13 }, | |
| 615 | { "CHR A14", 14 }, | |
| 616 | { "CHR A15", 15 }, | |
| 617 | { "CHR A16", 16 }, | |
| 618 | { "CHR A17", 17 }, | |
| 619 | { "NC", 127 }, | |
| 620 | { 0 } | |
| 621 | }; | |
| 622 | ||
| 623 | static int nes_cart_get_line( const char *feature ) | |
| 624 | { | |
| 625 | const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0]; | |
| 626 | ||
| 627 | if (feature == NULL) | |
| 628 | return 128; | |
| 629 | ||
| 630 | while (nes_line->tag) | |
| 631 | { | |
| 632 | if (strcmp(nes_line->tag, feature) == 0) | |
| 633 | break; | |
| 634 | ||
| 635 | nes_line++; | |
| 636 | } | |
| 637 | ||
| 638 | return nes_line->line; | |
| 639 | } | |
| 640 | ||
| 641 | DEVICE_IMAGE_LOAD( nes_cart ) | |
| 642 | { | |
| 643 | nes_state *state = image.device().machine().driver_data<nes_state>(); | |
| 644 | state->m_pcb_id = NO_BOARD; // initialization | |
| 645 | ||
| 646 | if (image.software_entry() == NULL) | |
| 647 | { | |
| 648 | const char *mapinfo = NULL; | |
| 649 | int mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0, goodcrcinfo = 0; | |
| 650 | char magic[4], extend[5]; | |
| 651 | int local_options = 0; | |
| 652 | char m; | |
| 653 | ||
| 654 | /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ | |
| 655 | /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ | |
| 656 | memset(magic, '\0', sizeof(magic)); | |
| 657 | image.fread(magic, 4); | |
| 658 | ||
| 659 | if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ | |
| 660 | { | |
| 661 | UINT32 prg_size; | |
| 662 | state->m_ines20 = 0; | |
| 663 | state->m_battery_size = NES_BATTERY_SIZE; // with iNES we can only support 8K WRAM battery (iNES 2.0 might fix this) | |
| 664 | state->m_prg_ram = 1; // always map state->m_wram in bank5 (eventually, this should be enabled only for some mappers) | |
| 665 | ||
| 666 | // check if the image is recognized by nes.hsi | |
| 667 | mapinfo = hashfile_extrainfo(image); | |
| 668 | ||
| 669 | // image_extrainfo() resets the file position back to start. | |
| 670 | // Let's skip past the magic header once again. | |
| 671 | image.fseek(4, SEEK_SET); | |
| 672 | ||
| 673 | image.fread(&state->m_prg_chunks, 1); | |
| 674 | image.fread(&state->m_chr_chunks, 1); | |
| 675 | /* Read the first ROM option byte (offset 6) */ | |
| 676 | image.fread(&m, 1); | |
| 677 | ||
| 678 | /* Interpret the iNES header flags */ | |
| 679 | state->m_mapper = (m & 0xf0) >> 4; | |
| 680 | local_options = m & 0x0f; | |
| 681 | ||
| 682 | /* Read the second ROM option byte (offset 7) */ | |
| 683 | image.fread(&m, 1); | |
| 684 | ||
| 685 | switch (m & 0xc) | |
| 686 | { | |
| 687 | case 0x4: | |
| 688 | case 0xc: | |
| 689 | // probably the header got corrupted: don't trust upper bits for mapper | |
| 690 | break; | |
| 691 | ||
| 692 | case 0x8: // it's iNES 2.0 format | |
| 693 | state->m_ines20 = 1; | |
| 694 | case 0x0: | |
| 695 | default: | |
| 696 | state->m_mapper = state->m_mapper | (m & 0xf0); | |
| 697 | break; | |
| 698 | } | |
| 699 | ||
| 700 | if (mapinfo /* && !state->m_ines20 */) | |
| 701 | { | |
| 702 | if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4)) | |
| 703 | { | |
| 704 | /* image is present in nes.hsi: overwrite the header settings with these */ | |
| 705 | state->m_mapper = mapint1; | |
| 706 | local_options = mapint2 & 0x0f; | |
| 707 | state->m_crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below) | |
| 708 | state->m_prg_chunks = mapint3; | |
| 709 | state->m_chr_chunks = mapint4; | |
| 710 | logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); | |
| 711 | // mame_printf_error("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); | |
| 712 | goodcrcinfo = 1; | |
| 713 | state->m_ines20 = 0; | |
| 714 | } | |
| 715 | else | |
| 716 | { | |
| 717 | logerror("NES: [%s], Invalid mapinfo found\n", mapinfo); | |
| 718 | } | |
| 719 | } | |
| 720 | else | |
| 721 | { | |
| 722 | logerror("NES: No extrainfo found\n"); | |
| 723 | } | |
| 724 | ||
| 725 | state->m_hard_mirroring = (local_options & 0x01) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ; | |
| 726 | // mame_printf_error("%s\n", state->m_hard_mirroring & 0x01 ? "Vertical" : "Horizontal"); | |
| 727 | state->m_battery = local_options & 0x02; | |
| 728 | state->m_trainer = local_options & 0x04; | |
| 729 | state->m_four_screen_vram = local_options & 0x08; | |
| 730 | ||
| 731 | if (state->m_battery) | |
| 732 | logerror("-- Battery found\n"); | |
| 733 | ||
| 734 | if (state->m_trainer) | |
| 735 | logerror("-- Trainer found\n"); | |
| 736 | ||
| 737 | if (state->m_four_screen_vram) | |
| 738 | logerror("-- 4-screen VRAM\n"); | |
| 739 | ||
| 740 | if (state->m_ines20) | |
| 741 | { | |
| 742 | logerror("Extended iNES format:\n"); | |
| 743 | image.fread(&extend, 5); | |
| 744 | state->m_mapper |= (extend[0] & 0x0f) << 8; | |
| 745 | logerror("-- mapper: %d\n", state->m_mapper); | |
| 746 | logerror("-- submapper: %d\n", (extend[0] & 0xf0) >> 4); | |
| 747 | state->m_prg_chunks |= ((extend[1] & 0x0f) << 8); | |
| 748 | state->m_chr_chunks |= ((extend[1] & 0xf0) << 4); | |
| 749 | logerror("-- PRG chunks: %d\n", state->m_prg_chunks); | |
| 750 | logerror("-- CHR chunks: %d\n", state->m_chr_chunks); | |
| 751 | logerror("-- PRG NVWRAM: %d\n", extend[2] & 0x0f); | |
| 752 | logerror("-- PRG WRAM: %d\n", (extend[2] & 0xf0) >> 4); | |
| 753 | logerror("-- CHR NVWRAM: %d\n", extend[3] & 0x0f); | |
| 754 | logerror("-- CHR WRAM: %d\n", (extend[3] & 0xf0) >> 4); | |
| 755 | logerror("-- TV System: %d\n", extend[4] & 3); | |
| 756 | } | |
| 757 | ||
| 758 | /* Free the regions that were allocated by the ROM loader */ | |
| 759 | image.device().machine().region_free("maincpu"); | |
| 760 | image.device().machine().region_free("gfx1"); | |
| 761 | ||
| 762 | /* Allocate them again with the proper size */ | |
| 763 | prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000; | |
| 764 | image.device().machine().region_alloc("maincpu", 0x10000 + prg_size, 1, ENDIANNESS_LITTLE); | |
| 765 | if (state->m_chr_chunks) | |
| 766 | image.device().machine().region_alloc("gfx1", state->m_chr_chunks * 0x2000, 1, ENDIANNESS_LITTLE); | |
| 767 | ||
| 768 | state->m_rom = image.device().machine().region("maincpu")->base(); | |
| 769 | state->m_vrom = image.device().machine().region("gfx1")->base(); | |
| 770 | ||
| 771 | state->m_vram_chunks = image.device().machine().region("gfx2")->bytes() / 0x2000; | |
| 772 | state->m_vram = image.device().machine().region("gfx2")->base(); | |
| 773 | // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)! | |
| 774 | // or if there is a trainer, I think | |
| 775 | state->m_wram_size = 0x10000; | |
| 776 | state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); | |
| 777 | ||
| 778 | /* Setup PCB type (needed to add proper handlers later) */ | |
| 779 | state->m_pcb_id = nes_get_mmc_id(image.device().machine(), state->m_mapper); | |
| 780 | ||
| 781 | // a few mappers correspond to multiple PCBs, so we need a few additional checks | |
| 782 | switch (state->m_pcb_id) | |
| 783 | { | |
| 784 | case STD_CNROM: | |
| 785 | if (state->m_mapper == 185) | |
| 786 | { | |
| 787 | switch (state->m_crc_hack) | |
| 788 | { | |
| 789 | case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week) | |
| 790 | state->m_ce_mask = 0x03; | |
| 791 | state->m_ce_state = 0x03; | |
| 792 | break; | |
| 793 | case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy) | |
| 794 | state->m_ce_mask = 0x03; | |
| 795 | state->m_ce_state = 0x01; | |
| 796 | break; | |
| 797 | case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen) | |
| 798 | state->m_ce_mask = 0x03; | |
| 799 | state->m_ce_state = 0x02; | |
| 800 | break; | |
| 801 | case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0) | |
| 802 | state->m_ce_mask = 0x03; | |
| 803 | state->m_ce_state = 0x00; | |
| 804 | break; | |
| 805 | } | |
| 806 | } | |
| 807 | break; | |
| 808 | case KONAMI_VRC2: | |
| 809 | if (state->m_mapper == 22) | |
| 810 | { | |
| 811 | state->m_vrc_ls_prg_a = 0; | |
| 812 | state->m_vrc_ls_prg_b = 1; | |
| 813 | state->m_vrc_ls_chr = 1; | |
| 814 | } | |
| 815 | if (state->m_mapper == 23 && !state->m_crc_hack) | |
| 816 | { | |
| 817 | state->m_vrc_ls_prg_a = 1; | |
| 818 | state->m_vrc_ls_prg_b = 0; | |
| 819 | state->m_vrc_ls_chr = 0; | |
| 820 | } | |
| 821 | if (state->m_mapper == 23 && state->m_crc_hack) | |
| 822 | { | |
| 823 | // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4 | |
| 824 | state->m_vrc_ls_prg_a = 3; | |
| 825 | state->m_vrc_ls_prg_b = 2; | |
| 826 | state->m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset | |
| 827 | } | |
| 828 | break; | |
| 829 | case KONAMI_VRC4: | |
| 830 | if (state->m_mapper == 21) | |
| 831 | { | |
| 832 | // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack) | |
| 833 | state->m_vrc_ls_prg_a = state->m_crc_hack ? 7 : 2; | |
| 834 | state->m_vrc_ls_prg_b = state->m_crc_hack ? 6 : 1; | |
| 835 | } | |
| 836 | if (state->m_mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2 | |
| 837 | { | |
| 838 | state->m_vrc_ls_prg_a = state->m_crc_hack ? 2 : 0; | |
| 839 | state->m_vrc_ls_prg_b = state->m_crc_hack ? 3 : 1; | |
| 840 | } | |
| 841 | break; | |
| 842 | case KONAMI_VRC6: | |
| 843 | if (state->m_mapper == 24) | |
| 844 | { | |
| 845 | state->m_vrc_ls_prg_a = 1; | |
| 846 | state->m_vrc_ls_prg_b = 0; | |
| 847 | } | |
| 848 | if (state->m_mapper == 26) | |
| 849 | { | |
| 850 | state->m_vrc_ls_prg_a = 0; | |
| 851 | state->m_vrc_ls_prg_b = 1; | |
| 852 | } | |
| 853 | break; | |
| 854 | case IREM_G101: | |
| 855 | if (state->m_crc_hack) | |
| 856 | state->m_hard_mirroring = PPU_MIRROR_HIGH; // Major League has hardwired mirroring | |
| 857 | break; | |
| 858 | case DIS_74X161X161X32: | |
| 859 | if (state->m_mapper == 70) | |
| 860 | state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 70 & 152 | |
| 861 | break; | |
| 862 | case SUNSOFT_2: | |
| 863 | if (state->m_mapper == 93) | |
| 864 | state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 89 & 93 | |
| 865 | break; | |
| 866 | case STD_BXROM: | |
| 867 | if (state->m_crc_hack) | |
| 868 | state->m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards | |
| 869 | break; | |
| 870 | case BANDAI_LZ93: | |
| 871 | if (state->m_crc_hack) | |
| 872 | state->m_pcb_id = BANDAI_JUMP2; // Mapper 153 is used for 2 diff boards | |
| 873 | break; | |
| 874 | case IREM_HOLYDIV: | |
| 875 | if (state->m_crc_hack) | |
| 876 | state->m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards | |
| 877 | break; | |
| 878 | case CAMERICA_BF9093: | |
| 879 | if (state->m_crc_hack) | |
| 880 | state->m_pcb_id = CAMERICA_BF9097; // Mapper 71 is used for 2 diff boards | |
| 881 | break; | |
| 882 | case HES_BOARD: | |
| 883 | if (state->m_crc_hack) | |
| 884 | state->m_pcb_id = HES6IN1_BOARD; // Mapper 113 is used for 2 diff boards | |
| 885 | break; | |
| 886 | case WAIXING_ZS: | |
| 887 | if (state->m_crc_hack) | |
| 888 | state->m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards | |
| 889 | break; | |
| 890 | //FIXME: we also have to fix Action 52 PRG loading somewhere... | |
| 891 | } | |
| 892 | ||
| 893 | /* Allocate internal Mapper RAM for boards which require it */ | |
| 894 | if (state->m_pcb_id == STD_EXROM) | |
| 895 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x400); | |
| 896 | ||
| 897 | if (state->m_pcb_id == TAITO_X1_005 || state->m_pcb_id == TAITO_X1_005_A) | |
| 898 | state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x80); | |
| 899 | ||
| 900 | if (state->m_pcb_id == TAITO_X1_017) | |
| 901 | state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x1400); | |
| 902 | ||
| 903 | if (state->m_pcb_id == NAMCOT_163) | |
| 904 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x2000); | |
| 905 | ||
| 906 | if (state->m_pcb_id == FUKUTAKE_BOARD) | |
| 907 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 2816); | |
| 908 | ||
| 909 | /* Position past the header */ | |
| 910 | image.fseek(16, SEEK_SET); | |
| 911 | ||
| 912 | /* Load the 0x200 byte trainer at 0x7000 if it exists */ | |
| 913 | if (state->m_trainer) | |
| 914 | image.fread(&state->m_wram[0x1000], 0x200); | |
| 915 | ||
| 916 | /* Read in the program chunks */ | |
| 917 | image.fread(&state->m_rom[0x10000], 0x4000 * state->m_prg_chunks); | |
| 918 | if (state->m_prg_chunks == 1) | |
| 919 | memcpy(&state->m_rom[0x14000], &state->m_rom[0x10000], 0x4000); | |
| 920 | ||
| 921 | #if SPLIT_PRG | |
| 922 | { | |
| 923 | FILE *prgout; | |
| 924 | char outname[255]; | |
| 925 | ||
| 926 | sprintf(outname, "%s.prg", image.filename()); | |
| 927 | prgout = fopen(outname, "wb"); | |
| 928 | if (prgout) | |
| 929 | { | |
| 930 | fwrite(&state->m_rom[0x10000], 1, 0x4000 * state->m_prg_chunks, prgout); | |
| 931 | mame_printf_error("Created PRG chunk\n"); | |
| 932 | } | |
| 933 | ||
| 934 | fclose(prgout); | |
| 935 | } | |
| 936 | #endif | |
| 937 | ||
| 938 | logerror("**\n"); | |
| 939 | logerror("Mapper: %d\n", state->m_mapper); | |
| 940 | logerror("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks); | |
| 941 | // mame_printf_error("Mapper: %d\n", state->m_mapper); | |
| 942 | // mame_printf_error("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks); | |
| 943 | ||
| 944 | /* Read in any chr chunks */ | |
| 945 | if (state->m_chr_chunks > 0) | |
| 946 | { | |
| 947 | image.fread(state->m_vrom, state->m_chr_chunks * 0x2000); | |
| 948 | if (state->m_mapper == 2) | |
| 949 | logerror("Warning: VROM has been found in VRAM-based mapper. Either the mapper is set wrong or the ROM image is incorrect.\n"); | |
| 950 | } | |
| 951 | ||
| 952 | #if SPLIT_CHR | |
| 953 | if (state->m_chr_chunks > 0) | |
| 954 | { | |
| 955 | FILE *chrout; | |
| 956 | char outname[255]; | |
| 957 | ||
| 958 | sprintf(outname, "%s.chr", image.filename()); | |
| 959 | chrout= fopen(outname, "wb"); | |
| 960 | if (chrout) | |
| 961 | { | |
| 962 | fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout); | |
| 963 | mame_printf_error("Created CHR chunk\n"); | |
| 964 | } | |
| 965 | fclose(chrout); | |
| 966 | } | |
| 967 | #endif | |
| 968 | ||
| 969 | logerror("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks); | |
| 970 | logerror("**\n"); | |
| 971 | // mame_printf_error("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks); | |
| 972 | // mame_printf_error("**\n"); | |
| 973 | } | |
| 974 | else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ | |
| 975 | { | |
| 976 | UINT32 unif_ver = 0; | |
| 977 | char magic2[4]; | |
| 978 | UINT8 buffer[4]; | |
| 979 | UINT32 chunk_length = 0, read_length = 0x20; | |
| 980 | UINT32 prg_start = 0, chr_start = 0, prg_size; | |
| 981 | char unif_mapr[32]; // here we should store MAPR chunks | |
| 982 | UINT32 size = image.length(); | |
| 983 | int mapr_chunk_found = 0; | |
| 984 | // allocate space to temporarily store PRG & CHR banks | |
| 985 | UINT8 *temp_prg = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x4000); | |
| 986 | UINT8 *temp_chr = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x2000); | |
| 987 | UINT8 temp_byte = 0; | |
| 988 | ||
| 989 | /* init prg/chr chunks to 0: the exact number of chunks will be determined while reading the file */ | |
| 990 | state->m_prg_chunks = 0; | |
| 991 | state->m_chr_chunks = 0; | |
| 992 | ||
| 993 | image.fread(&buffer, 4); | |
| 994 | unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 995 | logerror("UNIF file found, version %d\n", unif_ver); | |
| 996 | ||
| 997 | if (size <= 0x20) | |
| 998 | { | |
| 999 | logerror("%s only contains the UNIF header and no data.\n", image.filename()); | |
| 1000 | return IMAGE_INIT_FAIL; | |
| 1001 | } | |
| 1002 | ||
| 1003 | do | |
| 1004 | { | |
| 1005 | image.fseek(read_length, SEEK_SET); | |
| 1006 | ||
| 1007 | memset(magic2, '\0', sizeof(magic2)); | |
| 1008 | image.fread(&magic2, 4); | |
| 1009 | ||
| 1010 | /* We first run through the whole image to find a [MAPR] chunk. This is needed | |
| 1011 | because, unfortunately, the MAPR chunk is not always the first chunk (see | |
| 1012 | Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and | |
| 1013 | we go back to load other chunks! */ | |
| 1014 | if (!mapr_chunk_found) | |
| 1015 | { | |
| 1016 | if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) | |
| 1017 | { | |
| 1018 | mapr_chunk_found = 1; | |
| 1019 | logerror("[MAPR] chunk found: "); | |
| 1020 | image.fread(&buffer, 4); | |
| 1021 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1022 | ||
| 1023 | if (chunk_length <= 0x20) | |
| 1024 | image.fread(&unif_mapr, chunk_length); | |
| 1025 | ||
| 1026 | // find out prg/chr size, battery, wram, etc. | |
| 1027 | unif_mapr_setup(image.device().machine(), unif_mapr); | |
| 1028 | ||
| 1029 | /* now that we found the MAPR chunk, we can go back to load other chunks */ | |
| 1030 | image.fseek(0x20, SEEK_SET); | |
| 1031 | read_length = 0x20; | |
| 1032 | } | |
| 1033 | else | |
| 1034 | { | |
| 1035 | logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n"); | |
| 1036 | image.fread(&buffer, 4); | |
| 1037 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1038 | ||
| 1039 | read_length += (chunk_length + 8); | |
| 1040 | } | |
| 1041 | } | |
| 1042 | else | |
| 1043 | { | |
| 1044 | /* What kind of chunk do we have here? */ | |
| 1045 | if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) | |
| 1046 | { | |
| 1047 | /* The [MAPR] chunk has already been read, so we skip it */ | |
| 1048 | /* TO DO: it would be nice to check if more than one MAPR chunk is present */ | |
| 1049 | logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n"); | |
| 1050 | image.fread(&buffer, 4); | |
| 1051 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1052 | ||
| 1053 | read_length += (chunk_length + 8); | |
| 1054 | } | |
| 1055 | else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D')) | |
| 1056 | { | |
| 1057 | logerror("[READ] chunk found. No support yet.\n"); | |
| 1058 | image.fread(&buffer, 4); | |
| 1059 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1060 | ||
| 1061 | read_length += (chunk_length + 8); | |
| 1062 | } | |
| 1063 | else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E')) | |
| 1064 | { | |
| 1065 | logerror("[NAME] chunk found. No support yet.\n"); | |
| 1066 | image.fread(&buffer, 4); | |
| 1067 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1068 | ||
| 1069 | read_length += (chunk_length + 8); | |
| 1070 | } | |
| 1071 | else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R')) | |
| 1072 | { | |
| 1073 | logerror("[WRTR] chunk found. No support yet.\n"); | |
| 1074 | image.fread(&buffer, 4); | |
| 1075 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1076 | ||
| 1077 | read_length += (chunk_length + 8); | |
| 1078 | } | |
| 1079 | else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I')) | |
| 1080 | { | |
| 1081 | logerror("[TVCI] chunk found.\n"); | |
| 1082 | image.fread(&buffer, 4); | |
| 1083 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1084 | ||
| 1085 | image.fread(&temp_byte, 1); | |
| 1086 | logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter"); | |
| 1087 | ||
| 1088 | read_length += (chunk_length + 8); | |
| 1089 | } | |
| 1090 | else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI?? | |
| 1091 | { | |
| 1092 | logerror("[TVSC] chunk found. No support yet.\n"); | |
| 1093 | image.fread(&buffer, 4); | |
| 1094 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1095 | ||
| 1096 | read_length += (chunk_length + 8); | |
| 1097 | } | |
| 1098 | else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F')) | |
| 1099 | { | |
| 1100 | logerror("[DINF] chunk found. No support yet.\n"); | |
| 1101 | image.fread(&buffer, 4); | |
| 1102 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1103 | ||
| 1104 | read_length += (chunk_length + 8); | |
| 1105 | } | |
| 1106 | else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L')) | |
| 1107 | { | |
| 1108 | logerror("[CTRL] chunk found. No support yet.\n"); | |
| 1109 | image.fread(&buffer, 4); | |
| 1110 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1111 | ||
| 1112 | read_length += (chunk_length + 8); | |
| 1113 | } | |
| 1114 | else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R')) | |
| 1115 | { | |
| 1116 | logerror("[BATR] chunk found. No support yet.\n"); | |
| 1117 | image.fread(&buffer, 4); | |
| 1118 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1119 | ||
| 1120 | read_length += (chunk_length + 8); | |
| 1121 | } | |
| 1122 | else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R')) | |
| 1123 | { | |
| 1124 | logerror("[VROR] chunk found. No support yet.\n"); | |
| 1125 | image.fread(&buffer, 4); | |
| 1126 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1127 | ||
| 1128 | read_length += (chunk_length + 8); | |
| 1129 | } | |
| 1130 | else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R')) | |
| 1131 | { | |
| 1132 | logerror("[MIRR] chunk found.\n"); | |
| 1133 | image.fread(&buffer, 4); | |
| 1134 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1135 | ||
| 1136 | image.fread(&temp_byte, 1); | |
| 1137 | switch (temp_byte) | |
| 1138 | { | |
| 1139 | case 0: // Horizontal Mirroring (Hard Wired) | |
| 1140 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1141 | break; | |
| 1142 | case 1: // Vertical Mirroring (Hard Wired) | |
| 1143 | state->m_hard_mirroring = PPU_MIRROR_VERT; | |
| 1144 | break; | |
| 1145 | case 2: // Mirror All Pages From $2000 (Hard Wired) | |
| 1146 | state->m_hard_mirroring = PPU_MIRROR_LOW; | |
| 1147 | break; | |
| 1148 | case 3: // Mirror All Pages From $2400 (Hard Wired) | |
| 1149 | state->m_hard_mirroring = PPU_MIRROR_HIGH; | |
| 1150 | break; | |
| 1151 | case 4: // Four Screens of VRAM (Hard Wired) | |
| 1152 | state->m_four_screen_vram = 1; | |
| 1153 | break; | |
| 1154 | case 5: // Mirroring Controlled By Mapper Hardware | |
| 1155 | logerror("Mirroring handled by the board hardware.\n"); | |
| 1156 | // default to horizontal at start | |
| 1157 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1158 | break; | |
| 1159 | default: | |
| 1160 | logerror("Undocumented mirroring value.\n"); | |
| 1161 | // default to horizontal | |
| 1162 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1163 | break; | |
| 1164 | } | |
| 1165 | ||
| 1166 | read_length += (chunk_length + 8); | |
| 1167 | } | |
| 1168 | else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K')) | |
| 1169 | { | |
| 1170 | logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]); | |
| 1171 | image.fread(&buffer, 4); | |
| 1172 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1173 | ||
| 1174 | read_length += (chunk_length + 8); | |
| 1175 | } | |
| 1176 | else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K')) | |
| 1177 | { | |
| 1178 | logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]); | |
| 1179 | image.fread(&buffer, 4); | |
| 1180 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1181 | ||
| 1182 | read_length += (chunk_length + 8); | |
| 1183 | } | |
| 1184 | else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G')) | |
| 1185 | { | |
| 1186 | logerror("[PRG%c] chunk found. ", magic2[3]); | |
| 1187 | image.fread(&buffer, 4); | |
| 1188 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1189 | ||
| 1190 | // FIXME: we currently don't support PRG chunks smaller than 16K! | |
| 1191 | state->m_prg_chunks += (chunk_length / 0x4000); | |
| 1192 | ||
| 1193 | if (chunk_length / 0x4000) | |
| 1194 | logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000); | |
| 1195 | else | |
| 1196 | logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n"); | |
| 1197 | ||
| 1198 | /* Read in the program chunks */ | |
| 1199 | image.fread(&temp_prg[prg_start], chunk_length); | |
| 1200 | ||
| 1201 | prg_start += chunk_length; | |
| 1202 | read_length += (chunk_length + 8); | |
| 1203 | } | |
| 1204 | else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R')) | |
| 1205 | { | |
| 1206 | logerror("[CHR%c] chunk found. ", magic2[3]); | |
| 1207 | image.fread(&buffer, 4); | |
| 1208 | chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); | |
| 1209 | ||
| 1210 | state->m_chr_chunks += (chunk_length / 0x2000); | |
| 1211 | ||
| 1212 | logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000); | |
| 1213 | ||
| 1214 | /* Read in the vrom chunks */ | |
| 1215 | image.fread(&temp_chr[chr_start], chunk_length); | |
| 1216 | ||
| 1217 | chr_start += chunk_length; | |
| 1218 | read_length += (chunk_length + 8); | |
| 1219 | } | |
| 1220 | else | |
| 1221 | { | |
| 1222 | logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); | |
| 1223 | read_length = size; | |
| 1224 | } | |
| 1225 | } | |
| 1226 | } while (size > read_length); | |
| 1227 | ||
| 1228 | if (!mapr_chunk_found) | |
| 1229 | { | |
| 1230 | auto_free(image.device().machine(), temp_prg); | |
| 1231 | auto_free(image.device().machine(), temp_chr); | |
| 1232 | fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted"); | |
| 1233 | } | |
| 1234 | ||
| 1235 | if (!prg_start) | |
| 1236 | { | |
| 1237 | auto_free(image.device().machine(), temp_prg); | |
| 1238 | auto_free(image.device().machine(), temp_chr); | |
| 1239 | fatalerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); | |
| 1240 | } | |
| 1241 | ||
| 1242 | /* Free the regions that were allocated by the ROM loader */ | |
| 1243 | image.device().machine().region_free("maincpu"); | |
| 1244 | image.device().machine().region_free("gfx1"); | |
| 1245 | image.device().machine().region_free("gfx2"); | |
| 1246 | ||
| 1247 | /* Allocate them again, and copy PRG/CHR from temp buffers */ | |
| 1248 | /* Take care of PRG */ | |
| 1249 | prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000; | |
| 1250 | image.device().machine().region_alloc("maincpu", 0x10000 + prg_size, 1, ENDIANNESS_LITTLE); | |
| 1251 | state->m_rom = image.device().machine().region("maincpu")->base(); | |
| 1252 | memcpy(&state->m_rom[0x10000], &temp_prg[0x00000], state->m_prg_chunks * 0x4000); | |
| 1253 | /* If only a single 16K PRG chunk is present, mirror it! */ | |
| 1254 | if (state->m_prg_chunks == 1) | |
| 1255 | memcpy(&state->m_rom[0x14000], &state->m_rom[0x10000], 0x4000); | |
| 1256 | ||
| 1257 | /* Take care of CHR ROM */ | |
| 1258 | if (state->m_chr_chunks) | |
| 1259 | { | |
| 1260 | image.device().machine().region_alloc("gfx1", state->m_chr_chunks * 0x2000, 1, ENDIANNESS_LITTLE); | |
| 1261 | state->m_vrom = image.device().machine().region("gfx1")->base(); | |
| 1262 | memcpy(&state->m_vrom[0x00000], &temp_chr[0x00000], state->m_chr_chunks * 0x2000); | |
| 1263 | } | |
| 1264 | ||
| 1265 | /* Take care of CHR RAM */ | |
| 1266 | if (state->m_vram_chunks) | |
| 1267 | { | |
| 1268 | image.device().machine().region_alloc("gfx2", state->m_vram_chunks * 0x2000, 1, ENDIANNESS_LITTLE); | |
| 1269 | state->m_vram = image.device().machine().region("gfx2")->base(); | |
| 1270 | } | |
| 1271 | ||
| 1272 | // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)! | |
| 1273 | state->m_wram_size = 0x10000; | |
| 1274 | state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); | |
| 1275 | ||
| 1276 | #if SPLIT_PRG | |
| 1277 | { | |
| 1278 | FILE *prgout; | |
| 1279 | char outname[255]; | |
| 1280 | ||
| 1281 | sprintf(outname, "%s.prg", image.filename()); | |
| 1282 | prgout = fopen(outname, "wb"); | |
| 1283 | if (prgout) | |
| 1284 | { | |
| 1285 | fwrite(&state->m_rom[0x10000], 1, 0x4000 * state->m_prg_chunks, prgout); | |
| 1286 | mame_printf_error("Created PRG chunk\n"); | |
| 1287 | } | |
| 1288 | ||
| 1289 | fclose(prgout); | |
| 1290 | } | |
| 1291 | #endif | |
| 1292 | ||
| 1293 | #if SPLIT_CHR | |
| 1294 | if (state->m_chr_chunks > 0) | |
| 1295 | { | |
| 1296 | FILE *chrout; | |
| 1297 | char outname[255]; | |
| 1298 | ||
| 1299 | sprintf(outname, "%s.chr", image.filename()); | |
| 1300 | chrout= fopen(outname, "wb"); | |
| 1301 | if (chrout) | |
| 1302 | { | |
| 1303 | fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout); | |
| 1304 | mame_printf_error("Created CHR chunk\n"); | |
| 1305 | } | |
| 1306 | fclose(chrout); | |
| 1307 | } | |
| 1308 | #endif | |
| 1309 | // free the temporary copy of PRG/CHR | |
| 1310 | auto_free(image.device().machine(), temp_prg); | |
| 1311 | auto_free(image.device().machine(), temp_chr); | |
| 1312 | logerror("UNIF support is only very preliminary.\n"); | |
| 1313 | } | |
| 1314 | else | |
| 1315 | { | |
| 1316 | logerror("%s is NOT a file in either iNES or UNIF format.\n", image.filename()); | |
| 1317 | return IMAGE_INIT_FAIL; | |
| 1318 | } | |
| 1319 | } | |
| 1320 | else | |
| 1321 | { | |
| 1322 | UINT32 prg_size = image.get_software_region_length("prg"); | |
| 1323 | UINT32 chr_size = image.get_software_region_length("chr"); | |
| 1324 | UINT32 vram_size = image.get_software_region_length("vram"); | |
| 1325 | vram_size += image.get_software_region_length("vram2"); | |
| 1326 | ||
| 1327 | /* Free the regions that were allocated by the ROM loader */ | |
| 1328 | image.device().machine().region_free("maincpu"); | |
| 1329 | image.device().machine().region_free("gfx1"); | |
| 1330 | image.device().machine().region_free("gfx2"); | |
| 1331 | ||
| 1332 | /* Allocate them again with the proper size */ | |
| 1333 | image.device().machine().region_alloc("maincpu", 0x10000 + prg_size, 1, ENDIANNESS_LITTLE); | |
| 1334 | ||
| 1335 | // validate the xml fields | |
| 1336 | if (!prg_size) | |
| 1337 | fatalerror("No PRG entry for this software! Please check if the xml list got corrupted"); | |
| 1338 | if (prg_size < 0x8000) | |
| 1339 | fatalerror("PRG entry is too small! Please check if the xml list got corrupted"); | |
| 1340 | ||
| 1341 | if (chr_size) | |
| 1342 | image.device().machine().region_alloc("gfx1", chr_size, 1, ENDIANNESS_LITTLE); | |
| 1343 | ||
| 1344 | if (vram_size) | |
| 1345 | image.device().machine().region_alloc("gfx2", vram_size, 1, ENDIANNESS_LITTLE); | |
| 1346 | ||
| 1347 | state->m_rom = image.device().machine().region("maincpu")->base(); | |
| 1348 | state->m_vrom = image.device().machine().region("gfx1")->base(); | |
| 1349 | state->m_vram = image.device().machine().region("gfx2")->base(); | |
| 1350 | ||
| 1351 | memcpy(state->m_rom + 0x10000, image.get_software_region("prg"), prg_size); | |
| 1352 | ||
| 1353 | if (chr_size) | |
| 1354 | memcpy(state->m_vrom, image.get_software_region("chr"), chr_size); | |
| 1355 | ||
| 1356 | state->m_prg_chunks = prg_size / 0x4000; | |
| 1357 | state->m_chr_chunks = chr_size / 0x2000; | |
| 1358 | state->m_vram_chunks = vram_size / 0x2000; | |
| 1359 | ||
| 1360 | state->m_pcb_id = nes_get_pcb_id(image.device().machine(), image.get_feature("pcb")); | |
| 1361 | ||
| 1362 | if (state->m_pcb_id == STD_TVROM || state->m_pcb_id == STD_DRROM || state->m_pcb_id == IREM_LROG017) | |
| 1363 | state->m_four_screen_vram = 1; | |
| 1364 | else | |
| 1365 | state->m_four_screen_vram = 0; | |
| 1366 | ||
| 1367 | state->m_battery = (image.get_software_region("bwram") != NULL) ? 1 : 0; | |
| 1368 | state->m_battery_size = image.get_software_region_length("bwram"); | |
| 1369 | ||
| 1370 | if (state->m_pcb_id == BANDAI_LZ93EX) | |
| 1371 | { | |
| 1372 | // allocate the 24C01 or 24C02 EEPROM | |
| 1373 | state->m_battery = 1; | |
| 1374 | state->m_battery_size += 0x2000; | |
| 1375 | } | |
| 1376 | ||
| 1377 | if (state->m_pcb_id == BANDAI_DATACH) | |
| 1378 | { | |
| 1379 | // allocate the 24C01 and 24C02 EEPROM | |
| 1380 | state->m_battery = 1; | |
| 1381 | state->m_battery_size += 0x4000; | |
| 1382 | } | |
| 1383 | ||
| 1384 | state->m_prg_ram = (image.get_software_region("wram") != NULL) ? 1 : 0; | |
| 1385 | state->m_wram_size = image.get_software_region_length("wram"); | |
| 1386 | state->m_mapper_ram_size = image.get_software_region_length("mapper_ram"); | |
| 1387 | state->m_mapper_bram_size = image.get_software_region_length("mapper_bram"); | |
| 1388 | ||
| 1389 | if (state->m_prg_ram) | |
| 1390 | state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); | |
| 1391 | if (state->m_mapper_ram_size) | |
| 1392 | state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_ram_size); | |
| 1393 | if (state->m_mapper_bram_size) | |
| 1394 | state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_bram_size); | |
| 1395 | ||
| 1396 | /* Check for mirroring */ | |
| 1397 | if (image.get_feature("mirroring") != NULL) | |
| 1398 | { | |
| 1399 | const char *mirroring = image.get_feature("mirroring"); | |
| 1400 | if (!strcmp(mirroring, "horizontal")) | |
| 1401 | state->m_hard_mirroring = PPU_MIRROR_HORZ; | |
| 1402 | if (!strcmp(mirroring, "vertical")) | |
| 1403 | state->m_hard_mirroring = PPU_MIRROR_VERT; | |
| 1404 | if (!strcmp(mirroring, "high")) | |
| 1405 | state->m_hard_mirroring = PPU_MIRROR_HIGH; | |
| 1406 | if (!strcmp(mirroring, "low")) | |
| 1407 | state->m_hard_mirroring = PPU_MIRROR_LOW; | |
| 1408 | } | |
| 1409 | ||
| 1410 | state->m_chr_open_bus = 0; | |
| 1411 | state->m_ce_mask = 0; | |
| 1412 | state->m_ce_state = 0; | |
| 1413 | state->m_vrc_ls_prg_a = 0; | |
| 1414 | state->m_vrc_ls_prg_b = 0; | |
| 1415 | state->m_vrc_ls_chr = 0; | |
| 1416 | ||
| 1417 | /* Check for pins in specific boards which require them */ | |
| 1418 | if (state->m_pcb_id == STD_CNROM) | |
| 1419 | { | |
| 1420 | if (image.get_feature("chr-pin26") != NULL) | |
| 1421 | { | |
| 1422 | state->m_ce_mask |= 0x01; | |
| 1423 | state->m_ce_state |= !strcmp(image.get_feature("chr-pin26"), "CE") ? 0x01 : 0; | |
| 1424 | } | |
| 1425 | if (image.get_feature("chr-pin27") != NULL) | |
| 1426 | { | |
| 1427 | state->m_ce_mask |= 0x02; | |
| 1428 | state->m_ce_state |= !strcmp(image.get_feature("chr-pin27"), "CE") ? 0x02 : 0; | |
| 1429 | } | |
| 1430 | } | |
| 1431 | ||
| 1432 | if (state->m_pcb_id == TAITO_X1_005 && image.get_feature("x1-pin17") != NULL && image.get_feature("x1-pin31") != NULL) | |
| 1433 | { | |
| 1434 | if (!strcmp(image.get_feature("x1-pin17"), "CIRAM A10") && !strcmp(image.get_feature("x1-pin31"), "NC")) | |
| 1435 | state->m_pcb_id = TAITO_X1_005_A; | |
| 1436 | } | |
| 1437 | ||
| 1438 | if (state->m_pcb_id == KONAMI_VRC2) | |
| 1439 | { | |
| 1440 | state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc2-pin3")); | |
| 1441 | state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc2-pin4")); | |
| 1442 | state->m_vrc_ls_chr = (nes_cart_get_line(image.get_feature("vrc2-pin21")) != 10) ? 1 : 0; | |
| 1443 | // mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %s\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b, state->m_vrc_ls_chr ? "NC" : "A10"); | |
| 1444 | } | |
| 1445 | ||
| 1446 | if (state->m_pcb_id == KONAMI_VRC4) | |
| 1447 | { | |
| 1448 | state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc4-pin3")); | |
| 1449 | state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc4-pin4")); | |
| 1450 | // mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); | |
| 1451 | } | |
| 1452 | ||
| 1453 | if (state->m_pcb_id == KONAMI_VRC6) | |
| 1454 | { | |
| 1455 | state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc6-pin9")); | |
| 1456 | state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc6-pin10")); | |
| 1457 | // mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); | |
| 1458 | } | |
| 1459 | ||
| 1460 | /* Check for other misc board variants */ | |
| 1461 | if (state->m_pcb_id == STD_SOROM) | |
| 1462 | { | |
| 1463 | if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A")) | |
| 1464 | state->m_pcb_id = STD_SOROM_A; // in MMC1-A PRG RAM is always enabled | |
| 1465 | } | |
| 1466 | ||
| 1467 | if (state->m_pcb_id == STD_SXROM) | |
| 1468 | { | |
| 1469 | if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A")) | |
| 1470 | state->m_pcb_id = STD_SXROM_A; // in MMC1-A PRG RAM is always enabled | |
| 1471 | } | |
| 1472 | ||
| 1473 | if (state->m_pcb_id == STD_NXROM || state->m_pcb_id == SUNSOFT_DCS) | |
| 1474 | { | |
| 1475 | if (image.get_software_region("minicart") != NULL) // check for dual minicart | |
| 1476 | { | |
| 1477 | state->m_pcb_id = SUNSOFT_DCS; | |
| 1478 | // we shall load somewhere the minicart, but we still do not support this | |
| 1479 | } | |
| 1480 | } | |
| 1481 | ||
| 1482 | #if 0 | |
| 1483 | if (state->m_pcb_id == UNSUPPORTED_BOARD) | |
| 1484 | mame_printf_error("This board (%s) is currently not supported by MESS\n", image.get_feature("pcb")); | |
| 1485 | mame_printf_error("PCB Feature: %s\n", image.get_feature("pcb")); | |
| 1486 | mame_printf_error("PRG chunks: %d\n", state->m_prg_chunks); | |
| 1487 | mame_printf_error("CHR chunks: %d\n", state->m_chr_chunks); | |
| 1488 | mame_printf_error("VRAM: Present %s, size: %d\n", state->m_vram_chunks ? "Yes" : "No", vram_size); | |
| 1489 | mame_printf_error("NVWRAM: Present %s, size: %d\n", state->m_battery ? "Yes" : "No", state->m_battery_size); | |
| 1490 | mame_printf_error("WRAM: Present %s, size: %d\n", state->m_prg_ram ? "Yes" : "No", state->m_wram_size); | |
| 1491 | #endif | |
| 1492 | } | |
| 1493 | ||
| 1494 | // Attempt to load a battery file for this ROM | |
| 1495 | // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) | |
| 1496 | if (state->m_battery || state->m_mapper_bram_size) | |
| 1497 | { | |
| 1498 | UINT8 *temp_nvram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size + state->m_mapper_bram_size); | |
| 1499 | image.battery_load(temp_nvram, state->m_battery_size + state->m_mapper_bram_size, 0x00); | |
| 1500 | if (state->m_battery) | |
| 1501 | { | |
| 1502 | state->m_battery_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size); | |
| 1503 | memcpy(state->m_battery_ram, temp_nvram, state->m_battery_size); | |
| 1504 | } | |
| 1505 | if (state->m_mapper_bram_size) | |
| 1506 | memcpy(state->m_mapper_bram, temp_nvram + state->m_battery_size, state->m_mapper_bram_size); | |
| 1507 | ||
| 1508 | auto_free(image.device().machine(), temp_nvram); | |
| 1509 | } | |
| 1510 | ||
| 1511 | return IMAGE_INIT_PASS; | |
| 1512 | } | |
| 1513 | ||
| 1514 | ||
| 1515 | ||
| 1516 | void nes_partialhash(hash_collection &dest, const unsigned char *data, | |
| 1517 | unsigned long length, const char *functions) | |
| 1518 | { | |
| 1519 | if (length <= 16) | |
| 1520 | return; | |
| 1521 | dest.compute(&data[16], length - 16, functions); | |
| 1522 | } | |
| 1523 | ||
| 1524 | /************************** | |
| 1525 | ||
| 1526 | Disk System emulation | |
| 1527 | ||
| 1528 | **************************/ | |
| 1529 | ||
| 1530 | static void fds_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 1531 | { | |
| 1532 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 1533 | ||
| 1534 | if (state->m_IRQ_enable_latch) | |
| 1535 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1536 | ||
| 1537 | if (state->m_IRQ_enable) | |
| 1538 | { | |
| 1539 | if (state->m_IRQ_count <= 114) | |
| 1540 | { | |
| 1541 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 1542 | state->m_IRQ_enable = 0; | |
| 1543 | state->m_fds_status0 |= 0x01; | |
| 1544 | } | |
| 1545 | else | |
| 1546 | state->m_IRQ_count -= 114; | |
| 1547 | } | |
| 1548 | } | |
| 1549 | ||
| 1550 | static READ8_HANDLER( nes_fds_r ) | |
| 1551 | { | |
| 1552 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1553 | UINT8 ret = 0x00; | |
| 1554 | ||
| 1555 | switch (offset) | |
| 1556 | { | |
| 1557 | case 0x00: /* $4030 - disk status 0 */ | |
| 1558 | ret = state->m_fds_status0; | |
| 1559 | /* clear the disk IRQ detect flag */ | |
| 1560 | state->m_fds_status0 &= ~0x01; | |
| 1561 | break; | |
| 1562 | case 0x01: /* $4031 - data latch */ | |
| 1563 | /* don't read data if disk is unloaded */ | |
| 1564 | if (state->m_fds_data == NULL) | |
| 1565 | ret = 0; | |
| 1566 | else if (state->m_fds_current_side) | |
| 1567 | ret = state->m_fds_data[(state->m_fds_current_side - 1) * 65500 + state->m_fds_head_position++]; | |
| 1568 | else | |
| 1569 | ret = 0; | |
| 1570 | break; | |
| 1571 | case 0x02: /* $4032 - disk status 1 */ | |
| 1572 | /* return "no disk" status if disk is unloaded */ | |
| 1573 | if (state->m_fds_data == NULL) | |
| 1574 | ret = 1; | |
| 1575 | else if (state->m_fds_last_side != state->m_fds_current_side) | |
| 1576 | { | |
| 1577 | /* If we've switched disks, report "no disk" for a few reads */ | |
| 1578 | ret = 1; | |
| 1579 | state->m_fds_count++; | |
| 1580 | if (state->m_fds_count == 50) | |
| 1581 | { | |
| 1582 | state->m_fds_last_side = state->m_fds_current_side; | |
| 1583 | state->m_fds_count = 0; | |
| 1584 | } | |
| 1585 | } | |
| 1586 | else | |
| 1587 | ret = (state->m_fds_current_side == 0); /* 0 if a disk is inserted */ | |
| 1588 | break; | |
| 1589 | case 0x03: /* $4033 */ | |
| 1590 | ret = 0x80; | |
| 1591 | break; | |
| 1592 | default: | |
| 1593 | ret = 0x00; | |
| 1594 | break; | |
| 1595 | } | |
| 1596 | ||
| 1597 | return ret; | |
| 1598 | } | |
| 1599 | ||
| 1600 | static WRITE8_HANDLER( nes_fds_w ) | |
| 1601 | { | |
| 1602 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 1603 | ||
| 1604 | switch (offset) | |
| 1605 | { | |
| 1606 | case 0x00: | |
| 1607 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff00) | data; | |
| 1608 | break; | |
| 1609 | case 0x01: | |
| 1610 | state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x00ff) | (data << 8); | |
| 1611 | break; | |
| 1612 | case 0x02: | |
| 1613 | state->m_IRQ_count = state->m_IRQ_count_latch; | |
| 1614 | state->m_IRQ_enable = data; | |
| 1615 | break; | |
| 1616 | case 0x03: | |
| 1617 | // d0 = sound io (1 = enable) | |
| 1618 | // d1 = disk io (1 = enable) | |
| 1619 | break; | |
| 1620 | case 0x04: | |
| 1621 | /* write data out to disk */ | |
| 1622 | break; | |
| 1623 | case 0x05: | |
| 1624 | state->m_fds_motor_on = BIT(data, 0); | |
| 1625 | ||
| 1626 | if (BIT(data, 1)) | |
| 1627 | state->m_fds_head_position = 0; | |
| 1628 | ||
| 1629 | state->m_fds_read_mode = BIT(data, 2); | |
| 1630 | set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 1631 | ||
| 1632 | if ((!(data & 0x40)) && (state->m_fds_write_reg & 0x40)) | |
| 1633 | state->m_fds_head_position -= 2; // ??? | |
| 1634 | ||
| 1635 | state->m_IRQ_enable_latch = BIT(data, 7); | |
| 1636 | state->m_fds_write_reg = data; | |
| 1637 | break; | |
| 1638 | } | |
| 1639 | } | |
| 1640 | ||
| 1641 | static void nes_load_proc( device_image_interface &image ) | |
| 1642 | { | |
| 1643 | nes_state *state = image.device().machine().driver_data<nes_state>(); | |
| 1644 | int header = 0; | |
| 1645 | state->m_fds_sides = 0; | |
| 1646 | ||
| 1647 | if (image.length() % 65500) | |
| 1648 | header = 0x10; | |
| 1649 | ||
| 1650 | state->m_fds_sides = (image.length() - header) / 65500; | |
| 1651 | ||
| 1652 | if (state->m_fds_data == NULL) | |
| 1653 | state->m_fds_data = (UINT8*)image.image_malloc(state->m_fds_sides * 65500); // I don't think we can arrive here ever, probably it can be removed... | |
| 1654 | ||
| 1655 | /* if there is an header, skip it */ | |
| 1656 | image.fseek(header, SEEK_SET); | |
| 1657 | ||
| 1658 | image.fread(state->m_fds_data, 65500 * state->m_fds_sides); | |
| 1659 | return; | |
| 1660 | } | |
| 1661 | ||
| 1662 | static void nes_unload_proc( device_image_interface &image ) | |
| 1663 | { | |
| 1664 | nes_state *state = image.device().machine().driver_data<nes_state>(); | |
| 1665 | ||
| 1666 | /* TODO: should write out changes here as well */ | |
| 1667 | state->m_fds_sides = 0; | |
| 1668 | } | |
| 1669 | ||
| 1670 | DRIVER_INIT( famicom ) | |
| 1671 | { | |
| 1672 | nes_state *state = machine.driver_data<nes_state>(); | |
| 1673 | int i; | |
| 1674 | ||
| 1675 | /* clear some of the variables we don't use */ | |
| 1676 | state->m_trainer = 0; | |
| 1677 | state->m_battery = 0; | |
| 1678 | state->m_prg_ram = 0; | |
| 1679 | state->m_four_screen_vram = 0; | |
| 1680 | state->m_hard_mirroring = 0; | |
| 1681 | state->m_prg_chunks = state->m_chr_chunks = 0; | |
| 1682 | ||
| 1683 | /* initialize the disk system */ | |
| 1684 | state->m_disk_expansion = 1; | |
| 1685 | state->m_pcb_id = NO_BOARD; | |
| 1686 | ||
| 1687 | state->m_fds_sides = 0; | |
| 1688 | state->m_fds_last_side = 0; | |
| 1689 | state->m_fds_count = 0; | |
| 1690 | state->m_fds_motor_on = 0; | |
| 1691 | state->m_fds_door_closed = 0; | |
| 1692 | state->m_fds_current_side = 1; | |
| 1693 | state->m_fds_head_position = 0; | |
| 1694 | state->m_fds_status0 = 0; | |
| 1695 | state->m_fds_read_mode = state->m_fds_write_reg = 0; | |
| 1696 | ||
| 1697 | state->m_fds_data = auto_alloc_array_clear(machine, UINT8, 65500 * 2); | |
| 1698 | state->m_fds_ram = auto_alloc_array_clear(machine, UINT8, 0x8000); | |
| 1699 | state->save_pointer(NAME(state->m_fds_ram), 0x8000); | |
| 1700 | ||
| 1701 | // setup CHR accesses to 8k VRAM | |
| 1702 | state->m_vram = machine.region("gfx2")->base(); | |
| 1703 | for (i = 0; i < 8; i++) | |
| 1704 | { | |
| 1705 | state->m_chr_map[i].source = CHRRAM; | |
| 1706 | state->m_chr_map[i].origin = i * 0x400; // for save state uses! | |
| 1707 | state->m_chr_map[i].access = &state->m_vram[state->m_chr_map[i].origin]; | |
| 1708 | } | |
| 1709 | ||
| 1710 | floppy_install_load_proc(floppy_get_device(machine, 0), nes_load_proc); | |
| 1711 | floppy_install_unload_proc(floppy_get_device(machine, 0), nes_unload_proc); | |
| 1712 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | #ifndef __AMIGACD_H__ | |
| 2 | #define __AMIGACD_H__ | |
| 3 | ||
| 4 | ||
| 5 | MACHINE_START( amigacd ); | |
| 6 | MACHINE_RESET( amigacd ); | |
| 7 | ||
| 8 | /* 6525tpi */ | |
| 9 | READ8_DEVICE_HANDLER( amigacd_tpi6525_portc_r ); | |
| 10 | WRITE8_DEVICE_HANDLER( amigacd_tpi6525_portb_w ); | |
| 11 | WRITE_LINE_DEVICE_HANDLER( amigacd_tpi6525_irq ); | |
| 12 | ||
| 13 | ||
| 14 | #endif /* __AMIGACD_H__ */ |
| r0 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES MMC Emulation - UNIF boards | |
| 4 | ||
| 5 | Very preliminary support for UNIF boards | |
| 6 | ||
| 7 | TODO: | |
| 8 | - properly support WRAM, etc. | |
| 9 | ||
| 10 | ****************************************************************************************/ | |
| 11 | ||
| 12 | typedef struct __unif | |
| 13 | { | |
| 14 | const char *board; /* UNIF board */ | |
| 15 | ||
| 16 | int nvwram; | |
| 17 | int wram; | |
| 18 | int chrram; | |
| 19 | int board_idx; | |
| 20 | } unif; | |
| 21 | ||
| 22 | ||
| 23 | /************************************************************* | |
| 24 | ||
| 25 | Constants | |
| 26 | ||
| 27 | *************************************************************/ | |
| 28 | ||
| 29 | /* CHRRAM sizes */ | |
| 30 | enum | |
| 31 | { | |
| 32 | CHRRAM_0 = 0, | |
| 33 | CHRRAM_1, | |
| 34 | CHRRAM_2, | |
| 35 | CHRRAM_4, | |
| 36 | CHRRAM_6, | |
| 37 | CHRRAM_8, | |
| 38 | CHRRAM_16, | |
| 39 | CHRRAM_32 | |
| 40 | }; | |
| 41 | ||
| 42 | /************************************************************* | |
| 43 | ||
| 44 | unif_list | |
| 45 | ||
| 46 | Supported UNIF boards and corresponding handlers | |
| 47 | ||
| 48 | *************************************************************/ | |
| 49 | ||
| 50 | static const unif unif_list[] = | |
| 51 | { | |
| 52 | /* UNIF NVW WRAM CRAM IDX*/ | |
| 53 | { "DREAMTECH01", 0, 0, CHRRAM_8, DREAMTECH_BOARD}, //UNIF only! | |
| 54 | { "NES-ANROM", 0, 0, CHRRAM_8, STD_AXROM}, | |
| 55 | { "NES-AOROM", 0, 0, CHRRAM_8, STD_AXROM}, | |
| 56 | { "NES-CNROM", 0, 0, CHRRAM_0, STD_CNROM}, | |
| 57 | { "NES-NROM", 0, 0, CHRRAM_0, STD_NROM}, | |
| 58 | { "NES-NROM-128", 0, 0, CHRRAM_0, STD_NROM}, | |
| 59 | { "NES-NROM-256", 0, 0, CHRRAM_0, STD_NROM}, | |
| 60 | { "NES-NTBROM", 8, 0, CHRRAM_0, STD_NXROM}, | |
| 61 | { "NES-SLROM", 0, 0, CHRRAM_0, STD_SXROM}, | |
| 62 | { "NES-TBROM", 0, 0, CHRRAM_0, STD_TXROM}, | |
| 63 | { "NES-TFROM", 0, 0, CHRRAM_0, STD_TXROM}, | |
| 64 | { "NES-TKROM", 8, 0, CHRRAM_0, STD_TXROM}, | |
| 65 | { "NES-TLROM", 0, 0, CHRRAM_0, STD_TXROM}, | |
| 66 | { "NES-UOROM", 0, 0, CHRRAM_8, STD_UXROM}, | |
| 67 | { "UNL-22211", 0, 0, CHRRAM_0, TXC_22211A}, | |
| 68 | // mapper 172 & 173 are variant of this one... no UNIF? | |
| 69 | { "UNL-KOF97", 0, 0, CHRRAM_0, UNL_KOF97}, | |
| 70 | { "UNL-SA-NROM", 0, 0, CHRRAM_0, SACHEN_TCA01}, | |
| 71 | { "UNL-VRC7", 0, 0, CHRRAM_0, KONAMI_VRC7}, | |
| 72 | { "UNL-T-230", 0, 0, CHRRAM_8, UNL_T230}, | |
| 73 | { "UNL-CC-21", 0, 0, CHRRAM_0, UNL_CC21}, | |
| 74 | { "UNL-AX5705", 0, 0, CHRRAM_0, UNL_AX5705}, | |
| 75 | { "UNL-SMB2J", 8, 8, CHRRAM_0, UNL_SMB2J}, | |
| 76 | { "UNL-8237", 0, 0, CHRRAM_0, UNL_8237}, | |
| 77 | { "UNL-SL1632", 0, 0, CHRRAM_0, REXSOFT_SL1632}, | |
| 78 | { "UNL-SACHEN-74LS374N", 0, 0, CHRRAM_0, SACHEN_74LS374}, | |
| 79 | // mapper 243 variant exists! how to distinguish?!? mapper243_l_w, NULL, NULL, NULL, NULL, NULL, NULL (also uses NT_VERT!) | |
| 80 | { "UNL-TC-U01-1.5M", 0, 0, CHRRAM_0, SACHEN_TCU01}, | |
| 81 | { "UNL-SACHEN-8259C", 0, 0, CHRRAM_0, SACHEN_8259C}, | |
| 82 | { "UNL-SA-016-1M", 0, 0, CHRRAM_0, AVE_NINA06}, // actually this is Mapper 146, but works like 79! | |
| 83 | { "UNL-SACHEN-8259D", 0, 0, CHRRAM_0, SACHEN_8259D}, | |
| 84 | { "UNL-SA-72007", 0, 0, CHRRAM_0, SACHEN_SA72007}, | |
| 85 | { "UNL-SA-72008", 0, 0, CHRRAM_0, SACHEN_SA72008}, | |
| 86 | { "UNL-SA-0037", 0, 0, CHRRAM_0, SACHEN_SA0037}, | |
| 87 | { "UNL-SA-0036", 0, 0, CHRRAM_0, SACHEN_SA0036}, | |
| 88 | { "UNL-SACHEN-8259A", 0, 0, CHRRAM_0, SACHEN_8259A}, | |
| 89 | { "UNL-SACHEN-8259B", 0, 0, CHRRAM_0, SACHEN_8259B}, | |
| 90 | { "BMC-190IN1", 0, 0, CHRRAM_0, BMC_190IN1}, | |
| 91 | { "BMC-64IN1NOREPEAT", 0, 0, CHRRAM_0, BMC_64IN1NR}, //UNIF only! | |
| 92 | { "BMC-A65AS", 0, 0, CHRRAM_8, BMC_A65AS}, //UNIF only! | |
| 93 | { "BMC-GS-2004", 0, 0, CHRRAM_8, BMC_GS2004}, //UNIF only! | |
| 94 | { "BMC-GS-2013", 0, 0, CHRRAM_8, BMC_GS2013}, //UNIF only! | |
| 95 | { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVELDIAMOND}, | |
| 96 | { "BMC-SUPER24IN1SC03", 8, 0, CHRRAM_8, BMC_S24IN1SC03}, | |
| 97 | { "BMC-SUPERHIK8IN1", 8, 0, CHRRAM_0, BMC_HIK8IN1}, | |
| 98 | { "BMC-T-262", 0, 0, CHRRAM_8, BMC_T262}, //UNIF only! | |
| 99 | { "BMC-WS", 0, 0, CHRRAM_0, BMC_WS}, //UNIF only! | |
| 100 | { "BMC-N625092", 0, 0, CHRRAM_0, UNL_N625092}, | |
| 101 | // below are boards which are not yet supported, but are used by some UNIF files. they are here as a reminder to what is missing to be added | |
| 102 | { "UNL-TEK90", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // related to JY Company? (i.e. mappers 90, 209, 211?) | |
| 103 | { "UNL-KS7017", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 104 | { "UNL-KS7032", 0, 0, CHRRAM_0, KAISER_KS7032}, // mapper 142 | |
| 105 | { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 106 | { "UNL-603-5052", 0, 0, CHRRAM_0, UNL_603_5052}, // mapper 238? | |
| 107 | { "UNL-EDU2000", 32, 0, CHRRAM_8, UNL_EDU2K}, | |
| 108 | { "UNL-H2288", 0, 0, CHRRAM_0, UNL_H2288}, // mapper 123 | |
| 109 | { "UNL-SHERO", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*SACHEN_SHERO*/}, | |
| 110 | { "UNL-TF1201", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD /*UNL_TF1201*/}, | |
| 111 | { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info]} | |
| 112 | { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 113 | { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 55? | |
| 114 | { "BMC-FK23C", 0, 0, CHRRAM_0, BMC_FK23C}, | |
| 115 | { "BMC-FK23CA", 0, 0, CHRRAM_0, BMC_FK23CA}, | |
| 116 | { "BMC-GHOSTBUSTERS63IN1", 0, 0, CHRRAM_8, BMC_G63IN1 }, | |
| 117 | { "BMC-BS-5", 0, 0, CHRRAM_0, BMC_BENSHENG_BS5}, | |
| 118 | { "BMC-810544-C-A1", 0, 0, CHRRAM_0, BMC_810544}, | |
| 119 | { "BMC-411120-C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 120 | { "BMC-8157", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*BMC_8157*/}, | |
| 121 | { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60? | |
| 122 | { "BMC-830118C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 123 | { "BMC-D1038", 0, 0, CHRRAM_0, BMC_VT5201}, // mapper 60? | |
| 124 | { "BMC-12-IN-1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, | |
| 125 | { "BMC-70IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? | |
| 126 | { "BMC-70IN1B", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? | |
| 127 | { "BMC-SUPERVISION16IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 53 | |
| 128 | { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03} | |
| 129 | }; | |
| 130 | ||
| 131 | const unif *nes_unif_lookup( const char *board ) | |
| 132 | { | |
| 133 | int i; | |
| 134 | for (i = 0; i < ARRAY_LENGTH(unif_list); i++) | |
| 135 | { | |
| 136 | if (!mame_stricmp(unif_list[i].board, board)) | |
| 137 | return &unif_list[i]; | |
| 138 | } | |
| 139 | return NULL; | |
| 140 | } | |
| 141 | ||
| 142 | /************************************************************* | |
| 143 | ||
| 144 | unif_mapr_setup | |
| 145 | ||
| 146 | setup the board specific variables (wram, nvwram, pcb_id etc.) | |
| 147 | for a given board (after reading the MAPR chunk of the UNIF file) | |
| 148 | ||
| 149 | *************************************************************/ | |
| 150 | ||
| 151 | void unif_mapr_setup( running_machine &machine, const char *board ) | |
| 152 | { | |
| 153 | nes_state *state = machine.driver_data<nes_state>(); | |
| 154 | const unif *unif_board = nes_unif_lookup(board); | |
| 155 | ||
| 156 | logerror("%s\n", board); | |
| 157 | ||
| 158 | if (unif_board == NULL) | |
| 159 | fatalerror("Unknown UNIF board %s.", board); | |
| 160 | ||
| 161 | state->m_pcb_id = unif_board->board_idx; | |
| 162 | state->m_battery = unif_board->nvwram; // we should implement battery banks based on the size of this... | |
| 163 | state->m_battery_size = NES_BATTERY_SIZE; // FIXME: we should allow for smaller battery! | |
| 164 | state->m_prg_ram = unif_board->wram; // we should implement WRAM banks based on the size of this... | |
| 165 | ||
| 166 | if (unif_board->chrram <= CHRRAM_8) | |
| 167 | state->m_vram_chunks = 1; | |
| 168 | else if (unif_board->chrram == CHRRAM_16) | |
| 169 | state->m_vram_chunks = 2; | |
| 170 | else if (unif_board->chrram == CHRRAM_32) | |
| 171 | state->m_vram_chunks = 4; | |
| 172 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES MMC Emulation | |
| 4 | ||
| 5 | ||
| 6 | MESS source file to handle various Multi-Memory Controllers (aka Mappers) used by NES carts. | |
| 7 | ||
| 8 | Many information about the mappers below come from the wonderful doc written by Disch. | |
| 9 | Current info (when used) are based on v0.6.1 of his docs. | |
| 10 | You can find the latest version of the doc at http://www.romhacking.net/docs/362/ | |
| 11 | ||
| 12 | ||
| 13 | Missing components: | |
| 14 | * Currently, we are not emulating 4-screen mirroring (only 3 games use it) | |
| 15 | * We need a better way to implement CPU cycle based IRQ. Currently we update their counter once every scanline | |
| 16 | but, with this approach, every time 114 clocks have passed and for certain games it is too much! | |
| 17 | * We need to emulate additional sound hardware in mappers 019, 024, 026, 069, 085 (and possibly other ones) | |
| 18 | * We need to emulate EEPROM in mapper 016 and 159 | |
| 19 | * Barcode World (mapper 069) and Datach games (mapper 157) need Barcode Reader emulation | |
| 20 | Notice that for mapper 157, the barcode reader enters in the irq, so glitches may be related to this! | |
| 21 | * Karaoke Studio (mapper 188) misses input devices | |
| 22 | ||
| 23 | Known issues on specific mappers: | |
| 24 | ||
| 25 | * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches. | |
| 26 | * 001 Yoshi flashes in-game. Back to the Future have heavily corrupted graphics (since forever). | |
| 27 | * 001 SOROM boards do not properly handle the two WRAM/Battery banks | |
| 28 | * 002, 003, 094, 097, 152 Bus conflict? | |
| 29 | * 003 Firehouse Rescue has flashing graphics | |
| 30 | * 004 Mendel Palace has never worked properly | |
| 31 | * 004 Ninja Gaiden 2 has flashing bg graphics in the second level | |
| 32 | * 005 has issues (see e.g. Just Breed or Metal Slader Glory), RAM banking needs hardware flags to determine size | |
| 33 | * 007 Marble Madness has small graphics corruptions | |
| 34 | * 014 in-game graphics is glitched | |
| 35 | * 015 Shanghai Tycoon has corrupted graphics | |
| 36 | * 033 has still some graphics problem (e.g. missing text in Akira) | |
| 37 | * 034 Impossible Mission II does not show graphics | |
| 38 | * 038 seems to miss inputs. separate reads? | |
| 39 | * 042 Ai Senshi Nicol has broken graphics (our Mapper 42 implementation does not handle CHR banks) | |
| 40 | * 048 Don Doko Don 2 freezes when you reach the first boss | |
| 41 | * 051 only half of the games work | |
| 42 | * 064 has many IRQ problems (due to the way we implement CPU based IRQ) - see Skull & Crossbones. | |
| 43 | Klax has problems as well (even if it uses scanline based IRQ, according to Disch's docs). | |
| 44 | * 067 some 1-line glitches that cannot be solved without a better implementation for cycle-based IRQs | |
| 45 | * 071 Fire Hawk is flashing all the times. | |
| 46 | * 072, 086, 092 lack samples support (maybe others as well) | |
| 47 | * 073 16 bit IRQ mode is not implemented | |
| 48 | * 077 Requires 4-screen mirroring. Currently, it is very glitchy | |
| 49 | * 083 has serious glitches | |
| 50 | * 088 Quinty has never worked properly | |
| 51 | * 096 is preliminary (no correct chr switch in connection to PPU) | |
| 52 | * 104 Not all the games work | |
| 53 | * 107 Are the scrolling glitches (check status bar) correct? NEStopia behaves similarly | |
| 54 | * 112 Master Shooter is not working and misses some graphics | |
| 55 | * 117 In-game glitches | |
| 56 | * 119 Pin Bot has glitches when the ball is in the upper half of the screen | |
| 57 | * 133 Qi Wang starts with corrupted graphics (ingame seems better) | |
| 58 | * 143 are Dancing Block borders (in the intro) correct? | |
| 59 | * 158 In addition to IRQ problems (same as 64), mirroring was just a guess (wrong?). info needed! | |
| 60 | * 164 preliminary - no sprites? | |
| 61 | * 176 has some graphics problem | |
| 62 | * 178 Fan Kong Jin Ying is not working (but not even in NEStopia) | |
| 63 | * 180 Crazy Climber controller? | |
| 64 | * 187, 198, 208, 215 have some PRG banking issues - preliminary! | |
| 65 | * 188 needs mic input (reads from 0x6000-0x7fff) | |
| 66 | * 197 Super Fighter 3 has some glitch in-game (maybe mirroring?) | |
| 67 | * 222 is only preliminar (wrong IRQ, mirroring or CHR banking?) | |
| 68 | * 225 115-in-1 has glitches in the menu (games seem fine) | |
| 69 | * 229 is preliminary | |
| 70 | * 230 not working yet (needs a value to flip at reset) | |
| 71 | * 232 has graphics glitches | |
| 72 | * 241 Commandos is not working (but not even in NEStopia) | |
| 73 | * 242 In Dragon Quest VIII graphics of the main character is not drawn (it seems similar to Shanghai Tycoon [map15] | |
| 74 | because in place of the missing graphics we get glitches in the left border) | |
| 75 | * 249 only half of the games work (and Du Bao Ying Hao seems to suffer the same problem as DQ8 and Shanghai Tycoon) | |
| 76 | * 255 does not really select game (same in NEStopia apparently) | |
| 77 | ||
| 78 | A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than | |
| 79 | a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly | |
| 80 | emulation. Games which requires this hack are the following: | |
| 81 | * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise) | |
| 82 | * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still | |
| 83 | unplayable though (see above) | |
| 84 | * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics | |
| 85 | * 078 - Cosmo Carrier needs a different mirroring than Holy Diver | |
| 86 | * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer) | |
| 87 | * 153 - Famicom Jump II uses a different board (or the same in a very different way) | |
| 88 | * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though) | |
| 89 | ||
| 90 | crc_hacks have been added also to handle a few wiring settings which would require submappers: | |
| 91 | * CHR protection pins for mapper 185 | |
| 92 | * VRC-2, VRC-4 and VRC-6 line wiring | |
| 93 | ||
| 94 | Known issues on specific UNIF boards: | |
| 95 | * BMC-GS2004 is not working | |
| 96 | * BMC-GS2013 is not working | |
| 97 | * BMC-WS some games have corrupted graphics (e.g. Galaxian) | |
| 98 | * UNL-8237 is not working | |
| 99 | * UNL-KOF97 is not working | |
| 100 | ||
| 101 | Details to investigate: | |
| 102 | * 034 writes to 0x8000-0xffff should not be used for NINA-001 and BNROM, only unlicensed BxROM... | |
| 103 | * 144 we ignore writes to 0x8000 while NEStopia does not. is it a problem? | |
| 104 | * 240 we do not map writes to 0x4020-0x40ff. is this a problem? | |
| 105 | * some other emus uses mapper 210 for mapper 019 games without additional sound hardware and mirroring capabilities | |
| 106 | (in 210 mirroring is hardwired). However, simply initializing mirroring to Vertical in 019 seems to fix all glitches | |
| 107 | in 210 games, so there seems to be no reason to have this duplicate mapper | |
| 108 | ||
| 109 | Some mappers copy PRG rom in SRAM region. Below is a list of those which does it (in MESS) to further | |
| 110 | investigate if we are supporting them in the right way (e.g. do any of the following have conflicts with SRAM?): | |
| 111 | * 065 (Gimmick! breaks badly without it) | |
| 112 | * 040, 042, 050 | |
| 113 | ||
| 114 | Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is | |
| 115 | in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right? | |
| 116 | ||
| 117 | TODO: | |
| 118 | - add more info | |
| 119 | - add missing mappers | |
| 120 | ||
| 121 | ****************************************************************************************/ | |
| 122 | ||
| 123 | #include "emu.h" | |
| 124 | #include "cpu/m6502/m6502.h" | |
| 125 | #include "video/ppu2c0x.h" | |
| 126 | #include "includes/nes.h" | |
| 127 | #include "nes_mmc.h" | |
| 128 | #include "sound/nes_apu.h" | |
| 129 | ||
| 130 | #ifdef MAME_DEBUG | |
| 131 | #define VERBOSE 1 | |
| 132 | #else | |
| 133 | #define VERBOSE 0 | |
| 134 | #endif | |
| 135 | ||
| 136 | #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) | |
| 137 | #define LOG_FDS(x) do { if (VERBOSE) logerror x; } while (0) | |
| 138 | ||
| 139 | static void ffe_irq( device_t *device, int scanline, int vblank, int blanked ); | |
| 140 | static WRITE8_HANDLER( mapper6_l_w ); | |
| 141 | static WRITE8_HANDLER( mapper6_w ); | |
| 142 | static WRITE8_HANDLER( mapper8_w ); | |
| 143 | static WRITE8_HANDLER( mapper17_l_w ); | |
| 144 | ||
| 145 | /************************************************************* | |
| 146 | ||
| 147 | Base emulation (see drivers/nes.c): | |
| 148 | memory 0x0000-0x1fff RAM | |
| 149 | 0x2000-0x3fff PPU | |
| 150 | 0x4000-0x4017 APU | |
| 151 | 0x4018-0x5fff Expansion Area | |
| 152 | 0x6000-0x7fff PRG RAM | |
| 153 | 0x8000-0xffff PRG ROM | |
| 154 | ||
| 155 | nes_chr_r/w take care of RAM, nes_nt_r/w take care of PPU. | |
| 156 | for mapper specific emulation, we generically setup the | |
| 157 | following handlers: | |
| 158 | - nes_low_mapper_r/w take care of accesses to 0x4100-0x5fff | |
| 159 | (calling state->m_mmc_write_low/state->m_mmc_read_low) | |
| 160 | - state->m_mmc_write/read_mid take care of 0x6000-0x7fff | |
| 161 | - state->m_mmc_write/read take care of access to 0x8000-0xffff | |
| 162 | (most mappers only writes in this area) | |
| 163 | some mappers may access 0x4018-0x4100: this must be taken | |
| 164 | care separately in init_nes_core | |
| 165 | ||
| 166 | *************************************************************/ | |
| 167 | ||
| 168 | WRITE8_HANDLER( nes_chr_w ) | |
| 169 | { | |
| 170 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 171 | int bank = offset >> 10; | |
| 172 | ||
| 173 | if (state->m_chr_map[bank].source == CHRRAM) | |
| 174 | { | |
| 175 | state->m_chr_map[bank].access[offset & 0x3ff] = data; | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 179 | READ8_HANDLER( nes_chr_r ) | |
| 180 | { | |
| 181 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 182 | int bank = offset >> 10; | |
| 183 | ||
| 184 | // a few CNROM boards contained copy protection schemes through | |
| 185 | // suitably configured diodes, so that subsequent CHR reads can | |
| 186 | // give actual VROM content or open bus values. | |
| 187 | // For most boards, chr_open_bus remains always zero. | |
| 188 | if (state->m_chr_open_bus) | |
| 189 | return 0xff; | |
| 190 | ||
| 191 | return state->m_chr_map[bank].access[offset & 0x3ff]; | |
| 192 | } | |
| 193 | ||
| 194 | WRITE8_HANDLER( nes_nt_w ) | |
| 195 | { | |
| 196 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 197 | int page = ((offset & 0xc00) >> 10); | |
| 198 | ||
| 199 | if (state->m_nt_page[page].writable == 0) | |
| 200 | return; | |
| 201 | ||
| 202 | state->m_nt_page[page].access[offset & 0x3ff] = data; | |
| 203 | } | |
| 204 | ||
| 205 | READ8_HANDLER( nes_nt_r ) | |
| 206 | { | |
| 207 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 208 | int page = ((offset & 0xc00) >> 10); | |
| 209 | ||
| 210 | if (state->m_nt_page[page].source == MMC5FILL) | |
| 211 | { | |
| 212 | if ((offset & 0x3ff) >= 0x3c0) | |
| 213 | return state->m_MMC5_floodattr; | |
| 214 | ||
| 215 | return state->m_MMC5_floodtile; | |
| 216 | } | |
| 217 | return state->m_nt_page[page].access[offset & 0x3ff]; | |
| 218 | } | |
| 219 | ||
| 220 | WRITE8_HANDLER( nes_low_mapper_w ) | |
| 221 | { | |
| 222 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 223 | ||
| 224 | if (state->m_mmc_write_low) | |
| 225 | (*state->m_mmc_write_low)(space, offset, data); | |
| 226 | else | |
| 227 | logerror("Unimplemented LOW mapper write, offset: %04x, data: %02x\n", offset + 0x4100, data); | |
| 228 | } | |
| 229 | ||
| 230 | READ8_HANDLER( nes_low_mapper_r ) | |
| 231 | { | |
| 232 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 233 | ||
| 234 | if (state->m_mmc_read_low) | |
| 235 | return (*state->m_mmc_read_low)(space, offset); | |
| 236 | else | |
| 237 | logerror("Unimplemented LOW mapper read, offset: %04x\n", offset + 0x4100); | |
| 238 | ||
| 239 | return 0; | |
| 240 | } | |
| 241 | ||
| 242 | /************************************************************* | |
| 243 | ||
| 244 | Helpers to handle MMC | |
| 245 | ||
| 246 | *************************************************************/ | |
| 247 | ||
| 248 | static void wram_bank( running_machine &machine, int bank, int source ) | |
| 249 | { | |
| 250 | nes_state *state = machine.driver_data<nes_state>(); | |
| 251 | ||
| 252 | assert(state->m_battery || state->m_prg_ram); | |
| 253 | if (source == NES_BATTERY) | |
| 254 | { | |
| 255 | bank &= (state->m_battery_size / 0x2000) - 1; | |
| 256 | state->m_prg_bank[4] = state->m_battery_bank5_start + bank; | |
| 257 | } | |
| 258 | else | |
| 259 | { | |
| 260 | bank &= (state->m_wram_size / 0x2000) - 1; | |
| 261 | state->m_prg_bank[4] = state->m_prgram_bank5_start + bank; | |
| 262 | } | |
| 263 | memory_set_bank(machine, "bank5", state->m_prg_bank[4]); | |
| 264 | } | |
| 265 | ||
| 266 | INLINE void prg_bank_refresh( running_machine &machine ) | |
| 267 | { | |
| 268 | nes_state *state = machine.driver_data<nes_state>(); | |
| 269 | memory_set_bank(machine, "bank1", state->m_prg_bank[0]); | |
| 270 | memory_set_bank(machine, "bank2", state->m_prg_bank[1]); | |
| 271 | memory_set_bank(machine, "bank3", state->m_prg_bank[2]); | |
| 272 | memory_set_bank(machine, "bank4", state->m_prg_bank[3]); | |
| 273 | } | |
| 274 | ||
| 275 | /* PRG ROM in 8K, 16K or 32K blocks */ | |
| 276 | ||
| 277 | static void prg32( running_machine &machine, int bank ) | |
| 278 | { | |
| 279 | nes_state *state = machine.driver_data<nes_state>(); | |
| 280 | ||
| 281 | /* if there is only 16k PRG, return */ | |
| 282 | if (!(state->m_prg_chunks >> 1)) | |
| 283 | return; | |
| 284 | ||
| 285 | /* assumes that bank references a 32k chunk */ | |
| 286 | bank &= ((state->m_prg_chunks >> 1) - 1); | |
| 287 | ||
| 288 | state->m_prg_bank[0] = bank * 4 + 0; | |
| 289 | state->m_prg_bank[1] = bank * 4 + 1; | |
| 290 | state->m_prg_bank[2] = bank * 4 + 2; | |
| 291 | state->m_prg_bank[3] = bank * 4 + 3; | |
| 292 | prg_bank_refresh(machine); | |
| 293 | } | |
| 294 | ||
| 295 | static void prg16_89ab( running_machine &machine, int bank ) | |
| 296 | { | |
| 297 | nes_state *state = machine.driver_data<nes_state>(); | |
| 298 | ||
| 299 | /* assumes that bank references a 16k chunk */ | |
| 300 | bank &= (state->m_prg_chunks - 1); | |
| 301 | ||
| 302 | state->m_prg_bank[0] = bank * 2 + 0; | |
| 303 | state->m_prg_bank[1] = bank * 2 + 1; | |
| 304 | prg_bank_refresh(machine); | |
| 305 | } | |
| 306 | ||
| 307 | static void prg16_cdef( running_machine &machine, int bank ) | |
| 308 | { | |
| 309 | nes_state *state = machine.driver_data<nes_state>(); | |
| 310 | ||
| 311 | /* assumes that bank references a 16k chunk */ | |
| 312 | bank &= (state->m_prg_chunks - 1); | |
| 313 | ||
| 314 | state->m_prg_bank[2] = bank * 2 + 0; | |
| 315 | state->m_prg_bank[3] = bank * 2 + 1; | |
| 316 | prg_bank_refresh(machine); | |
| 317 | } | |
| 318 | ||
| 319 | static void prg8_89( running_machine &machine, int bank ) | |
| 320 | { | |
| 321 | nes_state *state = machine.driver_data<nes_state>(); | |
| 322 | ||
| 323 | /* assumes that bank references an 8k chunk */ | |
| 324 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 325 | ||
| 326 | state->m_prg_bank[0] = bank; | |
| 327 | prg_bank_refresh(machine); | |
| 328 | } | |
| 329 | ||
| 330 | static void prg8_ab( running_machine &machine, int bank ) | |
| 331 | { | |
| 332 | nes_state *state = machine.driver_data<nes_state>(); | |
| 333 | ||
| 334 | /* assumes that bank references an 8k chunk */ | |
| 335 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 336 | ||
| 337 | state->m_prg_bank[1] = bank; | |
| 338 | prg_bank_refresh(machine); | |
| 339 | } | |
| 340 | ||
| 341 | static void prg8_cd( running_machine &machine, int bank ) | |
| 342 | { | |
| 343 | nes_state *state = machine.driver_data<nes_state>(); | |
| 344 | ||
| 345 | /* assumes that bank references an 8k chunk */ | |
| 346 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 347 | ||
| 348 | state->m_prg_bank[2] = bank; | |
| 349 | prg_bank_refresh(machine); | |
| 350 | } | |
| 351 | ||
| 352 | static void prg8_ef( running_machine &machine, int bank ) | |
| 353 | { | |
| 354 | nes_state *state = machine.driver_data<nes_state>(); | |
| 355 | ||
| 356 | /* assumes that bank references an 8k chunk */ | |
| 357 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 358 | ||
| 359 | state->m_prg_bank[3] = bank; | |
| 360 | prg_bank_refresh(machine); | |
| 361 | } | |
| 362 | ||
| 363 | /* We define an additional helper to map PRG-ROM to 0x6000-0x7000 */ | |
| 364 | // TODO: are we implementing this correctly in the mappers which uses it? check! | |
| 365 | ||
| 366 | static void prg8_67( running_machine &machine, int bank ) | |
| 367 | { | |
| 368 | nes_state *state = machine.driver_data<nes_state>(); | |
| 369 | ||
| 370 | /* assumes that bank references an 8k chunk */ | |
| 371 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 372 | ||
| 373 | state->m_prg_bank[4] = bank; | |
| 374 | memory_set_bank(machine, "bank5", state->m_prg_bank[4]); | |
| 375 | } | |
| 376 | ||
| 377 | /* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */ | |
| 378 | static void prg8_x( running_machine &machine, int start, int bank ) | |
| 379 | { | |
| 380 | nes_state *state = machine.driver_data<nes_state>(); | |
| 381 | ||
| 382 | assert(start < 4); | |
| 383 | ||
| 384 | /* assumes that bank references an 8k chunk */ | |
| 385 | bank &= ((state->m_prg_chunks << 1) - 1); | |
| 386 | ||
| 387 | state->m_prg_bank[start] = bank; | |
| 388 | prg_bank_refresh(machine); | |
| 389 | } | |
| 390 | ||
| 391 | /* CHR ROM in 1K, 2K, 4K or 8K blocks */ | |
| 392 | ||
| 393 | // this can be probably removed later, but it is useful while testing xml and unf handling with VRAM & VROM | |
| 394 | INLINE void chr_sanity_check( running_machine &machine, int source ) | |
| 395 | { | |
| 396 | nes_state *state = machine.driver_data<nes_state>(); | |
| 397 | ||
| 398 | if (source == CHRRAM && state->m_vram == NULL) | |
| 399 | fatalerror("CHRRAM bankswitch with no VRAM"); | |
| 400 | ||
| 401 | if (source == CHRROM && state->m_vrom == NULL) | |
| 402 | fatalerror("CHRROM bankswitch with no VROM"); | |
| 403 | } | |
| 404 | ||
| 405 | static void chr8( running_machine &machine, int bank, int source ) | |
| 406 | { | |
| 407 | nes_state *state = machine.driver_data<nes_state>(); | |
| 408 | int i; | |
| 409 | ||
| 410 | chr_sanity_check(machine, source); | |
| 411 | ||
| 412 | if (source == CHRRAM) | |
| 413 | { | |
| 414 | bank &= (state->m_vram_chunks - 1); | |
| 415 | for (i = 0; i < 8; i++) | |
| 416 | { | |
| 417 | state->m_chr_map[i].source = source; | |
| 418 | state->m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses! | |
| 419 | state->m_chr_map[i].access = &state->m_vram[state->m_chr_map[i].origin]; | |
| 420 | } | |
| 421 | } | |
| 422 | else | |
| 423 | { | |
| 424 | bank &= (state->m_chr_chunks - 1); | |
| 425 | for (i = 0; i < 8; i++) | |
| 426 | { | |
| 427 | state->m_chr_map[i].source = source; | |
| 428 | state->m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses! | |
| 429 | state->m_chr_map[i].access = &state->m_vrom[state->m_chr_map[i].origin]; | |
| 430 | } | |
| 431 | } | |
| 432 | } | |
| 433 | ||
| 434 | static void chr4_x( running_machine &machine, int start, int bank, int source ) | |
| 435 | { | |
| 436 | nes_state *state = machine.driver_data<nes_state>(); | |
| 437 | int i; | |
| 438 | ||
| 439 | chr_sanity_check(machine, source); | |
| 440 | ||
| 441 | if (source == CHRRAM) | |
| 442 | { | |
| 443 | bank &= ((state->m_vram_chunks << 1) - 1); | |
| 444 | for (i = 0; i < 4; i++) | |
| 445 | { | |
| 446 | state->m_chr_map[i + start].source = source; | |
| 447 | state->m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses! | |
| 448 | state->m_chr_map[i + start].access = &state->m_vram[state->m_chr_map[i + start].origin]; | |
| 449 | } | |
| 450 | } | |
| 451 | else | |
| 452 | { | |
| 453 | bank &= ((state->m_chr_chunks << 1) - 1); | |
| 454 | for (i = 0; i < 4; i++) | |
| 455 | { | |
| 456 | state->m_chr_map[i + start].source = source; | |
| 457 | state->m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses! | |
| 458 | state->m_chr_map[i + start].access = &state->m_vrom[state->m_chr_map[i + start].origin]; | |
| 459 | } | |
| 460 | } | |
| 461 | } | |
| 462 | ||
| 463 | static void chr4_0( running_machine &machine, int bank, int source ) | |
| 464 | { | |
| 465 | chr4_x(machine, 0, bank, source); | |
| 466 | } | |
| 467 | ||
| 468 | static void chr4_4( running_machine &machine, int bank, int source ) | |
| 469 | { | |
| 470 | chr4_x(machine, 4, bank, source); | |
| 471 | } | |
| 472 | ||
| 473 | static void chr2_x( running_machine &machine, int start, int bank, int source ) | |
| 474 | { | |
| 475 | nes_state *state = machine.driver_data<nes_state>(); | |
| 476 | int i; | |
| 477 | ||
| 478 | chr_sanity_check(machine, source); | |
| 479 | ||
| 480 | if (source == CHRRAM) | |
| 481 | { | |
| 482 | bank &= ((state->m_vram_chunks << 2) - 1); | |
| 483 | for (i = 0; i < 2; i++) | |
| 484 | { | |
| 485 | state->m_chr_map[i + start].source = source; | |
| 486 | state->m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses! | |
| 487 | state->m_chr_map[i + start].access = &state->m_vram[state->m_chr_map[i + start].origin]; | |
| 488 | } | |
| 489 | } | |
| 490 | else | |
| 491 | { | |
| 492 | bank &= ((state->m_chr_chunks << 2) - 1); | |
| 493 | for (i = 0; i < 2; i++) | |
| 494 | { | |
| 495 | state->m_chr_map[i + start].source = source; | |
| 496 | state->m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses! | |
| 497 | state->m_chr_map[i + start].access = &state->m_vrom[state->m_chr_map[i + start].origin]; | |
| 498 | } | |
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | static void chr2_0( running_machine &machine, int bank, int source ) | |
| 503 | { | |
| 504 | chr2_x(machine, 0, bank, source); | |
| 505 | } | |
| 506 | ||
| 507 | static void chr2_2( running_machine &machine, int bank, int source ) | |
| 508 | { | |
| 509 | chr2_x(machine, 2, bank, source); | |
| 510 | } | |
| 511 | ||
| 512 | static void chr2_4( running_machine &machine, int bank, int source ) | |
| 513 | { | |
| 514 | chr2_x(machine, 4, bank, source); | |
| 515 | } | |
| 516 | ||
| 517 | static void chr2_6( running_machine &machine, int bank, int source ) | |
| 518 | { | |
| 519 | chr2_x(machine, 6, bank, source); | |
| 520 | } | |
| 521 | ||
| 522 | static void chr1_x( running_machine &machine, int start, int bank, int source ) | |
| 523 | { | |
| 524 | nes_state *state = machine.driver_data<nes_state>(); | |
| 525 | ||
| 526 | chr_sanity_check(machine, source); | |
| 527 | ||
| 528 | if (source == CHRRAM) | |
| 529 | { | |
| 530 | bank &= ((state->m_vram_chunks << 3) - 1); | |
| 531 | state->m_chr_map[start].source = source; | |
| 532 | state->m_chr_map[start].origin = (bank * 0x400); // for save state uses! | |
| 533 | state->m_chr_map[start].access = &state->m_vram[state->m_chr_map[start].origin]; | |
| 534 | } | |
| 535 | else | |
| 536 | { | |
| 537 | bank &= ((state->m_chr_chunks << 3) - 1); | |
| 538 | state->m_chr_map[start].source = source; | |
| 539 | state->m_chr_map[start].origin = (bank * 0x400); // for save state uses! | |
| 540 | state->m_chr_map[start].access = &state->m_vrom[state->m_chr_map[start].origin]; | |
| 541 | } | |
| 542 | } | |
| 543 | ||
| 544 | static void chr1_0 (running_machine &machine, int bank, int source) | |
| 545 | { | |
| 546 | chr1_x(machine, 0, bank, source); | |
| 547 | } | |
| 548 | ||
| 549 | static void chr1_1( running_machine &machine, int bank, int source ) | |
| 550 | { | |
| 551 | chr1_x(machine, 1, bank, source); | |
| 552 | } | |
| 553 | ||
| 554 | static void chr1_2( running_machine &machine, int bank, int source ) | |
| 555 | { | |
| 556 | chr1_x(machine, 2, bank, source); | |
| 557 | } | |
| 558 | ||
| 559 | static void chr1_3( running_machine &machine, int bank, int source ) | |
| 560 | { | |
| 561 | chr1_x(machine, 3, bank, source); | |
| 562 | } | |
| 563 | ||
| 564 | static void chr1_4( running_machine &machine, int bank, int source ) | |
| 565 | { | |
| 566 | chr1_x(machine, 4, bank, source); | |
| 567 | } | |
| 568 | ||
| 569 | static void chr1_5( running_machine &machine, int bank, int source ) | |
| 570 | { | |
| 571 | chr1_x(machine, 5, bank, source); | |
| 572 | } | |
| 573 | ||
| 574 | static void chr1_6( running_machine &machine, int bank, int source ) | |
| 575 | { | |
| 576 | chr1_x(machine, 6, bank, source); | |
| 577 | } | |
| 578 | ||
| 579 | static void chr1_7( running_machine &machine, int bank, int source ) | |
| 580 | { | |
| 581 | chr1_x(machine, 7, bank, source); | |
| 582 | } | |
| 583 | ||
| 584 | ||
| 585 | /* NameTable paging and mirroring */ | |
| 586 | ||
| 587 | static void set_nt_page( running_machine &machine, int page, int source, int bank, int writable ) | |
| 588 | { | |
| 589 | nes_state *state = machine.driver_data<nes_state>(); | |
| 590 | UINT8* base_ptr; | |
| 591 | ||
| 592 | switch (source) | |
| 593 | { | |
| 594 | case CART_NTRAM: | |
| 595 | base_ptr = state->m_extended_ntram; | |
| 596 | break; | |
| 597 | case MMC5FILL: | |
| 598 | base_ptr = NULL; | |
| 599 | break; | |
| 600 | case ROM: | |
| 601 | base_ptr = state->m_vrom; | |
| 602 | break; | |
| 603 | case EXRAM: | |
| 604 | base_ptr = state->m_mapper_ram; | |
| 605 | break; | |
| 606 | case CIRAM: | |
| 607 | default: | |
| 608 | base_ptr = state->m_ciram; | |
| 609 | break; | |
| 610 | } | |
| 611 | ||
| 612 | page &= 3; /* mask down to the 4 logical pages */ | |
| 613 | state->m_nt_page[page].source = source; | |
| 614 | ||
| 615 | if (base_ptr != NULL) | |
| 616 | { | |
| 617 | state->m_nt_page[page].origin = bank * 0x400; | |
| 618 | state->m_nt_page[page].access = base_ptr + state->m_nt_page[page].origin; | |
| 619 | } | |
| 620 | ||
| 621 | state->m_nt_page[page].writable = writable; | |
| 622 | } | |
| 623 | ||
| 624 | void set_nt_mirroring( running_machine &machine, int mirroring ) | |
| 625 | { | |
| 626 | /* setup our videomem handlers based on mirroring */ | |
| 627 | switch (mirroring) | |
| 628 | { | |
| 629 | case PPU_MIRROR_VERT: | |
| 630 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 631 | set_nt_page(machine, 1, CIRAM, 1, 1); | |
| 632 | set_nt_page(machine, 2, CIRAM, 0, 1); | |
| 633 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 634 | break; | |
| 635 | ||
| 636 | case PPU_MIRROR_HORZ: | |
| 637 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 638 | set_nt_page(machine, 1, CIRAM, 0, 1); | |
| 639 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 640 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 641 | break; | |
| 642 | ||
| 643 | case PPU_MIRROR_HIGH: | |
| 644 | set_nt_page(machine, 0, CIRAM, 1, 1); | |
| 645 | set_nt_page(machine, 1, CIRAM, 1, 1); | |
| 646 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 647 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 648 | break; | |
| 649 | ||
| 650 | case PPU_MIRROR_LOW: | |
| 651 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 652 | set_nt_page(machine, 1, CIRAM, 0, 1); | |
| 653 | set_nt_page(machine, 2, CIRAM, 0, 1); | |
| 654 | set_nt_page(machine, 3, CIRAM, 0, 1); | |
| 655 | break; | |
| 656 | ||
| 657 | case PPU_MIRROR_NONE: | |
| 658 | case PPU_MIRROR_4SCREEN: | |
| 659 | default: | |
| 660 | /* external RAM needs to be used somehow. */ | |
| 661 | /* but as a default, we'll arbitrarily set vertical so as not to crash*/ | |
| 662 | /* mappers should use set_nt_page and assign which pages are which */ | |
| 663 | ||
| 664 | logerror("Mapper set 4-screen mirroring without supplying external nametable memory!\n"); | |
| 665 | ||
| 666 | set_nt_page(machine, 0, CIRAM, 0, 1); | |
| 667 | set_nt_page(machine, 1, CIRAM, 0, 1); | |
| 668 | set_nt_page(machine, 2, CIRAM, 1, 1); | |
| 669 | set_nt_page(machine, 3, CIRAM, 1, 1); | |
| 670 | break; | |
| 671 | } | |
| 672 | } | |
| 673 | ||
| 674 | /* Other custom mirroring helpers are defined below: Waixing games use waixing_set_mirror (which swaps | |
| 675 | MIRROR_HIGH and MIRROR_LOW compared to the above) and Sachen games use sachen_set_mirror (which has | |
| 676 | a slightly different MIRROR_HIGH, with page 0 set to 0) */ | |
| 677 | ||
| 678 | ||
| 679 | /************************************************************* | |
| 680 | ||
| 681 | Support for xml list | |
| 682 | ||
| 683 | *************************************************************/ | |
| 684 | ||
| 685 | /* Include emulation of NES PCBs for softlist */ | |
| 686 | #include "machine/nes_pcb.c" | |
| 687 | ||
| 688 | ||
| 689 | /************************************************************* | |
| 690 | ||
| 691 | Support for .unf Files | |
| 692 | ||
| 693 | *************************************************************/ | |
| 694 | ||
| 695 | /* Include emulation of UNIF Boards for .unf files */ | |
| 696 | #include "machine/nes_unif.c" | |
| 697 | ||
| 698 | ||
| 699 | /************************************************************* | |
| 700 | ||
| 701 | Support for .nes Files | |
| 702 | ||
| 703 | *************************************************************/ | |
| 704 | ||
| 705 | /* Include emulation of iNES Mappers for .nes files */ | |
| 706 | #include "machine/nes_ines.c" | |
| 707 |
| r0 | r11532 | |
|---|---|---|
| 1 | #ifndef __MMC_H | |
| 2 | #define __MMC_H | |
| 3 | ||
| 4 | /* Boards */ | |
| 5 | enum | |
| 6 | { | |
| 7 | STD_NROM = 0, | |
| 8 | STD_AXROM, STD_BXROM, STD_CNROM, STD_CPROM, | |
| 9 | STD_DXROM, STD_EXROM, STD_FXROM, STD_GXROM, | |
| 10 | STD_HKROM, STD_JXROM, STD_MXROM, STD_NXROM, | |
| 11 | STD_PXROM, STD_SXROM, STD_TXROM, STD_TXSROM, | |
| 12 | STD_TKROM, STD_TQROM, STD_TVROM, | |
| 13 | STD_UN1ROM, STD_UXROM, | |
| 14 | HVC_FAMBASIC, NES_QJ, PAL_ZZ, UXROM_CC, | |
| 15 | STD_DRROM, STD_SXROM_A, STD_SOROM, STD_SOROM_A, | |
| 16 | /* Discrete components boards (by various manufacturer) */ | |
| 17 | DIS_74X161X138, DIS_74X139X74, | |
| 18 | DIS_74X377, DIS_74X161X161X32, | |
| 19 | /* Active Enterprises */ | |
| 20 | ACTENT_ACT52, | |
| 21 | /* AGCI */ | |
| 22 | AGCI_50282, | |
| 23 | /* AVE */ | |
| 24 | AVE_NINA01, AVE_NINA06, | |
| 25 | /* Bandai */ | |
| 26 | BANDAI_JUMP2, BANDAI_PT554, | |
| 27 | BANDAI_DATACH, BANDAI_KARAOKE, BANDAI_OEKAKIDS, | |
| 28 | BANDAI_FCG, BANDAI_LZ93, BANDAI_LZ93EX, | |
| 29 | /* Caltron */ | |
| 30 | CALTRON_6IN1, | |
| 31 | /* Camerica */ | |
| 32 | CAMERICA_BF9093, CAMERICA_BF9097, CAMERICA_BF9096, | |
| 33 | CAMERICA_GOLDENFIVE, GG_NROM, | |
| 34 | /* Dreamtech */ | |
| 35 | DREAMTECH_BOARD, | |
| 36 | /* Irem */ | |
| 37 | IREM_G101, IREM_H3001, IREM_LROG017, | |
| 38 | IREM_TAM_S1, IREM_HOLYDIV, | |
| 39 | /* Jaleco */ | |
| 40 | JALECO_SS88006, JALECO_JF11, JALECO_JF13, | |
| 41 | JALECO_JF16, JALECO_JF17, JALECO_JF19, | |
| 42 | /* Konami */ | |
| 43 | KONAMI_VRC1, KONAMI_VRC2, KONAMI_VRC3, | |
| 44 | KONAMI_VRC4, KONAMI_VRC6, KONAMI_VRC7, | |
| 45 | /* Namcot */ | |
| 46 | NAMCOT_163, NAMCOT_3453, | |
| 47 | NAMCOT_3425, NAMCOT_34X3, NAMCOT_3446, | |
| 48 | /* NTDEC */ | |
| 49 | NTDEC_ASDER, NTDEC_FIGHTINGHERO, | |
| 50 | /* Rex Soft */ | |
| 51 | REXSOFT_SL1632, REXSOFT_DBZ5, | |
| 52 | /* Sachen */ | |
| 53 | SACHEN_8259A, SACHEN_8259B, SACHEN_8259C, SACHEN_8259D, | |
| 54 | SACHEN_SA009, SACHEN_SA0036, SACHEN_SA0037, | |
| 55 | SACHEN_SA72007, SACHEN_SA72008, SACHEN_TCA01, | |
| 56 | SACHEN_TCU01, SACHEN_TCU02, | |
| 57 | SACHEN_74LS374, SACHEN_74LS374_A, | |
| 58 | /* Sunsoft */ | |
| 59 | SUNSOFT_1, SUNSOFT_2, SUNSOFT_3, SUNSOFT_4, | |
| 60 | SUNSOFT_DCS, SUNSOFT_5B, SUNSOFT_FME7, | |
| 61 | /* Taito */ | |
| 62 | TAITO_TC0190FMC, TAITO_TC0190FMCP, | |
| 63 | TAITO_X1_005, TAITO_X1_005_A, TAITO_X1_017, | |
| 64 | /* Tengen */ | |
| 65 | TENGEN_800008, TENGEN_800032, TENGEN_800037, | |
| 66 | /* TXC */ | |
| 67 | TXC_22211A, TXC_22211B, TXC_22211C, | |
| 68 | TXC_MXMDHTWO, TXC_TW, TXC_STRIKEWOLF, | |
| 69 | /* Multigame Carts */ | |
| 70 | BMC_64IN1NR, BMC_190IN1, BMC_A65AS, BMC_GS2004, BMC_GS2013, | |
| 71 | BMC_HIK8IN1, BMC_NOVELDIAMOND, BMC_S24IN1SC03, BMC_T262, | |
| 72 | BMC_WS, BMC_SUPERBIG_7IN1, BMC_SUPERHIK_4IN1, BMC_BALLGAMES_11IN1, | |
| 73 | BMC_MARIOPARTY_7IN1, BMC_SUPER_700IN1, BMC_FAMILY_4646B, | |
| 74 | BMC_36IN1, BMC_21IN1, BMC_150IN1, BMC_35IN1, BMC_64IN1, | |
| 75 | BMC_15IN1, BMC_SUPERHIK_300IN1, BMC_9999999IN1, BMC_SUPERGUN_20IN1, | |
| 76 | BMC_GOLDENCARD_6IN1, BMC_72IN1, BMC_SUPER_42IN1, BMC_76IN1, | |
| 77 | BMC_1200IN1, BMC_31IN1, BMC_22GAMES, BMC_20IN1, BMC_110IN1, | |
| 78 | BMC_GKA, BMC_GKB, BMC_VT5201, BMC_BENSHENG_BS5, BMC_810544, | |
| 79 | BMC_NTD_03, BMC_G63IN1, BMC_FK23C, BMC_FK23CA, BMC_PJOY84, | |
| 80 | /* Unlicensed */ | |
| 81 | UNL_8237, UNL_CC21, UNL_AX5705, UNL_KOF97, | |
| 82 | UNL_N625092, UNL_SC127, UNL_SMB2J, UNL_T230, | |
| 83 | UNL_UXROM, UNL_MK2, UNL_XZY, UNL_KOF96, | |
| 84 | UNL_SUPERFIGHTER3, UNL_RACERMATE, UNL_EDU2K, | |
| 85 | UNL_SHJY3, UNL_STUDYNGAME, UNL_603_5052, UNL_H2288, | |
| 86 | /* Bootleg boards */ | |
| 87 | BTL_SMB2A, BTL_MARIOBABY, BTL_AISENSHINICOL, BTL_TOBIDASE, | |
| 88 | BTL_SMB2B, BTL_SMB3, BTL_SUPERBROS11, BTL_DRAGONNINJA, | |
| 89 | BTL_PIKACHUY2K, | |
| 90 | /* Misc: these are needed to convert mappers to boards, I will sort them later */ | |
| 91 | OPENCORP_DAOU306, HES_BOARD, HES6IN1_BOARD, RUMBLESTATION_BOARD, | |
| 92 | MAGICSERIES_MD, KASING_BOARD, FUTUREMEDIA_BOARD, FUKUTAKE_BOARD, SOMERI_SL12, | |
| 93 | HENGEDIANZI_BOARD, HENGEDIANZI_XJZB, SUBOR_TYPE0, SUBOR_TYPE1, | |
| 94 | KAISER_KS7058, KAISER_KS7032, KAISER_KS7022, KAISER_KS7017, KAISER_KS202, CONY_BOARD, | |
| 95 | CNE_DECATHLON, CNE_FSB, CNE_SHLZ, RCM_GS2015, RCM_TETRISFAMILY, | |
| 96 | WAIXING_TYPE_A, WAIXING_TYPE_A_1, WAIXING_TYPE_B, WAIXING_TYPE_C, WAIXING_TYPE_D, | |
| 97 | WAIXING_TYPE_E, WAIXING_TYPE_F, WAIXING_TYPE_G, WAIXING_TYPE_H, | |
| 98 | WAIXING_TYPE_I, WAIXING_TYPE_J, | |
| 99 | WAIXING_SGZLZ, WAIXING_SGZ, WAIXING_ZS, WAIXING_SECURITY, WAIXING_SH2, | |
| 100 | WAIXING_DQ8, WAIXING_FFV, WAIXING_PS2, SUPERGAME_LIONKING, SUPERGAME_BOOGERMAN, | |
| 101 | KAY_PANDAPRINCE, HOSENKAN_BOARD, NITRA_TDA, GOUDER_37017, NANJING_BOARD, | |
| 102 | WHIRLWIND_2706, | |
| 103 | /* FFE boards, for mappers 6, 8, 17 */ | |
| 104 | FFE_MAPPER6, FFE_MAPPER8, FFE_MAPPER17, | |
| 105 | /* Unsupported (for place-holder boards, with no working emulation) & no-board (at init) */ | |
| 106 | UNSUPPORTED_BOARD, UNKNOWN_BOARD, NO_BOARD | |
| 107 | }; | |
| 108 | ||
| 109 | // these are used to setup the proper PCB ID, for each supported type of files | |
| 110 | int nes_get_pcb_id(running_machine &machine, const char *feature); // for softlist | |
| 111 | void unif_mapr_setup(running_machine &machine, const char *board); // for UNIF files | |
| 112 | int nes_get_mmc_id(running_machine &machine, int mapper); // for iNES files | |
| 113 | ||
| 114 | // these are used to setup handlers and callbacks necessary to the emulation (resp. at start and reset) | |
| 115 | void pcb_handlers_setup(running_machine &machine); | |
| 116 | int nes_pcb_reset(running_machine &machine); | |
| 117 | ||
| 118 | ||
| 119 | WRITE8_HANDLER( nes_low_mapper_w ); | |
| 120 | READ8_HANDLER( nes_low_mapper_r ); | |
| 121 | WRITE8_HANDLER( nes_chr_w ); | |
| 122 | READ8_HANDLER( nes_chr_r ); | |
| 123 | WRITE8_HANDLER( nes_nt_w ); | |
| 124 | READ8_HANDLER( nes_nt_r ); | |
| 125 | ||
| 126 | WRITE8_HANDLER( smb2jb_extra_w ); | |
| 127 | WRITE8_HANDLER( ks7017_extra_w ); | |
| 128 | READ8_HANDLER( ks7017_extra_r ); | |
| 129 | WRITE8_HANDLER( unl_6035052_extra_w ); | |
| 130 | READ8_HANDLER( unl_6035052_extra_r ); | |
| 131 | READ8_HANDLER( waixing_sh2_chr_r ); | |
| 132 | ||
| 133 | //TEMPORARY PPU STUFF | |
| 134 | ||
| 135 | /* mirroring types */ | |
| 136 | #define PPU_MIRROR_NONE 0 | |
| 137 | #define PPU_MIRROR_VERT 1 | |
| 138 | #define PPU_MIRROR_HORZ 2 | |
| 139 | #define PPU_MIRROR_HIGH 3 | |
| 140 | #define PPU_MIRROR_LOW 4 | |
| 141 | #define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror | |
| 142 | ||
| 143 | void set_nt_mirroring(running_machine &machine, int mirroring); | |
| 144 | ||
| 145 | ||
| 146 | #endif |
| r0 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************************** | |
| 2 | ||
| 3 | NES MMC Emulation | |
| 4 | ||
| 5 | Support for iNES Mappers | |
| 6 | ||
| 7 | ****************************************************************************************/ | |
| 8 | ||
| 9 | typedef struct _nes_mmc nes_mmc; | |
| 10 | struct _nes_mmc | |
| 11 | { | |
| 12 | int iNesMapper; /* iNES Mapper # */ | |
| 13 | int pcb_id; | |
| 14 | }; | |
| 15 | ||
| 16 | /************************************************************* | |
| 17 | ||
| 18 | Mapper 6 | |
| 19 | ||
| 20 | Known Boards: FFE4 Copier Board | |
| 21 | Games: Hacked versions of games | |
| 22 | ||
| 23 | In MESS: Supported? Not sure if we could also have ExRAM or not... | |
| 24 | However, priority is pretty low for this mapper. | |
| 25 | ||
| 26 | *************************************************************/ | |
| 27 | ||
| 28 | /* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline, | |
| 29 | we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC, | |
| 30 | there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */ | |
| 31 | static void ffe_irq( device_t *device, int scanline, int vblank, int blanked ) | |
| 32 | { | |
| 33 | nes_state *state = device->machine().driver_data<nes_state>(); | |
| 34 | ||
| 35 | /* 114 is the number of cycles per scanline */ | |
| 36 | /* TODO: change to reflect the actual number of cycles spent */ | |
| 37 | if (state->m_IRQ_enable) | |
| 38 | { | |
| 39 | if ((0xffff - state->m_IRQ_count) < 114) | |
| 40 | { | |
| 41 | device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE); | |
| 42 | state->m_IRQ_count = 0xffff; | |
| 43 | state->m_IRQ_enable = 0; | |
| 44 | } | |
| 45 | state->m_IRQ_count -= 114; | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | static WRITE8_HANDLER( mapper6_l_w ) | |
| 50 | { | |
| 51 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 52 | LOG_MMC(("mapper6_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 53 | ||
| 54 | switch (offset) | |
| 55 | { | |
| 56 | case 0x1fe: | |
| 57 | state->m_mmc_latch1 = data & 0x80; | |
| 58 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 59 | break; | |
| 60 | case 0x1ff: | |
| 61 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 62 | break; | |
| 63 | ||
| 64 | case 0x401: | |
| 65 | state->m_IRQ_enable = data & 0x01; | |
| 66 | break; | |
| 67 | case 0x402: | |
| 68 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 69 | break; | |
| 70 | case 0x403: | |
| 71 | state->m_IRQ_enable = 1; | |
| 72 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 73 | break; | |
| 74 | } | |
| 75 | } | |
| 76 | ||
| 77 | static WRITE8_HANDLER( mapper6_w ) | |
| 78 | { | |
| 79 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 80 | LOG_MMC(("mapper6_w, offset: %04x, data: %02x\n", offset, data)); | |
| 81 | ||
| 82 | if (!state->m_mmc_latch1) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank? | |
| 83 | { | |
| 84 | prg16_89ab(space->machine(), data >> 2); | |
| 85 | // chr8(space->machine(), data & 0x03, ???); | |
| 86 | // due to lack of info on the exact behavior, we simply act as if mmc_latch1=1 | |
| 87 | if (state->m_mmc_chr_source == CHRROM) | |
| 88 | chr8(space->machine(), data & 0x03, CHRROM); | |
| 89 | } | |
| 90 | else if (state->m_mmc_chr_source == CHRROM) // otherwise, we can use CHRROM (when present) | |
| 91 | chr8(space->machine(), data, CHRROM); | |
| 92 | } | |
| 93 | ||
| 94 | /************************************************************* | |
| 95 | ||
| 96 | Mapper 8 | |
| 97 | ||
| 98 | Known Boards: FFE3 Copier Board | |
| 99 | Games: Hacked versions of games | |
| 100 | ||
| 101 | In MESS: Supported? (I have no games to test this) | |
| 102 | ||
| 103 | *************************************************************/ | |
| 104 | ||
| 105 | static WRITE8_HANDLER( mapper8_w ) | |
| 106 | { | |
| 107 | LOG_MMC(("mapper8_w, offset: %04x, data: %02x\n", offset, data)); | |
| 108 | ||
| 109 | chr8(space->machine(), data & 0x07, CHRROM); | |
| 110 | prg16_89ab(space->machine(), data >> 3); | |
| 111 | } | |
| 112 | ||
| 113 | /************************************************************* | |
| 114 | ||
| 115 | Mapper 17 | |
| 116 | ||
| 117 | Known Boards: FFE8 Copier Board | |
| 118 | Games: Hacked versions of games | |
| 119 | ||
| 120 | In MESS: Supported?. IRQ support is just a guess (used to | |
| 121 | use MMC3 IRQ but it was wrong and it never enabled it) | |
| 122 | ||
| 123 | *************************************************************/ | |
| 124 | ||
| 125 | static WRITE8_HANDLER( mapper17_l_w ) | |
| 126 | { | |
| 127 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 128 | LOG_MMC(("mapper17_l_w, offset: %04x, data: %02x\n", offset, data)); | |
| 129 | ||
| 130 | switch (offset) | |
| 131 | { | |
| 132 | case 0x1fe: | |
| 133 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); | |
| 134 | break; | |
| 135 | case 0x1ff: | |
| 136 | set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); | |
| 137 | break; | |
| 138 | ||
| 139 | case 0x401: | |
| 140 | state->m_IRQ_enable = data & 0x01; | |
| 141 | break; | |
| 142 | case 0x402: | |
| 143 | state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data; | |
| 144 | break; | |
| 145 | case 0x403: | |
| 146 | state->m_IRQ_enable = 1; | |
| 147 | state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8); | |
| 148 | break; | |
| 149 | ||
| 150 | case 0x404: | |
| 151 | prg8_89(space->machine(), data); | |
| 152 | break; | |
| 153 | case 0x405: | |
| 154 | prg8_ab(space->machine(), data); | |
| 155 | break; | |
| 156 | case 0x406: | |
| 157 | prg8_cd(space->machine(), data); | |
| 158 | break; | |
| 159 | case 0x407: | |
| 160 | prg8_ef(space->machine(), data); | |
| 161 | break; | |
| 162 | ||
| 163 | case 0x410: | |
| 164 | case 0x411: | |
| 165 | case 0x412: | |
| 166 | case 0x413: | |
| 167 | case 0x414: | |
| 168 | case 0x415: | |
| 169 | case 0x416: | |
| 170 | case 0x417: | |
| 171 | chr1_x(space->machine(), offset & 7, data, CHRROM); | |
| 172 | break; | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | /************************************************************* | |
| 177 | ||
| 178 | mmc_list | |
| 179 | ||
| 180 | Supported mappers and corresponding pcb id | |
| 181 | ||
| 182 | *************************************************************/ | |
| 183 | ||
| 184 | static const nes_mmc mmc_list[] = | |
| 185 | { | |
| 186 | /* INES DESC LOW_W, LOW_R, MED_W, HIGH_W, PPU_latch, scanline CB, hblank CB */ | |
| 187 | { 0, STD_NROM }, | |
| 188 | { 1, STD_SXROM }, | |
| 189 | { 2, STD_UXROM }, | |
| 190 | { 3, STD_CNROM }, | |
| 191 | { 4, STD_TXROM }, | |
| 192 | { 5, STD_EXROM }, | |
| 193 | { 6, FFE_MAPPER6 }, | |
| 194 | { 7, STD_AXROM }, | |
| 195 | { 8, FFE_MAPPER8 }, | |
| 196 | { 9, STD_PXROM }, | |
| 197 | { 10, STD_FXROM }, | |
| 198 | { 11, DIS_74X377 }, | |
| 199 | { 12, REXSOFT_DBZ5 }, | |
| 200 | { 13, STD_CPROM }, | |
| 201 | { 14, REXSOFT_SL1632 }, | |
| 202 | { 15, WAIXING_PS2 }, | |
| 203 | { 16, BANDAI_LZ93EX }, // with 24c02 | |
| 204 | { 17, FFE_MAPPER17 }, | |
| 205 | { 18, JALECO_SS88006 }, | |
| 206 | { 19, NAMCOT_163 }, | |
| 207 | { 21, KONAMI_VRC4 }, | |
| 208 | { 22, KONAMI_VRC2 }, | |
| 209 | { 23, KONAMI_VRC2 }, | |
| 210 | { 24, KONAMI_VRC6 }, | |
| 211 | { 25, KONAMI_VRC4 }, | |
| 212 | { 26, KONAMI_VRC6 }, | |
| 213 | // 27 World Hero board - Unsupported | |
| 214 | // 28 Unused | |
| 215 | // 29 Unused | |
| 216 | // 30 Unused | |
| 217 | // 31 Unused | |
| 218 | { 32, IREM_G101 }, | |
| 219 | { 33, TAITO_TC0190FMC }, | |
| 220 | { 34, STD_BXROM }, | |
| 221 | { 35, UNL_SC127 }, | |
| 222 | { 36, TXC_STRIKEWOLF }, | |
| 223 | { 37, PAL_ZZ }, | |
| 224 | { 38, DIS_74X161X138 }, | |
| 225 | { 39, UNL_STUDYNGAME }, | |
| 226 | { 40, BTL_SMB2A }, | |
| 227 | { 41, CALTRON_6IN1 }, | |
| 228 | { 42, BTL_MARIOBABY }, // ai senshi nicol? | |
| 229 | { 43, UNL_SMB2J }, | |
| 230 | { 44, BMC_SUPERBIG_7IN1 }, | |
| 231 | { 45, BMC_HIK8IN1 }, | |
| 232 | { 46, RUMBLESTATION_BOARD }, | |
| 233 | { 47, NES_QJ }, | |
| 234 | { 48, TAITO_TC0190FMCP }, | |
| 235 | { 49, BMC_SUPERHIK_4IN1 }, | |
| 236 | { 50, BTL_SMB2B }, | |
| 237 | { 51, BMC_BALLGAMES_11IN1 }, | |
| 238 | { 52, BMC_MARIOPARTY_7IN1 }, | |
| 239 | // 53 Supervision 16-in-1 - Unsupported | |
| 240 | { 54, BMC_NOVELDIAMOND }, | |
| 241 | // 55 Genius SMB - No info (nor images) available | |
| 242 | { 56, KAISER_KS202 }, | |
| 243 | { 57, BMC_GKA }, | |
| 244 | { 58, BMC_GKB }, | |
| 245 | // 59 Unused | |
| 246 | // 60 4-in-1, 35-in-1 Reset based | |
| 247 | { 61, RCM_TETRISFAMILY }, | |
| 248 | { 62, BMC_SUPER_700IN1 }, | |
| 249 | // 63 CH001 X-in-1 - No info (nor images) available | |
| 250 | { 64, TENGEN_800032 }, | |
| 251 | { 65, IREM_H3001 }, | |
| 252 | { 66, STD_GXROM }, | |
| 253 | { 67, SUNSOFT_3 }, | |
| 254 | { 68, STD_NXROM }, | |
| 255 | { 69, STD_JXROM }, | |
| 256 | { 70, DIS_74X161X161X32 }, | |
| 257 | { 71, CAMERICA_BF9093 }, | |
| 258 | { 72, JALECO_JF17 }, | |
| 259 | { 73, KONAMI_VRC3 }, | |
| 260 | { 74, WAIXING_TYPE_A }, | |
| 261 | { 75, KONAMI_VRC1 }, | |
| 262 | { 76, NAMCOT_3446 }, | |
| 263 | { 77, IREM_LROG017 }, | |
| 264 | { 78, IREM_HOLYDIV }, | |
| 265 | { 79, AVE_NINA06 }, | |
| 266 | { 80, TAITO_X1_005 }, | |
| 267 | // 81 Unused | |
| 268 | { 82, TAITO_X1_017 }, | |
| 269 | { 83, CONY_BOARD }, | |
| 270 | // 84 Pasofami hacked images? | |
| 271 | { 85, KONAMI_VRC7 }, | |
| 272 | { 86, JALECO_JF13 }, | |
| 273 | { 87, DIS_74X139X74 }, | |
| 274 | { 88, NAMCOT_34X3 }, | |
| 275 | { 89, SUNSOFT_2 }, | |
| 276 | // 90 JY Company Type A (Aladdin, Final Fight 3, Super Mario World, Tekken 2) - Unsupported | |
| 277 | { 91, UNL_MK2 }, | |
| 278 | { 92, JALECO_JF19 }, | |
| 279 | { 93, SUNSOFT_2 }, | |
| 280 | { 94, STD_UN1ROM }, | |
| 281 | { 95, NAMCOT_3425 }, | |
| 282 | { 96, BANDAI_OEKAKIDS }, | |
| 283 | { 97, IREM_TAM_S1 }, | |
| 284 | // 98 Unused | |
| 285 | // 99 VS. system - Not going to be implemented (use MAME instead) | |
| 286 | // 100 images hacked to work with nesticle? | |
| 287 | // 101 Unused (Urusei Yatsura had been assigned to this mapper, but it's Mapper 87) | |
| 288 | // 102 Unused | |
| 289 | // 103 Bootleg cart 2708 (Doki Doki Panic - FDS Conversion) - Unsupported | |
| 290 | { 104, CAMERICA_GOLDENFIVE }, | |
| 291 | // 105 Nintendo World Championship - Unsupported | |
| 292 | { 106, BTL_SMB3 }, | |
| 293 | { 107, MAGICSERIES_MD }, | |
| 294 | { 108, WHIRLWIND_2706 }, | |
| 295 | // 109 Unused | |
| 296 | // 110 Unused | |
| 297 | // 111 Ninja Ryuukenden Chinese? - Unsupported | |
| 298 | { 112, NTDEC_ASDER }, | |
| 299 | { 113, HES_BOARD }, | |
| 300 | { 114, SUPERGAME_LIONKING }, | |
| 301 | { 115, KASING_BOARD }, | |
| 302 | { 116, SOMERI_SL12 }, | |
| 303 | { 117, FUTUREMEDIA_BOARD }, | |
| 304 | { 118, STD_TXSROM }, | |
| 305 | { 119, STD_TQROM }, | |
| 306 | { 120, BTL_TOBIDASE }, | |
| 307 | { 121, KAY_PANDAPRINCE }, | |
| 308 | // 122 Unused | |
| 309 | { 123, UNL_H2288 }, | |
| 310 | // 124 Unused | |
| 311 | // 125 Unused | |
| 312 | { 126, BMC_PJOY84 }, | |
| 313 | // 127 Unused | |
| 314 | // 128 Unused | |
| 315 | // 129 Unused | |
| 316 | // 130 Unused | |
| 317 | // 131 Unused | |
| 318 | { 132, TXC_22211B }, | |
| 319 | { 133, SACHEN_SA72008 }, | |
| 320 | { 134, BMC_FAMILY_4646B }, | |
| 321 | // 135 Unused | |
| 322 | { 136, SACHEN_TCU02 }, | |
| 323 | { 137, SACHEN_8259D }, | |
| 324 | { 138, SACHEN_8259B }, | |
| 325 | { 139, SACHEN_8259C }, | |
| 326 | { 140, JALECO_JF11 }, | |
| 327 | { 141, SACHEN_8259A }, | |
| 328 | { 142, KAISER_KS7032}, | |
| 329 | { 143, SACHEN_TCA01 }, | |
| 330 | { 144, AGCI_50282 }, | |
| 331 | { 145, SACHEN_SA72007 }, | |
| 332 | { 146, AVE_NINA06 }, // basically same as Mapper 79 (Nina006) | |
| 333 | { 147, SACHEN_TCU01 }, | |
| 334 | { 148, SACHEN_SA0037 }, | |
| 335 | { 149, SACHEN_SA0036 }, | |
| 336 | { 150, SACHEN_74LS374 }, | |
| 337 | // 151 VS. system by Konami - Not going to be implemented (use MAME instead) | |
| 338 | { 152, DIS_74X161X161X32 }, | |
| 339 | { 153, BANDAI_LZ93 }, | |
| 340 | { 154, NAMCOT_3453 }, | |
| 341 | { 155, STD_SXROM_A }, // diff compared to MMC1 concern WRAM | |
| 342 | { 156, OPENCORP_DAOU306 }, | |
| 343 | { 157, BANDAI_DATACH }, // no Datach Reader -> we fall back to mapper 16 | |
| 344 | { 158, TENGEN_800037 }, | |
| 345 | { 159, BANDAI_LZ93EX }, // with 24c01 | |
| 346 | { 160, SACHEN_SA009 }, | |
| 347 | // 161 Unused | |
| 348 | // 162 Unused | |
| 349 | { 163, NANJING_BOARD}, | |
| 350 | { 164, WAIXING_FFV }, | |
| 351 | { 165, WAIXING_SH2 }, | |
| 352 | { 166, SUBOR_TYPE1 }, | |
| 353 | { 167, SUBOR_TYPE0 }, | |
| 354 | { 168, UNL_RACERMATE }, | |
| 355 | // 169 Unused | |
| 356 | // 170 Fujiya | |
| 357 | { 171, KAISER_KS7058 }, | |
| 358 | { 172, TXC_22211B }, | |
| 359 | { 173, TXC_22211C }, | |
| 360 | // 174 Unused | |
| 361 | { 175, KAISER_KS7022}, | |
| 362 | { 176, UNL_XZY }, | |
| 363 | { 177, HENGEDIANZI_BOARD }, | |
| 364 | { 178, WAIXING_SGZLZ }, | |
| 365 | { 179, HENGEDIANZI_XJZB }, | |
| 366 | { 180, UXROM_CC }, | |
| 367 | // 181 Unused | |
| 368 | { 182, HOSENKAN_BOARD }, | |
| 369 | // 183 FDS bootleg (Shui Guan Pipe) - Unsupported | |
| 370 | { 184, SUNSOFT_1 }, | |
| 371 | { 185, STD_CNROM }, | |
| 372 | { 186, FUKUTAKE_BOARD }, | |
| 373 | { 187, UNL_KOF96 }, | |
| 374 | { 188, BANDAI_KARAOKE }, | |
| 375 | { 189, TXC_TW }, | |
| 376 | // 190 Unused | |
| 377 | { 191, WAIXING_TYPE_B }, | |
| 378 | { 192, WAIXING_TYPE_C }, | |
| 379 | { 193, NTDEC_FIGHTINGHERO }, | |
| 380 | { 194, WAIXING_TYPE_D }, | |
| 381 | { 195, WAIXING_TYPE_E }, | |
| 382 | { 196, BTL_SUPERBROS11 }, | |
| 383 | { 197, UNL_SUPERFIGHTER3 }, | |
| 384 | { 198, WAIXING_TYPE_F }, | |
| 385 | { 199, WAIXING_TYPE_G }, | |
| 386 | { 200, BMC_36IN1 }, | |
| 387 | { 201, BMC_21IN1 }, | |
| 388 | { 202, BMC_150IN1 }, | |
| 389 | { 203, BMC_35IN1 }, | |
| 390 | { 204, BMC_64IN1 }, | |
| 391 | { 205, BMC_15IN1 }, | |
| 392 | { 206, STD_DXROM }, | |
| 393 | { 207, TAITO_X1_005_A }, | |
| 394 | { 208, GOUDER_37017 }, | |
| 395 | // 209 JY Company Type B (Power Rangers 3 & 4, Shin Samurai Spirits 2) - Unsupported | |
| 396 | // 210 Some emu uses this as Mapper 19 without some features | |
| 397 | // 211 JY Company Type C (Tiny Toon Adventures 6, Donkey Kong Country 4) - Unsupported | |
| 398 | { 212, BMC_SUPERHIK_300IN1 }, | |
| 399 | { 213, BMC_9999999IN1 }, | |
| 400 | { 214, BMC_SUPERGUN_20IN1 }, | |
| 401 | { 215, SUPERGAME_BOOGERMAN }, | |
| 402 | { 216, RCM_GS2015 }, | |
| 403 | { 217, BMC_GOLDENCARD_6IN1 }, | |
| 404 | // 218 Unused | |
| 405 | // 219 Bootleg A9746 - Unsupported | |
| 406 | // 220 Unused | |
| 407 | { 221, UNL_N625092 }, | |
| 408 | { 222, BTL_DRAGONNINJA }, | |
| 409 | { 223, WAIXING_TYPE_I }, // (according to NEStopia source, it's MMC3 with more WRAM) | |
| 410 | { 224, WAIXING_TYPE_J }, // (according to NEStopia source, it's MMC3 with more WRAM) | |
| 411 | { 225, BMC_72IN1 }, | |
| 412 | { 226, BMC_76IN1 }, | |
| 413 | { 227, BMC_1200IN1 }, | |
| 414 | { 228, ACTENT_ACT52 }, | |
| 415 | { 229, BMC_31IN1 }, | |
| 416 | { 230, BMC_22GAMES }, | |
| 417 | { 231, BMC_20IN1 }, | |
| 418 | { 232, CAMERICA_BF9096 }, | |
| 419 | // 233 Super 22 Games - Unsupported | |
| 420 | // 234 AVE Maxi 15 - Unsupported | |
| 421 | // 235 Golden Game x-in-1 - Unsupported | |
| 422 | // 236 Game 800-in-1 - Unsupported | |
| 423 | // 237 Unused | |
| 424 | { 238, UNL_603_5052 }, | |
| 425 | // 239 Unused | |
| 426 | { 240, CNE_SHLZ }, | |
| 427 | { 241, TXC_MXMDHTWO }, | |
| 428 | { 242, WAIXING_ZS }, | |
| 429 | { 243, SACHEN_74LS374_A }, | |
| 430 | { 244, CNE_DECATHLON }, | |
| 431 | { 245, WAIXING_TYPE_H }, | |
| 432 | { 246, CNE_FSB }, | |
| 433 | // 247 Unused | |
| 434 | // 248 Unused | |
| 435 | { 249, WAIXING_SECURITY }, | |
| 436 | { 250, NITRA_TDA }, | |
| 437 | // 251 Shen Hua Jian Yun III?? - Unsupported | |
| 438 | { 252, WAIXING_SGZ }, | |
| 439 | // 253 Super 8-in-1 99 King Fighter?? - Unsupported | |
| 440 | { 254, BTL_PIKACHUY2K }, | |
| 441 | { 255, BMC_110IN1 }, | |
| 442 | }; | |
| 443 | ||
| 444 | const nes_mmc *nes_mapper_lookup( int mapper ) | |
| 445 | { | |
| 446 | int i; | |
| 447 | ||
| 448 | for (i = 0; i < ARRAY_LENGTH(mmc_list); i++) | |
| 449 | { | |
| 450 | if (mmc_list[i].iNesMapper == mapper) | |
| 451 | return &mmc_list[i]; | |
| 452 | } | |
| 453 | ||
| 454 | return NULL; | |
| 455 | } | |
| 456 | ||
| 457 | int nes_get_mmc_id( running_machine &machine, int mapper ) | |
| 458 | { | |
| 459 | const nes_mmc *mmc = nes_mapper_lookup(mapper); | |
| 460 | ||
| 461 | if (mmc == NULL) | |
| 462 | fatalerror("Unimplemented Mapper %d", mapper); | |
| 463 | ||
| 464 | return mmc->pcb_id; | |
| 465 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | snescart.c | |
| 4 | ||
| 5 | Machine file to handle cart loading in the Nintendo Super NES emulation. | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "includes/snes.h" | |
| 11 | #include "imagedev/cartslot.h" | |
| 12 | #include "snescart.h" | |
| 13 | ||
| 14 | #define SNES_CART_DEBUG 0 | |
| 15 | ||
| 16 | /****** Strings for Cart Header Logging ******/ | |
| 17 | ||
| 18 | #define UNK "Unknown" | |
| 19 | ||
| 20 | /* Some known type of cart */ | |
| 21 | static const char *const types[] = | |
| 22 | { | |
| 23 | "ROM", | |
| 24 | "ROM, DSP-1", | |
| 25 | "ROM, DSP-2", | |
| 26 | "ROM, DSP-3", | |
| 27 | "ROM, DSP-4", | |
| 28 | "ROM, Super FX / FX2", | |
| 29 | "ROM, SA-1", | |
| 30 | "ROM, S-DD1", | |
| 31 | "ROM, OBC-1", | |
| 32 | "ROM, S-RTC", | |
| 33 | "ROM, Z80GB (Super Game Boy)", | |
| 34 | "ROM, C4", | |
| 35 | "ROM, Seta ST-010", | |
| 36 | "ROM, Seta ST-011", | |
| 37 | "ROM, Seta ST-018", | |
| 38 | "ROM, SPC7110", | |
| 39 | "ROM, SPC7110, RTC", | |
| 40 | UNK, // to add: Satellaview BS-X detection | |
| 41 | }; | |
| 42 | ||
| 43 | /* Some known countries */ | |
| 44 | static const char *const countries[] = | |
| 45 | { | |
| 46 | /* 0*/ "Japan (NTSC)", "USA & Canada (NTSC)", "Europe, Oceania & Asia (PAL)", "Sweden (PAL)", | |
| 47 | /* 4*/ "Finland (PAL)", "Denmark (PAL)", "France (PAL)", "Holland (PAL)", | |
| 48 | /* 8*/ "Spain (PAL)", "Germany, Austria & Switzerland (PAL)", "Italy (PAL)", "Hong Kong & China (PAL)", | |
| 49 | /* c*/ "Indonesia (PAL)", "South Korea (NTSC)", UNK, UNK, | |
| 50 | }; | |
| 51 | ||
| 52 | /* Some known companies (integrations to the list from Snes9x) */ | |
| 53 | static const char *const companies[] = | |
| 54 | { | |
| 55 | /* 0*/ "Invalid", "Nintendo", "Ajinomoto", "Imagineer-Zoom", "Chris Gray Enterprises Inc.", "Zamuse", "Falcom", UNK, | |
| 56 | /* 8*/ "Capcom", "HOT-B", "Jaleco", "Coconuts", "Rage Software", "Micronet", "Technos", "Mebio Software", | |
| 57 | /*10*/ "SHOUEi System", "Starfish", "Gremlin Graphics", "Electronic Arts", "NCS / Masaya", "COBRA Team", "Human/Field", "KOEI", | |
| 58 | /*18*/ "Hudson Soft", "Game Village", "Yanoman", UNK, "Tecmo", UNK, "Open System", "Virgin Games", | |
| 59 | /*20*/ "KSS", "Sunsoft", "POW", "Micro World", UNK, UNK, "Enix", "Loriciel/Electro Brain", | |
| 60 | /*28*/ "Kemco", "Seta Co.,Ltd.", "Culture Brain", "Irem Japan", "Pal Soft", "Visit Co.,Ltd.", "INTEC Inc.", "System Sacom Corp.", | |
| 61 | /*30*/ "Viacom New Media", "Carrozzeria", "Dynamic", "Nintendo", "Magifact", "Hect", UNK, UNK, | |
| 62 | /*38*/ "Capcom Europe", "Accolade Europe", UNK, "Arcade Zone", "Empire Software", "Loriciel", "Gremlin Graphics", UNK, | |
| 63 | /*40*/ "Seika Corp.", "UBI Soft", UNK, UNK, "LifeFitness Exertainment", UNK, "System 3", "Spectrum Holobyte", | |
| 64 | /*48*/ UNK, "Irem", UNK, "Raya Systems/Sculptured Software", "Renovation Products", "Malibu Games/Black Pearl", UNK, "U.S. Gold", | |
| 65 | /*50*/ "Absolute Entertainment", "Acclaim", "Activision", "American Sammy", "GameTek", "Hi Tech Expressions", "LJN Toys", UNK, | |
| 66 | /*58*/ UNK, UNK, "Mindscape", "Romstar, Inc.", UNK, "Tradewest", UNK, "American Softworks Corp.", | |
| 67 | /*60*/ "Titus", "Virgin Interactive Entertainment", "Maxis", "Origin/FCI/Pony Canyon", UNK, UNK, UNK, "Ocean", | |
| 68 | /*68*/ UNK, "Electronic Arts", UNK, "Laser Beam", UNK, UNK, "Elite", "Electro Brain", | |
| 69 | /*70*/ "Infogrames", "Interplay", "LucasArts", "Parker Brothers", "Konami", "STORM", UNK, UNK, | |
| 70 | /*78*/ "THQ Software", "Accolade Inc.", "Triffix Entertainment", UNK, "Microprose", UNK, UNK, "Kemco", | |
| 71 | /*80*/ "Misawa", "Teichio", "Namco Ltd.", "Lozc", "Koei", UNK, "Tokuma Shoten Intermedia", "Tsukuda Original", | |
| 72 | /*88*/ "DATAM-Polystar", UNK, UNK, "Bullet-Proof Software", "Vic Tokai", UNK, "Character Soft", "I\'\'Max", | |
| 73 | /*90*/ "Takara", "CHUN Soft", "Video System Co., Ltd.", "BEC", UNK, "Varie", "Yonezawa / S'Pal Corp.", "Kaneco", | |
| 74 | /*98*/ UNK, "Pack in Video", "Nichibutsu", "TECMO", "Imagineer Co.", UNK, UNK, UNK, | |
| 75 | /*a0*/ "Telenet", "Hori", UNK, UNK, "Konami", "K.Amusement Leasing Co.", UNK, "Takara", | |
| 76 | /*a8*/ UNK, "Technos Jap.", "JVC", UNK, "Toei Animation", "Toho", UNK, "Namco Ltd.", | |
| 77 | /*b0*/ "Media Rings Corp.", "ASCII Co. Activison", "Bandai", UNK, "Enix America", UNK, "Halken", UNK, | |
| 78 | /*b8*/ UNK, UNK, "Culture Brain", "Sunsoft", "Toshiba EMI", "Sony Imagesoft", UNK, "Sammy", | |
| 79 | /*c0*/ "Taito", UNK, "Kemco", "Square", "Tokuma Soft", "Data East", "Tonkin House", UNK, | |
| 80 | /*c8*/ "KOEI", UNK, "Konami USA", "NTVIC", UNK, "Meldac", "Pony Canyon", "Sotsu Agency/Sunrise", | |
| 81 | /*d0*/ "Disco/Taito", "Sofel", "Quest Corp.", "Sigma", "Ask Kodansha Co., Ltd.", UNK, "Naxat", UNK, | |
| 82 | /*d8*/ "Capcom Co., Ltd.", "Banpresto", "Tomy", "Acclaim", UNK, "NCS", "Human Entertainment", "Altron", | |
| 83 | /*e0*/ "Jaleco", UNK, "Yutaka", UNK, "T&ESoft", "EPOCH Co.,Ltd.", UNK, "Athena", | |
| 84 | /*e8*/ "Asmik", "Natsume", "King Records", "Atlus", "Sony Music Entertainment", UNK, "IGS", UNK, | |
| 85 | /*f0*/ UNK, "Motown Software", "Left Field Entertainment", "Beam Software", "Tec Magik", UNK, UNK, UNK, | |
| 86 | /*f8*/ UNK, "Cybersoft", UNK, "Psygnosis", UNK, UNK, "Davidson", UNK, | |
| 87 | }; | |
| 88 | ||
| 89 | ||
| 90 | /* We use this to convert the company_id in the header to int value to be passed in companies[] */ | |
| 91 | static int char_to_int_conv( char id ) | |
| 92 | { | |
| 93 | int value; | |
| 94 | ||
| 95 | if (id == '1') value = 0x01; | |
| 96 | else if (id == '2') value = 0x02; | |
| 97 | else if (id == '3') value = 0x03; | |
| 98 | else if (id == '4') value = 0x04; | |
| 99 | else if (id == '5') value = 0x05; | |
| 100 | else if (id == '6') value = 0x06; | |
| 101 | else if (id == '7') value = 0x07; | |
| 102 | else if (id == '8') value = 0x08; | |
| 103 | else if (id == '9') value = 0x09; | |
| 104 | else if (id == 'A') value = 0x0a; | |
| 105 | else if (id == 'B') value = 0x0b; | |
| 106 | else if (id == 'C') value = 0x0c; | |
| 107 | else if (id == 'D') value = 0x0d; | |
| 108 | else if (id == 'E') value = 0x0e; | |
| 109 | else if (id == 'F') value = 0x0f; | |
| 110 | else value = 0x00; | |
| 111 | ||
| 112 | return value; | |
| 113 | } | |
| 114 | ||
| 115 | ||
| 116 | /*************************************************************************** | |
| 117 | ||
| 118 | SRAM handling | |
| 119 | ||
| 120 | ***************************************************************************/ | |
| 121 | ||
| 122 | /* Loads the battery backed RAM into the appropriate memory area */ | |
| 123 | static void snes_load_sram(running_machine &machine) | |
| 124 | { | |
| 125 | snes_state *state = machine.driver_data<snes_state>(); | |
| 126 | UINT8 ii; | |
| 127 | UINT8 *battery_ram, *ptr; | |
| 128 | ||
| 129 | battery_ram = (UINT8*)malloc(state->m_cart[0].sram_max); | |
| 130 | ptr = battery_ram; | |
| 131 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart")); | |
| 132 | image->battery_load(battery_ram, state->m_cart[0].sram_max, 0xff); | |
| 133 | ||
| 134 | if (state->m_cart[0].mode == SNES_MODE_20) | |
| 135 | { | |
| 136 | UINT32 size = state->m_cart[0].small_sram ? 0x8000 : 0x10000; | |
| 137 | ||
| 138 | /* There could be some larger image needing banks 0x70 to 0x7f at address 0x8000 for ROM | |
| 139 | * mirroring. These should be treated separately or data would be overwritten by SRAM */ | |
| 140 | for (ii = 0; ii < 16; ii++) | |
| 141 | { | |
| 142 | /* loading */ | |
| 143 | memmove(&snes_ram[0x700000 + (ii * 0x010000)], ptr, size); | |
| 144 | /* mirroring */ | |
| 145 | memcpy(&snes_ram[0xf00000 + (ii * 0x010000)], &snes_ram[0x700000 + (ii * 0x010000)], size); | |
| 146 | ptr += size; | |
| 147 | } | |
| 148 | } | |
| 149 | else if (state->m_cart[0].mode == SNES_MODE_21) | |
| 150 | { | |
| 151 | for (ii = 0; ii < 16; ii++) | |
| 152 | { | |
| 153 | /* loading */ | |
| 154 | memmove(&snes_ram[0x306000 + (ii * 0x010000)], ptr, 0x2000); | |
| 155 | /* mirroring */ | |
| 156 | memcpy(&snes_ram[0xb06000 + (ii * 0x010000)], &snes_ram[0x306000 + (ii * 0x010000)], 0x2000); | |
| 157 | ptr += 0x2000; | |
| 158 | } | |
| 159 | } | |
| 160 | else if (state->m_cart[0].mode == SNES_MODE_25) | |
| 161 | { | |
| 162 | for (ii = 0; ii < 16; ii++) | |
| 163 | { | |
| 164 | memmove(&snes_ram[0xb06000 + (ii * 0x010000)], ptr, 0x2000); | |
| 165 | ptr += 0x2000; | |
| 166 | } | |
| 167 | } | |
| 168 | ||
| 169 | free(battery_ram); | |
| 170 | } | |
| 171 | ||
| 172 | /* Saves the battery backed RAM from the appropriate memory area */ | |
| 173 | static void snes_save_sram(running_machine &machine) | |
| 174 | { | |
| 175 | snes_state *state = machine.driver_data<snes_state>(); | |
| 176 | UINT8 ii; | |
| 177 | UINT8 *battery_ram, *ptr; | |
| 178 | ||
| 179 | battery_ram = (UINT8*)malloc(state->m_cart[0].sram_max); | |
| 180 | ptr = battery_ram; | |
| 181 | ||
| 182 | if (state->m_cart[0].mode == SNES_MODE_20) | |
| 183 | { | |
| 184 | UINT32 size = state->m_cart[0].small_sram ? 0x8000 : 0x10000; | |
| 185 | ||
| 186 | for (ii = 0; ii < 16; ii++) | |
| 187 | { | |
| 188 | memmove(ptr, &snes_ram[0x700000 + (ii * 0x010000)], size); | |
| 189 | ptr += size; | |
| 190 | } | |
| 191 | } | |
| 192 | else if (state->m_cart[0].mode == SNES_MODE_21) | |
| 193 | { | |
| 194 | for (ii = 0; ii < 16; ii++) | |
| 195 | { | |
| 196 | memmove(ptr, &snes_ram[0x306000 + (ii * 0x010000)], 0x2000); | |
| 197 | ptr += 0x2000; | |
| 198 | } | |
| 199 | } | |
| 200 | else if (state->m_cart[0].mode == SNES_MODE_25) | |
| 201 | { | |
| 202 | for (ii = 0; ii < 16; ii++) | |
| 203 | { | |
| 204 | memmove(ptr, &snes_ram[0xb06000 + (ii * 0x010000)], 0x2000); | |
| 205 | ptr += 0x2000; | |
| 206 | } | |
| 207 | } | |
| 208 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart")); | |
| 209 | image->battery_save(battery_ram, state->m_cart[0].sram_max); | |
| 210 | ||
| 211 | free(battery_ram); | |
| 212 | } | |
| 213 | ||
| 214 | static void snes_machine_stop(running_machine &machine) | |
| 215 | { | |
| 216 | snes_state *state = machine.driver_data<snes_state>(); | |
| 217 | ||
| 218 | /* Save SRAM */ | |
| 219 | if (state->m_cart[0].sram > 0) | |
| 220 | snes_save_sram(machine); | |
| 221 | } | |
| 222 | ||
| 223 | MACHINE_START( snes_mess ) | |
| 224 | { | |
| 225 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(snes_machine_stop),&machine)); | |
| 226 | MACHINE_START_CALL(snes); | |
| 227 | } | |
| 228 | ||
| 229 | ||
| 230 | static void sufami_load_sram(running_machine &machine, const char *cart_tag) | |
| 231 | { | |
| 232 | UINT8 ii; | |
| 233 | UINT8 *battery_ram, *ptr; | |
| 234 | int st_sram_offset = 0; | |
| 235 | ||
| 236 | battery_ram = (UINT8*)malloc(0x20000); | |
| 237 | ptr = battery_ram; | |
| 238 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device(cart_tag)); | |
| 239 | image->battery_load(battery_ram, 0x20000, 0); | |
| 240 | ||
| 241 | if (strcmp(cart_tag, "slot_a") == 0) | |
| 242 | st_sram_offset = 0x608000; | |
| 243 | ||
| 244 | if (strcmp(cart_tag, "slot_b") == 0) | |
| 245 | st_sram_offset = 0x708000; | |
| 246 | ||
| 247 | /* Cart RAM is at 0x60-0x63:0x8000-0xffff (+0x10 for slot2) */ | |
| 248 | for (ii = 0; ii < 4; ii++) | |
| 249 | { | |
| 250 | /* loading */ | |
| 251 | memcpy(&snes_ram[st_sram_offset + (ii * 0x010000)], ptr + (ii * 0x8000), 0x8000); | |
| 252 | /* mirroring */ | |
| 253 | memcpy(&snes_ram[0x800000 + st_sram_offset + (ii * 0x010000)], &snes_ram[st_sram_offset + (ii * 0x010000)], 0x8000); | |
| 254 | } | |
| 255 | ||
| 256 | free(battery_ram); | |
| 257 | } | |
| 258 | ||
| 259 | static void sufami_machine_stop(running_machine &machine) | |
| 260 | { | |
| 261 | snes_state *state = machine.driver_data<snes_state>(); | |
| 262 | UINT8 ii; | |
| 263 | UINT8 *battery_ram, *ptr; | |
| 264 | ||
| 265 | battery_ram = (UINT8*)malloc(0x20000); | |
| 266 | ptr = battery_ram; | |
| 267 | ||
| 268 | if (state->m_cart[0].slot_in_use) | |
| 269 | { | |
| 270 | for (ii = 0; ii < 4; ii++) | |
| 271 | { | |
| 272 | memmove(ptr + ii * 0x8000, &snes_ram[0x608000 + (ii * 0x010000)], 0x8000); | |
| 273 | } | |
| 274 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_a")); | |
| 275 | image->battery_save(battery_ram, 0x20000); | |
| 276 | } | |
| 277 | ||
| 278 | if (state->m_cart[1].slot_in_use) | |
| 279 | { | |
| 280 | for (ii = 0; ii < 4; ii++) | |
| 281 | { | |
| 282 | memmove(ptr + ii * 0x8000, &snes_ram[0x708000 + (ii * 0x010000)], 0x8000); | |
| 283 | } | |
| 284 | device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_b")); | |
| 285 | image->battery_save(battery_ram, 0x20000); | |
| 286 | } | |
| 287 | ||
| 288 | free(battery_ram); | |
| 289 | } | |
| 290 | ||
| 291 | MACHINE_START( snesst ) | |
| 292 | { | |
| 293 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(sufami_machine_stop),&machine)); | |
| 294 | MACHINE_START_CALL(snes); | |
| 295 | } | |
| 296 | ||
| 297 | ||
| 298 | /*************************************************************************** | |
| 299 | ||
| 300 | Cart handling | |
| 301 | ||
| 302 | ***************************************************************************/ | |
| 303 | ||
| 304 | /* This function assign a 'score' to data immediately after 'offset' to measure how valid they are | |
| 305 | as information block (to decide if the image is HiRom, LoRom, ExLoRom or ExHiRom) */ | |
| 306 | /* Code from bsnes, courtesy of byuu - http://byuu.cinnamonpirate.com/ */ | |
| 307 | static int snes_validate_infoblock( UINT8 *infoblock, UINT32 offset ) | |
| 308 | { | |
| 309 | int score = 0; | |
| 310 | UINT16 reset_vector = infoblock[offset + 0x3c] | (infoblock[offset + 0x3d] << 8); | |
| 311 | UINT16 checksum = infoblock[offset + 0x1e] | (infoblock[offset + 0x1f] << 8); | |
| 312 | UINT16 ichecksum = infoblock[offset + 0x1c] | (infoblock[offset + 0x1d] << 8); | |
| 313 | UINT8 reset_opcode = infoblock[(offset & ~0x7fff) | (reset_vector & 0x7fff)]; //first opcode executed upon reset | |
| 314 | UINT8 mapper = infoblock[offset + 0x15] & ~0x10; //mask off irrelevent FastROM-capable bit | |
| 315 | ||
| 316 | /* $00:[000-7fff] contains uninitialized RAM and MMIO. | |
| 317 | reset vector must point to ROM at $00:[8000-ffff] to be considered valid. */ | |
| 318 | if (reset_vector < 0x8000) | |
| 319 | return 0; | |
| 320 | ||
| 321 | /* some images duplicate the header in multiple locations, and others have completely | |
| 322 | invalid header information that cannot be relied upon. The code below will analyze | |
| 323 | the first opcode executed at the specified reset vector to determine the probability | |
| 324 | that this is the correct header. Score is assigned accordingly. */ | |
| 325 | ||
| 326 | /* most likely opcodes */ | |
| 327 | if (reset_opcode == 0x78 //sei | |
| 328 | || reset_opcode == 0x18 //clc (clc; xce) | |
| 329 | || reset_opcode == 0x38 //sec (sec; xce) | |
| 330 | || reset_opcode == 0x9c //stz $nnnn (stz $4200) | |
| 331 | || reset_opcode == 0x4c //jmp $nnnn | |
| 332 | || reset_opcode == 0x5c //jml $nnnnnn | |
| 333 | ) | |
| 334 | score += 8; | |
| 335 | ||
| 336 | /* plausible opcodes */ | |
| 337 | if (reset_opcode == 0xc2 //rep #$nn | |
| 338 | || reset_opcode == 0xe2 //sep #$nn | |
| 339 | || reset_opcode == 0xad //lda $nnnn | |
| 340 | || reset_opcode == 0xae //ldx $nnnn | |
| 341 | || reset_opcode == 0xac //ldy $nnnn | |
| 342 | || reset_opcode == 0xaf //lda $nnnnnn | |
| 343 | || reset_opcode == 0xa9 //lda #$nn | |
| 344 | || reset_opcode == 0xa2 //ldx #$nn | |
| 345 | || reset_opcode == 0xa0 //ldy #$nn | |
| 346 | || reset_opcode == 0x20 //jsr $nnnn | |
| 347 | || reset_opcode == 0x22 //jsl $nnnnnn | |
| 348 | ) | |
| 349 | score += 4; | |
| 350 | ||
| 351 | /* implausible opcodes */ | |
| 352 | if (reset_opcode == 0x40 //rti | |
| 353 | || reset_opcode == 0x60 //rts | |
| 354 | || reset_opcode == 0x6b //rtl | |
| 355 | || reset_opcode == 0xcd //cmp $nnnn | |
| 356 | || reset_opcode == 0xec //cpx $nnnn | |
| 357 | || reset_opcode == 0xcc //cpy $nnnn | |
| 358 | ) | |
| 359 | score -= 4; | |
| 360 | ||
| 361 | /* least likely opcodes */ | |
| 362 | if (reset_opcode == 0x00 //brk #$nn | |
| 363 | || reset_opcode == 0x02 //cop #$nn | |
| 364 | || reset_opcode == 0xdb //stp | |
| 365 | || reset_opcode == 0x42 //wdm | |
| 366 | || reset_opcode == 0xff //sbc $nnnnnn,x | |
| 367 | ) | |
| 368 | score -= 8; | |
| 369 | ||
| 370 | /* Sometimes, both the header and reset vector's first opcode will match ... | |
| 371 | fallback and rely on info validity in these cases to determine more likely header. */ | |
| 372 | ||
| 373 | /* a valid checksum is the biggest indicator of a valid header. */ | |
| 374 | if ((checksum + ichecksum) == 0xffff && (checksum != 0) && (ichecksum != 0)) | |
| 375 | score += 4; | |
| 376 | ||
| 377 | /* then there are the expected mapper values */ | |
| 378 | if (offset == 0x007fc0 && mapper == 0x20) // 0x20 is usually LoROM | |
| 379 | score += 2; | |
| 380 | ||
| 381 | if (offset == 0x00ffc0 && mapper == 0x21) // 0x21 is usually HiROM | |
| 382 | score += 2; | |
| 383 | ||
| 384 | if (offset == 0x007fc0 && mapper == 0x22) // 0x22 is usually ExLoROM | |
| 385 | score += 2; | |
| 386 | ||
| 387 | if (offset == 0x40ffc0 && mapper == 0x25) // 0x25 is usually ExHiROM | |
| 388 | score += 2; | |
| 389 | ||
| 390 | /* finally, there are valid values in the Company, Region etc. fields */ | |
| 391 | if (infoblock[offset + 0x1a] == 0x33) // Company field: 0x33 indicates extended header | |
| 392 | score += 2; | |
| 393 | ||
| 394 | if (infoblock[offset + 0x16] < 0x08) // ROM Type field | |
| 395 | score++; | |
| 396 | ||
| 397 | if (infoblock[offset + 0x17] < 0x10) // ROM Size field | |
| 398 | score++; | |
| 399 | ||
| 400 | if (infoblock[offset + 0x18] < 0x08) // SRAM Size field | |
| 401 | score++; | |
| 402 | ||
| 403 | if (infoblock[offset + 0x19] < 14) // Region field | |
| 404 | score++; | |
| 405 | ||
| 406 | /* do we still have a positive score? */ | |
| 407 | if (score < 0) | |
| 408 | score = 0; | |
| 409 | ||
| 410 | return score; | |
| 411 | } | |
| 412 | ||
| 413 | /* Here we add a couple of cart utilities, to avoid duplicating the code in each DEVICE_IMAGE_LOAD */ | |
| 414 | static UINT32 snes_skip_header( device_image_interface &image, UINT32 snes_rom_size ) | |
| 415 | { | |
| 416 | UINT8 header[512]; | |
| 417 | UINT32 offset = 512; | |
| 418 | ||
| 419 | /* Check for a header (512 bytes) */ | |
| 420 | if (image.software_entry() == NULL) | |
| 421 | image.fread( header, 512); | |
| 422 | else | |
| 423 | memcpy(header, image.get_software_region("rom"), 512); | |
| 424 | ||
| 425 | if ((header[8] == 0xaa) && (header[9] == 0xbb) && (header[10] == 0x04)) | |
| 426 | { | |
| 427 | /* Found an SWC identifier */ | |
| 428 | logerror("Found header (SWC) - Skipped\n"); | |
| 429 | } | |
| 430 | else if ((header[0] | (header[1] << 8)) == (((snes_rom_size - 512) / 1024) / 8)) | |
| 431 | { | |
| 432 | /* Some headers have the rom size at the start, if this matches with the actual rom size, we probably have a header */ | |
| 433 | logerror("Found header (size) - Skipped\n"); | |
| 434 | } | |
| 435 | else if ((snes_rom_size % 0x8000) == 512) | |
| 436 | { | |
| 437 | /* As a last check we'll see if there's exactly 512 bytes extra to this image. */ | |
| 438 | logerror("Found header (extra) - Skipped\n"); | |
| 439 | } | |
| 440 | else | |
| 441 | { | |
| 442 | /* No header found so go back to the start of the file */ | |
| 443 | logerror("No header found.\n"); | |
| 444 | offset = 0; | |
| 445 | } | |
| 446 | ||
| 447 | return offset; | |
| 448 | } | |
| 449 | ||
| 450 | ||
| 451 | /* This determines if a cart is in Mode 20, 21, 22 or 25; sets state->m_cart[0].mode and | |
| 452 | state->m_cart[0].sram accordingly; and returns the offset of the internal header (needed to | |
| 453 | detect BSX and ST carts) */ | |
| 454 | static UINT32 snes_find_hilo_mode( device_image_interface &image, UINT8 *buffer, UINT32 offset, int cartid ) | |
| 455 | { | |
| 456 | snes_state *state = image.device().machine().driver_data<snes_state>(); | |
| 457 | UINT8 valid_mode20, valid_mode21, valid_mode25; | |
| 458 | UINT32 retvalue; | |
| 459 | ||
| 460 | /* Now to determine if this is a lo-ROM, a hi-ROM or an extended lo/hi-ROM */ | |
| 461 | valid_mode20 = snes_validate_infoblock(buffer, 0x007fc0); | |
| 462 | valid_mode21 = snes_validate_infoblock(buffer, 0x00ffc0); | |
| 463 | valid_mode25 = snes_validate_infoblock(buffer, 0x40ffc0); | |
| 464 | ||
| 465 | /* Images larger than 32mbits are likely ExHiRom */ | |
| 466 | if (valid_mode25) | |
| 467 | valid_mode25 += 4; | |
| 468 | ||
| 469 | if ((valid_mode20 >= valid_mode21) && (valid_mode20 >= valid_mode25)) | |
| 470 | { | |
| 471 | if ((buffer[0x007fd5] == 0x32) || ((state->m_cart_size - offset) > 0x401000)) | |
| 472 | state->m_cart[cartid].mode = SNES_MODE_22; // ExLoRom | |
| 473 | else | |
| 474 | state->m_cart[cartid].mode = SNES_MODE_20; // LoRom | |
| 475 | ||
| 476 | retvalue = 0x007fc0; | |
| 477 | ||
| 478 | /* a few games require 512k, however we store twice as much to be sure to cover the various mirrors */ | |
| 479 | state->m_cart[cartid].sram_max = 0x100000; | |
| 480 | } | |
| 481 | else if (valid_mode21 >= valid_mode25) | |
| 482 | { | |
| 483 | state->m_cart[cartid].mode = SNES_MODE_21; // HiRom | |
| 484 | retvalue = 0x00ffc0; | |
| 485 | state->m_cart[cartid].sram_max = 0x20000; | |
| 486 | } | |
| 487 | else | |
| 488 | { | |
| 489 | state->m_cart[cartid].mode = SNES_MODE_25; // ExHiRom | |
| 490 | retvalue = 0x40ffc0; | |
| 491 | state->m_cart[cartid].sram_max = 0x20000; | |
| 492 | } | |
| 493 | ||
| 494 | logerror( "\t HiROM/LoROM id: %s (LoROM: %d , HiROM: %d, ExHiROM: %d)\n", | |
| 495 | (state->m_cart[cartid].mode == SNES_MODE_20) ? "LoROM" : | |
| 496 | (state->m_cart[cartid].mode == SNES_MODE_21) ? "HiROM" : | |
| 497 | (state->m_cart[cartid].mode == SNES_MODE_22) ? "ExLoROM" : | |
| 498 | (state->m_cart[cartid].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)", | |
| 499 | valid_mode20, valid_mode21, valid_mode25); | |
| 500 | ||
| 501 | return retvalue; | |
| 502 | } | |
| 503 | ||
| 504 | static int snes_find_addon_chip( running_machine &machine ) | |
| 505 | { | |
| 506 | snes_state *state = machine.driver_data<snes_state>(); | |
| 507 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 508 | int supported_type = 1; | |
| 509 | int dsp_prg_offset = 0; | |
| 510 | ||
| 511 | /* Info mostly taken from http://snesemu.black-ship.net/misc/-from%20nsrt.edgeemu.com-chipinfo.htm */ | |
| 512 | switch (snes_r_bank1(space, 0x00ffd6)) | |
| 513 | { | |
| 514 | case 0x00: | |
| 515 | case 0x01: | |
| 516 | case 0x02: | |
| 517 | state->m_has_addon_chip = HAS_NONE; | |
| 518 | break; | |
| 519 | ||
| 520 | case 0x03: | |
| 521 | if (snes_r_bank1(space, 0x00ffd5) == 0x30) | |
| 522 | { | |
| 523 | state->m_has_addon_chip = HAS_DSP4; | |
| 524 | dsp_prg_offset = SNES_DSP4_OFFSET; | |
| 525 | } | |
| 526 | else | |
| 527 | { | |
| 528 | state->m_has_addon_chip = HAS_DSP1; | |
| 529 | dsp_prg_offset = SNES_DSP1B_OFFSET; | |
| 530 | } | |
| 531 | break; | |
| 532 | ||
| 533 | case 0x04: | |
| 534 | state->m_has_addon_chip = HAS_DSP1; | |
| 535 | dsp_prg_offset = SNES_DSP1B_OFFSET; | |
| 536 | break; | |
| 537 | ||
| 538 | case 0x05: | |
| 539 | if (snes_r_bank1(space, 0x00ffd5) == 0x20) | |
| 540 | { | |
| 541 | state->m_has_addon_chip = HAS_DSP2; | |
| 542 | dsp_prg_offset = SNES_DSP2_OFFSET; | |
| 543 | } | |
| 544 | /* DSP-3 is hard to detect. We exploit the fact that the only game has been manufactured by Bandai */ | |
| 545 | else if ((snes_r_bank1(space, 0x00ffd5) == 0x30) && (snes_r_bank1(space, 0x00ffda) == 0xb2)) | |
| 546 | { | |
| 547 | state->m_has_addon_chip = HAS_DSP3; | |
| 548 | dsp_prg_offset = SNES_DSP3_OFFSET; | |
| 549 | } | |
| 550 | else | |
| 551 | { | |
| 552 | state->m_has_addon_chip = HAS_DSP1; | |
| 553 | dsp_prg_offset = SNES_DSP1B_OFFSET; | |
| 554 | } | |
| 555 | break; | |
| 556 | ||
| 557 | case 0x13: // Mario Chip 1 | |
| 558 | case 0x14: // GSU-x | |
| 559 | case 0x15: // GSU-x | |
| 560 | case 0x1a: // GSU-1 (21 MHz at start) | |
| 561 | if (snes_r_bank1(space, 0x00ffd5) == 0x20) | |
| 562 | state->m_has_addon_chip = HAS_SUPERFX; | |
| 563 | break; | |
| 564 | ||
| 565 | case 0x25: | |
| 566 | state->m_has_addon_chip = HAS_OBC1; | |
| 567 | break; | |
| 568 | ||
| 569 | case 0x32: // needed by a Sample game (according to ZSNES) | |
| 570 | case 0x34: | |
| 571 | case 0x35: | |
| 572 | if (snes_r_bank1(space, 0x00ffd5) == 0x23) | |
| 573 | { | |
| 574 | state->m_has_addon_chip = HAS_SA1; | |
| 575 | supported_type = 0; | |
| 576 | mame_printf_error("This is a SA-1 type game, currently unsupported by the driver\n"); | |
| 577 | } | |
| 578 | break; | |
| 579 | ||
| 580 | case 0x43: | |
| 581 | case 0x45: | |
| 582 | if (snes_r_bank1(space, 0x00ffd5) == 0x32) | |
| 583 | { | |
| 584 | state->m_has_addon_chip = HAS_SDD1; | |
| 585 | } | |
| 586 | break; | |
| 587 | ||
| 588 | case 0x55: | |
| 589 | if (snes_r_bank1(space, 0x00ffd5) == 0x35) | |
| 590 | { | |
| 591 | state->m_has_addon_chip = HAS_RTC; | |
| 592 | } | |
| 593 | break; | |
| 594 | ||
| 595 | case 0xe3: | |
| 596 | state->m_has_addon_chip = HAS_Z80GB; | |
| 597 | supported_type = 0; | |
| 598 | break; | |
| 599 | ||
| 600 | case 0xf3: | |
| 601 | state->m_has_addon_chip = HAS_CX4; | |
| 602 | break; | |
| 603 | ||
| 604 | case 0xf5: | |
| 605 | if (snes_r_bank1(space, 0x00ffd5) == 0x30) | |
| 606 | { | |
| 607 | state->m_has_addon_chip = HAS_ST018; | |
| 608 | supported_type = 0; | |
| 609 | } | |
| 610 | else if (snes_r_bank1(space, 0x00ffd5) == 0x3a) | |
| 611 | { | |
| 612 | state->m_has_addon_chip = HAS_SPC7110; | |
| 613 | } | |
| 614 | break; | |
| 615 | ||
| 616 | case 0xf6: | |
| 617 | /* These Seta ST-01X chips have both 0x30 at 0x00ffd5, | |
| 618 | they only differ for the 'size' at 0x00ffd7 */ | |
| 619 | if (snes_r_bank1(space, 0x00ffd7) < 0x0a) | |
| 620 | state->m_has_addon_chip = HAS_ST011; | |
| 621 | else | |
| 622 | state->m_has_addon_chip = HAS_ST010; | |
| 623 | ||
| 624 | // if we are loading the game in a driver without the ST01X DSP, revert to HAS_NONE to avoid crash | |
| 625 | if (!state->m_upd96050) | |
| 626 | state->m_has_addon_chip = HAS_NONE; | |
| 627 | break; | |
| 628 | ||
| 629 | case 0xf9: | |
| 630 | if (snes_r_bank1(space, 0x00ffd5) == 0x3a) | |
| 631 | { | |
| 632 | state->m_has_addon_chip = HAS_SPC7110_RTC; | |
| 633 | supported_type = 0; | |
| 634 | } | |
| 635 | break; | |
| 636 | ||
| 637 | default: | |
| 638 | state->m_has_addon_chip = HAS_UNK; | |
| 639 | supported_type = 0; | |
| 640 | break; | |
| 641 | } | |
| 642 | ||
| 643 | if ((state->m_has_addon_chip >= HAS_DSP1) && (state->m_has_addon_chip <= HAS_DSP4)) | |
| 644 | { | |
| 645 | UINT8 *dspsrc = (UINT8 *)machine.region("addons")->base(); | |
| 646 | UINT32 *dspprg = (UINT32 *)machine.region("dspprg")->base(); | |
| 647 | UINT16 *dspdata = (UINT16 *)machine.region("dspdata")->base(); | |
| 648 | ||
| 649 | // copy DSP program | |
| 650 | for (int i = 0; i < 0x2000; i+= 4) | |
| 651 | { | |
| 652 | *dspprg = dspsrc[dsp_prg_offset+0+i]<<24 | dspsrc[dsp_prg_offset+1+i]<<16 | dspsrc[dsp_prg_offset+2+i]<<8; | |
| 653 | dspprg++; | |
| 654 | } | |
| 655 | ||
| 656 | // copy DSP data | |
| 657 | for (int i = 0; i < 0x800; i+= 2) | |
| 658 | { | |
| 659 | *dspdata++ = dspsrc[dsp_prg_offset+0x2000+i]<<8 | dspsrc[dsp_prg_offset+0x2001+i]; | |
| 660 | } | |
| 661 | } | |
| 662 | ||
| 663 | if ((state->m_has_addon_chip == HAS_ST010) || (state->m_has_addon_chip == HAS_ST011)) | |
| 664 | { | |
| 665 | UINT8 *dspsrc = (UINT8 *)machine.region("addons")->base(); | |
| 666 | UINT32 *dspprg = (UINT32 *)machine.region("dspprg")->base(); | |
| 667 | UINT16 *dspdata = (UINT16 *)machine.region("dspdata")->base(); | |
| 668 | ||
| 669 | // copy DSP program | |
| 670 | for (int i = 0; i < 0x10000; i+= 4) | |
| 671 | { | |
| 672 | *dspprg = dspsrc[0+i]<<24 | dspsrc[1+i]<<16 | dspsrc[2+i]<<8; | |
| 673 | dspprg++; | |
| 674 | } | |
| 675 | ||
| 676 | // copy DSP data | |
| 677 | for (int i = 0; i < 0x1000; i+= 2) | |
| 678 | { | |
| 679 | *dspdata++ = dspsrc[0x10000+i]<<8 | dspsrc[0x10001+i]; | |
| 680 | } | |
| 681 | } | |
| 682 | ||
| 683 | return supported_type; | |
| 684 | } | |
| 685 | ||
| 686 | static void snes_cart_log_info( running_machine &machine, int total_blocks, int supported ) | |
| 687 | { | |
| 688 | snes_state *state = machine.driver_data<snes_state>(); | |
| 689 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 690 | char title[21], rom_id[4], company_id[2]; | |
| 691 | int i, company, has_ram = 0, has_sram = 0; | |
| 692 | ||
| 693 | /* Company */ | |
| 694 | for (i = 0; i < 2; i++) | |
| 695 | company_id[i] = snes_r_bank1(space, 0x00ffb0 + i); | |
| 696 | company = (char_to_int_conv(company_id[0]) << 4) + char_to_int_conv(company_id[1]); | |
| 697 | if (company == 0) | |
| 698 | company = snes_r_bank1(space, 0x00ffda); | |
| 699 | ||
| 700 | /* ROM ID */ | |
| 701 | for( i = 0; i < 4; i++ ) | |
| 702 | rom_id[i] = snes_r_bank1(space, 0x00ffb2 + i); | |
| 703 | ||
| 704 | /* Title */ | |
| 705 | for( i = 0; i < 21; i++ ) | |
| 706 | title[i] = snes_r_bank1(space, 0x00ffc0 + i); | |
| 707 | ||
| 708 | /* RAM */ | |
| 709 | if (((snes_r_bank1(space, 0x00ffd6) & 0xf) == 1) || | |
| 710 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 2) || | |
| 711 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 4) || | |
| 712 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 5)) | |
| 713 | has_ram = 1; | |
| 714 | ||
| 715 | /* SRAM */ | |
| 716 | if (((snes_r_bank1(space, 0x00ffd6) & 0xf) == 2) || | |
| 717 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 5) || | |
| 718 | ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 6)) | |
| 719 | has_sram = 1; | |
| 720 | ||
| 721 | logerror( "ROM DETAILS\n" ); | |
| 722 | logerror( "===========\n\n" ); | |
| 723 | logerror( "\tTotal blocks: %d (%dmb)\n", total_blocks, total_blocks / (state->m_cart[0].mode & 5 ? 32 : 16) ); | |
| 724 | logerror( "\tROM bank size: %s \n", | |
| 725 | (state->m_cart[0].mode == SNES_MODE_20) ? "LoROM" : | |
| 726 | (state->m_cart[0].mode == SNES_MODE_21) ? "HiROM" : | |
| 727 | (state->m_cart[0].mode == SNES_MODE_22) ? "ExLoROM" : | |
| 728 | (state->m_cart[0].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)" ); | |
| 729 | logerror( "\tCompany: %s [%.2s]\n", companies[company], company_id ); | |
| 730 | logerror( "\tROM ID: %.4s\n\n", rom_id ); | |
| 731 | ||
| 732 | logerror( "HEADER DETAILS\n" ); | |
| 733 | logerror( "==============\n\n" ); | |
| 734 | logerror( "\tName: %.21s\n", title ); | |
| 735 | logerror( "\tSpeed: %s [%d]\n", ((snes_r_bank1(space, 0x00ffd5) & 0xf0)) ? "FastROM" : "SlowROM", (snes_r_bank1(space, 0x00ffd5) & 0xf0) >> 4 ); | |
| 736 | logerror( "\tBank size: %s [%d]\n", (snes_r_bank1(space, 0x00ffd5) & 0xf) ? "HiROM" : "LoROM", snes_r_bank1(space, 0x00ffd5) & 0xf ); | |
| 737 | ||
| 738 | logerror( "\tType: %s", types[state->m_has_addon_chip]); | |
| 739 | if (has_ram) | |
| 740 | logerror( ", RAM"); | |
| 741 | if (has_sram) | |
| 742 | logerror( ", SRAM"); | |
| 743 | logerror( " [%d]\n", snes_r_bank1(space, 0x00ffd6) ); | |
| 744 | ||
| 745 | logerror( "\tSize: %d megabits [%d]\n", 1 << (snes_r_bank1(space, 0x00ffd7) - 7), snes_r_bank1(space, 0x00ffd7) ); | |
| 746 | logerror( "\tSRAM: %d kilobits [%d]\n", state->m_cart[0].sram * 8, snes_ram[0xffd8] ); | |
| 747 | logerror( "\tCountry: %s [%d]\n", countries[snes_r_bank1(space, 0x00ffd9)], snes_r_bank1(space, 0x00ffd9) ); | |
| 748 | logerror( "\tLicense: %s [%X]\n", companies[snes_r_bank1(space, 0x00ffda)], snes_r_bank1(space, 0x00ffda) ); | |
| 749 | logerror( "\tVersion: 1.%d\n", snes_r_bank1(space, 0x00ffdb) ); | |
| 750 | logerror( "\tInv Checksum: %X %X\n", snes_r_bank1(space, 0x00ffdd), snes_r_bank1(space, 0x00ffdc) ); | |
| 751 | logerror( "\tChecksum: %X %X\n", snes_r_bank1(space, 0x00ffdf), snes_r_bank1(space, 0x00ffde) ); | |
| 752 | logerror( "\tNMI Address: %2X%2Xh\n", snes_r_bank1(space, 0x00fffb), snes_r_bank1(space, 0x00fffa) ); | |
| 753 | logerror( "\tStart Address: %2X%2Xh\n\n", snes_r_bank1(space, 0x00fffd), snes_r_bank1(space, 0x00fffc) ); | |
| 754 | ||
| 755 | logerror( "\tMode: %d\n", state->m_cart[0].mode); | |
| 756 | ||
| 757 | if (!supported) | |
| 758 | logerror("WARNING: This cart type \"%s\" is not supported yet!\n", types[state->m_has_addon_chip]); | |
| 759 | } | |
| 760 | ||
| 761 | static DEVICE_IMAGE_LOAD( snes_cart ) | |
| 762 | { | |
| 763 | int supported_type = 1, i, j; | |
| 764 | running_machine &machine = image.device().machine(); | |
| 765 | snes_state *state = machine.driver_data<snes_state>(); | |
| 766 | address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM ); | |
| 767 | int total_blocks, read_blocks, has_bsx_slot = 0, st_bios = 0; | |
| 768 | UINT32 offset, int_header_offs; | |
| 769 | UINT8 *ROM = image.device().machine().region("cart")->base(); | |
| 770 | ||
| 771 | if (image.software_entry() == NULL) | |
| 772 | state->m_cart_size = image.length(); | |
| 773 | else | |
| 774 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 775 | ||
| 776 | /* Check for a header (512 bytes), and skip it if found */ | |
| 777 | offset = snes_skip_header(image, state->m_cart_size); | |
| 778 | ||
| 779 | if (image.software_entry() == NULL) | |
| 780 | { | |
| 781 | image.fseek(offset, SEEK_SET); | |
| 782 | image.fread( ROM, state->m_cart_size - offset); | |
| 783 | } | |
| 784 | else | |
| 785 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 786 | ||
| 787 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 788 | ||
| 789 | /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */ | |
| 790 | int_header_offs = snes_find_hilo_mode(image, ROM, offset, 0); | |
| 791 | ||
| 792 | /* Then, detect BS-X carts */ | |
| 793 | // Detect presence of BS-X Flash Cart | |
| 794 | if ((ROM[int_header_offs + 0x13] == 0x00 || ROM[int_header_offs + 0x13] == 0xff) && | |
| 795 | ROM[int_header_offs + 0x14] == 0x00) | |
| 796 | { | |
| 797 | UINT8 n15 = ROM[int_header_offs + 0x15]; | |
| 798 | if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) | |
| 799 | { | |
| 800 | if (ROM[int_header_offs + 0x1a] == 0x33 || ROM[int_header_offs + 0x1a] == 0xff) | |
| 801 | { | |
| 802 | // BS-X Flash Cart | |
| 803 | state->m_cart[0].mode = SNES_MODE_BSX; | |
| 804 | } | |
| 805 | } | |
| 806 | } | |
| 807 | ||
| 808 | // Detect presence of BS-X flash cartridge connector | |
| 809 | if ((ROM[int_header_offs - 14] == 'Z') && (ROM[int_header_offs - 11] == 'J')) | |
| 810 | { | |
| 811 | UINT8 n13 = ROM[int_header_offs - 13]; | |
| 812 | if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) | |
| 813 | { | |
| 814 | if (ROM[int_header_offs + 0x1a] == 0x33 || | |
| 815 | (ROM[int_header_offs - 10] == 0x00 && ROM[int_header_offs - 4] == 0x00)) | |
| 816 | { | |
| 817 | has_bsx_slot = 1; | |
| 818 | } | |
| 819 | } | |
| 820 | } | |
| 821 | ||
| 822 | // If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart | |
| 823 | if (has_bsx_slot) | |
| 824 | { | |
| 825 | if (!memcmp(ROM + int_header_offs, "Satellaview BS-X ", 21)) | |
| 826 | { | |
| 827 | //BS-X Base Cart | |
| 828 | state->m_cart[0].mode = SNES_MODE_BSX; | |
| 829 | // handle RAM | |
| 830 | } | |
| 831 | else | |
| 832 | { | |
| 833 | state->m_cart[0].mode = (int_header_offs ==0x007fc0) ? SNES_MODE_BSLO : SNES_MODE_BSHI; | |
| 834 | // handle RAM? | |
| 835 | } | |
| 836 | } | |
| 837 | ||
| 838 | /* Then, detect Sufami Turbo carts */ | |
| 839 | if (!memcmp(ROM, "BANDAI SFC-ADX", 14)) | |
| 840 | { | |
| 841 | state->m_cart[0].mode = SNES_MODE_ST; | |
| 842 | if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14)) | |
| 843 | st_bios = 1; | |
| 844 | } | |
| 845 | ||
| 846 | if (SNES_CART_DEBUG) mame_printf_error("mode %d\n", state->m_cart[0].mode); | |
| 847 | ||
| 848 | /* FIXME: Insert crc check here? */ | |
| 849 | ||
| 850 | /* How many blocks of data are available to be loaded? */ | |
| 851 | total_blocks = ((state->m_cart_size - offset) / (state->m_cart[0].mode & 0xa5 ? 0x8000 : 0x10000)); | |
| 852 | read_blocks = 0; | |
| 853 | ||
| 854 | if (SNES_CART_DEBUG) mame_printf_error("blocks %d\n", total_blocks); | |
| 855 | ||
| 856 | /* Loading all the data blocks from cart, we only partially cover banks 0x00 to 0x7f. Therefore, we | |
| 857 | * have to mirror the blocks until we reach the end. E.g. for a 11Mbits image (44 blocks), we proceed | |
| 858 | * as follows: | |
| 859 | * 11 Mbits = 8 Mbits (blocks 1->32) + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44). | |
| 860 | * Hence, we fill memory up to 16 Mbits (banks 0x00 to 0x3f) mirroring as follows | |
| 861 | * 8 Mbits (blocks 1->32) + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44) + 1 Mbit (blocks 41->44) | |
| 862 | * + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44) + 1 Mbit (blocks 41->44) | |
| 863 | * and we repeat the same blocks in the second half of the banks (banks 0x40 to 0x7f). | |
| 864 | * This is likely what happens in the real SNES as well, because the unit cannot be aware of the exact | |
| 865 | * size of data in the cart (procedure confirmed by byuu) | |
| 866 | */ | |
| 867 | switch (state->m_cart[0].mode) | |
| 868 | { | |
| 869 | case SNES_MODE_21: | |
| 870 | /* HiROM carts load data in banks 0xc0 to 0xff. Each bank is fully mirrored in banks 0x40 to 0x7f | |
| 871 | * (actually up to 0x7d, because 0x7e and 0x7f are overwritten by WRAM). The top half (address | |
| 872 | * range 0x8000 - 0xffff) of each bank is also mirrored in banks 0x00 to 0x3f and 0x80 to 0xbf. | |
| 873 | */ | |
| 874 | /* SPC7110 games needs this different loading routine */ | |
| 875 | if ((ROM[0x00ffd6] == 0xf9 || ROM[0x00ffd6] == 0xf5) && (ROM[0x00ffd5] == 0x3a)) | |
| 876 | { | |
| 877 | while (read_blocks < 16 && read_blocks < total_blocks) | |
| 878 | { | |
| 879 | /* Loading data */ | |
| 880 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 881 | /* Mirroring */ | |
| 882 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 883 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 884 | read_blocks++; | |
| 885 | } | |
| 886 | } | |
| 887 | else | |
| 888 | { | |
| 889 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 890 | { | |
| 891 | /* Loading data */ | |
| 892 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 893 | /* Mirroring */ | |
| 894 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 895 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0xc00000 + read_blocks * 0x10000], 0x10000); | |
| 896 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 897 | read_blocks++; | |
| 898 | } | |
| 899 | /* Filling banks up to 0xff and their mirrors */ | |
| 900 | while (read_blocks % 64) | |
| 901 | { | |
| 902 | int j = 0, repeat_blocks; | |
| 903 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 904 | j++; | |
| 905 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 906 | ||
| 907 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &snes_ram[0xc00000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 908 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 909 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 910 | memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[0x800000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 911 | read_blocks += repeat_blocks; | |
| 912 | } | |
| 913 | } | |
| 914 | break; | |
| 915 | ||
| 916 | case SNES_MODE_25: | |
| 917 | /* Extendend HiROM carts start to load data in banks 0xc0 to 0xff. However, they exceed the | |
| 918 | * available space in these banks, and continue loading at banks 0x40 to 0x7f. The top half | |
| 919 | * (address range 0x8000 - 0xffff) of each bank is also mirrored either to banks 0x00 to 0x3f | |
| 920 | * (for data in banks 0x40 to 0x7f) or to banks 0x80 to 0xbf (for data in banks 0xc0 to 0xff). | |
| 921 | * Notice that banks 0x7e and 0x7f are overwritten by WRAM, but they could contain data at | |
| 922 | * address > 0x8000 because the mirrors at 0x3e and 0x3f are not overwritten. | |
| 923 | */ | |
| 924 | /* Reading the first 64 blocks */ | |
| 925 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 926 | { | |
| 927 | /* Loading data */ | |
| 928 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 929 | /* Mirroring */ | |
| 930 | memcpy( &snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000); | |
| 931 | read_blocks++; | |
| 932 | } | |
| 933 | /* ExHiROMs are supposed to be larger than 32Mbits! */ | |
| 934 | if (read_blocks < 64) | |
| 935 | { | |
| 936 | logerror("This image has been identified as ExHiROM, but it's too small!\n"); | |
| 937 | logerror("Please verify if it's corrupted. If it's not please report this as a bug.\n"); | |
| 938 | return IMAGE_INIT_FAIL; | |
| 939 | } | |
| 940 | /* Scaling down the counter */ | |
| 941 | read_blocks -= 64; | |
| 942 | /* Reading the next blocks */ | |
| 943 | while (read_blocks < 64 && read_blocks < (total_blocks - 64)) | |
| 944 | { | |
| 945 | /* Loading data */ | |
| 946 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &ROM[0x400000 + read_blocks * 0x10000], 0x10000); | |
| 947 | /* Mirroring */ | |
| 948 | memcpy(&snes_ram[0x8000 + read_blocks * 0x10000], &snes_ram[0x408000 + read_blocks * 0x10000], 0x8000); | |
| 949 | read_blocks++; | |
| 950 | } | |
| 951 | /* Filling banks up to 0x7f and their mirrors */ | |
| 952 | while (read_blocks % 64) | |
| 953 | { | |
| 954 | int j = 0, repeat_blocks; | |
| 955 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 956 | j++; | |
| 957 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 958 | ||
| 959 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 960 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 961 | read_blocks += repeat_blocks; | |
| 962 | } | |
| 963 | break; | |
| 964 | ||
| 965 | case SNES_MODE_22: | |
| 966 | /* "Extendend LoROM" carts have their data loaded in banks 0x00 to 0x3f at address 0x8000. | |
| 967 | * These are then mirrored in banks 0x40 to 0x7f, both at address 0x0000 and at address | |
| 968 | * 0x8000, in banks 0x80 to 0xbf at address 0x8000 and in banks 0xc0 to 0xff, both at address | |
| 969 | * 0x0000 and at address 0x8000. Notice that SDD-1 games (Star Ocean and Street Fighter Zero 2) | |
| 970 | * use SNES_MODE_22 | |
| 971 | */ | |
| 972 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 973 | { | |
| 974 | /* Loading and mirroring data */ | |
| 975 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 976 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 977 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 978 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000); | |
| 979 | read_blocks++; | |
| 980 | } | |
| 981 | /* Filling banks up to 0x3f and their mirrors */ | |
| 982 | while (read_blocks % 64) | |
| 983 | { | |
| 984 | int j = 0, repeat_blocks; | |
| 985 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 986 | j++; | |
| 987 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 988 | ||
| 989 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 990 | memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[0x800000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 991 | memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 992 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &snes_ram[0xc00000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 993 | read_blocks += repeat_blocks; | |
| 994 | } | |
| 995 | break; | |
| 996 | ||
| 997 | case SNES_MODE_ST: | |
| 998 | if (!st_bios) | |
| 999 | { | |
| 1000 | mame_printf_error("This is a Sufami Turbo data cart and cannot be loaded for snes/snespal in MESS.\n"); | |
| 1001 | mame_printf_error("Please use snesst driver to load it, instead.\n"); | |
| 1002 | return IMAGE_INIT_FAIL; | |
| 1003 | } | |
| 1004 | else | |
| 1005 | { | |
| 1006 | // The Base ST cart consists of 8 * 0x8000 block which have to be loaded (and mirrored) | |
| 1007 | // at 0x00-0x1f:0x8000-0xffff and 0x80-0x9f:0x8000-0xffff | |
| 1008 | for (i = 0; i < 8; i++) | |
| 1009 | { | |
| 1010 | /* Loading data */ | |
| 1011 | memcpy(&snes_ram[0x008000 + i * 0x10000], &ROM[0x000000 + i * 0x8000], 0x8000); | |
| 1012 | /* Mirroring */ | |
| 1013 | memcpy(&snes_ram[0x808000 + i * 0x10000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1014 | ||
| 1015 | /* Additional mirrors (to fill snes_ram up to 0x1fffff) */ | |
| 1016 | for (j = 1; j < 4; j++) | |
| 1017 | { | |
| 1018 | memcpy(&snes_ram[0x008000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1019 | memcpy(&snes_ram[0x808000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1020 | } | |
| 1021 | } | |
| 1022 | } | |
| 1023 | break; | |
| 1024 | ||
| 1025 | case SNES_MODE_BSX: | |
| 1026 | case SNES_MODE_BSLO: | |
| 1027 | case SNES_MODE_BSHI: | |
| 1028 | /* not handled yet */ | |
| 1029 | mame_printf_error("This is a BS-X Satellaview image: MESS does not support these yet, sorry.\n"); | |
| 1030 | #if 0 | |
| 1031 | // shall we force incompatibility of flash carts without a base unit? | |
| 1032 | if (!has_bsx_slot) | |
| 1033 | { | |
| 1034 | mame_printf_error("This is a BS-X flash cart and cannot be loaded in snes/snespal.\n"); | |
| 1035 | // mame_printf_error("Please use snesbsx driver to load it, instead.\n"); | |
| 1036 | return IMAGE_INIT_FAIL; | |
| 1037 | } | |
| 1038 | #endif | |
| 1039 | break; | |
| 1040 | ||
| 1041 | default: | |
| 1042 | case SNES_MODE_20: | |
| 1043 | /* LoROM carts load data in banks 0x00 to 0x7f at address 0x8000 (actually up to 0x7d, because 0x7e and | |
| 1044 | * 0x7f are overwritten by WRAM). Each block is also mirrored in banks 0x80 to 0xff (up to 0xff for real) | |
| 1045 | */ | |
| 1046 | /* SuperFX games needs this different loading routine */ | |
| 1047 | if (((ROM[0x007fd6] >= 0x13 && ROM[0x007fd6] <= 0x15) || ROM[0x007fd6] == 0x1a) && (ROM[0x007fd5] == 0x20)) | |
| 1048 | { | |
| 1049 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 1050 | { | |
| 1051 | /* Loading data primary: banks 0-3f from 8000-ffff*/ | |
| 1052 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1053 | /* Mirroring at banks 80-bf from 8000-ffff */ | |
| 1054 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000); | |
| 1055 | /* Mirroring at banks 40-5f and c0-df */ | |
| 1056 | memcpy(&snes_ram[0x400000 + read_blocks * 0x8000], &snes_ram[0x8000 + (read_blocks * 0x10000)], total_blocks * 0x8000); | |
| 1057 | memcpy(&snes_ram[0xc00000 + read_blocks * 0x8000], &snes_ram[0x8000 + (read_blocks * 0x10000)], total_blocks * 0x8000); | |
| 1058 | ||
| 1059 | read_blocks++; | |
| 1060 | } | |
| 1061 | /* SuperFX games are supposed to contain 64 blocks! */ | |
| 1062 | if (read_blocks < total_blocks) | |
| 1063 | { | |
| 1064 | logerror("This image has been identified as a SuperFX game, but it's too large!\n"); | |
| 1065 | logerror("Please verify if it's corrupted. If it's not please report this as a bug.\n"); | |
| 1066 | return IMAGE_INIT_FAIL; | |
| 1067 | } | |
| 1068 | } | |
| 1069 | else | |
| 1070 | { | |
| 1071 | while (read_blocks < 128 && read_blocks < total_blocks) | |
| 1072 | { | |
| 1073 | /* Loading data */ | |
| 1074 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1075 | /* Mirroring */ | |
| 1076 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000); | |
| 1077 | read_blocks++; | |
| 1078 | } | |
| 1079 | /* Filling banks up to 0x7f and their mirrors */ | |
| 1080 | while (read_blocks % 128) | |
| 1081 | { | |
| 1082 | int j = 0, repeat_blocks; | |
| 1083 | while ((read_blocks % (128 >> j)) && j < 7) | |
| 1084 | j++; | |
| 1085 | repeat_blocks = read_blocks % (128 >> (j - 1)); | |
| 1086 | ||
| 1087 | memcpy( &snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1088 | memcpy( &snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1089 | read_blocks += repeat_blocks; | |
| 1090 | } | |
| 1091 | } | |
| 1092 | break; | |
| 1093 | } | |
| 1094 | ||
| 1095 | /* Detect special chips */ | |
| 1096 | supported_type = snes_find_addon_chip(machine); | |
| 1097 | ||
| 1098 | /* Find the amount of cart ram (even if we call it sram...) */ | |
| 1099 | if (image.software_entry() == NULL) | |
| 1100 | { | |
| 1101 | if ((state->m_has_addon_chip != HAS_SUPERFX)) | |
| 1102 | state->m_cart[0].sram = snes_r_bank1(space, 0x00ffd8); | |
| 1103 | else | |
| 1104 | state->m_cart[0].sram = (snes_r_bank1(space, 0x00ffbd) & 0x07); | |
| 1105 | ||
| 1106 | if (state->m_cart[0].sram > 0) | |
| 1107 | { | |
| 1108 | state->m_cart[0].sram = (1024 << state->m_cart[0].sram); | |
| 1109 | if (state->m_cart[0].sram > state->m_cart[0].sram_max) | |
| 1110 | state->m_cart[0].sram = state->m_cart[0].sram_max; | |
| 1111 | } | |
| 1112 | // printf("size %x\n", state->m_cart[0].sram); | |
| 1113 | } | |
| 1114 | else | |
| 1115 | { | |
| 1116 | // if we are loading from softlist, take sram from the xml | |
| 1117 | state->m_cart[0].sram = image.get_software_region("sram") ? image.get_software_region_length("sram") : 0; | |
| 1118 | ||
| 1119 | if (state->m_cart[0].sram > 0) | |
| 1120 | { | |
| 1121 | if (state->m_cart[0].sram > state->m_cart[0].sram_max) | |
| 1122 | fatalerror("Found more SRAM than max allowed (found: %x, max: %x), check xml file!\n", state->m_cart[0].sram, state->m_cart[0].sram_max); | |
| 1123 | } | |
| 1124 | // TODO: Eventually sram handlers should point to the allocated cart:sram region! | |
| 1125 | // For now, we only use the region as a placeholder to carry size info... | |
| 1126 | // printf("size %x\n", state->m_cart[0].sram); | |
| 1127 | } | |
| 1128 | ||
| 1129 | /* adjust size for very large carts */ | |
| 1130 | if (state->m_cart[0].mode == SNES_MODE_20 && ((state->m_cart_size - offset) > 0x200000 || state->m_cart[0].sram > (32 * 1024))) | |
| 1131 | state->m_cart[0].small_sram = 1; | |
| 1132 | else | |
| 1133 | state->m_cart[0].small_sram = 0; | |
| 1134 | ||
| 1135 | /* Log snes_cart information */ | |
| 1136 | snes_cart_log_info(machine, total_blocks, supported_type); | |
| 1137 | ||
| 1138 | /* Load SRAM */ | |
| 1139 | snes_load_sram(machine); | |
| 1140 | ||
| 1141 | /* All done */ | |
| 1142 | return IMAGE_INIT_PASS; | |
| 1143 | } | |
| 1144 | ||
| 1145 | static DEVICE_IMAGE_LOAD( sufami_cart ) | |
| 1146 | { | |
| 1147 | running_machine &machine = image.device().machine(); | |
| 1148 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1149 | int total_blocks, read_blocks; | |
| 1150 | int st_bios = 0, slot_id = 0; | |
| 1151 | UINT32 offset, st_data_offset = 0; | |
| 1152 | UINT8 *ROM = image.device().machine().region(image.device().tag())->base(); | |
| 1153 | ||
| 1154 | snes_ram = machine.region("maincpu")->base(); | |
| 1155 | ||
| 1156 | if (strcmp(image.device().tag(), "slot_a") == 0) | |
| 1157 | { | |
| 1158 | st_data_offset = 0x200000; | |
| 1159 | slot_id = 0; | |
| 1160 | } | |
| 1161 | ||
| 1162 | if (strcmp(image.device().tag(), "slot_b") == 0) | |
| 1163 | { | |
| 1164 | st_data_offset = 0x400000; | |
| 1165 | slot_id = 1; | |
| 1166 | } | |
| 1167 | ||
| 1168 | if (image.software_entry() == NULL) | |
| 1169 | state->m_cart_size = image.length(); | |
| 1170 | else | |
| 1171 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 1172 | ||
| 1173 | /* Check for a header (512 bytes), and skip it if found */ | |
| 1174 | offset = snes_skip_header(image, state->m_cart_size); | |
| 1175 | ||
| 1176 | if (image.software_entry() == NULL) | |
| 1177 | { | |
| 1178 | image.fseek(offset, SEEK_SET); | |
| 1179 | image.fread( ROM, state->m_cart_size - offset); | |
| 1180 | } | |
| 1181 | else | |
| 1182 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 1183 | ||
| 1184 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 1185 | ||
| 1186 | /* Detect Sufami Turbo carts */ | |
| 1187 | if (!memcmp(ROM, "BANDAI SFC-ADX", 14)) | |
| 1188 | { | |
| 1189 | state->m_cart[slot_id].mode = SNES_MODE_ST; | |
| 1190 | if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14)) | |
| 1191 | st_bios = 1; | |
| 1192 | } | |
| 1193 | else | |
| 1194 | { | |
| 1195 | mame_printf_error("This is not a Sufami Turbo data pack.\n"); | |
| 1196 | mame_printf_error("This image cannot be loaded in snesst (Use snes or snespal drivers, instead).\n"); | |
| 1197 | return IMAGE_INIT_FAIL; | |
| 1198 | } | |
| 1199 | ||
| 1200 | if (st_bios == 1) | |
| 1201 | { | |
| 1202 | mame_printf_error("This is the Sufami Turbo BIOS and not a Sufami Turbo data pack.\n"); | |
| 1203 | mame_printf_error("This image cannot be loaded in snesst.\n"); | |
| 1204 | return IMAGE_INIT_FAIL; | |
| 1205 | } | |
| 1206 | ||
| 1207 | /* FIXME: Insert crc check here? */ | |
| 1208 | ||
| 1209 | /* How many blocks of data are available to be loaded? */ | |
| 1210 | total_blocks = (state->m_cart_size - offset) / 0x8000; | |
| 1211 | read_blocks = 0; | |
| 1212 | ||
| 1213 | if (SNES_CART_DEBUG) | |
| 1214 | mame_printf_error("blocks %d\n", total_blocks); | |
| 1215 | ||
| 1216 | // actually load the cart | |
| 1217 | while (read_blocks < 32 && read_blocks < total_blocks) | |
| 1218 | { | |
| 1219 | /* Loading data */ | |
| 1220 | // CART (either A or B) | |
| 1221 | memcpy(&snes_ram[0x008000 + st_data_offset + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1222 | /* Mirroring */ | |
| 1223 | memcpy(&snes_ram[0x808000 + st_data_offset + read_blocks * 0x10000], &snes_ram[0x8000 + st_data_offset + (read_blocks * 0x10000)], 0x8000); | |
| 1224 | ||
| 1225 | read_blocks++; | |
| 1226 | } | |
| 1227 | ||
| 1228 | /* Filling banks up to 0x1f and their mirrors */ | |
| 1229 | while (read_blocks % 32) | |
| 1230 | { | |
| 1231 | int j = 0, repeat_blocks; | |
| 1232 | while ((read_blocks % (32 >> j)) && j < 5) | |
| 1233 | j++; | |
| 1234 | repeat_blocks = read_blocks % (32 >> (j - 1)); | |
| 1235 | ||
| 1236 | memcpy(&snes_ram[st_data_offset + read_blocks * 0x10000], &snes_ram[st_data_offset + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1237 | memcpy(&snes_ram[0x800000 + st_data_offset + read_blocks * 0x10000], &snes_ram[st_data_offset + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1238 | read_blocks += repeat_blocks; | |
| 1239 | } | |
| 1240 | ||
| 1241 | sufami_load_sram(machine, image.device().tag()); | |
| 1242 | ||
| 1243 | state->m_cart[slot_id].slot_in_use = 1; // aknowledge the cart in this slot, for saving sram at exit | |
| 1244 | ||
| 1245 | auto_free(image.device().machine(), ROM); | |
| 1246 | ||
| 1247 | return IMAGE_INIT_PASS; | |
| 1248 | } | |
| 1249 | ||
| 1250 | static DEVICE_IMAGE_LOAD( bsx_cart ) | |
| 1251 | { | |
| 1252 | running_machine &machine = image.device().machine(); | |
| 1253 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1254 | int total_blocks, read_blocks; | |
| 1255 | int has_bsx_slot = 0; | |
| 1256 | UINT32 offset, int_header_offs; | |
| 1257 | UINT8 *ROM = image.device().machine().region("cart")->base(); | |
| 1258 | ||
| 1259 | if (image.software_entry() == NULL) | |
| 1260 | state->m_cart_size = image.length(); | |
| 1261 | else | |
| 1262 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 1263 | ||
| 1264 | /* Check for a header (512 bytes), and skip it if found */ | |
| 1265 | offset = snes_skip_header(image, state->m_cart_size); | |
| 1266 | ||
| 1267 | if (image.software_entry() == NULL) | |
| 1268 | { | |
| 1269 | image.fseek(offset, SEEK_SET); | |
| 1270 | image.fread( ROM, state->m_cart_size - offset); | |
| 1271 | } | |
| 1272 | else | |
| 1273 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 1274 | ||
| 1275 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 1276 | ||
| 1277 | /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */ | |
| 1278 | int_header_offs = snes_find_hilo_mode(image, ROM, offset, 0); | |
| 1279 | ||
| 1280 | // Detect presence of BS-X flash cartridge connector | |
| 1281 | if ((ROM[int_header_offs - 14] == 'Z') && (ROM[int_header_offs - 11] == 'J')) | |
| 1282 | { | |
| 1283 | UINT8 n13 = ROM[int_header_offs - 13]; | |
| 1284 | if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) | |
| 1285 | { | |
| 1286 | if (ROM[int_header_offs + 0x1a] == 0x33 || | |
| 1287 | (ROM[int_header_offs - 10] == 0x00 && ROM[int_header_offs - 4] == 0x00)) | |
| 1288 | { | |
| 1289 | has_bsx_slot = 1; | |
| 1290 | } | |
| 1291 | } | |
| 1292 | } | |
| 1293 | ||
| 1294 | // If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart | |
| 1295 | if (has_bsx_slot) | |
| 1296 | { | |
| 1297 | if (!memcmp(ROM + int_header_offs, "Satellaview BS-X ", 21)) | |
| 1298 | { | |
| 1299 | //BS-X Base Cart | |
| 1300 | state->m_cart[0].mode = SNES_MODE_BSX; | |
| 1301 | // handle RAM | |
| 1302 | } | |
| 1303 | else | |
| 1304 | { | |
| 1305 | state->m_cart[0].mode = (int_header_offs ==0x007fc0) ? SNES_MODE_BSLO : SNES_MODE_BSHI; | |
| 1306 | // handle RAM? | |
| 1307 | } | |
| 1308 | } | |
| 1309 | else | |
| 1310 | { | |
| 1311 | mame_printf_error("This is not a BS-X compatible cart.\n"); | |
| 1312 | mame_printf_error("This image cannot be loaded in the first cartslot of snesbsx.\n"); | |
| 1313 | return IMAGE_INIT_FAIL; | |
| 1314 | } | |
| 1315 | ||
| 1316 | ||
| 1317 | /* FIXME: Insert crc check here? */ | |
| 1318 | ||
| 1319 | /* How many blocks of data are available to be loaded? */ | |
| 1320 | total_blocks = (state->m_cart_size - offset) / 0x8000; | |
| 1321 | read_blocks = 0; | |
| 1322 | ||
| 1323 | if (SNES_CART_DEBUG) mame_printf_error("blocks %d\n", total_blocks); | |
| 1324 | ||
| 1325 | // actually load the cart | |
| 1326 | while (read_blocks < 64 && read_blocks < total_blocks) | |
| 1327 | { | |
| 1328 | /* Loading data */ | |
| 1329 | memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000); | |
| 1330 | /* Mirroring */ | |
| 1331 | memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000); | |
| 1332 | ||
| 1333 | read_blocks++; | |
| 1334 | } | |
| 1335 | ||
| 1336 | /* Filling banks up to 0x3f and their mirrors */ | |
| 1337 | while (read_blocks % 64) | |
| 1338 | { | |
| 1339 | int j = 0, repeat_blocks; | |
| 1340 | while ((read_blocks % (64 >> j)) && j < 6) | |
| 1341 | j++; | |
| 1342 | repeat_blocks = read_blocks % (64 >> (j - 1)); | |
| 1343 | ||
| 1344 | memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1345 | memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000); | |
| 1346 | read_blocks += repeat_blocks; | |
| 1347 | } | |
| 1348 | ||
| 1349 | return IMAGE_INIT_PASS; | |
| 1350 | } | |
| 1351 | ||
| 1352 | static DEVICE_IMAGE_LOAD( bsx2slot_cart ) | |
| 1353 | { | |
| 1354 | running_machine &machine = image.device().machine(); | |
| 1355 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1356 | UINT32 offset, int_header_offs; | |
| 1357 | UINT8 *ROM = image.device().machine().region("flash")->base(); | |
| 1358 | ||
| 1359 | if (image.software_entry() == NULL) | |
| 1360 | state->m_cart_size = image.length(); | |
| 1361 | else | |
| 1362 | state->m_cart_size = image.get_software_region_length("rom"); | |
| 1363 | ||
| 1364 | /* Check for a header (512 bytes), and skip it if found */ | |
| 1365 | offset = snes_skip_header(image, state->m_cart_size); | |
| 1366 | ||
| 1367 | if (image.software_entry() == NULL) | |
| 1368 | { | |
| 1369 | image.fseek(offset, SEEK_SET); | |
| 1370 | image.fread( ROM, state->m_cart_size - offset); | |
| 1371 | } | |
| 1372 | else | |
| 1373 | memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset); | |
| 1374 | ||
| 1375 | if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset); | |
| 1376 | ||
| 1377 | /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */ | |
| 1378 | int_header_offs = snes_find_hilo_mode(image, ROM, offset, 1); | |
| 1379 | ||
| 1380 | // Detect presence of BS-X Flash Cart | |
| 1381 | if ((ROM[int_header_offs + 0x13] == 0x00 || ROM[int_header_offs + 0x13] == 0xff) && | |
| 1382 | ROM[int_header_offs + 0x14] == 0x00) | |
| 1383 | { | |
| 1384 | UINT8 n15 = ROM[int_header_offs + 0x15]; | |
| 1385 | if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) | |
| 1386 | { | |
| 1387 | if (ROM[int_header_offs + 0x1a] == 0x33 || ROM[int_header_offs + 0x1a] == 0xff) | |
| 1388 | { | |
| 1389 | // BS-X Flash Cart | |
| 1390 | state->m_cart[1].mode = SNES_MODE_BSX; | |
| 1391 | } | |
| 1392 | } | |
| 1393 | } | |
| 1394 | ||
| 1395 | if (state->m_cart[1].mode != SNES_MODE_BSX) | |
| 1396 | { | |
| 1397 | mame_printf_error("This is not a BS-X flash cart.\n"); | |
| 1398 | mame_printf_error("This image cannot be loaded in the second cartslot of snesbsx.\n"); | |
| 1399 | return IMAGE_INIT_FAIL; | |
| 1400 | } | |
| 1401 | ||
| 1402 | // actually load the cart | |
| 1403 | return IMAGE_INIT_PASS; | |
| 1404 | } | |
| 1405 | ||
| 1406 | MACHINE_CONFIG_FRAGMENT( snes_cartslot ) | |
| 1407 | MCFG_CARTSLOT_ADD("cart") | |
| 1408 | MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin") | |
| 1409 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1410 | MCFG_CARTSLOT_INTERFACE("snes_cart") | |
| 1411 | MCFG_CARTSLOT_LOAD(snes_cart) | |
| 1412 | MCFG_SOFTWARE_LIST_ADD("cart_list","snes") | |
| 1413 | MACHINE_CONFIG_END | |
| 1414 | ||
| 1415 | // This (hackily) emulates a SNES unit with a Sufami Turbo Unit cart inserted: | |
| 1416 | // hence, the user can mount two data cart in the two slots available on the ST Unit | |
| 1417 | MACHINE_CONFIG_FRAGMENT( sufami_cartslot ) | |
| 1418 | MCFG_CARTSLOT_ADD("slot_a") | |
| 1419 | MCFG_CARTSLOT_EXTENSION_LIST("st,sfc") | |
| 1420 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1421 | MCFG_CARTSLOT_INTERFACE("sufami_cart") | |
| 1422 | MCFG_CARTSLOT_LOAD(sufami_cart) | |
| 1423 | ||
| 1424 | MCFG_CARTSLOT_ADD("slot_b") | |
| 1425 | MCFG_CARTSLOT_EXTENSION_LIST("st,sfc") | |
| 1426 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1427 | MCFG_CARTSLOT_INTERFACE("sufami_cart") | |
| 1428 | MCFG_CARTSLOT_LOAD(sufami_cart) | |
| 1429 | ||
| 1430 | // MCFG_SOFTWARE_LIST_ADD("cart_list","snes") | |
| 1431 | MACHINE_CONFIG_END | |
| 1432 | ||
| 1433 | // This (hackily) emulates a SNES unit where you want to load a BS-X compatible cart: | |
| 1434 | // hence, the user can mount a SNES cart in the first slot (either a BS-X BIOS cart, or a | |
| 1435 | // BS-X compatible one, e.g. Same Game), and there is a second slot for the 8M data pack | |
| 1436 | // (in a real SNES this would have been inserted in the smaller slot on the cart itself) | |
| 1437 | MACHINE_CONFIG_FRAGMENT( bsx_cartslot ) | |
| 1438 | MCFG_CARTSLOT_ADD("cart") | |
| 1439 | MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin") | |
| 1440 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1441 | MCFG_CARTSLOT_INTERFACE("snes_cart") | |
| 1442 | MCFG_CARTSLOT_LOAD(bsx_cart) | |
| 1443 | ||
| 1444 | MCFG_CARTSLOT_ADD("slot2") | |
| 1445 | MCFG_CARTSLOT_EXTENSION_LIST("bs,sfc") | |
| 1446 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1447 | MCFG_CARTSLOT_INTERFACE("bsx_cart") | |
| 1448 | MCFG_CARTSLOT_LOAD(bsx2slot_cart) | |
| 1449 | ||
| 1450 | // MCFG_SOFTWARE_LIST_ADD("cart_list","snes") | |
| 1451 | MACHINE_CONFIG_END | |
| 1452 | ||
| 1453 | DRIVER_INIT( snes_mess ) | |
| 1454 | { | |
| 1455 | snes_ram = machine.region("maincpu")->base(); | |
| 1456 | memset(snes_ram, 0, 0x1000000); | |
| 1457 | } | |
| 1458 | ||
| 1459 | DRIVER_INIT( snesst ) | |
| 1460 | { | |
| 1461 | snes_state *state = machine.driver_data<snes_state>(); | |
| 1462 | UINT8 *STBIOS = machine.region("sufami")->base(); | |
| 1463 | int i, j; | |
| 1464 | ||
| 1465 | state->m_cart[0].slot_in_use = 0; | |
| 1466 | state->m_cart[1].slot_in_use = 0; | |
| 1467 | ||
| 1468 | DRIVER_INIT_CALL(snes_mess); | |
| 1469 | ||
| 1470 | // the Base ST cart consists of 8 * 0x8000 block which have to be loaded (and mirrored) | |
| 1471 | // at 0x00-0x1f:0x8000-0xffff and 0x80-0x9f:0x8000-0xffff | |
| 1472 | for (i = 0; i < 8; i++) | |
| 1473 | { | |
| 1474 | /* Loading data */ | |
| 1475 | memcpy(&snes_ram[0x008000 + i * 0x10000], &STBIOS[0x000000 + i * 0x8000], 0x8000); | |
| 1476 | /* Mirroring */ | |
| 1477 | memcpy(&snes_ram[0x808000 + i * 0x10000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1478 | ||
| 1479 | /* Additional mirrors (to fill snes_ram up to 0x1fffff) */ | |
| 1480 | for (j = 1; j < 4; j++) | |
| 1481 | { | |
| 1482 | memcpy(&snes_ram[0x008000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1483 | memcpy(&snes_ram[0x808000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000); | |
| 1484 | } | |
| 1485 | } | |
| 1486 | ||
| 1487 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | snescart.h | |
| 3 | ||
| 4 | */ | |
| 5 | ||
| 6 | #ifndef _SNESCART_H | |
| 7 | #define _SNESCART_H | |
| 8 | ||
| 9 | #include "imagedev/cartslot.h" | |
| 10 | ||
| 11 | MACHINE_START( snes_mess ); | |
| 12 | MACHINE_START( snesst ); | |
| 13 | ||
| 14 | DRIVER_INIT( snes_mess ); | |
| 15 | DRIVER_INIT( snesst ); | |
| 16 | ||
| 17 | MACHINE_CONFIG_EXTERN( snes_cartslot ); | |
| 18 | MACHINE_CONFIG_EXTERN( sufami_cartslot ); | |
| 19 | MACHINE_CONFIG_EXTERN( bsx_cartslot ); | |
| 20 | ||
| 21 | #endif /* _SNESCART_H */ | |
| 22 |
| r0 | r11532 | |
|---|---|---|
| 1 | /************************************************************ | |
| 2 | ||
| 3 | PC Engine CD HW notes: | |
| 4 | ||
| 5 | CD Interface Register 0x00 - CDC status | |
| 6 | x--- ---- busy signal | |
| 7 | -x-- ---- request signal | |
| 8 | ---x ---- cd signal | |
| 9 | ---- x--- i/o signal | |
| 10 | ||
| 11 | CD Interface Register 0x03 - BRAM lock / CD status | |
| 12 | -x-- ---- acknowledge signal | |
| 13 | --x- ---- done signal | |
| 14 | ---x ---- bram signal | |
| 15 | ---- x--- ADPCM 2 | |
| 16 | ---- -x-- ADPCM 1 | |
| 17 | ---- --x- CDDA left/right speaker select | |
| 18 | ||
| 19 | CD Interface Register 0x05 - CD-DA Volume low 8-bit port | |
| 20 | ||
| 21 | CD Interface Register 0x06 - CD-DA Volume high 8-bit port | |
| 22 | ||
| 23 | CD Interface Register 0x07 - BRAM unlock / CD status | |
| 24 | x--- ---- Enables BRAM | |
| 25 | ||
| 26 | CD Interface Register 0x0c - ADPCM status | |
| 27 | x--- ---- ADPCM is reading data | |
| 28 | ---- x--- ADPCM playback (0) stopped (1) currently playing | |
| 29 | ---- -x-- pending ADPCM data write | |
| 30 | ---- ---x ADPCM playback (1) stopped (0) currently playing | |
| 31 | ||
| 32 | CD Interface Register 0x0d - ADPCM address control | |
| 33 | x--- ---- ADPCM reset | |
| 34 | -x-- ---- ADPCM play | |
| 35 | --x- ---- ADPCM repeat | |
| 36 | ---x ---- ADPCM set length | |
| 37 | ---- x--- ADPCM set read address | |
| 38 | ---- --xx ADPCM set write address | |
| 39 | (note: some games reads bit 5 and wants it to be low otherwise they hangs, surely NOT an ADPCM repeat flag read because it doesn't make sense) | |
| 40 | ||
| 41 | CD Interface Register 0x0e - ADPCM playback rate | |
| 42 | ||
| 43 | CD Interface Register 0x0f - ADPCM fade in/out register | |
| 44 | ---- xxxx command setting: | |
| 45 | 0x00 ADPCM/CD-DA Fade-in | |
| 46 | 0x01 CD-DA fade-in | |
| 47 | 0x08 CD-DA fade-out (short) ADPCM fade-in | |
| 48 | 0x09 CD-DA fade-out (long) | |
| 49 | 0x0a ADPCM fade-out (long) | |
| 50 | 0x0c CD-DA fade-out (short) ADPCM fade-in | |
| 51 | 0x0d CD-DA fade-out (short) | |
| 52 | 0x0e ADPCM fade-out (short) | |
| 53 | ||
| 54 | *************************************************************/ | |
| 55 | ||
| 56 | #include "emu.h" | |
| 57 | #include "coreutil.h" | |
| 58 | #include "cpu/h6280/h6280.h" | |
| 59 | #include "includes/pce.h" | |
| 60 | #include "imagedev/chd_cd.h" | |
| 61 | #include "sound/msm5205.h" | |
| 62 | #include "sound/cdda.h" | |
| 63 | #include "hashfile.h" | |
| 64 | ||
| 65 | ||
| 66 | #define PCE_BRAM_SIZE 0x800 | |
| 67 | #define PCE_ADPCM_RAM_SIZE 0x10000 | |
| 68 | #define PCE_ACARD_RAM_SIZE 0x200000 | |
| 69 | #define PCE_CD_COMMAND_BUFFER_SIZE 0x100 | |
| 70 | ||
| 71 | #define PCE_CD_IRQ_TRANSFER_READY 0x40 | |
| 72 | #define PCE_CD_IRQ_TRANSFER_DONE 0x20 | |
| 73 | #define PCE_CD_IRQ_SAMPLE_FULL_PLAY 0x08 | |
| 74 | #define PCE_CD_IRQ_SAMPLE_HALF_PLAY 0x04 | |
| 75 | ||
| 76 | #define PCE_CD_ADPCM_PLAY_FLAG 0x08 | |
| 77 | #define PCE_CD_ADPCM_STOP_FLAG 0x01 | |
| 78 | ||
| 79 | #define PCE_CD_DATA_FRAMES_PER_SECOND 75 | |
| 80 | ||
| 81 | enum { | |
| 82 | PCE_CD_CDDA_OFF=0, | |
| 83 | PCE_CD_CDDA_PLAYING, | |
| 84 | PCE_CD_CDDA_PAUSED | |
| 85 | }; | |
| 86 | ||
| 87 | ||
| 88 | /* CD Unit RAM */ | |
| 89 | ||
| 90 | /* MSM5205 ADPCM decoder definition */ | |
| 91 | static void pce_cd_msm5205_int(device_t *device); | |
| 92 | const msm5205_interface pce_cd_msm5205_interface = { | |
| 93 | pce_cd_msm5205_int, /* interrupt function */ | |
| 94 | MSM5205_S48_4B /* 1/48 prescaler, 4bit data */ | |
| 95 | }; | |
| 96 | ||
| 97 | ||
| 98 | /* joystick related data*/ | |
| 99 | ||
| 100 | #define JOY_CLOCK 0x01 | |
| 101 | #define JOY_RESET 0x02 | |
| 102 | ||
| 103 | ||
| 104 | /* prototypes */ | |
| 105 | static void pce_cd_init( running_machine &machine ); | |
| 106 | static void pce_cd_set_irq_line( running_machine &machine, int num, int state ); | |
| 107 | static TIMER_CALLBACK( pce_cd_adpcm_dma_timer_callback ); | |
| 108 | static TIMER_CALLBACK( pce_cd_cdda_fadeout_callback ); | |
| 109 | static TIMER_CALLBACK( pce_cd_cdda_fadein_callback ); | |
| 110 | static TIMER_CALLBACK( pce_cd_adpcm_fadeout_callback ); | |
| 111 | static TIMER_CALLBACK( pce_cd_adpcm_fadein_callback ); | |
| 112 | ||
| 113 | static WRITE8_HANDLER( pce_sf2_banking_w ) | |
| 114 | { | |
| 115 | memory_set_bankptr( space->machine(), "bank2", space->machine().region("user1")->base() + offset * 0x080000 + 0x080000 ); | |
| 116 | memory_set_bankptr( space->machine(), "bank3", space->machine().region("user1")->base() + offset * 0x080000 + 0x088000 ); | |
| 117 | memory_set_bankptr( space->machine(), "bank4", space->machine().region("user1")->base() + offset * 0x080000 + 0x0D0000 ); | |
| 118 | } | |
| 119 | ||
| 120 | static WRITE8_HANDLER( pce_cartridge_ram_w ) | |
| 121 | { | |
| 122 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 123 | state->m_cartridge_ram[offset] = data; | |
| 124 | } | |
| 125 | ||
| 126 | DEVICE_IMAGE_LOAD(pce_cart) | |
| 127 | { | |
| 128 | pce_state *state = image.device().machine().driver_data<pce_state>(); | |
| 129 | UINT32 size; | |
| 130 | int split_rom = 0, offset = 0; | |
| 131 | const char *extrainfo = NULL; | |
| 132 | unsigned char *ROM; | |
| 133 | logerror("*** DEVICE_IMAGE_LOAD(pce_cart) : %s\n", image.filename()); | |
| 134 | ||
| 135 | /* open file to get size */ | |
| 136 | ROM = image.device().machine().region("user1")->base(); | |
| 137 | ||
| 138 | if (image.software_entry() == NULL) | |
| 139 | size = image.length(); | |
| 140 | else | |
| 141 | size = image.get_software_region_length("rom"); | |
| 142 | ||
| 143 | /* handle header accordingly */ | |
| 144 | if ((size / 512) & 1) | |
| 145 | { | |
| 146 | logerror("*** DEVICE_IMAGE_LOAD(pce_cart) : Header present\n"); | |
| 147 | size -= 512; | |
| 148 | offset = 512; | |
| 149 | } | |
| 150 | ||
| 151 | if (size > PCE_ROM_MAXSIZE) | |
| 152 | size = PCE_ROM_MAXSIZE; | |
| 153 | ||
| 154 | if (image.software_entry() == NULL) | |
| 155 | { | |
| 156 | image.fseek(offset, SEEK_SET); | |
| 157 | image.fread( ROM, size); | |
| 158 | extrainfo = hashfile_extrainfo(image); | |
| 159 | } | |
| 160 | else | |
| 161 | memcpy(ROM, image.get_software_region("rom") + offset, size); | |
| 162 | ||
| 163 | if (extrainfo) | |
| 164 | { | |
| 165 | logerror("extrainfo: %s\n", extrainfo); | |
| 166 | if (strstr(extrainfo, "ROM_SPLIT")) | |
| 167 | split_rom = 1; | |
| 168 | } | |
| 169 | ||
| 170 | if (ROM[0x1fff] < 0xe0) | |
| 171 | { | |
| 172 | int i; | |
| 173 | UINT8 decrypted[256]; | |
| 174 | ||
| 175 | logerror( "*** DEVICE_IMAGE_LOAD(pce_cart) : ROM image seems encrypted, decrypting...\n" ); | |
| 176 | ||
| 177 | /* Initialize decryption table */ | |
| 178 | for (i = 0; i < 256; i++) | |
| 179 | decrypted[i] = ((i & 0x01) << 7) | ((i & 0x02) << 5) | ((i & 0x04) << 3) | ((i & 0x08) << 1) | ((i & 0x10) >> 1) | ((i & 0x20 ) >> 3) | ((i & 0x40) >> 5) | ((i & 0x80) >> 7); | |
| 180 | ||
| 181 | /* Decrypt ROM image */ | |
| 182 | for (i = 0; i < size; i++) | |
| 183 | ROM[i] = decrypted[ROM[i]]; | |
| 184 | } | |
| 185 | ||
| 186 | /* check if we're dealing with a split rom image */ | |
| 187 | if (size == 384 * 1024) | |
| 188 | { | |
| 189 | split_rom = 1; | |
| 190 | /* Mirror the upper 128KB part of the image */ | |
| 191 | memcpy(ROM + 0x060000, ROM + 0x040000, 0x020000); /* Set up 060000 - 07FFFF mirror */ | |
| 192 | } | |
| 193 | ||
| 194 | /* set up the memory for a split rom image */ | |
| 195 | if (split_rom) | |
| 196 | { | |
| 197 | logerror("Split rom detected, setting up memory accordingly\n"); | |
| 198 | /* Set up ROM address space as follows: */ | |
| 199 | /* 000000 - 03FFFF : ROM data 000000 - 03FFFF */ | |
| 200 | /* 040000 - 07FFFF : ROM data 000000 - 03FFFF */ | |
| 201 | /* 080000 - 0BFFFF : ROM data 040000 - 07FFFF */ | |
| 202 | /* 0C0000 - 0FFFFF : ROM data 040000 - 07FFFF */ | |
| 203 | memcpy(ROM + 0x080000, ROM + 0x040000, 0x040000); /* Set up 080000 - 0BFFFF region */ | |
| 204 | memcpy(ROM + 0x0C0000, ROM + 0x040000, 0x040000); /* Set up 0C0000 - 0FFFFF region */ | |
| 205 | memcpy(ROM + 0x040000, ROM, 0x040000); /* Set up 040000 - 07FFFF region */ | |
| 206 | } | |
| 207 | else | |
| 208 | { | |
| 209 | /* mirror 256KB rom data */ | |
| 210 | if (size <= 0x040000) | |
| 211 | memcpy(ROM + 0x040000, ROM, 0x040000); | |
| 212 | ||
| 213 | /* mirror 512KB rom data */ | |
| 214 | if (size <= 0x080000) | |
| 215 | memcpy(ROM + 0x080000, ROM, 0x080000); | |
| 216 | } | |
| 217 | ||
| 218 | memory_set_bankptr(image.device().machine(), "bank1", ROM); | |
| 219 | memory_set_bankptr(image.device().machine(), "bank2", ROM + 0x080000); | |
| 220 | memory_set_bankptr(image.device().machine(), "bank3", ROM + 0x088000); | |
| 221 | memory_set_bankptr(image.device().machine(), "bank4", ROM + 0x0d0000); | |
| 222 | ||
| 223 | /* Check for Street fighter 2 */ | |
| 224 | if (size == PCE_ROM_MAXSIZE) | |
| 225 | { | |
| 226 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x01ff0, 0x01ff3, FUNC(pce_sf2_banking_w)); | |
| 227 | } | |
| 228 | ||
| 229 | /* Check for Populous */ | |
| 230 | if (!memcmp(ROM + 0x1F26, "POPULOUS", 8)) | |
| 231 | { | |
| 232 | state->m_cartridge_ram = auto_alloc_array(image.device().machine(), UINT8, 0x8000); | |
| 233 | memory_set_bankptr(image.device().machine(), "bank2", state->m_cartridge_ram); | |
| 234 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x080000, 0x087FFF, FUNC(pce_cartridge_ram_w)); | |
| 235 | } | |
| 236 | ||
| 237 | /* Check for CD system card */ | |
| 238 | state->m_sys3_card = 0; | |
| 239 | if (!memcmp(ROM + 0x3FFB6, "PC Engine CD-ROM SYSTEM", 23)) | |
| 240 | { | |
| 241 | /* Check if 192KB additional system card ram should be used */ | |
| 242 | if(!memcmp(ROM + 0x29D1, "VER. 3.", 7)) { state->m_sys3_card = 1; } // JP version | |
| 243 | else if(!memcmp(ROM + 0x29C4, "VER. 3.", 7 )) { state->m_sys3_card = 3; } // US version | |
| 244 | ||
| 245 | if(state->m_sys3_card) | |
| 246 | { | |
| 247 | state->m_cartridge_ram = auto_alloc_array(image.device().machine(), UINT8, 0x30000); | |
| 248 | memory_set_bankptr(image.device().machine(), "bank4", state->m_cartridge_ram); | |
| 249 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x0D0000, 0x0FFFFF, FUNC(pce_cartridge_ram_w)); | |
| 250 | image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x080000, 0x087FFF, FUNC(pce_cd_acard_wram_r),FUNC(pce_cd_acard_wram_w)); | |
| 251 | } | |
| 252 | } | |
| 253 | return 0; | |
| 254 | } | |
| 255 | ||
| 256 | #ifdef MESS | |
| 257 | DRIVER_INIT( pce ) | |
| 258 | { | |
| 259 | pce_state *state = machine.driver_data<pce_state>(); | |
| 260 | state->m_io_port_options = PCE_JOY_SIG | CONST_SIG; | |
| 261 | } | |
| 262 | #endif | |
| 263 | ||
| 264 | DRIVER_INIT( tg16 ) | |
| 265 | { | |
| 266 | pce_state *state = machine.driver_data<pce_state>(); | |
| 267 | state->m_io_port_options = TG_16_JOY_SIG | CONST_SIG; | |
| 268 | } | |
| 269 | ||
| 270 | DRIVER_INIT( sgx ) | |
| 271 | { | |
| 272 | pce_state *state = machine.driver_data<pce_state>(); | |
| 273 | state->m_io_port_options = PCE_JOY_SIG | CONST_SIG; | |
| 274 | } | |
| 275 | ||
| 276 | MACHINE_START( pce ) | |
| 277 | { | |
| 278 | pce_cd_init( machine ); | |
| 279 | } | |
| 280 | ||
| 281 | #ifdef MESS | |
| 282 | MACHINE_RESET( pce ) | |
| 283 | { | |
| 284 | pce_state *state = machine.driver_data<pce_state>(); | |
| 285 | pce_cd_t &pce_cd = state->m_cd; | |
| 286 | int joy_i; | |
| 287 | ||
| 288 | for (joy_i = 0; joy_i < 5; joy_i++) | |
| 289 | state->m_joy_6b_packet[joy_i] = 0; | |
| 290 | ||
| 291 | pce_cd.adpcm_read_buf = 0; | |
| 292 | pce_cd.adpcm_write_buf = 0; | |
| 293 | ||
| 294 | // TODO: add CD-DA stop command here | |
| 295 | ||
| 296 | pce_cd.regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG; | |
| 297 | pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG; | |
| 298 | //pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c) | (PCE_CD_SAMPLE_STOP_PLAY); | |
| 299 | ||
| 300 | /* Note: Arcade Card BIOS contents are the same as System 3, only internal HW differs. | |
| 301 | We use a category to select between modes (some games can be run in either S-CD or A-CD modes) */ | |
| 302 | state->m_acard = input_port_read(machine, "A_CARD") & 1; | |
| 303 | } | |
| 304 | ||
| 305 | /* todo: how many input ports does the PCE have? */ | |
| 306 | WRITE8_HANDLER ( pce_joystick_w ) | |
| 307 | { | |
| 308 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 309 | int joy_i; | |
| 310 | UINT8 joy_type = input_port_read(space->machine(),"JOY_TYPE"); | |
| 311 | ||
| 312 | h6280io_set_buffer(&space->device(), data); | |
| 313 | ||
| 314 | /* bump counter on a low-to-high transition of bit 1 */ | |
| 315 | if ((!state->m_joystick_data_select) && (data & JOY_CLOCK)) | |
| 316 | { | |
| 317 | state->m_joystick_port_select = (state->m_joystick_port_select + 1) & 0x07; | |
| 318 | } | |
| 319 | ||
| 320 | /* do we want buttons or direction? */ | |
| 321 | state->m_joystick_data_select = data & JOY_CLOCK; | |
| 322 | ||
| 323 | /* clear counter if bit 2 is set */ | |
| 324 | if (data & JOY_RESET) | |
| 325 | { | |
| 326 | state->m_joystick_port_select = 0; | |
| 327 | ||
| 328 | for (joy_i = 0; joy_i < 5; joy_i++) | |
| 329 | { | |
| 330 | if (((joy_type >> (joy_i*2)) & 3) == 2) | |
| 331 | state->m_joy_6b_packet[joy_i] ^= 1; | |
| 332 | } | |
| 333 | } | |
| 334 | } | |
| 335 | ||
| 336 | READ8_HANDLER ( pce_joystick_r ) | |
| 337 | { | |
| 338 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 339 | static const char *const joyname[4][5] = { | |
| 340 | { "JOY_P1", "JOY_P2", "JOY_P3", "JOY_P4", "JOY_P5" }, | |
| 341 | { }, | |
| 342 | { "JOY6B_P1", "JOY6B_P2", "JOY6B_P3", "JOY6B_P4", "JOY6B_P5" }, | |
| 343 | { } | |
| 344 | }; | |
| 345 | UINT8 joy_type = input_port_read(space->machine(), "JOY_TYPE"); | |
| 346 | UINT8 ret, data; | |
| 347 | ||
| 348 | if (state->m_joystick_port_select <= 4) | |
| 349 | { | |
| 350 | switch((joy_type >> (state->m_joystick_port_select*2)) & 3) | |
| 351 | { | |
| 352 | case 0: //2-buttons pad | |
| 353 | data = input_port_read(space->machine(), joyname[0][state->m_joystick_port_select]); | |
| 354 | break; | |
| 355 | case 2: //6-buttons pad | |
| 356 | /* | |
| 357 | Two packets: | |
| 358 | 1st packet: directions + I, II, Run, Select | |
| 359 | 2nd packet: 6 buttons "header" (high 4 bits active low) + III, IV, V, VI | |
| 360 | Note that six buttons pad just doesn't work with (almost?) every single 2-button-only games, it's really just an after-thought and it is like this | |
| 361 | on real HW. | |
| 362 | */ | |
| 363 | data = input_port_read(space->machine(), joyname[2][state->m_joystick_port_select]) >> (state->m_joy_6b_packet[state->m_joystick_port_select]*8); | |
| 364 | break; | |
| 365 | default: | |
| 366 | data = 0xff; | |
| 367 | break; | |
| 368 | } | |
| 369 | } | |
| 370 | else | |
| 371 | data = 0xff; | |
| 372 | ||
| 373 | ||
| 374 | if (state->m_joystick_data_select) | |
| 375 | data >>= 4; | |
| 376 | ||
| 377 | ret = (data & 0x0f) | state->m_io_port_options; | |
| 378 | #ifdef UNIFIED_PCE | |
| 379 | ret &= ~0x40; | |
| 380 | #endif | |
| 381 | ||
| 382 | return (ret); | |
| 383 | } | |
| 384 | #endif | |
| 385 | NVRAM_HANDLER( pce ) | |
| 386 | { | |
| 387 | pce_state *state = machine.driver_data<pce_state>(); | |
| 388 | pce_cd_t &pce_cd = state->m_cd; | |
| 389 | if (read_or_write) | |
| 390 | { | |
| 391 | file->write(pce_cd.bram, PCE_BRAM_SIZE); | |
| 392 | } | |
| 393 | else | |
| 394 | { | |
| 395 | /* load battery backed memory from disk */ | |
| 396 | if (file) | |
| 397 | file->read(pce_cd.bram, PCE_BRAM_SIZE); | |
| 398 | } | |
| 399 | } | |
| 400 | ||
| 401 | static void pce_set_cd_bram( running_machine &machine ) | |
| 402 | { | |
| 403 | pce_state *state = machine.driver_data<pce_state>(); | |
| 404 | pce_cd_t &pce_cd = state->m_cd; | |
| 405 | memory_set_bankptr( machine, "bank10", pce_cd.bram + ( pce_cd.bram_locked ? PCE_BRAM_SIZE : 0 ) ); | |
| 406 | } | |
| 407 | ||
| 408 | static void adpcm_stop(running_machine &machine) | |
| 409 | { | |
| 410 | pce_state *state = machine.driver_data<pce_state>(); | |
| 411 | pce_cd_t &pce_cd = state->m_cd; | |
| 412 | pce_cd.regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG; | |
| 413 | pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG; | |
| 414 | //pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c) | (PCE_CD_SAMPLE_STOP_PLAY); | |
| 415 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE ); | |
| 416 | pce_cd.regs[0x0d] &= ~0x60; | |
| 417 | pce_cd.msm_idle = 1; | |
| 418 | } | |
| 419 | ||
| 420 | static void adpcm_play(running_machine &machine) | |
| 421 | { | |
| 422 | pce_state *state = machine.driver_data<pce_state>(); | |
| 423 | pce_cd_t &pce_cd = state->m_cd; | |
| 424 | pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_STOP_FLAG; | |
| 425 | pce_cd.regs[0x0c] |= PCE_CD_ADPCM_PLAY_FLAG; | |
| 426 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE ); | |
| 427 | pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c); | |
| 428 | pce_cd.msm_idle = 0; | |
| 429 | } | |
| 430 | ||
| 431 | ||
| 432 | /* Callback for new data from the MSM5205. | |
| 433 | The PCE cd unit actually divides the clock signal supplied to | |
| 434 | the MSM5205. Currently we can only use static clocks for the | |
| 435 | MSM5205. | |
| 436 | */ | |
| 437 | static void pce_cd_msm5205_int(device_t *device) | |
| 438 | { | |
| 439 | pce_state *state = device->machine().driver_data<pce_state>(); | |
| 440 | pce_cd_t &pce_cd = state->m_cd; | |
| 441 | UINT8 msm_data; | |
| 442 | ||
| 443 | // popmessage("%08x %08x %08x %02x %02x",pce_cd.msm_start_addr,pce_cd.msm_end_addr,pce_cd.msm_half_addr,pce_cd.regs[0x0c],pce_cd.regs[0x0d]); | |
| 444 | ||
| 445 | if ( pce_cd.msm_idle ) | |
| 446 | return; | |
| 447 | ||
| 448 | /* Supply new ADPCM data */ | |
| 449 | msm_data = (pce_cd.msm_nibble) ? (pce_cd.adpcm_ram[pce_cd.msm_start_addr] & 0x0f) : ((pce_cd.adpcm_ram[pce_cd.msm_start_addr] & 0xf0) >> 4); | |
| 450 | ||
| 451 | msm5205_data_w(device, msm_data); | |
| 452 | pce_cd.msm_nibble ^= 1; | |
| 453 | ||
| 454 | if(pce_cd.msm_nibble == 0) | |
| 455 | { | |
| 456 | pce_cd.msm_start_addr++; | |
| 457 | ||
| 458 | if(pce_cd.msm_start_addr == pce_cd.msm_half_addr) | |
| 459 | { | |
| 460 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE ); | |
| 461 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE ); | |
| 462 | } | |
| 463 | ||
| 464 | if(pce_cd.msm_start_addr > pce_cd.msm_end_addr) | |
| 465 | { | |
| 466 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE ); | |
| 467 | //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE ); | |
| 468 | adpcm_stop(device->machine()); | |
| 469 | msm5205_reset_w(device, 1); | |
| 470 | } | |
| 471 | } | |
| 472 | } | |
| 473 | ||
| 474 | #define SCSI_STATUS_OK 0x00 | |
| 475 | #define SCSI_CHECK_CONDITION 0x02 | |
| 476 | ||
| 477 | static void pce_cd_reply_status_byte( pce_state *state, UINT8 status ) | |
| 478 | { | |
| 479 | pce_cd_t &pce_cd = state->m_cd; | |
| 480 | logerror("Setting CD in reply_status_byte\n"); | |
| 481 | pce_cd.scsi_CD = pce_cd.scsi_IO = pce_cd.scsi_REQ = 1; | |
| 482 | pce_cd.scsi_MSG = 0; | |
| 483 | pce_cd.message_after_status = 1; | |
| 484 | pce_cd.status_sent = pce_cd.message_sent = 0; | |
| 485 | ||
| 486 | if ( status == SCSI_STATUS_OK ) | |
| 487 | { | |
| 488 | pce_cd.regs[0x01] = 0x00; | |
| 489 | } | |
| 490 | else | |
| 491 | { | |
| 492 | pce_cd.regs[0x01] = 0x01; | |
| 493 | } | |
| 494 | } | |
| 495 | ||
| 496 | /* 0x00 - TEST UNIT READY */ | |
| 497 | static void pce_cd_test_unit_ready( running_machine &machine ) | |
| 498 | { | |
| 499 | pce_state *state = machine.driver_data<pce_state>(); | |
| 500 | pce_cd_t &pce_cd = state->m_cd; | |
| 501 | logerror("test unit ready\n"); | |
| 502 | if ( pce_cd.cd ) | |
| 503 | { | |
| 504 | logerror( "Sending STATUS_OK status\n" ); | |
| 505 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 506 | } | |
| 507 | else | |
| 508 | { | |
| 509 | logerror( "Sending CHECK_CONDITION status\n" ); | |
| 510 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 511 | } | |
| 512 | } | |
| 513 | ||
| 514 | /* 0x08 - READ (6) */ | |
| 515 | static void pce_cd_read_6( running_machine &machine ) | |
| 516 | { | |
| 517 | pce_state *state = machine.driver_data<pce_state>(); | |
| 518 | pce_cd_t &pce_cd = state->m_cd; | |
| 519 | UINT32 frame = ( ( pce_cd.command_buffer[1] & 0x1F ) << 16 ) | ( pce_cd.command_buffer[2] << 8 ) | pce_cd.command_buffer[3]; | |
| 520 | UINT32 frame_count = pce_cd.command_buffer[4]; | |
| 521 | ||
| 522 | /* Check for presence of a CD */ | |
| 523 | if ( ! pce_cd.cd ) | |
| 524 | { | |
| 525 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 526 | return; | |
| 527 | } | |
| 528 | ||
| 529 | if ( pce_cd.cdda_status != PCE_CD_CDDA_OFF ) | |
| 530 | { | |
| 531 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 532 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 533 | pce_cd.end_mark = 0; | |
| 534 | } | |
| 535 | ||
| 536 | pce_cd.current_frame = frame; | |
| 537 | pce_cd.end_frame = frame + frame_count; | |
| 538 | ||
| 539 | if ( frame_count == 0 ) | |
| 540 | { | |
| 541 | /* Star Breaker uses this */ | |
| 542 | popmessage("Read Sector frame count == 0, contact MESSdev"); | |
| 543 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 544 | } | |
| 545 | else | |
| 546 | { | |
| 547 | pce_cd.data_timer->adjust(attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND ), 0, attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND )); | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | /* 0xD8 - SET AUDIO PLAYBACK START POSITION (NEC) */ | |
| 552 | static void pce_cd_nec_set_audio_start_position( running_machine &machine ) | |
| 553 | { | |
| 554 | pce_state *state = machine.driver_data<pce_state>(); | |
| 555 | pce_cd_t &pce_cd = state->m_cd; | |
| 556 | UINT32 frame = 0; | |
| 557 | ||
| 558 | if ( ! pce_cd.cd ) | |
| 559 | { | |
| 560 | /* Throw some error here */ | |
| 561 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 562 | return; | |
| 563 | } | |
| 564 | ||
| 565 | switch( pce_cd.command_buffer[9] & 0xC0 ) | |
| 566 | { | |
| 567 | case 0x00: | |
| 568 | popmessage("CD-DA set start mode 0x00, contact MESSdev"); | |
| 569 | frame = ( pce_cd.command_buffer[3] << 16 ) | ( pce_cd.command_buffer[4] << 8 ) | pce_cd.command_buffer[5]; | |
| 570 | break; | |
| 571 | case 0x40: | |
| 572 | { | |
| 573 | UINT8 m,s,f; | |
| 574 | ||
| 575 | m = bcd_2_dec( pce_cd.command_buffer[2]); | |
| 576 | s = bcd_2_dec( pce_cd.command_buffer[3]); | |
| 577 | f = bcd_2_dec( pce_cd.command_buffer[4]); | |
| 578 | ||
| 579 | frame = f + 75 * (s + m * 60); | |
| 580 | if(frame >= 525) // TODO: seven seconds gap? O_o | |
| 581 | frame -= 525; | |
| 582 | break; | |
| 583 | } | |
| 584 | case 0x80: | |
| 585 | frame = pce_cd.toc->tracks[ bcd_2_dec( pce_cd.command_buffer[2] ) - 1 ].physframeofs; | |
| 586 | break; | |
| 587 | default: | |
| 588 | popmessage("CD-DA set start mode 0xc0, contact MESSdev"); | |
| 589 | //assert( NULL == pce_cd_nec_set_audio_start_position ); | |
| 590 | break; | |
| 591 | } | |
| 592 | ||
| 593 | pce_cd.current_frame = frame; | |
| 594 | ||
| 595 | if ( pce_cd.cdda_status == PCE_CD_CDDA_PAUSED ) | |
| 596 | { | |
| 597 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 598 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 599 | pce_cd.end_frame = pce_cd.last_frame; | |
| 600 | pce_cd.end_mark = 0; | |
| 601 | } | |
| 602 | else | |
| 603 | { | |
| 604 | if(pce_cd.command_buffer[1] & 0x03) | |
| 605 | { | |
| 606 | pce_cd.cdda_status = PCE_CD_CDDA_PLAYING; | |
| 607 | pce_cd.end_frame = pce_cd.last_frame; //get the end of the CD | |
| 608 | cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); | |
| 609 | pce_cd.cdda_play_mode = (pce_cd.command_buffer[1] & 0x02) ? 2 : 3; // mode 2 sets IRQ at end | |
| 610 | pce_cd.end_mark = (pce_cd.command_buffer[1] & 0x02) ? 1 : 0; | |
| 611 | } | |
| 612 | else | |
| 613 | { | |
| 614 | pce_cd.cdda_status = PCE_CD_CDDA_PLAYING; | |
| 615 | pce_cd.end_frame = pce_cd.toc->tracks[ cdrom_get_track(pce_cd.cd, pce_cd.current_frame) + 1 ].physframeofs; //get the end of THIS track | |
| 616 | cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); | |
| 617 | pce_cd.end_mark = 0; | |
| 618 | pce_cd.cdda_play_mode = 3; | |
| 619 | } | |
| 620 | } | |
| 621 | ||
| 622 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 623 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); | |
| 624 | } | |
| 625 | ||
| 626 | /* 0xD9 - SET AUDIO PLAYBACK END POSITION (NEC) */ | |
| 627 | static void pce_cd_nec_set_audio_stop_position( running_machine &machine ) | |
| 628 | { | |
| 629 | pce_state *state = machine.driver_data<pce_state>(); | |
| 630 | pce_cd_t &pce_cd = state->m_cd; | |
| 631 | UINT32 frame = 0; | |
| 632 | ||
| 633 | if ( ! pce_cd.cd ) | |
| 634 | { | |
| 635 | /* Throw some error here */ | |
| 636 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 637 | return; | |
| 638 | } | |
| 639 | ||
| 640 | switch( pce_cd.command_buffer[9] & 0xC0 ) | |
| 641 | { | |
| 642 | case 0x00: | |
| 643 | popmessage("CD-DA set end mode 0x00, contact MESSdev"); | |
| 644 | frame = ( pce_cd.command_buffer[3] << 16 ) | ( pce_cd.command_buffer[4] << 8 ) | pce_cd.command_buffer[5]; | |
| 645 | break; | |
| 646 | case 0x40: | |
| 647 | { | |
| 648 | UINT8 m,s,f; | |
| 649 | ||
| 650 | m = bcd_2_dec( pce_cd.command_buffer[2]); | |
| 651 | s = bcd_2_dec( pce_cd.command_buffer[3]); | |
| 652 | f = bcd_2_dec( pce_cd.command_buffer[4]); | |
| 653 | ||
| 654 | frame = f + 75 * (s + m * 60); | |
| 655 | if(frame >= 525) // TODO: seven seconds gap? O_o | |
| 656 | frame -= 525; | |
| 657 | break; | |
| 658 | } | |
| 659 | case 0x80: | |
| 660 | frame = pce_cd.toc->tracks[ bcd_2_dec( pce_cd.command_buffer[2] ) - 1 ].physframeofs; | |
| 661 | break; | |
| 662 | default: | |
| 663 | popmessage("CD-DA set end mode 0xc0, contact MESSdev"); | |
| 664 | //assert( NULL == pce_cd_nec_set_audio_start_position ); | |
| 665 | break; | |
| 666 | } | |
| 667 | ||
| 668 | pce_cd.end_frame = frame; | |
| 669 | pce_cd.cdda_play_mode = pce_cd.command_buffer[1] & 0x03; | |
| 670 | ||
| 671 | if ( pce_cd.cdda_play_mode ) | |
| 672 | { | |
| 673 | if ( pce_cd.cdda_status == PCE_CD_CDDA_PAUSED ) | |
| 674 | { | |
| 675 | cdda_pause_audio( machine.device( "cdda" ), 0 ); | |
| 676 | } | |
| 677 | else | |
| 678 | { | |
| 679 | cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); | |
| 680 | pce_cd.end_mark = 1; | |
| 681 | } | |
| 682 | pce_cd.cdda_status = PCE_CD_CDDA_PLAYING; | |
| 683 | } | |
| 684 | else | |
| 685 | { | |
| 686 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 687 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 688 | pce_cd.end_frame = pce_cd.last_frame; | |
| 689 | pce_cd.end_mark = 0; | |
| 690 | // assert( NULL == pce_cd_nec_set_audio_stop_position ); | |
| 691 | } | |
| 692 | ||
| 693 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 694 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); | |
| 695 | } | |
| 696 | ||
| 697 | /* 0xDA - PAUSE (NEC) */ | |
| 698 | static void pce_cd_nec_pause( running_machine &machine ) | |
| 699 | { | |
| 700 | pce_state *state = machine.driver_data<pce_state>(); | |
| 701 | pce_cd_t &pce_cd = state->m_cd; | |
| 702 | ||
| 703 | /* If no cd mounted throw an error */ | |
| 704 | if ( ! pce_cd.cd ) | |
| 705 | { | |
| 706 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 707 | return; | |
| 708 | } | |
| 709 | ||
| 710 | /* If there was no cdda playing, throw an error */ | |
| 711 | if ( pce_cd.cdda_status == PCE_CD_CDDA_OFF ) | |
| 712 | { | |
| 713 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 714 | return; | |
| 715 | } | |
| 716 | ||
| 717 | pce_cd.cdda_status = PCE_CD_CDDA_PAUSED; | |
| 718 | pce_cd.current_frame = cdda_get_audio_lba( machine.device( "cdda" ) ); | |
| 719 | cdda_pause_audio( machine.device( "cdda" ), 1 ); | |
| 720 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 721 | } | |
| 722 | ||
| 723 | /* 0xDD - READ SUBCHANNEL Q (NEC) */ | |
| 724 | static void pce_cd_nec_get_subq( running_machine &machine ) | |
| 725 | { | |
| 726 | pce_state *state = machine.driver_data<pce_state>(); | |
| 727 | pce_cd_t &pce_cd = state->m_cd; | |
| 728 | /* WP - I do not have access to chds with subchannel information yet, so I'm faking something here */ | |
| 729 | UINT32 msf_abs, msf_rel, track, frame; | |
| 730 | ||
| 731 | if ( ! pce_cd.cd ) | |
| 732 | { | |
| 733 | /* Throw some error here */ | |
| 734 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 735 | return; | |
| 736 | } | |
| 737 | ||
| 738 | frame = pce_cd.current_frame; | |
| 739 | ||
| 740 | switch( pce_cd.cdda_status ) | |
| 741 | { | |
| 742 | case PCE_CD_CDDA_PAUSED: | |
| 743 | pce_cd.data_buffer[0] = 2; | |
| 744 | frame = cdda_get_audio_lba( machine.device( "cdda" ) ); | |
| 745 | break; | |
| 746 | case PCE_CD_CDDA_PLAYING: | |
| 747 | pce_cd.data_buffer[0] = 0; | |
| 748 | frame = cdda_get_audio_lba( machine.device( "cdda" ) ); | |
| 749 | break; | |
| 750 | default: | |
| 751 | pce_cd.data_buffer[0] = 3; | |
| 752 | break; | |
| 753 | } | |
| 754 | ||
| 755 | msf_abs = lba_to_msf( frame ); | |
| 756 | track = cdrom_get_track( pce_cd.cd, frame ); | |
| 757 | msf_rel = lba_to_msf( frame - cdrom_get_track_start( pce_cd.cd, track ) ); | |
| 758 | ||
| 759 | pce_cd.data_buffer[1] = 0; | |
| 760 | pce_cd.data_buffer[2] = dec_2_bcd( track+1 ); /* track */ | |
| 761 | pce_cd.data_buffer[3] = 1; /* index */ | |
| 762 | pce_cd.data_buffer[4] = ( msf_rel >> 16 ) & 0xFF; /* M (relative) */ | |
| 763 | pce_cd.data_buffer[5] = ( msf_rel >> 8 ) & 0xFF; /* S (relative) */ | |
| 764 | pce_cd.data_buffer[6] = msf_rel & 0xFF; /* F (relative) */ | |
| 765 | pce_cd.data_buffer[7] = ( msf_abs >> 16 ) & 0xFF; /* M (absolute) */ | |
| 766 | pce_cd.data_buffer[8] = ( msf_abs >> 8 ) & 0xFF; /* S (absolute) */ | |
| 767 | pce_cd.data_buffer[9] = msf_abs & 0xFF; /* F (absolute) */ | |
| 768 | pce_cd.data_buffer_size = 10; | |
| 769 | ||
| 770 | pce_cd.data_buffer_index = 0; | |
| 771 | pce_cd.data_transferred = 1; | |
| 772 | pce_cd.scsi_IO = 1; | |
| 773 | pce_cd.scsi_CD = 0; | |
| 774 | } | |
| 775 | ||
| 776 | /* 0xDE - GET DIR INFO (NEC) */ | |
| 777 | static void pce_cd_nec_get_dir_info( running_machine &machine ) | |
| 778 | { | |
| 779 | pce_state *state = machine.driver_data<pce_state>(); | |
| 780 | pce_cd_t &pce_cd = state->m_cd; | |
| 781 | UINT32 frame, msf, track = 0; | |
| 782 | const cdrom_toc *toc; | |
| 783 | logerror("nec get dir info\n"); | |
| 784 | ||
| 785 | if ( ! pce_cd.cd ) | |
| 786 | { | |
| 787 | /* Throw some error here */ | |
| 788 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 789 | } | |
| 790 | ||
| 791 | toc = cdrom_get_toc( pce_cd.cd ); | |
| 792 | ||
| 793 | switch( pce_cd.command_buffer[1] ) | |
| 794 | { | |
| 795 | case 0x00: /* Get first and last track numbers */ | |
| 796 | pce_cd.data_buffer[0] = dec_2_bcd(1); | |
| 797 | pce_cd.data_buffer[1] = dec_2_bcd(toc->numtrks); | |
| 798 | pce_cd.data_buffer_size = 2; | |
| 799 | break; | |
| 800 | case 0x01: /* Get total disk size in MSF format */ | |
| 801 | frame = toc->tracks[toc->numtrks-1].physframeofs; | |
| 802 | frame += toc->tracks[toc->numtrks-1].frames; | |
| 803 | msf = lba_to_msf( frame + 150 ); | |
| 804 | ||
| 805 | pce_cd.data_buffer[0] = ( msf >> 16 ) & 0xFF; /* M */ | |
| 806 | pce_cd.data_buffer[1] = ( msf >> 8 ) & 0xFF; /* S */ | |
| 807 | pce_cd.data_buffer[2] = msf & 0xFF; /* F */ | |
| 808 | pce_cd.data_buffer_size = 3; | |
| 809 | break; | |
| 810 | case 0x02: /* Get track information */ | |
| 811 | if ( pce_cd.command_buffer[2] == 0xAA ) | |
| 812 | { | |
| 813 | frame = toc->tracks[toc->numtrks-1].physframeofs; | |
| 814 | frame += toc->tracks[toc->numtrks-1].frames; | |
| 815 | pce_cd.data_buffer[3] = 0x04; /* correct? */ | |
| 816 | } else | |
| 817 | { | |
| 818 | track = MAX( bcd_2_dec( pce_cd.command_buffer[2] ), 1 ); | |
| 819 | frame = toc->tracks[track-1].physframeofs; | |
| 820 | pce_cd.data_buffer[3] = ( toc->tracks[track-1].trktype == CD_TRACK_AUDIO ) ? 0x00 : 0x04; | |
| 821 | } | |
| 822 | logerror("track = %d, frame = %d\n", track, frame ); | |
| 823 | msf = lba_to_msf( frame + 150 ); | |
| 824 | pce_cd.data_buffer[0] = ( msf >> 16 ) & 0xFF; /* M */ | |
| 825 | pce_cd.data_buffer[1] = ( msf >> 8 ) & 0xFF; /* S */ | |
| 826 | pce_cd.data_buffer[2] = msf & 0xFF; /* F */ | |
| 827 | pce_cd.data_buffer_size = 4; | |
| 828 | break; | |
| 829 | default: | |
| 830 | // assert( pce_cd_nec_get_dir_info == NULL ); // Not implemented yet | |
| 831 | break; | |
| 832 | } | |
| 833 | ||
| 834 | pce_cd.data_buffer_index = 0; | |
| 835 | pce_cd.data_transferred = 1; | |
| 836 | pce_cd.scsi_IO = 1; | |
| 837 | pce_cd.scsi_CD = 0; | |
| 838 | } | |
| 839 | ||
| 840 | static void pce_cd_end_of_list( running_machine &machine ) | |
| 841 | { | |
| 842 | pce_state *state = machine.driver_data<pce_state>(); | |
| 843 | pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION ); | |
| 844 | } | |
| 845 | ||
| 846 | static void pce_cd_handle_data_output( running_machine &machine ) | |
| 847 | { | |
| 848 | pce_state *state = machine.driver_data<pce_state>(); | |
| 849 | pce_cd_t &pce_cd = state->m_cd; | |
| 850 | static const struct { | |
| 851 | UINT8 command_byte; | |
| 852 | UINT8 command_size; | |
| 853 | void (*command_handler)(running_machine &machine); | |
| 854 | } pce_cd_commands[] = { | |
| 855 | { 0x00, 6, pce_cd_test_unit_ready }, /* TEST UNIT READY */ | |
| 856 | { 0x08, 6, pce_cd_read_6 }, /* READ (6) */ | |
| 857 | { 0xD8,10, pce_cd_nec_set_audio_start_position }, /* NEC SET AUDIO PLAYBACK START POSITION */ | |
| 858 | { 0xD9,10, pce_cd_nec_set_audio_stop_position }, /* NEC SET AUDIO PLAYBACK END POSITION */ | |
| 859 | { 0xDA,10, pce_cd_nec_pause }, /* NEC PAUSE */ | |
| 860 | { 0xDD,10, pce_cd_nec_get_subq }, /* NEC GET SUBCHANNEL Q */ | |
| 861 | { 0xDE,10, pce_cd_nec_get_dir_info }, /* NEC GET DIR INFO */ | |
| 862 | { 0xFF, 1, pce_cd_end_of_list } /* end of list marker */ | |
| 863 | }; | |
| 864 | ||
| 865 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 866 | { | |
| 867 | /* Command byte received */ | |
| 868 | logerror( "Command byte $%02X received\n", pce_cd.regs[0x01] ); | |
| 869 | ||
| 870 | /* Check for buffer overflow */ | |
| 871 | assert( pce_cd.command_buffer_index < PCE_CD_COMMAND_BUFFER_SIZE ); | |
| 872 | ||
| 873 | pce_cd.command_buffer[pce_cd.command_buffer_index] = pce_cd.regs[0x01]; | |
| 874 | pce_cd.command_buffer_index++; | |
| 875 | pce_cd.scsi_REQ = 0; | |
| 876 | } | |
| 877 | ||
| 878 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.command_buffer_index ) | |
| 879 | { | |
| 880 | int i = 0; | |
| 881 | ||
| 882 | logerror( "Check if command done\n" ); | |
| 883 | ||
| 884 | for( i = 0; pce_cd.command_buffer[0] > pce_cd_commands[i].command_byte; i++ ); | |
| 885 | ||
| 886 | /* Check for unknown commands */ | |
| 887 | if ( pce_cd.command_buffer[0] != pce_cd_commands[i].command_byte ) | |
| 888 | { | |
| 889 | logerror("Unrecognized command: %02X\n", pce_cd.command_buffer[0] ); | |
| 890 | if(pce_cd.command_buffer[0] == 0x03) | |
| 891 | popmessage("CD command 0x03 issued (Request Sense), contact MESSdev"); | |
| 892 | } | |
| 893 | assert( pce_cd.command_buffer[0] == pce_cd_commands[i].command_byte ); | |
| 894 | ||
| 895 | if ( pce_cd.command_buffer_index == pce_cd_commands[i].command_size ) | |
| 896 | { | |
| 897 | (pce_cd_commands[i].command_handler)( machine ); | |
| 898 | pce_cd.command_buffer_index = 0; | |
| 899 | } | |
| 900 | else | |
| 901 | { | |
| 902 | pce_cd.scsi_REQ = 1; | |
| 903 | } | |
| 904 | } | |
| 905 | } | |
| 906 | ||
| 907 | static void pce_cd_handle_data_input( running_machine &machine ) | |
| 908 | { | |
| 909 | pce_state *state = machine.driver_data<pce_state>(); | |
| 910 | pce_cd_t &pce_cd = state->m_cd; | |
| 911 | if ( pce_cd.scsi_CD ) | |
| 912 | { | |
| 913 | /* Command / Status byte */ | |
| 914 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 915 | { | |
| 916 | logerror( "status sent\n" ); | |
| 917 | pce_cd.scsi_REQ = 0; | |
| 918 | pce_cd.status_sent = 1; | |
| 919 | } | |
| 920 | ||
| 921 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.status_sent ) | |
| 922 | { | |
| 923 | pce_cd.status_sent = 0; | |
| 924 | if ( pce_cd.message_after_status ) | |
| 925 | { | |
| 926 | logerror( "message after status\n" ); | |
| 927 | pce_cd.message_after_status = 0; | |
| 928 | pce_cd.scsi_MSG = pce_cd.scsi_REQ = 1; | |
| 929 | pce_cd.regs[0x01] = 0; | |
| 930 | } | |
| 931 | } | |
| 932 | } | |
| 933 | else | |
| 934 | { | |
| 935 | /* Data */ | |
| 936 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 937 | { | |
| 938 | pce_cd.scsi_REQ = 0; | |
| 939 | } | |
| 940 | ||
| 941 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK ) | |
| 942 | { | |
| 943 | if ( pce_cd.data_buffer_index == pce_cd.data_buffer_size ) | |
| 944 | { | |
| 945 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE ); | |
| 946 | if ( pce_cd.data_transferred ) | |
| 947 | { | |
| 948 | pce_cd.data_transferred = 0; | |
| 949 | pce_cd_reply_status_byte( state, SCSI_STATUS_OK ); | |
| 950 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); | |
| 951 | } | |
| 952 | } | |
| 953 | else | |
| 954 | { | |
| 955 | logerror("Transfer byte from offset %d\n", pce_cd.data_buffer_index); | |
| 956 | pce_cd.regs[0x01] = pce_cd.data_buffer[pce_cd.data_buffer_index]; | |
| 957 | pce_cd.data_buffer_index++; | |
| 958 | pce_cd.scsi_REQ = 1; | |
| 959 | } | |
| 960 | } | |
| 961 | } | |
| 962 | } | |
| 963 | ||
| 964 | static void pce_cd_handle_message_output( pce_state *state ) | |
| 965 | { | |
| 966 | pce_cd_t &pce_cd = state->m_cd; | |
| 967 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 968 | { | |
| 969 | pce_cd.scsi_REQ = 0; | |
| 970 | } | |
| 971 | } | |
| 972 | ||
| 973 | static void pce_cd_handle_message_input( pce_state *state ) | |
| 974 | { | |
| 975 | pce_cd_t &pce_cd = state->m_cd; | |
| 976 | if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK ) | |
| 977 | { | |
| 978 | pce_cd.scsi_REQ = 0; | |
| 979 | pce_cd.message_sent = 1; | |
| 980 | } | |
| 981 | ||
| 982 | if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.message_sent ) | |
| 983 | { | |
| 984 | pce_cd.message_sent = 0; | |
| 985 | pce_cd.scsi_BSY = 0; | |
| 986 | } | |
| 987 | } | |
| 988 | ||
| 989 | /* Update internal CD statuses */ | |
| 990 | static void pce_cd_update( running_machine &machine ) | |
| 991 | { | |
| 992 | pce_state *state = machine.driver_data<pce_state>(); | |
| 993 | pce_cd_t &pce_cd = state->m_cd; | |
| 994 | /* Check for reset of CD unit */ | |
| 995 | if ( pce_cd.scsi_RST != pce_cd.scsi_last_RST ) | |
| 996 | { | |
| 997 | if ( pce_cd.scsi_RST ) | |
| 998 | { | |
| 999 | logerror("Performing CD reset\n"); | |
| 1000 | /* Reset internal data */ | |
| 1001 | pce_cd.scsi_BSY = pce_cd.scsi_SEL = pce_cd.scsi_CD = pce_cd.scsi_IO = 0; | |
| 1002 | pce_cd.scsi_MSG = pce_cd.scsi_REQ = pce_cd.scsi_ATN = 0; | |
| 1003 | pce_cd.cd_motor_on = 0; | |
| 1004 | pce_cd.selected = 0; | |
| 1005 | pce_cd.cdda_status = PCE_CD_CDDA_OFF; | |
| 1006 | cdda_stop_audio( machine.device( "cdda" ) ); | |
| 1007 | pce_cd.adpcm_dma_timer->adjust(attotime::never); // stop ADPCM DMA here | |
| 1008 | } | |
| 1009 | pce_cd.scsi_last_RST = pce_cd.scsi_RST; | |
| 1010 | } | |
| 1011 | ||
| 1012 | /* Check if bus can be freed */ | |
| 1013 | if ( ! pce_cd.scsi_SEL && ! pce_cd.scsi_BSY && pce_cd.selected ) | |
| 1014 | { | |
| 1015 | logerror( "freeing bus\n" ); | |
| 1016 | pce_cd.selected = 0; | |
| 1017 | pce_cd.scsi_CD = pce_cd.scsi_MSG = pce_cd.scsi_IO = pce_cd.scsi_REQ = 0; | |
| 1018 | pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, CLEAR_LINE ); | |
| 1019 | } | |
| 1020 | ||
| 1021 | /* Select the CD device */ | |
| 1022 | if ( pce_cd.scsi_SEL ) | |
| 1023 | { | |
| 1024 | if ( ! pce_cd.selected ) | |
| 1025 | { | |
| 1026 | pce_cd.selected = 1; | |
| 1027 | logerror("Setting CD in device selection\n"); | |
| 1028 | pce_cd.scsi_BSY = pce_cd.scsi_REQ = pce_cd.scsi_CD = 1; | |
| 1029 | pce_cd.scsi_MSG = pce_cd.scsi_IO = 0; | |
| 1030 | } | |
| 1031 | } | |
| 1032 | ||
| 1033 | if ( pce_cd.scsi_ATN ) | |
| 1034 | { | |
| 1035 | } | |
| 1036 | else | |
| 1037 | { | |
| 1038 | /* Check for data and pessage phases */ | |
| 1039 | if ( pce_cd.scsi_BSY ) | |
| 1040 | { | |
| 1041 | if ( pce_cd.scsi_MSG ) | |
| 1042 | { | |
| 1043 | /* message phase */ | |
| 1044 | if ( pce_cd.scsi_IO ) | |
| 1045 | { | |
| 1046 | pce_cd_handle_message_input(state); | |
| 1047 | } | |
| 1048 | else | |
| 1049 | { | |
| 1050 | pce_cd_handle_message_output(state); | |
| 1051 | } | |
| 1052 | } | |
| 1053 | else | |
| 1054 | { | |
| 1055 | /* data phase */ | |
| 1056 | if ( pce_cd.scsi_IO ) | |
| 1057 | { | |
| 1058 | /* Reading data from target */ | |
| 1059 | pce_cd_handle_data_input( machine ); | |
| 1060 | } | |
| 1061 | else | |
| 1062 | { | |
| 1063 | /* Sending data to target */ | |
| 1064 | pce_cd_handle_data_output( machine ); | |
| 1065 | } | |
| 1066 | } | |
| 1067 | } | |
| 1068 | } | |
| 1069 | ||
| 1070 | /* FIXME: presumably CD-DA needs an irq interface for this */ | |
| 1071 | if(cdda_audio_ended(machine.device("cdda")) && pce_cd.end_mark == 1) | |
| 1072 | { | |
| 1073 | switch(pce_cd.cdda_play_mode & 3) | |
| 1074 | { | |
| 1075 | case 1: cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); pce_cd.end_mark = 1; break; //play with repeat | |
| 1076 | case 2: pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); pce_cd.end_mark = 0; break; //irq when finished | |
| 1077 | case 3: pce_cd.end_mark = 0; break; //play without repeat | |
| 1078 | } | |
| 1079 | } | |
| 1080 | } | |
| 1081 | ||
| 1082 | static void pce_cd_set_irq_line( running_machine &machine, int num, int state ) | |
| 1083 | { | |
| 1084 | pce_state *drvstate = machine.driver_data<pce_state>(); | |
| 1085 | pce_cd_t &pce_cd = drvstate->m_cd; | |
| 1086 | switch( num ) | |
| 1087 | { | |
| 1088 | case PCE_CD_IRQ_TRANSFER_DONE: | |
| 1089 | if ( state == ASSERT_LINE ) | |
| 1090 | { | |
| 1091 | pce_cd.regs[0x03] |= PCE_CD_IRQ_TRANSFER_DONE; | |
| 1092 | } | |
| 1093 | else | |
| 1094 | { | |
| 1095 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_TRANSFER_DONE; | |
| 1096 | } | |
| 1097 | break; | |
| 1098 | case PCE_CD_IRQ_TRANSFER_READY: | |
| 1099 | if ( state == ASSERT_LINE ) | |
| 1100 | { | |
| 1101 | pce_cd.regs[0x03] |= PCE_CD_IRQ_TRANSFER_READY; | |
| 1102 | } | |
| 1103 | else | |
| 1104 | { | |
| 1105 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_TRANSFER_READY; | |
| 1106 | } | |
| 1107 | break; | |
| 1108 | case PCE_CD_IRQ_SAMPLE_FULL_PLAY: | |
| 1109 | if ( state == ASSERT_LINE ) | |
| 1110 | { | |
| 1111 | pce_cd.regs[0x03] |= PCE_CD_IRQ_SAMPLE_FULL_PLAY; | |
| 1112 | //printf("x %02x %02x\n",pce_cd.regs[0x02],pce_cd.regs[0x03]); | |
| 1113 | } | |
| 1114 | else | |
| 1115 | { | |
| 1116 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_SAMPLE_FULL_PLAY; | |
| 1117 | } | |
| 1118 | break; | |
| 1119 | case PCE_CD_IRQ_SAMPLE_HALF_PLAY: | |
| 1120 | if ( state == ASSERT_LINE ) | |
| 1121 | { | |
| 1122 | pce_cd.regs[0x03] |= PCE_CD_IRQ_SAMPLE_HALF_PLAY; | |
| 1123 | //printf("y %02x %02x\n",pce_cd.regs[0x02],pce_cd.regs[0x03]); | |
| 1124 | } | |
| 1125 | else | |
| 1126 | { | |
| 1127 | pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_SAMPLE_HALF_PLAY; | |
| 1128 | } | |
| 1129 | break; | |
| 1130 | default: | |
| 1131 | break; | |
| 1132 | } | |
| 1133 | ||
| 1134 | if ( pce_cd.regs[0x02] & pce_cd.regs[0x03] & ( PCE_CD_IRQ_TRANSFER_DONE | PCE_CD_IRQ_TRANSFER_READY | PCE_CD_IRQ_SAMPLE_HALF_PLAY | PCE_CD_IRQ_SAMPLE_FULL_PLAY) ) | |
| 1135 | { | |
| 1136 | cputag_set_input_line(machine, "maincpu", 1, ASSERT_LINE ); | |
| 1137 | } | |
| 1138 | else | |
| 1139 | { | |
| 1140 | cputag_set_input_line(machine, "maincpu", 1, CLEAR_LINE ); | |
| 1141 | } | |
| 1142 | } | |
| 1143 | ||
| 1144 | static TIMER_CALLBACK( pce_cd_data_timer_callback ) | |
| 1145 | { | |
| 1146 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1147 | pce_cd_t &pce_cd = state->m_cd; | |
| 1148 | if ( pce_cd.data_buffer_index == pce_cd.data_buffer_size ) | |
| 1149 | { | |
| 1150 | /* Read next data sector */ | |
| 1151 | logerror("read sector %d\n", pce_cd.current_frame ); | |
| 1152 | if ( ! cdrom_read_data( pce_cd.cd, pce_cd.current_frame, pce_cd.data_buffer, CD_TRACK_MODE1 ) ) | |
| 1153 | { | |
| 1154 | logerror("Mode1 CD read failed for frame #%d\n", pce_cd.current_frame ); | |
| 1155 | } | |
| 1156 | else | |
| 1157 | { | |
| 1158 | logerror("Succesfully read mode1 frame #%d\n", pce_cd.current_frame ); | |
| 1159 | } | |
| 1160 | ||
| 1161 | pce_cd.data_buffer_index = 0; | |
| 1162 | pce_cd.data_buffer_size = 2048; | |
| 1163 | pce_cd.current_frame++; | |
| 1164 | ||
| 1165 | pce_cd.scsi_IO = 1; | |
| 1166 | pce_cd.scsi_CD = 0; | |
| 1167 | ||
| 1168 | if ( pce_cd.current_frame == pce_cd.end_frame ) | |
| 1169 | { | |
| 1170 | /* We are done, disable the timer */ | |
| 1171 | logerror("Last frame read from CD\n"); | |
| 1172 | pce_cd.data_transferred = 1; | |
| 1173 | pce_cd.data_timer->adjust(attotime::never); | |
| 1174 | } | |
| 1175 | else | |
| 1176 | { | |
| 1177 | pce_cd.data_transferred = 0; | |
| 1178 | } | |
| 1179 | } | |
| 1180 | } | |
| 1181 | ||
| 1182 | static void pce_cd_init( running_machine &machine ) | |
| 1183 | { | |
| 1184 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1185 | pce_cd_t &pce_cd = state->m_cd; | |
| 1186 | device_t *device; | |
| 1187 | ||
| 1188 | /* Initialize pce_cd struct */ | |
| 1189 | memset( &pce_cd, 0, sizeof(pce_cd) ); | |
| 1190 | ||
| 1191 | /* Initialize BRAM */ | |
| 1192 | pce_cd.bram = auto_alloc_array(machine, UINT8, PCE_BRAM_SIZE * 2 ); | |
| 1193 | memset( pce_cd.bram, 0, PCE_BRAM_SIZE ); | |
| 1194 | memset( pce_cd.bram + PCE_BRAM_SIZE, 0xFF, PCE_BRAM_SIZE ); | |
| 1195 | pce_cd.bram_locked = 1; | |
| 1196 | pce_set_cd_bram(machine); | |
| 1197 | ||
| 1198 | /* set up adpcm related things */ | |
| 1199 | pce_cd.adpcm_ram = auto_alloc_array(machine, UINT8, PCE_ADPCM_RAM_SIZE ); | |
| 1200 | memset( pce_cd.adpcm_ram, 0, PCE_ADPCM_RAM_SIZE ); | |
| 1201 | pce_cd.adpcm_clock_divider = 1; | |
| 1202 | msm5205_change_clock_w(machine.device("msm5205"), (PCE_CD_CLOCK / 6) / pce_cd.adpcm_clock_divider); | |
| 1203 | ||
| 1204 | /* Set up cd command buffer */ | |
| 1205 | pce_cd.command_buffer = auto_alloc_array(machine, UINT8, PCE_CD_COMMAND_BUFFER_SIZE ); | |
| 1206 | memset( pce_cd.command_buffer, 0, PCE_CD_COMMAND_BUFFER_SIZE ); | |
| 1207 | pce_cd.command_buffer_index = 0; | |
| 1208 | ||
| 1209 | /* Set up Arcade Card RAM buffer */ | |
| 1210 | pce_cd.acard_ram = auto_alloc_array(machine, UINT8, PCE_ACARD_RAM_SIZE ); | |
| 1211 | memset( pce_cd.acard_ram, 0, PCE_ACARD_RAM_SIZE ); | |
| 1212 | ||
| 1213 | pce_cd.data_buffer = auto_alloc_array(machine, UINT8, 8192 ); | |
| 1214 | memset( pce_cd.data_buffer, 0, 8192 ); | |
| 1215 | pce_cd.data_buffer_size = 0; | |
| 1216 | pce_cd.data_buffer_index = 0; | |
| 1217 | ||
| 1218 | pce_cd.subcode_buffer = auto_alloc_array(machine, UINT8, 96 ); | |
| 1219 | ||
| 1220 | device = machine.device("cdrom"); | |
| 1221 | if ( device ) | |
| 1222 | { | |
| 1223 | pce_cd.cd = cd_get_cdrom_file(device); | |
| 1224 | if ( pce_cd.cd ) | |
| 1225 | { | |
| 1226 | pce_cd.toc = cdrom_get_toc( pce_cd.cd ); | |
| 1227 | cdda_set_cdrom( machine.device("cdda"), pce_cd.cd ); | |
| 1228 | pce_cd.last_frame = cdrom_get_track_start( pce_cd.cd, cdrom_get_last_track( pce_cd.cd ) - 1 ); | |
| 1229 | pce_cd.last_frame += pce_cd.toc->tracks[ cdrom_get_last_track( pce_cd.cd ) - 1 ].frames; | |
| 1230 | pce_cd.end_frame = pce_cd.last_frame; | |
| 1231 | } | |
| 1232 | } | |
| 1233 | ||
| 1234 | pce_cd.data_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_data_timer_callback)); | |
| 1235 | pce_cd.data_timer->adjust(attotime::never); | |
| 1236 | pce_cd.adpcm_dma_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_dma_timer_callback)); | |
| 1237 | pce_cd.adpcm_dma_timer->adjust(attotime::never); | |
| 1238 | ||
| 1239 | pce_cd.cdda_fadeout_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_cdda_fadeout_callback)); | |
| 1240 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1241 | pce_cd.cdda_fadein_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_cdda_fadein_callback)); | |
| 1242 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1243 | ||
| 1244 | pce_cd.adpcm_fadeout_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_fadeout_callback)); | |
| 1245 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1246 | pce_cd.adpcm_fadein_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_fadein_callback)); | |
| 1247 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1248 | } | |
| 1249 | ||
| 1250 | WRITE8_HANDLER( pce_cd_bram_w ) | |
| 1251 | { | |
| 1252 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1253 | pce_cd_t &pce_cd = state->m_cd; | |
| 1254 | if ( ! pce_cd.bram_locked ) | |
| 1255 | { | |
| 1256 | pce_cd.bram[ offset ] = data; | |
| 1257 | } | |
| 1258 | } | |
| 1259 | ||
| 1260 | static void pce_cd_set_adpcm_ram_byte(running_machine &machine, UINT8 val) | |
| 1261 | { | |
| 1262 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1263 | pce_cd_t &pce_cd = state->m_cd; | |
| 1264 | if(pce_cd.adpcm_write_buf > 0) | |
| 1265 | { | |
| 1266 | pce_cd.adpcm_write_buf--; | |
| 1267 | } | |
| 1268 | else | |
| 1269 | { | |
| 1270 | pce_cd.adpcm_ram[pce_cd.adpcm_write_ptr] = val; | |
| 1271 | pce_cd.adpcm_write_ptr = ((pce_cd.adpcm_write_ptr + 1) & 0xffff); | |
| 1272 | //TODO: length + 1 | |
| 1273 | } | |
| 1274 | } | |
| 1275 | ||
| 1276 | static TIMER_CALLBACK( pce_cd_cdda_fadeout_callback ) | |
| 1277 | { | |
| 1278 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1279 | pce_cd_t &pce_cd = state->m_cd; | |
| 1280 | pce_cd.cdda_volume-= 0.1; | |
| 1281 | ||
| 1282 | if(pce_cd.cdda_volume <= 0) | |
| 1283 | { | |
| 1284 | pce_cd.cdda_volume = 0.0; | |
| 1285 | cdda_set_volume(machine.device("cdda"), 0.0); | |
| 1286 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1287 | } | |
| 1288 | else | |
| 1289 | { | |
| 1290 | cdda_set_volume(machine.device("cdda"), pce_cd.cdda_volume); | |
| 1291 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(param), param); | |
| 1292 | } | |
| 1293 | } | |
| 1294 | ||
| 1295 | static TIMER_CALLBACK( pce_cd_cdda_fadein_callback ) | |
| 1296 | { | |
| 1297 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1298 | pce_cd_t &pce_cd = state->m_cd; | |
| 1299 | pce_cd.cdda_volume+= 0.1; | |
| 1300 | ||
| 1301 | if(pce_cd.cdda_volume >= 100.0) | |
| 1302 | { | |
| 1303 | pce_cd.cdda_volume = 100.0; | |
| 1304 | cdda_set_volume(machine.device("cdda"), 100.0); | |
| 1305 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1306 | } | |
| 1307 | else | |
| 1308 | { | |
| 1309 | cdda_set_volume(machine.device("cdda"), pce_cd.cdda_volume); | |
| 1310 | pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(param), param); | |
| 1311 | } | |
| 1312 | } | |
| 1313 | ||
| 1314 | static TIMER_CALLBACK( pce_cd_adpcm_fadeout_callback ) | |
| 1315 | { | |
| 1316 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1317 | pce_cd_t &pce_cd = state->m_cd; | |
| 1318 | pce_cd.adpcm_volume-= 0.1; | |
| 1319 | ||
| 1320 | if(pce_cd.adpcm_volume <= 0) | |
| 1321 | { | |
| 1322 | pce_cd.adpcm_volume = 0.0; | |
| 1323 | msm5205_set_volume(machine.device("msm5205"), 0.0); | |
| 1324 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1325 | } | |
| 1326 | else | |
| 1327 | { | |
| 1328 | msm5205_set_volume(machine.device("msm5205"), pce_cd.adpcm_volume); | |
| 1329 | pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(param), param); | |
| 1330 | } | |
| 1331 | } | |
| 1332 | ||
| 1333 | static TIMER_CALLBACK( pce_cd_adpcm_fadein_callback ) | |
| 1334 | { | |
| 1335 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1336 | pce_cd_t &pce_cd = state->m_cd; | |
| 1337 | pce_cd.adpcm_volume+= 0.1; | |
| 1338 | ||
| 1339 | if(pce_cd.adpcm_volume >= 100.0) | |
| 1340 | { | |
| 1341 | pce_cd.adpcm_volume = 100.0; | |
| 1342 | msm5205_set_volume(machine.device("msm5205"), 100.0); | |
| 1343 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1344 | } | |
| 1345 | else | |
| 1346 | { | |
| 1347 | msm5205_set_volume(machine.device("msm5205"), pce_cd.adpcm_volume); | |
| 1348 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(param), param); | |
| 1349 | } | |
| 1350 | } | |
| 1351 | ||
| 1352 | ||
| 1353 | WRITE8_HANDLER( pce_cd_intf_w ) | |
| 1354 | { | |
| 1355 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1356 | pce_cd_t &pce_cd = state->m_cd; | |
| 1357 | pce_cd_update(space->machine()); | |
| 1358 | ||
| 1359 | if(offset & 0x200 && state->m_sys3_card && state->m_acard) // route Arcade Card handling ports | |
| 1360 | return pce_cd_acard_w(space,offset,data); | |
| 1361 | ||
| 1362 | logerror("%04X: write to CD interface offset %02X, data %02X\n", cpu_get_pc(&space->device()), offset, data ); | |
| 1363 | ||
| 1364 | switch( offset & 0xf ) | |
| 1365 | { | |
| 1366 | case 0x00: /* CDC status */ | |
| 1367 | /* select device (which bits??) */ | |
| 1368 | pce_cd.scsi_SEL = 1; | |
| 1369 | pce_cd_update(space->machine()); | |
| 1370 | pce_cd.scsi_SEL = 0; | |
| 1371 | pce_cd.adpcm_dma_timer->adjust(attotime::never); // stop ADPCM DMA here | |
| 1372 | /* any write here clears CD transfer irqs */ | |
| 1373 | pce_cd.regs[0x03] &= ~0x70; | |
| 1374 | cputag_set_input_line(space->machine(), "maincpu", 1, CLEAR_LINE ); | |
| 1375 | break; | |
| 1376 | case 0x01: /* CDC command / status / data */ | |
| 1377 | break; | |
| 1378 | case 0x02: /* ADPCM / CD control / IRQ enable/disable */ | |
| 1379 | /* bit 6 - transfer ready irq */ | |
| 1380 | /* bit 5 - transfer done irq */ | |
| 1381 | /* bit 4 - ?? irq */ | |
| 1382 | /* bit 3 - ?? irq */ | |
| 1383 | /* bit 2 - ?? irq */ | |
| 1384 | pce_cd.scsi_ACK = data & 0x80; | |
| 1385 | /* Don't set or reset any irq lines, but just verify the current state */ | |
| 1386 | pce_cd_set_irq_line( space->machine(), 0, 0 ); | |
| 1387 | break; | |
| 1388 | case 0x03: /* BRAM lock / CD status / IRQ - Read Only register */ | |
| 1389 | break; | |
| 1390 | case 0x04: /* CD reset */ | |
| 1391 | pce_cd.scsi_RST = data & 0x02; | |
| 1392 | break; | |
| 1393 | case 0x05: /* Convert PCM data / PCM data */ | |
| 1394 | case 0x06: /* PCM data */ | |
| 1395 | break; | |
| 1396 | case 0x07: /* BRAM unlock / CD status */ | |
| 1397 | if ( data & 0x80 ) | |
| 1398 | { | |
| 1399 | pce_cd.bram_locked = 0; | |
| 1400 | pce_set_cd_bram(space->machine()); | |
| 1401 | } | |
| 1402 | break; | |
| 1403 | case 0x08: /* ADPCM address (LSB) / CD data */ | |
| 1404 | break; | |
| 1405 | case 0x09: /* ADPCM address (MSB) */ | |
| 1406 | break; | |
| 1407 | case 0x0A: /* ADPCM RAM data port */ | |
| 1408 | pce_cd_set_adpcm_ram_byte(space->machine(), data); | |
| 1409 | break; | |
| 1410 | case 0x0B: /* ADPCM DMA control */ | |
| 1411 | if ( data & 0x03 ) | |
| 1412 | { | |
| 1413 | /* Start CD to ADPCM transfer */ | |
| 1414 | pce_cd.adpcm_dma_timer->adjust(attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND * 2048 ), 0, attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND * 2048 ) ); | |
| 1415 | pce_cd.regs[0x0c] |= 4; | |
| 1416 | } | |
| 1417 | break; | |
| 1418 | case 0x0C: /* ADPCM status */ | |
| 1419 | break; | |
| 1420 | case 0x0D: /* ADPCM address control */ | |
| 1421 | if ( ( pce_cd.regs[0x0D] & 0x80 ) && ! ( data & 0x80 ) ) // ADPCM reset | |
| 1422 | { | |
| 1423 | /* Reset ADPCM hardware */ | |
| 1424 | pce_cd.adpcm_read_ptr = 0; | |
| 1425 | pce_cd.adpcm_write_ptr = 0; | |
| 1426 | pce_cd.msm_start_addr = 0; | |
| 1427 | pce_cd.msm_end_addr = 0; | |
| 1428 | pce_cd.msm_half_addr = 0; | |
| 1429 | pce_cd.msm_nibble = 0; | |
| 1430 | adpcm_stop(space->machine()); | |
| 1431 | msm5205_reset_w( space->machine().device( "msm5205"), 1 ); | |
| 1432 | } | |
| 1433 | ||
| 1434 | if(data & 0x20) | |
| 1435 | pce_cd.msm_half_addr = (pce_cd.adpcm_read_ptr + (pce_cd.adpcm_length / ((data & 0x40) ? 2 : 1))) & 0xffff; | |
| 1436 | ||
| 1437 | if ( ( data & 0x40) && ((pce_cd.regs[0x0D] & 0x40) == 0) ) // ADPCM play | |
| 1438 | { | |
| 1439 | pce_cd.msm_start_addr = (pce_cd.adpcm_read_ptr); | |
| 1440 | pce_cd.msm_end_addr = (pce_cd.adpcm_read_ptr + pce_cd.adpcm_length) & 0xffff; | |
| 1441 | pce_cd.msm_nibble = 0; | |
| 1442 | adpcm_play(space->machine()); | |
| 1443 | msm5205_reset_w( space->machine().device( "msm5205"), 0 ); | |
| 1444 | ||
| 1445 | //popmessage("%08x %08x",pce_cd.adpcm_read_ptr,pce_cd.adpcm_length); | |
| 1446 | } | |
| 1447 | else if ( (data & 0x40) == 0 ) | |
| 1448 | { | |
| 1449 | /* used by Buster Bros to cancel an in-flight sample */ | |
| 1450 | adpcm_stop(space->machine()); | |
| 1451 | msm5205_reset_w( space->machine().device( "msm5205"), 1 ); | |
| 1452 | } | |
| 1453 | ||
| 1454 | if ( data & 0x10 ) //ADPCM set length | |
| 1455 | { | |
| 1456 | pce_cd.adpcm_length = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08]; | |
| 1457 | } | |
| 1458 | if ( data & 0x08 ) //ADPCM set read address | |
| 1459 | { | |
| 1460 | pce_cd.adpcm_read_ptr = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08]; | |
| 1461 | pce_cd.adpcm_read_buf = 2; | |
| 1462 | } | |
| 1463 | if ( ( data & 0x02 ) == 0x02 ) //ADPCM set write address | |
| 1464 | { | |
| 1465 | pce_cd.adpcm_write_ptr = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08]; | |
| 1466 | pce_cd.adpcm_write_buf = data & 1; | |
| 1467 | } | |
| 1468 | break; | |
| 1469 | case 0x0E: /* ADPCM playback rate */ | |
| 1470 | pce_cd.adpcm_clock_divider = 0x10 - ( data & 0x0F ); | |
| 1471 | msm5205_change_clock_w(space->machine().device("msm5205"), (PCE_CD_CLOCK / 6) / pce_cd.adpcm_clock_divider); | |
| 1472 | break; | |
| 1473 | case 0x0F: /* ADPCM and CD audio fade timer */ | |
| 1474 | /* TODO: timers needs HW tests */ | |
| 1475 | if(pce_cd.regs[0xf] != data) | |
| 1476 | { | |
| 1477 | switch(data & 0xf) | |
| 1478 | { | |
| 1479 | case 0x00: //CD-DA / ADPCM enable (100 msecs) | |
| 1480 | pce_cd.cdda_volume = 0.0; | |
| 1481 | pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1482 | pce_cd.adpcm_volume = 0.0; | |
| 1483 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1484 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1485 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1486 | break; | |
| 1487 | case 0x01: //CD-DA enable (100 msecs) | |
| 1488 | pce_cd.cdda_volume = 0.0; | |
| 1489 | pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1490 | pce_cd.cdda_fadeout_timer->adjust(attotime::never); | |
| 1491 | break; | |
| 1492 | case 0x08: //CD-DA short (1500 msecs) fade out / ADPCM enable | |
| 1493 | pce_cd.cdda_volume = 100.0; | |
| 1494 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1495 | pce_cd.adpcm_volume = 0.0; | |
| 1496 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1497 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1498 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1499 | break; | |
| 1500 | case 0x09: //CD-DA long (5000 msecs) fade out | |
| 1501 | pce_cd.cdda_volume = 100.0; | |
| 1502 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(5000), 5000); | |
| 1503 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1504 | break; | |
| 1505 | case 0x0a: //ADPCM long (5000 msecs) fade out | |
| 1506 | pce_cd.adpcm_volume = 100.0; | |
| 1507 | pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(5000), 5000); | |
| 1508 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1509 | break; | |
| 1510 | case 0x0c: //CD-DA short (1500 msecs) fade out / ADPCM enable | |
| 1511 | pce_cd.cdda_volume = 100.0; | |
| 1512 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1513 | pce_cd.adpcm_volume = 0.0; | |
| 1514 | pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100); | |
| 1515 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1516 | pce_cd.adpcm_fadeout_timer->adjust(attotime::never); | |
| 1517 | break; | |
| 1518 | case 0x0d: //CD-DA short (1500 msecs) fade out | |
| 1519 | pce_cd.cdda_volume = 100.0; | |
| 1520 | pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1521 | pce_cd.cdda_fadein_timer->adjust(attotime::never); | |
| 1522 | break; | |
| 1523 | case 0x0e: //ADPCM short (1500 msecs) fade out | |
| 1524 | pce_cd.adpcm_volume = 100.0; | |
| 1525 | pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(1500), 1500); | |
| 1526 | pce_cd.adpcm_fadein_timer->adjust(attotime::never); | |
| 1527 | break; | |
| 1528 | default: | |
| 1529 | popmessage("CD-DA / ADPCM Fade effect mode %02x, contact MESSdev",data & 0x0f); | |
| 1530 | break; | |
| 1531 | } | |
| 1532 | } | |
| 1533 | break; | |
| 1534 | default: | |
| 1535 | return; | |
| 1536 | } | |
| 1537 | pce_cd.regs[offset & 0xf] = data; | |
| 1538 | pce_cd_update(space->machine()); | |
| 1539 | } | |
| 1540 | ||
| 1541 | static TIMER_CALLBACK( pce_cd_clear_ack ) | |
| 1542 | { | |
| 1543 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1544 | pce_cd_t &pce_cd = state->m_cd; | |
| 1545 | pce_cd_update(machine); | |
| 1546 | pce_cd.scsi_ACK = 0; | |
| 1547 | pce_cd_update(machine); | |
| 1548 | if ( pce_cd.scsi_CD ) | |
| 1549 | { | |
| 1550 | pce_cd.regs[0x0B] &= 0xFE; | |
| 1551 | } | |
| 1552 | } | |
| 1553 | ||
| 1554 | static UINT8 pce_cd_get_cd_data_byte(running_machine &machine) | |
| 1555 | { | |
| 1556 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1557 | pce_cd_t &pce_cd = state->m_cd; | |
| 1558 | UINT8 data = pce_cd.regs[0x01]; | |
| 1559 | if ( pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && ! pce_cd.scsi_CD ) | |
| 1560 | { | |
| 1561 | if ( pce_cd.scsi_IO ) | |
| 1562 | { | |
| 1563 | pce_cd.scsi_ACK = 1; | |
| 1564 | machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(15), FUNC(pce_cd_clear_ack)); | |
| 1565 | } | |
| 1566 | } | |
| 1567 | return data; | |
| 1568 | } | |
| 1569 | ||
| 1570 | ||
| 1571 | static TIMER_CALLBACK( pce_cd_adpcm_dma_timer_callback ) | |
| 1572 | { | |
| 1573 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1574 | pce_cd_t &pce_cd = state->m_cd; | |
| 1575 | if ( pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && ! pce_cd.scsi_CD && pce_cd.scsi_IO ) | |
| 1576 | { | |
| 1577 | pce_cd.adpcm_ram[pce_cd.adpcm_write_ptr] = pce_cd_get_cd_data_byte(machine); | |
| 1578 | pce_cd.adpcm_write_ptr = ( pce_cd.adpcm_write_ptr + 1 ) & 0xFFFF; | |
| 1579 | ||
| 1580 | pce_cd.regs[0x0c] &= ~4; | |
| 1581 | } | |
| 1582 | } | |
| 1583 | ||
| 1584 | static UINT8 pce_cd_get_adpcm_ram_byte(running_machine &machine) | |
| 1585 | { | |
| 1586 | pce_state *state = machine.driver_data<pce_state>(); | |
| 1587 | pce_cd_t &pce_cd = state->m_cd; | |
| 1588 | if(pce_cd.adpcm_read_buf > 0) | |
| 1589 | { | |
| 1590 | pce_cd.adpcm_read_buf--; | |
| 1591 | return 0; | |
| 1592 | } | |
| 1593 | else | |
| 1594 | { | |
| 1595 | UINT8 res; | |
| 1596 | ||
| 1597 | res = pce_cd.adpcm_ram[pce_cd.adpcm_read_ptr]; | |
| 1598 | pce_cd.adpcm_read_ptr = ((pce_cd.adpcm_read_ptr + 1) & 0xffff); | |
| 1599 | ||
| 1600 | return res; | |
| 1601 | } | |
| 1602 | } | |
| 1603 | ||
| 1604 | READ8_HANDLER( pce_cd_intf_r ) | |
| 1605 | { | |
| 1606 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1607 | pce_cd_t &pce_cd = state->m_cd; | |
| 1608 | UINT8 data = pce_cd.regs[offset & 0x0F]; | |
| 1609 | ||
| 1610 | pce_cd_update(space->machine()); | |
| 1611 | ||
| 1612 | if(offset & 0x200 && state->m_sys3_card && state->m_acard) // route Arcade Card handling ports | |
| 1613 | return pce_cd_acard_r(space,offset); | |
| 1614 | ||
| 1615 | logerror("%04X: read from CD interface offset %02X\n", cpu_get_pc(&space->device()), offset ); | |
| 1616 | ||
| 1617 | if((offset & 0xc0) == 0xc0 && state->m_sys3_card) //System 3 Card header handling | |
| 1618 | { | |
| 1619 | switch(offset & 0xcf) | |
| 1620 | { | |
| 1621 | case 0xc1: return 0xaa; | |
| 1622 | case 0xc2: return 0x55; | |
| 1623 | case 0xc3: return 0x00; | |
| 1624 | case 0xc5: return (state->m_sys3_card & 2) ? 0x55 : 0xaa; | |
| 1625 | case 0xc6: return (state->m_sys3_card & 2) ? 0xaa : 0x55; | |
| 1626 | case 0xc7: return 0x03; | |
| 1627 | } | |
| 1628 | } | |
| 1629 | ||
| 1630 | switch( offset & 0xf ) | |
| 1631 | { | |
| 1632 | case 0x00: /* CDC status */ | |
| 1633 | data &= 0x07; | |
| 1634 | data |= pce_cd.scsi_BSY ? 0x80 : 0; | |
| 1635 | data |= pce_cd.scsi_REQ ? 0x40 : 0; | |
| 1636 | data |= pce_cd.scsi_MSG ? 0x20 : 0; | |
| 1637 | data |= pce_cd.scsi_CD ? 0x10 : 0; | |
| 1638 | data |= pce_cd.scsi_IO ? 0x08 : 0; | |
| 1639 | break; | |
| 1640 | case 0x01: /* CDC command / status / data */ | |
| 1641 | break; | |
| 1642 | case 0x02: /* ADPCM / CD control */ | |
| 1643 | break; | |
| 1644 | case 0x03: /* BRAM lock / CD status */ | |
| 1645 | /* bit 4 set when CD motor is on */ | |
| 1646 | /* bit 2 set when less than half of the ADPCM data is remaining ?? */ | |
| 1647 | pce_cd.bram_locked = 1; | |
| 1648 | pce_set_cd_bram(space->machine()); | |
| 1649 | data = data & 0x6E; | |
| 1650 | data |= ( pce_cd.cd_motor_on ? 0x10 : 0 ); | |
| 1651 | pce_cd.regs[0x03] ^= 0x02; /* TODO: get rid of this hack */ | |
| 1652 | break; | |
| 1653 | case 0x04: /* CD reset */ | |
| 1654 | break; | |
| 1655 | case 0x05: /* Convert PCM data / PCM data */ | |
| 1656 | case 0x06: /* PCM data */ | |
| 1657 | break; | |
| 1658 | case 0x07: /* BRAM unlock / CD status */ | |
| 1659 | data = ( pce_cd.bram_locked ? ( data & 0x7F ) : ( data | 0x80 ) ); | |
| 1660 | break; | |
| 1661 | case 0x08: /* ADPCM address (LSB) / CD data */ | |
| 1662 | data = pce_cd_get_cd_data_byte(space->machine()); | |
| 1663 | break; | |
| 1664 | case 0x0A: /* ADPCM RAM data port */ | |
| 1665 | data = pce_cd_get_adpcm_ram_byte(space->machine()); | |
| 1666 | break; | |
| 1667 | case 0x0B: /* ADPCM DMA control */ | |
| 1668 | break; | |
| 1669 | case 0x0C: /* ADPCM status */ | |
| 1670 | break; | |
| 1671 | case 0x0D: /* ADPCM address control */ | |
| 1672 | break; | |
| 1673 | /* These are read-only registers */ | |
| 1674 | case 0x09: /* ADPCM address (MSB) */ | |
| 1675 | case 0x0E: /* ADPCM playback rate */ | |
| 1676 | case 0x0F: /* ADPCM and CD audio fade timer */ | |
| 1677 | return 0; | |
| 1678 | default: | |
| 1679 | data = 0xFF; | |
| 1680 | break; | |
| 1681 | } | |
| 1682 | ||
| 1683 | return data; | |
| 1684 | } | |
| 1685 | ||
| 1686 | ||
| 1687 | /* | |
| 1688 | ||
| 1689 | PC Engine Arcade Card emulation | |
| 1690 | ||
| 1691 | */ | |
| 1692 | ||
| 1693 | READ8_HANDLER( pce_cd_acard_r ) | |
| 1694 | { | |
| 1695 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1696 | pce_cd_t &pce_cd = state->m_cd; | |
| 1697 | UINT8 r_num; | |
| 1698 | ||
| 1699 | if((offset & 0x2e0) == 0x2e0) | |
| 1700 | { | |
| 1701 | switch(offset & 0x2ef) | |
| 1702 | { | |
| 1703 | case 0x2e0: return (pce_cd.acard_shift >> 0) & 0xff; | |
| 1704 | case 0x2e1: return (pce_cd.acard_shift >> 8) & 0xff; | |
| 1705 | case 0x2e2: return (pce_cd.acard_shift >> 16) & 0xff; | |
| 1706 | case 0x2e3: return (pce_cd.acard_shift >> 24) & 0xff; | |
| 1707 | case 0x2e4: return (pce_cd.acard_shift_reg); | |
| 1708 | case 0x2e5: return pce_cd.acard_latch; | |
| 1709 | case 0x2ee: return 0x10; | |
| 1710 | case 0x2ef: return 0x51; | |
| 1711 | } | |
| 1712 | ||
| 1713 | return 0; | |
| 1714 | } | |
| 1715 | ||
| 1716 | r_num = (offset & 0x30) >> 4; | |
| 1717 | ||
| 1718 | switch(offset & 0x0f) | |
| 1719 | { | |
| 1720 | case 0x00: | |
| 1721 | case 0x01: | |
| 1722 | { | |
| 1723 | UINT8 res; | |
| 1724 | if(pce_cd.acard_ctrl[r_num] & 2) | |
| 1725 | res = pce_cd.acard_ram[(pce_cd.acard_base_addr[r_num] + pce_cd.acard_addr_offset[r_num]) & 0x1fffff]; | |
| 1726 | else | |
| 1727 | res = pce_cd.acard_ram[pce_cd.acard_base_addr[r_num] & 0x1fffff]; | |
| 1728 | ||
| 1729 | if(pce_cd.acard_ctrl[r_num] & 0x1) | |
| 1730 | { | |
| 1731 | if(pce_cd.acard_ctrl[r_num] & 0x10) | |
| 1732 | { | |
| 1733 | pce_cd.acard_base_addr[r_num] += pce_cd.acard_addr_inc[r_num]; | |
| 1734 | pce_cd.acard_base_addr[r_num] &= 0xffffff; | |
| 1735 | } | |
| 1736 | else | |
| 1737 | { | |
| 1738 | pce_cd.acard_addr_offset[r_num] += pce_cd.acard_addr_inc[r_num]; | |
| 1739 | } | |
| 1740 | } | |
| 1741 | ||
| 1742 | return res; | |
| 1743 | } | |
| 1744 | case 0x02: return (pce_cd.acard_base_addr[r_num] >> 0) & 0xff; | |
| 1745 | case 0x03: return (pce_cd.acard_base_addr[r_num] >> 8) & 0xff; | |
| 1746 | case 0x04: return (pce_cd.acard_base_addr[r_num] >> 16) & 0xff; | |
| 1747 | case 0x05: return (pce_cd.acard_addr_offset[r_num] >> 0) & 0xff; | |
| 1748 | case 0x06: return (pce_cd.acard_addr_offset[r_num] >> 8) & 0xff; | |
| 1749 | case 0x07: return (pce_cd.acard_addr_inc[r_num] >> 0) & 0xff; | |
| 1750 | case 0x08: return (pce_cd.acard_addr_inc[r_num] >> 8) & 0xff; | |
| 1751 | case 0x09: return pce_cd.acard_ctrl[r_num]; | |
| 1752 | default: return 0; | |
| 1753 | } | |
| 1754 | ||
| 1755 | return 0; | |
| 1756 | } | |
| 1757 | ||
| 1758 | WRITE8_HANDLER( pce_cd_acard_w ) | |
| 1759 | { | |
| 1760 | pce_state *state = space->machine().driver_data<pce_state>(); | |
| 1761 | pce_cd_t &pce_cd = state->m_cd; | |
| 1762 | UINT8 w_num; | |
| 1763 | ||
| 1764 | if((offset & 0x2e0) == 0x2e0) | |
| 1765 | { | |
| 1766 | switch(offset & 0x0f) | |
| 1767 | { | |
| 1768 | case 0: pce_cd.acard_shift = (data & 0xff) | (pce_cd.acard_shift & 0xffffff00); break; | |
| 1769 | case 1: pce_cd.acard_shift = (data << 8) | (pce_cd.acard_shift & 0xffff00ff); break; | |
| 1770 | case 2: pce_cd.acard_shift = (data << 16) | (pce_cd.acard_shift & 0xff00ffff); break; | |
| 1771 | case 3: pce_cd.acard_shift = (data << 24) | (pce_cd.acard_shift & 0x00ffffff); break; | |
| 1772 | case 4: | |
| 1773 | { | |
| 1774 | pce_cd.acard_shift_reg = data & 0x0f; | |
| 1775 | ||
| 1776 | if(pce_cd.acard_shift_reg != 0) | |
| 1777 | { | |
| 1778 | pce_cd.acard_shift = (pce_cd.acard_shift_reg < 8) ? | |
| 1779 | (pce_cd.acard_shift << pce_cd.acard_shift_reg) | |
| 1780 | : (pce_cd.acard_shift >> (16 - pce_cd.acard_shift_reg)); | |
| 1781 | } | |
| 1782 | } | |
| 1783 | break; | |
| 1784 | case 5: pce_cd.acard_latch = data; break; | |
| 1785 | } | |
| 1786 | } | |
| 1787 | else | |
| 1788 | { | |
| 1789 | w_num = (offset & 0x30) >> 4; | |
| 1790 | ||
| 1791 | switch(offset & 0x0f) | |
| 1792 | { | |
| 1793 | case 0x00: | |
| 1794 | case 0x01: | |
| 1795 | if(pce_cd.acard_ctrl[w_num] & 2) | |
| 1796 | pce_cd.acard_ram[(pce_cd.acard_base_addr[w_num] + pce_cd.acard_addr_offset[w_num]) & 0x1fffff] = data; | |
| 1797 | else | |
| 1798 | pce_cd.acard_ram[pce_cd.acard_base_addr[w_num] & 0x1FFFFF] = data; | |
| 1799 | ||
| 1800 | if(pce_cd.acard_ctrl[w_num] & 0x1) | |
| 1801 | { | |
| 1802 | if(pce_cd.acard_ctrl[w_num] & 0x10) | |
| 1803 | { | |
| 1804 | pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_inc[w_num]; | |
| 1805 | pce_cd.acard_base_addr[w_num] &= 0xffffff; | |
| 1806 | } | |
| 1807 | else | |
| 1808 | { | |
| 1809 | pce_cd.acard_addr_offset[w_num] += pce_cd.acard_addr_inc[w_num]; | |
| 1810 | } | |
| 1811 | } | |
| 1812 | ||
| 1813 | break; | |
| 1814 | ||
| 1815 | case 0x02: pce_cd.acard_base_addr[w_num] = (data & 0xff) | (pce_cd.acard_base_addr[w_num] & 0xffff00); break; | |
| 1816 | case 0x03: pce_cd.acard_base_addr[w_num] = (data << 8) | (pce_cd.acard_base_addr[w_num] & 0xff00ff); break; | |
| 1817 | case 0x04: pce_cd.acard_base_addr[w_num] = (data << 16) | (pce_cd.acard_base_addr[w_num] & 0x00ffff); break; | |
| 1818 | case 0x05: pce_cd.acard_addr_offset[w_num] = (data & 0xff) | (pce_cd.acard_addr_offset[w_num] & 0xff00); break; | |
| 1819 | case 0x06: | |
| 1820 | pce_cd.acard_addr_offset[w_num] = (data << 8) | (pce_cd.acard_addr_offset[w_num] & 0x00ff); | |
| 1821 | ||
| 1822 | if((pce_cd.acard_ctrl[w_num] & 0x60) == 0x40) | |
| 1823 | { | |
| 1824 | pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_offset[w_num] + ((pce_cd.acard_ctrl[w_num] & 0x08) ? 0xff0000 : 0); | |
| 1825 | pce_cd.acard_base_addr[w_num] &= 0xffffff; | |
| 1826 | } | |
| 1827 | break; | |
| 1828 | case 0x07: pce_cd.acard_addr_inc[w_num] = (data & 0xff) | (pce_cd.acard_addr_inc[w_num] & 0xff00); break; | |
| 1829 | case 0x08: pce_cd.acard_addr_inc[w_num] = (data << 8) | (pce_cd.acard_addr_inc[w_num] & 0x00ff); break; | |
| 1830 | case 0x09: pce_cd.acard_ctrl[w_num] = data & 0x7f; break; | |
| 1831 | case 0x0a: | |
| 1832 | if((pce_cd.acard_ctrl[w_num] & 0x60) == 0x60) | |
| 1833 | { | |
| 1834 | pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_offset[w_num]; | |
| 1835 | pce_cd.acard_base_addr[w_num] &= 0xffffff; | |
| 1836 | } | |
| 1837 | break; | |
| 1838 | } | |
| 1839 | } | |
| 1840 | } | |
| 1841 | ||
| 1842 | READ8_HANDLER( pce_cd_acard_wram_r ) | |
| 1843 | { | |
| 1844 | return pce_cd_intf_r(space,0x200 | (offset & 0x6000) >> 9); | |
| 1845 | } | |
| 1846 | ||
| 1847 | WRITE8_HANDLER( pce_cd_acard_wram_w ) | |
| 1848 | { | |
| 1849 | pce_cd_intf_w(space,0x200 | (offset & 0x6000) >> 9,data); | |
| 1850 | } | |
| 1851 |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Atari 400/800 | |
| 4 | ||
| 5 | Floppy Disk Controller code | |
| 6 | ||
| 7 | Juergen Buchmueller, June 1998 | |
| 8 | ||
| 9 | ***************************************************************************/ | |
| 10 | ||
| 11 | #include <ctype.h> | |
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "cpu/m6502/m6502.h" | |
| 15 | #include "includes/atari.h" | |
| 16 | #include "ataridev.h" | |
| 17 | #include "sound/pokey.h" | |
| 18 | #include "machine/6821pia.h" | |
| 19 | #include "imagedev/flopdrv.h" | |
| 20 | #include "image.h" | |
| 21 | ||
| 22 | #define VERBOSE_SERIAL 0 | |
| 23 | #define VERBOSE_CHKSUM 0 | |
| 24 | ||
| 25 | typedef struct _atari_drive atari_drive; | |
| 26 | struct _atari_drive | |
| 27 | { | |
| 28 | UINT8 *image; /* malloc'd image */ | |
| 29 | int type; /* type of image (XFD, ATR, DSK) */ | |
| 30 | int mode; /* 0 read only, != 0 read/write */ | |
| 31 | int density; /* 0 SD, 1 MD, 2 DD */ | |
| 32 | int header_skip; /* number of bytes in format header */ | |
| 33 | int tracks; /* number of tracks (35,40,77,80) */ | |
| 34 | int heads; /* number of heads (1,2) */ | |
| 35 | int spt; /* sectors per track (18,26) */ | |
| 36 | int seclen; /* sector length (128,256) */ | |
| 37 | int bseclen; /* boot sector length (sectors 1..3) */ | |
| 38 | int sectors; /* total sectors, ie. tracks x heads x spt */ | |
| 39 | }; | |
| 40 | ||
| 41 | typedef struct _atari_fdc_t atari_fdc_t; | |
| 42 | struct _atari_fdc_t | |
| 43 | { | |
| 44 | int serout_count; | |
| 45 | int serout_offs; | |
| 46 | UINT8 serout_buff[512]; | |
| 47 | UINT8 serout_chksum; | |
| 48 | int serout_delay; | |
| 49 | ||
| 50 | int serin_count; | |
| 51 | int serin_offs; | |
| 52 | UINT8 serin_buff[512]; | |
| 53 | UINT8 serin_chksum; | |
| 54 | int serin_delay; | |
| 55 | ||
| 56 | atari_drive drv[4]; | |
| 57 | }; | |
| 58 | ||
| 59 | /************************************* | |
| 60 | * | |
| 61 | * Disk stuff | |
| 62 | * | |
| 63 | *************************************/ | |
| 64 | ||
| 65 | #define FORMAT_XFD 0 | |
| 66 | #define FORMAT_ATR 1 | |
| 67 | #define FORMAT_DSK 2 | |
| 68 | ||
| 69 | /***************************************************************************** | |
| 70 | INLINE FUNCTIONS | |
| 71 | *****************************************************************************/ | |
| 72 | INLINE atari_fdc_t *get_safe_token(device_t *device) | |
| 73 | { | |
| 74 | assert(device != NULL); | |
| 75 | assert(device->type() == ATARI_FDC); | |
| 76 | ||
| 77 | return (atari_fdc_t *)downcast<legacy_device_base *>(device)->token(); | |
| 78 | } | |
| 79 | ||
| 80 | /***************************************************************************** | |
| 81 | * This is the structure I used in my own Atari 800 emulator some years ago | |
| 82 | * Though it's a bit overloaded, I used it as it is the maximum of all | |
| 83 | * supported formats: | |
| 84 | * XFD no header at all | |
| 85 | * ATR 16 bytes header | |
| 86 | * DSK this struct | |
| 87 | * It is used to determine the format of a XFD image by it's size only | |
| 88 | *****************************************************************************/ | |
| 89 | ||
| 90 | typedef struct _dsk_format dsk_format; | |
| 91 | struct _dsk_format | |
| 92 | { | |
| 93 | UINT8 density; | |
| 94 | UINT8 tracks; | |
| 95 | UINT8 door; | |
| 96 | UINT8 sta1; | |
| 97 | UINT8 spt; | |
| 98 | UINT8 doublesided; | |
| 99 | UINT8 highdensity; | |
| 100 | UINT8 seclen_hi; | |
| 101 | UINT8 seclen_lo; | |
| 102 | UINT8 status; | |
| 103 | UINT8 sta2; | |
| 104 | UINT8 sta3; | |
| 105 | UINT8 sta4; | |
| 106 | UINT8 cr; | |
| 107 | UINT8 info[65+1]; | |
| 108 | }; | |
| 109 | ||
| 110 | /* combined with the size the image should have */ | |
| 111 | typedef struct _xfd_format xfd_format; | |
| 112 | struct _xfd_format | |
| 113 | { | |
| 114 | int size; | |
| 115 | dsk_format dsk; | |
| 116 | }; | |
| 117 | ||
| 118 | /* here's a table of known xfd formats */ | |
| 119 | static const xfd_format xfd_formats[] = | |
| 120 | { | |
| 121 | {35 * 18 * 1 * 128, {0,35,1,0,18,0,0,0,128,255,0,0,0,13,"35 SS/SD"}}, | |
| 122 | {35 * 26 * 1 * 128, {1,35,1,0,26,0,4,0,128,255,0,0,0,13,"35 SS/MD"}}, | |
| 123 | {(35 * 18 * 1 - 3) * 256 + 3 * 128, {2,35,1,0,18,0,4,1, 0,255,0,0,0,13,"35 SS/DD"}}, | |
| 124 | {40 * 18 * 1 * 128, {0,40,1,0,18,0,0,0,128,255,0,0,0,13,"40 SS/SD"}}, | |
| 125 | {40 * 26 * 1 * 128, {1,40,1,0,26,0,4,0,128,255,0,0,0,13,"40 SS/MD"}}, | |
| 126 | {(40 * 18 * 1 - 3) * 256 + 3 * 128, {2,40,1,0,18,0,4,1, 0,255,0,0,0,13,"40 SS/DD"}}, | |
| 127 | {40 * 18 * 2 * 128, {0,40,1,0,18,1,0,0,128,255,0,0,0,13,"40 DS/SD"}}, | |
| 128 | {40 * 26 * 2 * 128, {1,40,1,0,26,1,4,0,128,255,0,0,0,13,"40 DS/MD"}}, | |
| 129 | {(40 * 18 * 2 - 3) * 256 + 3 * 128, {2,40,1,0,18,1,4,1, 0,255,0,0,0,13,"40 DS/DD"}}, | |
| 130 | {77 * 18 * 1 * 128, {0,77,1,0,18,0,0,0,128,255,0,0,0,13,"77 SS/SD"}}, | |
| 131 | {77 * 26 * 1 * 128, {1,77,1,0,26,0,4,0,128,255,0,0,0,13,"77 SS/MD"}}, | |
| 132 | {(77 * 18 * 1 - 3) * 256 + 3 * 128, {2,77,1,0,18,0,4,1, 0,255,0,0,0,13,"77 SS/DD"}}, | |
| 133 | {77 * 18 * 2 * 128, {0,77,1,0,18,1,0,0,128,255,0,0,0,13,"77 DS/SD"}}, | |
| 134 | {77 * 26 * 2 * 128, {1,77,1,0,26,1,4,0,128,255,0,0,0,13,"77 DS/MD"}}, | |
| 135 | {(77 * 18 * 2 - 3) * 256 + 3 * 128, {2,77,1,0,18,1,4,1, 0,255,0,0,0,13,"77 DS/DD"}}, | |
| 136 | {80 * 18 * 2 * 128, {0,80,1,0,18,1,0,0,128,255,0,0,0,13,"80 DS/SD"}}, | |
| 137 | {80 * 26 * 2 * 128, {1,80,1,0,26,1,4,0,128,255,0,0,0,13,"80 DS/MD"}}, | |
| 138 | {(80 * 18 * 2 - 3) * 256 + 3 * 128, {2,80,1,0,18,1,4,1, 0,255,0,0,0,13,"80 DS/DD"}}, | |
| 139 | {0, {0,}} | |
| 140 | }; | |
| 141 | ||
| 142 | /***************************************************************************** | |
| 143 | * | |
| 144 | * Open a floppy image for drive 'drive' if it is not yet openend | |
| 145 | * and a name was given. Determine the image geometry depending on the | |
| 146 | * type of image and store the results into the global drv[] structure | |
| 147 | * | |
| 148 | *****************************************************************************/ | |
| 149 | ||
| 150 | #define MAXSIZE 5760 * 256 + 80 | |
| 151 | static void atari_load_proc(device_image_interface &image) | |
| 152 | { | |
| 153 | atari_fdc_t *fdc = get_safe_token(image.device().owner()); | |
| 154 | int id = floppy_get_drive(image); | |
| 155 | int size, i; | |
| 156 | const char *ext; | |
| 157 | ||
| 158 | fdc->drv[id].image = (UINT8*)image.image_malloc(MAXSIZE); | |
| 159 | if (!fdc->drv[id].image) | |
| 160 | return; | |
| 161 | ||
| 162 | /* tell whether the image is writable */ | |
| 163 | fdc->drv[id].mode = !image.is_readonly(); | |
| 164 | /* set up image if it has been created */ | |
| 165 | if (image.has_been_created()) | |
| 166 | { | |
| 167 | int sector; | |
| 168 | char buff[256]; | |
| 169 | memset(buff, 0, sizeof(buff)); | |
| 170 | /* default to 720 sectors */ | |
| 171 | for( sector = 0; sector < 720; sector++ ) | |
| 172 | image.fwrite(buff, 256); | |
| 173 | image.fseek(0, SEEK_SET); | |
| 174 | } | |
| 175 | ||
| 176 | size = image.fread(fdc->drv[id].image, MAXSIZE); | |
| 177 | if( size <= 0 ) | |
| 178 | { | |
| 179 | fdc->drv[id].image = NULL; | |
| 180 | return; | |
| 181 | } | |
| 182 | /* re allocate the buffer; we don't want to be too lazy ;) */ | |
| 183 | fdc->drv[id].image = (UINT8*)image.image_realloc(fdc->drv[id].image, size); | |
| 184 | ||
| 185 | ext = image.filetype(); | |
| 186 | /* no extension: assume XFD format (no header) */ | |
| 187 | if (!ext) | |
| 188 | { | |
| 189 | fdc->drv[id].type = FORMAT_XFD; | |
| 190 | fdc->drv[id].header_skip = 0; | |
| 191 | } | |
| 192 | else | |
| 193 | /* XFD extension */ | |
| 194 | if( toupper(ext[0])=='X' && toupper(ext[1])=='F' && toupper(ext[2])=='D' ) | |
| 195 | { | |
| 196 | fdc->drv[id].type = FORMAT_XFD; | |
| 197 | fdc->drv[id].header_skip = 0; | |
| 198 | } | |
| 199 | else | |
| 200 | /* ATR extension */ | |
| 201 | if( toupper(ext[0])=='A' && toupper(ext[1])=='T' && toupper(ext[2])=='R' ) | |
| 202 | { | |
| 203 | fdc->drv[id].type = FORMAT_ATR; | |
| 204 | fdc->drv[id].header_skip = 16; | |
| 205 | } | |
| 206 | else | |
| 207 | /* DSK extension */ | |
| 208 | if( toupper(ext[0])=='D' && toupper(ext[1])=='S' && toupper(ext[2])=='K' ) | |
| 209 | { | |
| 210 | fdc->drv[id].type = FORMAT_DSK; | |
| 211 | fdc->drv[id].header_skip = sizeof(dsk_format); | |
| 212 | } | |
| 213 | else | |
| 214 | { | |
| 215 | fdc->drv[id].type = FORMAT_XFD; | |
| 216 | fdc->drv[id].header_skip = 0; | |
| 217 | } | |
| 218 | ||
| 219 | if( fdc->drv[id].type == FORMAT_ATR && | |
| 220 | (fdc->drv[id].image[0] != 0x96 || fdc->drv[id].image[1] != 0x02) ) | |
| 221 | { | |
| 222 | fdc->drv[id].type = FORMAT_XFD; | |
| 223 | fdc->drv[id].header_skip = 0; | |
| 224 | } | |
| 225 | ||
| 226 | switch (fdc->drv[id].type) | |
| 227 | { | |
| 228 | /* XFD or unknown format: find a matching size from the table */ | |
| 229 | case FORMAT_XFD: | |
| 230 | for( i = 0; xfd_formats[i].size; i++ ) | |
| 231 | { | |
| 232 | if( size == xfd_formats[i].size ) | |
| 233 | { | |
| 234 | fdc->drv[id].density = xfd_formats[i].dsk.density; | |
| 235 | fdc->drv[id].tracks = xfd_formats[i].dsk.tracks; | |
| 236 | fdc->drv[id].spt = xfd_formats[i].dsk.spt; | |
| 237 | fdc->drv[id].heads = (xfd_formats[i].dsk.doublesided) ? 2 : 1; | |
| 238 | fdc->drv[id].bseclen = 128; | |
| 239 | fdc->drv[id].seclen = 256 * xfd_formats[i].dsk.seclen_hi + xfd_formats[i].dsk.seclen_lo; | |
| 240 | fdc->drv[id].sectors = fdc->drv[id].tracks * fdc->drv[id].heads * fdc->drv[id].spt; | |
| 241 | break; | |
| 242 | } | |
| 243 | } | |
| 244 | break; | |
| 245 | /* ATR format: find a size including the 16 bytes header */ | |
| 246 | case FORMAT_ATR: | |
| 247 | { | |
| 248 | int s; | |
| 249 | ||
| 250 | fdc->drv[id].bseclen = 128; | |
| 251 | /* get sectors from ATR header */ | |
| 252 | s = (size - 16) / 128; | |
| 253 | /* 3 + odd number of sectors ? */ | |
| 254 | if ( fdc->drv[id].image[4] == 128 || (s % 18) == 0 || (s % 26) == 0 || ((s - 3) % 1) != 0 ) | |
| 255 | { | |
| 256 | fdc->drv[id].sectors = s; | |
| 257 | fdc->drv[id].seclen = 128; | |
| 258 | /* sector size 128 or count not evenly dividable by 26 ? */ | |
| 259 | if( fdc->drv[id].seclen == 128 || (s % 26) != 0 ) | |
| 260 | { | |
| 261 | /* yup! single density */ | |
| 262 | fdc->drv[id].density = 0; | |
| 263 | fdc->drv[id].spt = 18; | |
| 264 | fdc->drv[id].heads = 1; | |
| 265 | fdc->drv[id].tracks = s / 18; | |
| 266 | if( s % 18 != 0 ) | |
| 267 | fdc->drv[id].tracks += 1; | |
| 268 | if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 ) | |
| 269 | { | |
| 270 | fdc->drv[id].heads = 2; | |
| 271 | fdc->drv[id].tracks /= 2; | |
| 272 | } | |
| 273 | } | |
| 274 | else | |
| 275 | { | |
| 276 | /* yes: medium density */ | |
| 277 | fdc->drv[id].density = 0; | |
| 278 | fdc->drv[id].spt = 26; | |
| 279 | fdc->drv[id].heads = 1; | |
| 280 | fdc->drv[id].tracks = s / 26; | |
| 281 | if( s % 26 != 0 ) | |
| 282 | fdc->drv[id].tracks += 1; | |
| 283 | if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 ) | |
| 284 | { | |
| 285 | fdc->drv[id].heads = 2; | |
| 286 | fdc->drv[id].tracks /= 2; | |
| 287 | } | |
| 288 | } | |
| 289 | } | |
| 290 | else | |
| 291 | { | |
| 292 | /* it's double density */ | |
| 293 | s = (s - 3) / 2 + 3; | |
| 294 | fdc->drv[id].sectors = s; | |
| 295 | fdc->drv[id].density = 2; | |
| 296 | fdc->drv[id].seclen = 256; | |
| 297 | fdc->drv[id].spt = 18; | |
| 298 | fdc->drv[id].heads = 1; | |
| 299 | fdc->drv[id].tracks = s / 18; | |
| 300 | if( s % 18 != 0 ) | |
| 301 | fdc->drv[id].tracks += 1; | |
| 302 | if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 ) | |
| 303 | { | |
| 304 | fdc->drv[id].heads = 2; | |
| 305 | fdc->drv[id].tracks /= 2; | |
| 306 | } | |
| 307 | } | |
| 308 | } | |
| 309 | break; | |
| 310 | /* DSK format: it's all in the header */ | |
| 311 | case FORMAT_DSK: | |
| 312 | { | |
| 313 | dsk_format *dsk = (dsk_format *) fdc->drv[id].image; | |
| 314 | ||
| 315 | fdc->drv[id].tracks = dsk->tracks; | |
| 316 | fdc->drv[id].spt = dsk->spt; | |
| 317 | fdc->drv[id].heads = (dsk->doublesided) ? 2 : 1; | |
| 318 | fdc->drv[id].seclen = 256 * dsk->seclen_hi + dsk->seclen_lo; | |
| 319 | fdc->drv[id].bseclen = fdc->drv[id].seclen; | |
| 320 | fdc->drv[id].sectors = fdc->drv[id].tracks * fdc->drv[id].heads * fdc->drv[id].spt; | |
| 321 | } | |
| 322 | break; | |
| 323 | } | |
| 324 | logerror("atari opened floppy '%s', %d sectors (%d %s%s) %d bytes/sector\n", | |
| 325 | image.filename(), | |
| 326 | fdc->drv[id].sectors, | |
| 327 | fdc->drv[id].tracks, | |
| 328 | (fdc->drv[id].heads == 1) ? "SS" : "DS", | |
| 329 | (fdc->drv[id].density == 0) ? "SD" : (fdc->drv[id].density == 1) ? "MD" : "DD", | |
| 330 | fdc->drv[id].seclen); | |
| 331 | return; | |
| 332 | } | |
| 333 | ||
| 334 | ||
| 335 | ||
| 336 | /***************************************************************************** | |
| 337 | * | |
| 338 | * This is a description of the data flow between Atari (A) and the | |
| 339 | * Floppy (F) for the supported commands. | |
| 340 | * | |
| 341 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 342 | * '1' 'S' 00 00 get status | |
| 343 | * F->A ACK CPL 04 FF E0 00 CKS | |
| 344 | * ^ ^ | |
| 345 | * | | | |
| 346 | * | bit 7 : door closed | |
| 347 | * | | |
| 348 | * bit7 : MD 128 bytes/sector, 26 sectors/track | |
| 349 | * bit5 : DD 256 bytes/sector, 18 sectors/track | |
| 350 | * else : SD 128 bytes/sector, 18 sectors/track | |
| 351 | * | |
| 352 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 353 | * '1' 'R' SECL SECH read sector | |
| 354 | * F->A ACK command acknowledge | |
| 355 | * *** now read the sector | |
| 356 | * F->A CPL complete: sector read | |
| 357 | * F->A 128/256 byte CKS | |
| 358 | * | |
| 359 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 360 | * '1' 'W' SECL SECH write with verify | |
| 361 | * F->A ACK command acknowledge | |
| 362 | * A->F 128/256 data CKS | |
| 363 | * F->A CPL complete: CKS okay | |
| 364 | * execute writing the sector | |
| 365 | * F->A CPL complete: sector written | |
| 366 | * | |
| 367 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 368 | * '1' 'P' SECL SECH put sector | |
| 369 | * F->A ACK command acknowledge | |
| 370 | * A->F 128/256 data CKS | |
| 371 | * F->A CPL complete: CKS okay | |
| 372 | * execute writing the sector | |
| 373 | * F->A CPL complete: sector written | |
| 374 | * | |
| 375 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 376 | * '1' '!' xx xx single density format | |
| 377 | * F->A ACK command acknowledge | |
| 378 | * execute formatting | |
| 379 | * F->A CPL complete: format | |
| 380 | * F->A 128/256 byte CKS bad sector table | |
| 381 | * | |
| 382 | * | |
| 383 | * A->F DEV CMD AUX1 AUX2 CKS | |
| 384 | * '1' '"' xx xx double density format | |
| 385 | * F->A ACK command acknowledge | |
| 386 | * execute formatting | |
| 387 | * F->A CPL complete: format | |
| 388 | * F->A 128/256 byte CKS bad sector table | |
| 389 | * | |
| 390 | *****************************************************************************/ | |
| 391 | static void make_chksum(UINT8 * chksum, UINT8 data) | |
| 392 | { | |
| 393 | UINT8 newone; | |
| 394 | newone= *chksum + data; | |
| 395 | if (newone < *chksum) | |
| 396 | newone++; | |
| 397 | ||
| 398 | if (VERBOSE_CHKSUM) | |
| 399 | logerror("atari chksum old $%02x + data $%02x -> new $%02x\n", *chksum, data, newone); | |
| 400 | ||
| 401 | *chksum = newone; | |
| 402 | } | |
| 403 | ||
| 404 | static void clr_serout(device_t *device,int expect_data) | |
| 405 | { | |
| 406 | atari_fdc_t *fdc = get_safe_token(device); | |
| 407 | ||
| 408 | fdc->serout_chksum = 0; | |
| 409 | fdc->serout_offs = 0; | |
| 410 | fdc->serout_count = expect_data + 1; | |
| 411 | } | |
| 412 | ||
| 413 | static void add_serout(device_t *device,int expect_data) | |
| 414 | { | |
| 415 | atari_fdc_t *fdc = get_safe_token(device); | |
| 416 | ||
| 417 | fdc->serout_chksum = 0; | |
| 418 | fdc->serout_count = expect_data + 1; | |
| 419 | } | |
| 420 | ||
| 421 | static void clr_serin(device_t *device, int ser_delay) | |
| 422 | { | |
| 423 | atari_fdc_t *fdc = get_safe_token(device); | |
| 424 | device_t *pokey = device->machine().device("pokey"); | |
| 425 | fdc->serin_chksum = 0; | |
| 426 | fdc->serin_offs = 0; | |
| 427 | fdc->serin_count = 0; | |
| 428 | pokey_serin_ready(pokey, ser_delay * 40); | |
| 429 | } | |
| 430 | ||
| 431 | static void add_serin(device_t *device,UINT8 data, int with_checksum) | |
| 432 | { | |
| 433 | atari_fdc_t *fdc = get_safe_token(device); | |
| 434 | fdc->serin_buff[fdc->serin_count++] = data; | |
| 435 | if (with_checksum) | |
| 436 | make_chksum(&fdc->serin_chksum, data); | |
| 437 | } | |
| 438 | ||
| 439 | static void ATTR_PRINTF(2,3) atari_set_frame_message(device_t *device,const char *fmt, ...) | |
| 440 | { | |
| 441 | va_list arg; | |
| 442 | va_start(arg, fmt); | |
| 443 | ||
| 444 | vsprintf(atari_frame_message, fmt, arg); | |
| 445 | atari_frame_counter = 30; /* FIXME */ | |
| 446 | ||
| 447 | va_end(arg); | |
| 448 | } | |
| 449 | ||
| 450 | static void a800_serial_command(device_t *device) | |
| 451 | { | |
| 452 | int i, drive, sector, offset; | |
| 453 | atari_fdc_t *fdc = get_safe_token(device); | |
| 454 | ||
| 455 | if( !fdc->serout_offs ) | |
| 456 | { | |
| 457 | if (VERBOSE_SERIAL) | |
| 458 | logerror("atari serout command offset = 0\n"); | |
| 459 | return; | |
| 460 | } | |
| 461 | clr_serin(device, 10); | |
| 462 | ||
| 463 | if (VERBOSE_SERIAL) | |
| 464 | { | |
| 465 | logerror("atari serout command %d: %02X %02X %02X %02X %02X : %02X ", | |
| 466 | fdc->serout_offs, | |
| 467 | fdc->serout_buff[0], fdc->serout_buff[1], fdc->serout_buff[2], | |
| 468 | fdc->serout_buff[3], fdc->serout_buff[4], fdc->serout_chksum); | |
| 469 | } | |
| 470 | ||
| 471 | if (fdc->serout_chksum == 0) | |
| 472 | { | |
| 473 | if (VERBOSE_SERIAL) | |
| 474 | logerror("OK\n"); | |
| 475 | ||
| 476 | drive = fdc->serout_buff[0] - '1'; /* drive # */ | |
| 477 | /* sector # */ | |
| 478 | if (drive < 0 || drive > 3) /* ignore unknown drives */ | |
| 479 | { | |
| 480 | logerror("atari unsupported drive #%d\n", drive+1); | |
| 481 | atari_set_frame_message(device, "DRIVE #%d not supported", drive+1); | |
| 482 | return; | |
| 483 | } | |
| 484 | ||
| 485 | /* extract sector number from the command buffer */ | |
| 486 | sector = fdc->serout_buff[2] + 256 * fdc->serout_buff[3]; | |
| 487 | ||
| 488 | switch (fdc->serout_buff[1]) /* command ? */ | |
| 489 | { | |
| 490 | case 'S': /* status */ | |
| 491 | atari_set_frame_message(device, "DRIVE #%d STATUS", drive+1); | |
| 492 | ||
| 493 | if (VERBOSE_SERIAL) | |
| 494 | logerror("atari status\n"); | |
| 495 | ||
| 496 | add_serin(device,'A',0); | |
| 497 | add_serin(device,'C',0); | |
| 498 | if (!fdc->drv[drive].mode) /* read only mode ? */ | |
| 499 | { | |
| 500 | if (fdc->drv[drive].spt == 26) | |
| 501 | add_serin(device,0x80,1); /* MD: 0x80 */ | |
| 502 | else | |
| 503 | if (fdc->drv[drive].seclen == 128) | |
| 504 | add_serin(device,0x00,1); /* SD: 0x00 */ | |
| 505 | else | |
| 506 | add_serin(device,0x20,1); /* DD: 0x20 */ | |
| 507 | } | |
| 508 | else | |
| 509 | { | |
| 510 | if (fdc->drv[drive].spt == 26) | |
| 511 | add_serin(device,0x84,1); /* MD: 0x84 */ | |
| 512 | else | |
| 513 | if (fdc->drv[drive].seclen == 128) | |
| 514 | add_serin(device,0x04,1); /* SD: 0x04 */ | |
| 515 | else | |
| 516 | add_serin(device,0x24,1); /* DD: 0x24 */ | |
| 517 | } | |
| 518 | if (fdc->drv[drive].image) | |
| 519 | add_serin(device,0xff,1); /* door closed: 0xff */ | |
| 520 | else | |
| 521 | add_serin(device,0x7f,1); /* door open: 0x7f */ | |
| 522 | add_serin(device,0xe0,1); /* dunno */ | |
| 523 | add_serin(device,0x00,1); /* dunno */ | |
| 524 | add_serin(device,fdc->serin_chksum,0); | |
| 525 | break; | |
| 526 | ||
| 527 | case 'R': /* read sector */ | |
| 528 | if (VERBOSE_SERIAL) | |
| 529 | logerror("atari read sector #%d\n", sector); | |
| 530 | ||
| 531 | if( sector < 1 || sector > fdc->drv[drive].sectors ) | |
| 532 | { | |
| 533 | atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - ERR", drive+1, sector); | |
| 534 | ||
| 535 | if (VERBOSE_SERIAL) | |
| 536 | logerror("atari bad sector #\n"); | |
| 537 | ||
| 538 | add_serin(device,'E',0); | |
| 539 | break; | |
| 540 | } | |
| 541 | add_serin(device,'A',0); /* acknowledge */ | |
| 542 | add_serin(device,'C',0); /* completed */ | |
| 543 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 544 | { | |
| 545 | atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - SD", drive+1, sector); | |
| 546 | offset = (sector - 1) * fdc->drv[drive].bseclen + fdc->drv[drive].header_skip; | |
| 547 | for (i = 0; i < 128; i++) | |
| 548 | add_serin(device,fdc->drv[drive].image[offset++],1); | |
| 549 | } | |
| 550 | else | |
| 551 | { | |
| 552 | atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 553 | offset = (sector - 1) * fdc->drv[drive].seclen + fdc->drv[drive].header_skip; | |
| 554 | for (i = 0; i < fdc->drv[drive].seclen; i++) | |
| 555 | add_serin(device,fdc->drv[drive].image[offset++],1); | |
| 556 | } | |
| 557 | add_serin(device,fdc->serin_chksum,0); | |
| 558 | break; | |
| 559 | ||
| 560 | case 'W': /* write sector with verify */ | |
| 561 | if (VERBOSE_SERIAL) | |
| 562 | logerror("atari write sector #%d\n", sector); | |
| 563 | ||
| 564 | add_serin(device,'A',0); | |
| 565 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 566 | { | |
| 567 | add_serout(device,fdc->drv[drive].bseclen); | |
| 568 | atari_set_frame_message(device, "DRIVE #%d WRITE SECTOR #%3d - SD", drive+1, sector); | |
| 569 | } | |
| 570 | else | |
| 571 | { | |
| 572 | add_serout(device,fdc->drv[drive].seclen); | |
| 573 | atari_set_frame_message(device, "DRIVE #%d WRITE SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 574 | } | |
| 575 | break; | |
| 576 | ||
| 577 | case 'P': /* put sector (no verify) */ | |
| 578 | if (VERBOSE_SERIAL) | |
| 579 | logerror("atari put sector #%d\n", sector); | |
| 580 | ||
| 581 | add_serin(device,'A',0); | |
| 582 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 583 | { | |
| 584 | add_serout(device,fdc->drv[drive].bseclen); | |
| 585 | atari_set_frame_message(device, "DRIVE #%d PUT SECTOR #%3d - SD", drive+1, sector); | |
| 586 | } | |
| 587 | else | |
| 588 | { | |
| 589 | add_serout(device,fdc->drv[drive].seclen); | |
| 590 | atari_set_frame_message(device, "DRIVE #%d PUT SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 591 | } | |
| 592 | break; | |
| 593 | ||
| 594 | case '!': /* SD format */ | |
| 595 | if (VERBOSE_SERIAL) | |
| 596 | logerror("atari format SD drive #%d\n", drive+1); | |
| 597 | ||
| 598 | atari_set_frame_message(device, "DRIVE #%d FORMAT SD", drive+1); | |
| 599 | add_serin(device,'A',0); /* acknowledge */ | |
| 600 | add_serin(device,'C',0); /* completed */ | |
| 601 | for (i = 0; i < 128; i++) | |
| 602 | add_serin(device,0,1); | |
| 603 | add_serin(device,fdc->serin_chksum,0); | |
| 604 | break; | |
| 605 | ||
| 606 | case '"': /* DD format */ | |
| 607 | if (VERBOSE_SERIAL) | |
| 608 | logerror("atari format DD drive #%d\n", drive+1); | |
| 609 | ||
| 610 | atari_set_frame_message(device, "DRIVE #%d FORMAT DD", drive+1); | |
| 611 | add_serin(device,'A',0); /* acknowledge */ | |
| 612 | add_serin(device,'C',0); /* completed */ | |
| 613 | for (i = 0; i < 256; i++) | |
| 614 | add_serin(device,0,1); | |
| 615 | add_serin(device,fdc->serin_chksum,0); | |
| 616 | break; | |
| 617 | ||
| 618 | default: | |
| 619 | if (VERBOSE_SERIAL) | |
| 620 | logerror("atari unknown command #%c\n", fdc->serout_buff[1]); | |
| 621 | ||
| 622 | atari_set_frame_message(device, "DRIVE #%d UNKNOWN CMD '%c'", drive+1, fdc->serout_buff[1]); | |
| 623 | add_serin(device,'N',0); /* negative acknowledge */ | |
| 624 | } | |
| 625 | } | |
| 626 | else | |
| 627 | { | |
| 628 | atari_set_frame_message(device, "serial cmd chksum error"); | |
| 629 | if (VERBOSE_SERIAL) | |
| 630 | logerror("BAD\n"); | |
| 631 | ||
| 632 | add_serin(device,'E',0); | |
| 633 | } | |
| 634 | if (VERBOSE_SERIAL) | |
| 635 | logerror("atari %d bytes to read\n", fdc->serin_count); | |
| 636 | } | |
| 637 | ||
| 638 | static void a800_serial_write(device_t *device) | |
| 639 | { | |
| 640 | int i, drive, sector, offset; | |
| 641 | atari_fdc_t *fdc = get_safe_token(device); | |
| 642 | ||
| 643 | if (VERBOSE_SERIAL) | |
| 644 | { | |
| 645 | logerror("atari serout %d bytes written : %02X ", | |
| 646 | fdc->serout_offs, fdc->serout_chksum); | |
| 647 | } | |
| 648 | ||
| 649 | clr_serin(device, 80); | |
| 650 | if (fdc->serout_chksum == 0) | |
| 651 | { | |
| 652 | if (VERBOSE_SERIAL) | |
| 653 | logerror("OK\n"); | |
| 654 | ||
| 655 | add_serin(device,'C',0); | |
| 656 | /* write the sector */ | |
| 657 | drive = fdc->serout_buff[0] - '1'; /* drive # */ | |
| 658 | /* not write protected and image available ? */ | |
| 659 | if (fdc->drv[drive].mode && fdc->drv[drive].image) | |
| 660 | { | |
| 661 | /* extract sector number from the command buffer */ | |
| 662 | sector = fdc->serout_buff[2] + 256 * fdc->serout_buff[3]; | |
| 663 | if (sector < 4) /* sector 1 .. 3 might be different length */ | |
| 664 | { | |
| 665 | offset = (sector - 1) * fdc->drv[drive].bseclen + fdc->drv[drive].header_skip; | |
| 666 | ||
| 667 | if (VERBOSE_SERIAL) | |
| 668 | logerror("atari storing 128 byte sector %d at offset 0x%08X", sector, offset ); | |
| 669 | ||
| 670 | for (i = 0; i < 128; i++) | |
| 671 | fdc->drv[drive].image[offset++] = fdc->serout_buff[5+i]; | |
| 672 | atari_set_frame_message(device, "DRIVE #%d WROTE SECTOR #%3d - SD", drive+1, sector); | |
| 673 | } | |
| 674 | else | |
| 675 | { | |
| 676 | offset = (sector - 1) * fdc->drv[drive].seclen + fdc->drv[drive].header_skip; | |
| 677 | ||
| 678 | if (VERBOSE_SERIAL) | |
| 679 | logerror("atari storing %d byte sector %d at offset 0x%08X", fdc->drv[drive].seclen, sector, offset ); | |
| 680 | ||
| 681 | for (i = 0; i < fdc->drv[drive].seclen; i++) | |
| 682 | fdc->drv[drive].image[offset++] = fdc->serout_buff[5+i]; | |
| 683 | atari_set_frame_message(device, "DRIVE #%d WROTE SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D'); | |
| 684 | } | |
| 685 | add_serin(device,'C',0); | |
| 686 | } | |
| 687 | else | |
| 688 | { | |
| 689 | add_serin(device,'E',0); | |
| 690 | } | |
| 691 | } | |
| 692 | else | |
| 693 | { | |
| 694 | if (VERBOSE_SERIAL) | |
| 695 | logerror("BAD\n"); | |
| 696 | ||
| 697 | add_serin(device,'E',0); | |
| 698 | } | |
| 699 | } | |
| 700 | ||
| 701 | READ8_DEVICE_HANDLER ( atari_serin_r ) | |
| 702 | { | |
| 703 | int data = 0x00; | |
| 704 | int ser_delay = 0; | |
| 705 | atari_fdc_t *fdc = get_safe_token(device); | |
| 706 | ||
| 707 | if (fdc->serin_count) | |
| 708 | { | |
| 709 | device_t *pokey = device->machine().device("pokey"); | |
| 710 | ||
| 711 | data = fdc->serin_buff[fdc->serin_offs]; | |
| 712 | ser_delay = 2 * 40; | |
| 713 | if (fdc->serin_offs < 3) | |
| 714 | { | |
| 715 | ser_delay = 4 * 40; | |
| 716 | if (fdc->serin_offs < 2) | |
| 717 | ser_delay = 200 * 40; | |
| 718 | } | |
| 719 | fdc->serin_offs++; | |
| 720 | if (--fdc->serin_count == 0) | |
| 721 | fdc->serin_offs = 0; | |
| 722 | else | |
| 723 | pokey_serin_ready(pokey, ser_delay); | |
| 724 | } | |
| 725 | ||
| 726 | if (VERBOSE_SERIAL) | |
| 727 | logerror("atari serin[$%04x] -> $%02x; delay %d\n", fdc->serin_offs, data, ser_delay); | |
| 728 | ||
| 729 | return data; | |
| 730 | } | |
| 731 | ||
| 732 | WRITE8_DEVICE_HANDLER ( atari_serout_w ) | |
| 733 | { | |
| 734 | pia6821_device *pia = device->machine().device<pia6821_device>( "pia" ); | |
| 735 | atari_fdc_t *fdc = get_safe_token(device); | |
| 736 | ||
| 737 | /* ignore serial commands if no floppy image is specified */ | |
| 738 | if( !fdc->drv[0].image ) | |
| 739 | return; | |
| 740 | if (fdc->serout_count) | |
| 741 | { | |
| 742 | /* store data */ | |
| 743 | fdc->serout_buff[fdc->serout_offs] = data; | |
| 744 | ||
| 745 | if (VERBOSE_SERIAL) | |
| 746 | logerror("atari serout[$%04x] <- $%02x; count %d\n", fdc->serout_offs, data, fdc->serout_count); | |
| 747 | ||
| 748 | fdc->serout_offs++; | |
| 749 | if (--fdc->serout_count == 0) | |
| 750 | { | |
| 751 | /* exclusive or written checksum with calculated */ | |
| 752 | fdc->serout_chksum ^= data; | |
| 753 | /* if the attention line is high, this should be data */ | |
| 754 | if (pia->irq_b_state()) | |
| 755 | a800_serial_write(device); | |
| 756 | } | |
| 757 | else | |
| 758 | { | |
| 759 | make_chksum(&fdc->serout_chksum, data); | |
| 760 | } | |
| 761 | } | |
| 762 | } | |
| 763 | ||
| 764 | WRITE_LINE_DEVICE_HANDLER(atarifdc_pia_cb2_w) | |
| 765 | { | |
| 766 | atari_fdc_t *fdc = get_safe_token(device); | |
| 767 | if (!state) | |
| 768 | { | |
| 769 | clr_serout(device,4); /* expect 4 command bytes + checksum */ | |
| 770 | } | |
| 771 | else | |
| 772 | { | |
| 773 | fdc->serin_delay = 0; | |
| 774 | a800_serial_command(device); | |
| 775 | } | |
| 776 | } | |
| 777 | ||
| 778 | static FLOPPY_IDENTIFY( atari_dsk_identify ) | |
| 779 | { | |
| 780 | *vote = 100; | |
| 781 | return FLOPPY_ERROR_SUCCESS; | |
| 782 | } | |
| 783 | ||
| 784 | ||
| 785 | static FLOPPY_CONSTRUCT( atari_dsk_construct ) | |
| 786 | { | |
| 787 | return FLOPPY_ERROR_SUCCESS; | |
| 788 | } | |
| 789 | ||
| 790 | FLOPPY_OPTIONS_START( atari_only ) | |
| 791 | FLOPPY_OPTION( | |
| 792 | atari_dsk, | |
| 793 | "atr,dsk,xfd", | |
| 794 | "Atari floppy disk image", | |
| 795 | atari_dsk_identify, | |
| 796 | atari_dsk_construct, | |
| 797 | NULL, | |
| 798 | NULL | |
| 799 | ) | |
| 800 | FLOPPY_OPTIONS_END0 | |
| 801 | ||
| 802 | static const floppy_config atari_floppy_config = | |
| 803 | { | |
| 804 | DEVCB_NULL, | |
| 805 | DEVCB_NULL, | |
| 806 | DEVCB_NULL, | |
| 807 | DEVCB_NULL, | |
| 808 | DEVCB_NULL, | |
| 809 | FLOPPY_STANDARD_5_25_DSHD, | |
| 810 | FLOPPY_OPTIONS_NAME(atari_only), | |
| 811 | NULL | |
| 812 | }; | |
| 813 | ||
| 814 | static MACHINE_CONFIG_FRAGMENT( atari_fdc ) | |
| 815 | MCFG_FLOPPY_4_DRIVES_ADD(atari_floppy_config) | |
| 816 | MACHINE_CONFIG_END | |
| 817 | ||
| 818 | device_t *atari_floppy_get_device_child(device_t *device,int drive) | |
| 819 | { | |
| 820 | switch(drive) { | |
| 821 | case 0 : return device->subdevice(FLOPPY_0); | |
| 822 | case 1 : return device->subdevice(FLOPPY_1); | |
| 823 | case 2 : return device->subdevice(FLOPPY_2); | |
| 824 | case 3 : return device->subdevice(FLOPPY_3); | |
| 825 | } | |
| 826 | return NULL; | |
| 827 | } | |
| 828 | ||
| 829 | static DEVICE_START(atari_fdc) | |
| 830 | { | |
| 831 | int id; | |
| 832 | for(id=0;id<4;id++) | |
| 833 | { | |
| 834 | floppy_install_load_proc(atari_floppy_get_device_child(device, id), atari_load_proc); | |
| 835 | } | |
| 836 | } | |
| 837 | ||
| 838 | static DEVICE_RESET(atari_fdc) | |
| 839 | { | |
| 840 | } | |
| 841 | ||
| 842 | DEVICE_GET_INFO( atari_fdc ) | |
| 843 | { | |
| 844 | switch (state) | |
| 845 | { | |
| 846 | /* --- the following bits of info are returned as 64-bit signed integers --- */ | |
| 847 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; | |
| 848 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(atari_fdc_t); break; | |
| 849 | ||
| 850 | /* --- the following bits of info are returned as pointers --- */ | |
| 851 | case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(atari_fdc); break; | |
| 852 | ||
| 853 | /* --- the following bits of info are returned as pointers to data or functions --- */ | |
| 854 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(atari_fdc); break; | |
| 855 | case DEVINFO_FCT_STOP: /* Nothing */ break; | |
| 856 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(atari_fdc); break; | |
| 857 | ||
| 858 | /* --- the following bits of info are returned as NULL-terminated strings --- */ | |
| 859 | case DEVINFO_STR_NAME: strcpy(info->s, "Atari FDC"); break; | |
| 860 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Atari FDC"); break; | |
| 861 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; | |
| 862 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; | |
| 863 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; | |
| 864 | } | |
| 865 | } | |
| 866 | ||
| 867 | DEFINE_LEGACY_DEVICE(ATARI_FDC, atari_fdc); |
| r0 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * includes/nes.h | |
| 4 | * | |
| 5 | * Nintendo Entertainment System (Famicom) | |
| 6 | * | |
| 7 | ****************************************************************************/ | |
| 8 | ||
| 9 | #ifndef NES_H_ | |
| 10 | #define NES_H_ | |
| 11 | ||
| 12 | ||
| 13 | /*************************************************************************** | |
| 14 | CONSTANTS | |
| 15 | ***************************************************************************/ | |
| 16 | ||
| 17 | #define NTSC_CLOCK N2A03_DEFAULTCLOCK /* 1.789772 MHz */ | |
| 18 | #define PAL_CLOCK (26601712.0/16) /* 1.662607 MHz */ | |
| 19 | ||
| 20 | #define NES_BATTERY_SIZE 0x2000 | |
| 21 | ||
| 22 | ||
| 23 | /*************************************************************************** | |
| 24 | TYPE DEFINITIONS | |
| 25 | ***************************************************************************/ | |
| 26 | ||
| 27 | struct nes_input | |
| 28 | { | |
| 29 | UINT32 shift; | |
| 30 | UINT32 i0, i1, i2; | |
| 31 | }; | |
| 32 | ||
| 33 | /*PPU fast banking constants and structures */ | |
| 34 | ||
| 35 | #define CHRROM 0 | |
| 36 | #define CHRRAM 1 | |
| 37 | ||
| 38 | typedef struct | |
| 39 | { | |
| 40 | int source; //defines source of base pointer | |
| 41 | int origin; //defines offset of 0x400 byte segment at base pointer | |
| 42 | UINT8* access; //source translated + origin -> valid pointer! | |
| 43 | } chr_bank; | |
| 44 | ||
| 45 | /*PPU nametable fast banking constants and structures */ | |
| 46 | ||
| 47 | #define CIRAM 0 | |
| 48 | #define ROM 1 | |
| 49 | #define EXRAM 2 | |
| 50 | #define MMC5FILL 3 | |
| 51 | #define CART_NTRAM 4 | |
| 52 | ||
| 53 | #define NES_BATTERY 0 | |
| 54 | #define NES_WRAM 1 | |
| 55 | ||
| 56 | typedef struct | |
| 57 | { | |
| 58 | int source; /* defines source of base pointer */ | |
| 59 | int origin; /* defines offset of 0x400 byte segment at base pointer */ | |
| 60 | int writable; /* ExRAM, at least, can be write-protected AND used as nametable */ | |
| 61 | UINT8* access; /* direct access when possible */ | |
| 62 | } name_table; | |
| 63 | ||
| 64 | typedef void (*nes_prg_callback)(running_machine &machine, int start, int bank); | |
| 65 | typedef void (*nes_chr_callback)(running_machine &machine, int start, int bank, int source); | |
| 66 | ||
| 67 | class nes_state : public driver_device | |
| 68 | { | |
| 69 | public: | |
| 70 | nes_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 71 | : driver_device(mconfig, type, tag) { } | |
| 72 | ||
| 73 | /* input_related - this part has to be cleaned up (e.g. in_2 and in_3 are not really necessary here...) */ | |
| 74 | nes_input m_in_0, m_in_1, m_in_2, m_in_3; | |
| 75 | UINT8 m_fck_scan, m_fck_mode; | |
| 76 | ||
| 77 | int m_prg_bank[5]; | |
| 78 | chr_bank m_chr_map[8]; //quick banking structure, because some of this changes multiple times per scanline! | |
| 79 | name_table m_nt_page[4]; //quick banking structure for a maximum of 4K of RAM/ROM/ExRAM | |
| 80 | ||
| 81 | int m_chr_open_bus; | |
| 82 | int m_prgram_bank5_start, m_battery_bank5_start, m_empty_bank5_start; | |
| 83 | ||
| 84 | UINT8 m_ce_mask, m_ce_state; | |
| 85 | UINT8 m_vrc_ls_prg_a, m_vrc_ls_prg_b, m_vrc_ls_chr; | |
| 86 | ||
| 87 | int m_MMC5_floodtile; | |
| 88 | int m_MMC5_floodattr; | |
| 89 | int m_mmc5_vram_control; | |
| 90 | UINT8 m_mmc5_high_chr; | |
| 91 | UINT8 m_mmc5_split_scr; | |
| 92 | UINT8 *m_extended_ntram; | |
| 93 | ||
| 94 | UINT8 m_mmc5_last_chr_a; | |
| 95 | UINT16 m_mmc5_vrom_regA[8]; | |
| 96 | UINT16 m_mmc5_vrom_regB[4]; | |
| 97 | UINT8 m_mmc5_prg_regs[4]; | |
| 98 | UINT8 m_mmc5_bank_security; | |
| 99 | UINT8 m_mmc5_prg_mode; | |
| 100 | UINT8 m_mmc5_chr_mode; | |
| 101 | UINT8 m_mmc5_chr_high; | |
| 102 | UINT8 m_mmc5_split_ctrl; | |
| 103 | UINT8 m_mmc5_split_yst; | |
| 104 | UINT8 m_mmc5_split_bank; | |
| 105 | ||
| 106 | /* video-related */ | |
| 107 | int m_nes_vram_sprite[8]; /* Used only by mmc5 for now */ | |
| 108 | int m_last_frame_flip; | |
| 109 | ||
| 110 | /* misc */ | |
| 111 | write8_space_func m_mmc_write_low; | |
| 112 | const char *m_mmc_write_low_name; | |
| 113 | write8_space_func m_mmc_write_mid; | |
| 114 | const char *m_mmc_write_mid_name; | |
| 115 | write8_space_func m_mmc_write; | |
| 116 | const char *m_mmc_write_name; | |
| 117 | read8_space_func m_mmc_read_low; | |
| 118 | const char *m_mmc_read_low_name; | |
| 119 | read8_space_func m_mmc_read_mid; | |
| 120 | const char *m_mmc_read_mid_name; | |
| 121 | read8_space_func m_mmc_read; | |
| 122 | const char *m_mmc_read_name; | |
| 123 | emu_timer *m_irq_timer; | |
| 124 | ||
| 125 | nes_prg_callback m_mmc3_prg_cb; // these are used to simplify a lot emulation of some MMC3 pirate clones | |
| 126 | nes_chr_callback m_mmc3_chr_cb; | |
| 127 | ||
| 128 | /* devices */ | |
| 129 | device_t *m_maincpu; | |
| 130 | device_t *m_ppu; | |
| 131 | device_t *m_sound; | |
| 132 | device_t *m_cart; | |
| 133 | ||
| 134 | /* misc region to be allocated at init */ | |
| 135 | // variables which don't change at run-time | |
| 136 | UINT8 *m_rom; | |
| 137 | UINT8 *m_vrom; | |
| 138 | UINT8 *m_vram; | |
| 139 | UINT8 *m_wram; | |
| 140 | UINT8 *m_ciram; //PPU nametable RAM - external to PPU! | |
| 141 | UINT8 *m_battery_ram; | |
| 142 | UINT8 *m_mapper_ram; | |
| 143 | UINT8 *m_mapper_bram; | |
| 144 | ||
| 145 | /***** Mapper-related variables *****/ | |
| 146 | ||
| 147 | // common ones | |
| 148 | int m_IRQ_enable, m_IRQ_enable_latch; | |
| 149 | UINT16 m_IRQ_count, m_IRQ_count_latch; | |
| 150 | UINT8 m_IRQ_toggle; | |
| 151 | UINT8 m_IRQ_reset; | |
| 152 | UINT8 m_IRQ_status; | |
| 153 | UINT8 m_IRQ_mode; | |
| 154 | UINT8 m_IRQ_clear; | |
| 155 | int m_mult1, m_mult2; | |
| 156 | ||
| 157 | UINT8 m_mmc_chr_source; // This is set at init to CHRROM or CHRRAM. a few mappers can swap between | |
| 158 | // the two (this is done in the specific handlers). | |
| 159 | ||
| 160 | UINT8 m_mmc_cmd1, m_mmc_cmd2; // These represent registers where the mapper writes important values | |
| 161 | UINT8 m_mmc_count; // This is used as counter in mappers like 1 and 45 | |
| 162 | ||
| 163 | int m_mmc_prg_base, m_mmc_prg_mask; // MMC3 based multigame carts select a block of banks by using these (and then act like normal MMC3), | |
| 164 | int m_mmc_chr_base, m_mmc_chr_mask; // while MMC3 and clones (mapper 118 & 119) simply set them as 0 and 0xff resp. | |
| 165 | ||
| 166 | UINT8 m_mmc_prg_bank[6]; // Many mappers writes only some bits of the selected bank (for both PRG and CHR), | |
| 167 | UINT8 m_mmc_vrom_bank[16]; // hence these are handy to latch bank values. | |
| 168 | ||
| 169 | UINT16 m_MMC5_vrom_bank[12]; // MMC5 has 10bit wide VROM regs! | |
| 170 | UINT8 m_mmc_extra_bank[16]; // some MMC3 clone have 2 series of PRG/CHR banks... | |
| 171 | // we collect them all here: first 4 elements PRG banks, then 6/8 CHR banks | |
| 172 | ||
| 173 | UINT8 m_mmc_latch1, m_mmc_latch2; | |
| 174 | UINT8 m_mmc_reg[16]; | |
| 175 | ||
| 176 | UINT8 m_mmc_dipsetting; | |
| 177 | ||
| 178 | // misc mapper related variables which should be merged with the above one, where possible | |
| 179 | int m_mmc1_reg_write_enable; | |
| 180 | int m_mmc1_latch; | |
| 181 | int m_mmc1_count; | |
| 182 | ||
| 183 | int m_mmc3_latch; | |
| 184 | int m_mmc3_wram_protect; | |
| 185 | int m_mmc3_alt_irq; | |
| 186 | ||
| 187 | int m_MMC5_rom_bank_mode; | |
| 188 | int m_MMC5_vrom_bank_mode; | |
| 189 | int m_MMC5_vram_protect; | |
| 190 | int m_MMC5_scanline; | |
| 191 | int m_vrom_page_a; | |
| 192 | int m_vrom_page_b; | |
| 193 | // int vrom_next[4]; | |
| 194 | ||
| 195 | UINT8 m_mmc6_reg; | |
| 196 | ||
| 197 | // these might be unified in single mmc_reg[] array, together with state->m_mmc_cmd1 & state->m_mmc_cmd2 | |
| 198 | // but be careful that MMC3 clones often use state->m_mmc_cmd1/state->m_mmc_cmd2 (from base MMC3) AND additional regs below! | |
| 199 | UINT8 m_mapper83_reg[10]; | |
| 200 | UINT8 m_mapper83_low_reg[4]; | |
| 201 | UINT8 m_txc_reg[4]; // used by mappers 132, 172 & 173 | |
| 202 | UINT8 m_subor_reg[4]; // used by mappers 166 & 167 | |
| 203 | UINT8 m_sachen_reg[8]; // used by mappers 137, 138, 139 & 141 | |
| 204 | UINT8 m_map52_reg_written; | |
| 205 | UINT8 m_map114_reg, m_map114_reg_enabled; | |
| 206 | ||
| 207 | /***** NES-cart related *****/ | |
| 208 | ||
| 209 | /* load-time cart variables which remain constant */ | |
| 210 | UINT16 m_prg_chunks; // iNES 2.0 allows for more chunks (a recently dumped multigame cart has 256 chunks of both PRG & CHR!) | |
| 211 | UINT16 m_chr_chunks; | |
| 212 | UINT16 m_vram_chunks; | |
| 213 | UINT8 m_trainer; | |
| 214 | UINT8 m_battery; // if there is PRG RAM with battery backup | |
| 215 | UINT32 m_battery_size; | |
| 216 | UINT8 m_prg_ram; // if there is PRG RAM with no backup | |
| 217 | UINT32 m_wram_size; | |
| 218 | UINT32 m_mapper_ram_size; | |
| 219 | UINT32 m_mapper_bram_size; | |
| 220 | ||
| 221 | /* system variables which don't change at run-time */ | |
| 222 | UINT16 m_mapper; // for iNES | |
| 223 | UINT16 m_pcb_id; // for UNIF & xml | |
| 224 | UINT8 m_four_screen_vram; | |
| 225 | UINT8 m_hard_mirroring; | |
| 226 | UINT8 m_crc_hack; // this is needed to detect different boards sharing the same Mappers (shame on .nes format) | |
| 227 | UINT8 m_ines20; | |
| 228 | ||
| 229 | /***** FDS-floppy related *****/ | |
| 230 | ||
| 231 | int m_disk_expansion; | |
| 232 | ||
| 233 | UINT8 m_fds_sides; | |
| 234 | UINT8 *m_fds_data; // here, we store a copy of the disk | |
| 235 | UINT8 *m_fds_ram; // here, we emulate the RAM adapter | |
| 236 | ||
| 237 | /* Variables which can change */ | |
| 238 | UINT8 m_fds_motor_on; | |
| 239 | UINT8 m_fds_door_closed; | |
| 240 | UINT8 m_fds_current_side; | |
| 241 | UINT32 m_fds_head_position; | |
| 242 | UINT8 m_fds_status0; | |
| 243 | UINT8 m_fds_read_mode; | |
| 244 | UINT8 m_fds_write_reg; | |
| 245 | ||
| 246 | /* these are used in the mapper 20 handlers */ | |
| 247 | int m_fds_last_side; | |
| 248 | int m_fds_count; | |
| 249 | }; | |
| 250 | ||
| 251 | ||
| 252 | /*----------- defined in machine/nes.c -----------*/ | |
| 253 | ||
| 254 | WRITE8_HANDLER ( nes_IN0_w ); | |
| 255 | WRITE8_HANDLER ( nes_IN1_w ); | |
| 256 | ||
| 257 | /* protos */ | |
| 258 | ||
| 259 | DEVICE_IMAGE_LOAD(nes_cart); | |
| 260 | DEVICE_START(nes_disk); | |
| 261 | DEVICE_IMAGE_LOAD(nes_disk); | |
| 262 | DEVICE_IMAGE_UNLOAD(nes_disk); | |
| 263 | ||
| 264 | MACHINE_START( nes ); | |
| 265 | MACHINE_RESET( nes ); | |
| 266 | ||
| 267 | DRIVER_INIT( famicom ); | |
| 268 | ||
| 269 | READ8_HANDLER( nes_IN0_r ); | |
| 270 | READ8_HANDLER( nes_IN1_r ); | |
| 271 | ||
| 272 | int nes_ppu_vidaccess( device_t *device, int address, int data ); | |
| 273 | ||
| 274 | void nes_partialhash(hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions); | |
| 275 | ||
| 276 | /*----------- defined in video/nes.c -----------*/ | |
| 277 | ||
| 278 | PALETTE_INIT( nes ); | |
| 279 | VIDEO_START( nes ); | |
| 280 | SCREEN_UPDATE( nes ); | |
| 281 | ||
| 282 | ||
| 283 | #endif /* NES_H_ */ |
| r0 | r11532 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * includes/pce.h | |
| 4 | * | |
| 5 | * NEC PC Engine/TurboGrafx16 | |
| 6 | * | |
| 7 | ****************************************************************************/ | |
| 8 | ||
| 9 | #ifndef PCE_H_ | |
| 10 | #define PCE_H_ | |
| 11 | ||
| 12 | #include "cdrom.h" | |
| 13 | #include "sound/msm5205.h" | |
| 14 | ||
| 15 | #define C6280_TAG "c6280" | |
| 16 | ||
| 17 | #define MAIN_CLOCK 21477270 | |
| 18 | #define PCE_CD_CLOCK 9216000 | |
| 19 | ||
| 20 | #define PCE_HEADER_SIZE 512 | |
| 21 | ||
| 22 | #define TG_16_JOY_SIG 0x00 | |
| 23 | #define PCE_JOY_SIG 0x40 | |
| 24 | #define NO_CD_SIG 0x80 | |
| 25 | #define CD_SIG 0x00 | |
| 26 | /* these might be used to indicate something, but they always seem to return 1 */ | |
| 27 | #define CONST_SIG 0x30 | |
| 28 | ||
| 29 | /* the largest possible cartridge image (street fighter 2 - 2.5MB) */ | |
| 30 | #define PCE_ROM_MAXSIZE 0x280000 | |
| 31 | ||
| 32 | typedef struct | |
| 33 | { | |
| 34 | UINT8 regs[16]; | |
| 35 | UINT8 *bram; | |
| 36 | UINT8 *adpcm_ram; | |
| 37 | int bram_locked; | |
| 38 | int adpcm_read_ptr; | |
| 39 | UINT8 adpcm_read_buf; | |
| 40 | int adpcm_write_ptr; | |
| 41 | UINT8 adpcm_write_buf; | |
| 42 | int adpcm_length; | |
| 43 | int adpcm_clock_divider; | |
| 44 | UINT32 msm_start_addr; | |
| 45 | UINT32 msm_end_addr; | |
| 46 | UINT32 msm_half_addr; | |
| 47 | UINT8 msm_nibble; | |
| 48 | UINT8 msm_idle; | |
| 49 | ||
| 50 | /* SCSI signals */ | |
| 51 | int scsi_BSY; /* Busy. Bus in use */ | |
| 52 | int scsi_SEL; /* Select. Initiator has won arbitration and has selected a target */ | |
| 53 | int scsi_CD; /* Control/Data. Target is sending control (data) information */ | |
| 54 | int scsi_IO; /* Input/Output. Target is sending (receiving) information */ | |
| 55 | int scsi_MSG; /* Message. Target is sending or receiving a message */ | |
| 56 | int scsi_REQ; /* Request. Target is requesting a data transfer */ | |
| 57 | int scsi_ACK; /* Acknowledge. Initiator acknowledges that it is ready for a data transfer */ | |
| 58 | int scsi_ATN; /* Attention. Initiator has a message ready for the target */ | |
| 59 | int scsi_RST; /* Reset. Initiator forces all targets and any other initiators to do a warm reset */ | |
| 60 | int scsi_last_RST; /* To catch setting of RST signal */ | |
| 61 | int cd_motor_on; | |
| 62 | int selected; | |
| 63 | UINT8 *command_buffer; | |
| 64 | int command_buffer_index; | |
| 65 | int status_sent; | |
| 66 | int message_after_status; | |
| 67 | int message_sent; | |
| 68 | UINT8 *data_buffer; | |
| 69 | int data_buffer_size; | |
| 70 | int data_buffer_index; | |
| 71 | int data_transferred; | |
| 72 | ||
| 73 | /* Arcade Card specific */ | |
| 74 | UINT8 *acard_ram; | |
| 75 | UINT8 acard_latch; | |
| 76 | UINT8 acard_ctrl[4]; | |
| 77 | UINT32 acard_base_addr[4]; | |
| 78 | UINT16 acard_addr_offset[4]; | |
| 79 | UINT16 acard_addr_inc[4]; | |
| 80 | UINT32 acard_shift; | |
| 81 | UINT8 acard_shift_reg; | |
| 82 | ||
| 83 | UINT32 current_frame; | |
| 84 | UINT32 end_frame; | |
| 85 | UINT32 last_frame; | |
| 86 | UINT8 cdda_status; | |
| 87 | UINT8 cdda_play_mode; | |
| 88 | UINT8 *subcode_buffer; | |
| 89 | UINT8 end_mark; | |
| 90 | cdrom_file *cd; | |
| 91 | const cdrom_toc* toc; | |
| 92 | emu_timer *data_timer; | |
| 93 | emu_timer *adpcm_dma_timer; | |
| 94 | ||
| 95 | emu_timer *cdda_fadeout_timer; | |
| 96 | emu_timer *cdda_fadein_timer; | |
| 97 | double cdda_volume; | |
| 98 | emu_timer *adpcm_fadeout_timer; | |
| 99 | emu_timer *adpcm_fadein_timer; | |
| 100 | double adpcm_volume; | |
| 101 | } pce_cd_t; | |
| 102 | ||
| 103 | ||
| 104 | class pce_state : public driver_device | |
| 105 | { | |
| 106 | public: | |
| 107 | pce_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 108 | : driver_device(mconfig, type, tag) { } | |
| 109 | ||
| 110 | unsigned char *m_user_ram; | |
| 111 | UINT8 *m_cd_ram; | |
| 112 | UINT8 m_io_port_options; | |
| 113 | UINT8 m_sys3_card; | |
| 114 | UINT8 m_acard; | |
| 115 | pce_cd_t m_cd; | |
| 116 | UINT8 *m_cartridge_ram; | |
| 117 | int m_joystick_port_select; | |
| 118 | int m_joystick_data_select; | |
| 119 | UINT8 m_joy_6b_packet[5]; | |
| 120 | }; | |
| 121 | ||
| 122 | ||
| 123 | /*----------- defined in machine/pce.c -----------*/ | |
| 124 | ||
| 125 | DEVICE_IMAGE_LOAD(pce_cart); | |
| 126 | NVRAM_HANDLER( pce ); | |
| 127 | WRITE8_HANDLER ( pce_joystick_w ); | |
| 128 | READ8_HANDLER ( pce_joystick_r ); | |
| 129 | ||
| 130 | extern const msm5205_interface pce_cd_msm5205_interface; | |
| 131 | WRITE8_HANDLER( pce_cd_bram_w ); | |
| 132 | WRITE8_HANDLER( pce_cd_intf_w ); | |
| 133 | READ8_HANDLER( pce_cd_intf_r ); | |
| 134 | WRITE8_HANDLER( pce_cd_acard_w ); | |
| 135 | READ8_HANDLER( pce_cd_acard_r ); | |
| 136 | WRITE8_HANDLER( pce_cd_acard_wram_w ); | |
| 137 | READ8_HANDLER( pce_cd_acard_wram_r ); | |
| 138 | ||
| 139 | DRIVER_INIT( pce ); | |
| 140 | DRIVER_INIT( tg16 ); | |
| 141 | DRIVER_INIT( sgx ); | |
| 142 | MACHINE_START( pce ); | |
| 143 | MACHINE_RESET( pce ); | |
| 144 | ||
| 145 | ||
| 146 | #endif /* PCE_H_ */ |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | video/nes.c | |
| 4 | ||
| 5 | Routines to control the unique NES video hardware/PPU. | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "video/ppu2c0x.h" | |
| 11 | #include "includes/nes.h" | |
| 12 | #include "machine/nes_mmc.h" | |
| 13 | ||
| 14 | static void nes_vh_reset( running_machine &machine ) | |
| 15 | { | |
| 16 | nes_state *state = machine.driver_data<nes_state>(); | |
| 17 | ppu2c0x_set_vidaccess_callback(machine.device("ppu"), nes_ppu_vidaccess); | |
| 18 | ||
| 19 | if (state->m_four_screen_vram) | |
| 20 | set_nt_mirroring(machine, PPU_MIRROR_4SCREEN); | |
| 21 | else | |
| 22 | { | |
| 23 | switch (state->m_hard_mirroring) | |
| 24 | { | |
| 25 | case PPU_MIRROR_HORZ: | |
| 26 | case PPU_MIRROR_VERT: | |
| 27 | case PPU_MIRROR_HIGH: | |
| 28 | case PPU_MIRROR_LOW: | |
| 29 | set_nt_mirroring(machine, state->m_hard_mirroring); | |
| 30 | break; | |
| 31 | default: | |
| 32 | set_nt_mirroring(machine, PPU_MIRROR_NONE); | |
| 33 | break; | |
| 34 | } | |
| 35 | } | |
| 36 | } | |
| 37 | ||
| 38 | VIDEO_START( nes ) | |
| 39 | { | |
| 40 | nes_state *state = machine.driver_data<nes_state>(); | |
| 41 | ||
| 42 | state->m_last_frame_flip = 0; | |
| 43 | ||
| 44 | machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(nes_vh_reset),&machine)); | |
| 45 | } | |
| 46 | ||
| 47 | PALETTE_INIT( nes ) | |
| 48 | { | |
| 49 | ppu2c0x_init_palette(machine, 0); | |
| 50 | } | |
| 51 | ||
| 52 | ||
| 53 | /*************************************************************************** | |
| 54 | ||
| 55 | Display refresh | |
| 56 | ||
| 57 | ***************************************************************************/ | |
| 58 | ||
| 59 | SCREEN_UPDATE( nes ) | |
| 60 | { | |
| 61 | nes_state *state = screen->machine().driver_data<nes_state>(); | |
| 62 | ||
| 63 | /* render the ppu */ | |
| 64 | ppu2c0x_render(state->m_ppu, bitmap, 0, 0, 0, 0); | |
| 65 | ||
| 66 | /* if this is a disk system game, check for the flip-disk key */ | |
| 67 | if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD) | |
| 68 | { | |
| 69 | // latch this input so it doesn't go at warp speed | |
| 70 | if ((input_port_read(screen->machine(), "FLIPDISK") & 0x01) && (!state->m_last_frame_flip)) | |
| 71 | { | |
| 72 | state->m_last_frame_flip = 1; | |
| 73 | state->m_fds_current_side++; | |
| 74 | if (state->m_fds_current_side > state->m_fds_sides) | |
| 75 | state->m_fds_current_side = 0; | |
| 76 | ||
| 77 | if (state->m_fds_current_side == 0) | |
| 78 | popmessage("No disk inserted."); | |
| 79 | else | |
| 80 | popmessage("Disk set to side %d", state->m_fds_current_side); | |
| 81 | } | |
| 82 | ||
| 83 | if (!(input_port_read(screen->machine(), "FLIPDISK") & 0x01)) | |
| 84 | state->m_last_frame_flip = 0; | |
| 85 | } | |
| 86 | return 0; | |
| 87 | } |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Commodore Amiga 3000 | |
| 4 | ||
| 5 | Skeleton driver | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "cpu/m68000/m68000.h" | |
| 11 | ||
| 12 | ||
| 13 | class a3000_state : public driver_device | |
| 14 | { | |
| 15 | public: | |
| 16 | a3000_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 17 | : driver_device(mconfig, type, tag) { } | |
| 18 | ||
| 19 | }; | |
| 20 | ||
| 21 | ||
| 22 | ||
| 23 | /*************************************************************************** | |
| 24 | CONSTANTS | |
| 25 | ***************************************************************************/ | |
| 26 | ||
| 27 | #define XTAL_U104 XTAL_32MHz | |
| 28 | ||
| 29 | ||
| 30 | /*************************************************************************** | |
| 31 | ADDRESS MAPS | |
| 32 | ***************************************************************************/ | |
| 33 | ||
| 34 | static ADDRESS_MAP_START( a3000_mem, AS_PROGRAM, 32 ) | |
| 35 | ADDRESS_MAP_UNMAP_HIGH | |
| 36 | AM_RANGE(0x000000, 0x1fffff) AM_RAMBANK("chipram") | |
| 37 | AM_RANGE(0xf80000, 0xffffff) AM_ROM AM_REGION("kickstart", 0) | |
| 38 | ADDRESS_MAP_END | |
| 39 | ||
| 40 | ||
| 41 | /*************************************************************************** | |
| 42 | INPUT PORTS | |
| 43 | ***************************************************************************/ | |
| 44 | ||
| 45 | static INPUT_PORTS_START( a3000 ) | |
| 46 | INPUT_PORTS_END | |
| 47 | ||
| 48 | ||
| 49 | /*************************************************************************** | |
| 50 | MACHINE DRIVERS | |
| 51 | ***************************************************************************/ | |
| 52 | ||
| 53 | static MACHINE_CONFIG_START( a3000, a3000_state ) | |
| 54 | MCFG_CPU_ADD("maincpu", M68030, XTAL_U104 / 2) | |
| 55 | MCFG_CPU_PROGRAM_MAP(a3000_mem) | |
| 56 | ||
| 57 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 58 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 59 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 60 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 61 | MCFG_SCREEN_SIZE(512*2, 312) | |
| 62 | MCFG_SCREEN_VISIBLE_AREA((129-8-8)*2, (449+8-1+8)*2, 44-8, 300+8-1) | |
| 63 | MACHINE_CONFIG_END | |
| 64 | ||
| 65 | ||
| 66 | /*************************************************************************** | |
| 67 | ROM DEFINITIONS | |
| 68 | ***************************************************************************/ | |
| 69 | ||
| 70 | /* Note: I think those ROMs are correct, but they should be verified */ | |
| 71 | ROM_START( a3000 ) | |
| 72 | ROM_REGION32_BE(0x80000, "kickstart", 0) | |
| 73 | ROM_DEFAULT_BIOS("kick14") | |
| 74 | ROM_SYSTEM_BIOS(0, "kick14", "Kickstart 1.4 (36.16)") | |
| 75 | /* COPYRIGHT 1990 CAI // ALL RIGHTS RESERVED // ALPHA 5 ROM 0 CS=9713 */ | |
| 76 | ROMX_LOAD("390629-02.u182", 0x00000, 0x40000, CRC(58327536) SHA1(d1713d7f31474a5948e6d488e33686061cf3d1e2), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 77 | /* COPYRIGHT 1990 CAI // ALL RIGHTS RESERVED // ALPHA 5 ROM 1 CS=9B21 */ | |
| 78 | ROMX_LOAD("390630-02.u183", 0x00002, 0x40000, CRC(fe2f7fb9) SHA1(c05c9c52d014c66f9019152b3f2a2adc2c678794), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 79 | ROM_SYSTEM_BIOS(1, "kick204", "Kickstart 2.04 (37.175)") | |
| 80 | ROMX_LOAD("390629-03.u182", 0x00000, 0x40000, CRC(a245dbdf) SHA1(83bab8e95d378b55b0c6ae6561385a96f638598f), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) | |
| 81 | ROMX_LOAD("390630-03.u183", 0x00002, 0x40000, CRC(7db1332b) SHA1(48f14b31279da6757848df6feb5318818f8f576c), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) | |
| 82 | ROM_SYSTEM_BIOS(2, "kick31", "Kickstart 3.1 (40.68)") | |
| 83 | ROMX_LOAD("kick31.u182", 0x00000, 0x40000, CRC(286b9a0d) SHA1(6763a2258ec493f7408cf663110dae9a17803ad1), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(3)) | |
| 84 | ROMX_LOAD("kick31.u183", 0x00002, 0x40000, CRC(0b8cde6a) SHA1(5f02e97b48ebbba87d516a56b0400c6fc3434d8d), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(3)) | |
| 85 | ROM_END | |
| 86 | ||
| 87 | ||
| 88 | /*************************************************************************** | |
| 89 | GAME DRIVERS | |
| 90 | ***************************************************************************/ | |
| 91 | ||
| 92 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 93 | COMP( 1990, a3000, 0, 0, a3000, a3000, 0, "Commodore Business Machines", "Amiga 3000", GAME_NOT_WORKING | GAME_NO_SOUND ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /****************************************************************************** | |
| 2 | Atari 400/800 | |
| 3 | ||
| 4 | MESS Driver | |
| 5 | ||
| 6 | Juergen Buchmueller, June 1998 | |
| 7 | ||
| 8 | 2009-05 FP changes: | |
| 9 | Factored out MESS specific code from MAME | |
| 10 | Added skeleton support for other XL/XE machines (VERY preliminary): | |
| 11 | - a600xl based on maxaflex emulation in MAME | |
| 12 | - a1200xl sharing a800xl code without BASIC | |
| 13 | - a65xe, a65xea, a130xe, a800xe, xegs sharing a800xl code (and this is wrong | |
| 14 | at least for xegs) | |
| 15 | Added proper dumps and labels, thanks to Freddy Offenga researches (a few | |
| 16 | are still marked BAD_DUMP while waiting for crc confirmation, since they | |
| 17 | have been obtained by splitting whole dumps) | |
| 18 | ||
| 19 | To Do: | |
| 20 | - Find out why a600xl and a800xl don't work (xe machines should then follow) | |
| 21 | - Investigate supported RAM sizes and OS versions in different models | |
| 22 | - Implement differences between various models (currently most of the | |
| 23 | XL/XE are exactly an a800xl, but this will change as soon as emulation | |
| 24 | starts to work) | |
| 25 | - Fix various keyboard differences | |
| 26 | - Freddy emulation for 800XLF? | |
| 27 | - Add support for proto boards and expansions (a1400xl, C/PM board, etc.) | |
| 28 | - Clean up the whole driver + cart + floppy structure | |
| 29 | ||
| 30 | ******************************************************************************/ | |
| 31 | ||
| 32 | #include "emu.h" | |
| 33 | #include "deprecat.h" | |
| 34 | #include "cpu/m6502/m6502.h" | |
| 35 | #include "includes/atari.h" | |
| 36 | #include "machine/ataridev.h" | |
| 37 | #include "imagedev/cartslot.h" | |
| 38 | #include "sound/pokey.h" | |
| 39 | #include "machine/6821pia.h" | |
| 40 | #include "video/gtia.h" | |
| 41 | #include "sound/dac.h" | |
| 42 | #include "machine/ram.h" | |
| 43 | ||
| 44 | /****************************************************************************** | |
| 45 | Atari 800 memory map (preliminary) | |
| 46 | ||
| 47 | ***************** read access ******************* | |
| 48 | range short description | |
| 49 | 0000-9FFF RAM main memory | |
| 50 | A000-BFFF RAM/ROM RAM or (banked) ROM cartridges | |
| 51 | C000-CFFF ROM unused or monitor ROM | |
| 52 | ||
| 53 | ********* GTIA ******************************** | |
| 54 | ||
| 55 | D000 m0pf missile 0 playfield collisions | |
| 56 | D001 m1pf missile 1 playfield collisions | |
| 57 | D002 m2pf missile 2 playfield collisions | |
| 58 | D003 m3pf missile 3 playfield collisions | |
| 59 | D004 p0pf player 0 playfield collisions | |
| 60 | D005 p1pf player 1 playfield collisions | |
| 61 | D006 p2pf player 2 playfield collisions | |
| 62 | D007 p3pf player 3 playfield collisions | |
| 63 | D008 m0pl missile 0 player collisions | |
| 64 | D009 m1pl missile 1 player collisions | |
| 65 | D00A m2pl missile 2 player collisions | |
| 66 | D00B m3pl missile 3 player collisions | |
| 67 | D00C p0pl player 0 player collisions | |
| 68 | D00D p1pl player 1 player collisions | |
| 69 | D00E p2pl player 2 player collisions | |
| 70 | D00F p3pl player 3 player collisions | |
| 71 | D010 but0 button stick 0 | |
| 72 | D011 but1 button stick 1 | |
| 73 | D012 but2 button stick 2 | |
| 74 | D013 but3 button stick 3 | |
| 75 | D014 xff unused | |
| 76 | D015 xff unused | |
| 77 | D016 xff unused | |
| 78 | D017 xff unused | |
| 79 | D018 xff unused | |
| 80 | D019 xff unused | |
| 81 | D01A xff unused | |
| 82 | D01B xff unused | |
| 83 | D01C xff unused | |
| 84 | D01D xff unused | |
| 85 | D01E xff unused | |
| 86 | D01F cons console keys | |
| 87 | D020-D0FF repeated 7 times | |
| 88 | ||
| 89 | D100-D1FF xff | |
| 90 | ||
| 91 | ********* POKEY ******************************** | |
| 92 | D200 pot0 paddle 0 | |
| 93 | D201 pot1 paddle 1 | |
| 94 | D202 pot2 paddle 2 | |
| 95 | D203 pot3 paddle 3 | |
| 96 | D204 pot4 paddle 4 | |
| 97 | D205 pot5 paddle 5 | |
| 98 | D206 pot6 paddle 6 | |
| 99 | D207 pot7 paddle 7 | |
| 100 | D208 potb all paddles | |
| 101 | D209 kbcode keyboard scan code | |
| 102 | D20A random random number generator | |
| 103 | D20B xff unused | |
| 104 | D20C xff unused | |
| 105 | D20D serin serial input | |
| 106 | D20E irqst IRQ status | |
| 107 | D20F skstat sk status | |
| 108 | D210-D2FF repeated 15 times | |
| 109 | ||
| 110 | ********* PIO ******************************** | |
| 111 | D300 porta read pio port A | |
| 112 | D301 portb read pio port B | |
| 113 | D302 pactl read pio port A control | |
| 114 | D303 pbctl read pio port B control | |
| 115 | D304-D3FF repeated 63 times | |
| 116 | ||
| 117 | ********* ANTIC ******************************** | |
| 118 | D400 xff unused | |
| 119 | D401 xff unused | |
| 120 | D402 xff unused | |
| 121 | D403 xff unused | |
| 122 | D404 xff unused | |
| 123 | D405 xff unused | |
| 124 | D406 xff unused | |
| 125 | D407 xff unused | |
| 126 | D408 xff unused | |
| 127 | D409 xff unused | |
| 128 | D40A xff unused | |
| 129 | D40B vcount vertical (scanline) counter | |
| 130 | D40C penh light pen horizontal pos | |
| 131 | D40D penv light pen vertical pos | |
| 132 | D40E xff unused | |
| 133 | D40F nmist NMI status | |
| 134 | ||
| 135 | D500-D7FF xff unused memory | |
| 136 | ||
| 137 | D800-DFFF ROM floating point ROM | |
| 138 | E000-FFFF ROM bios ROM | |
| 139 | ||
| 140 | ***************** write access ******************* | |
| 141 | range short description | |
| 142 | 0000-9FFF RAM main memory | |
| 143 | A000-BFFF RAM/ROM RAM or (banked) ROM | |
| 144 | C000-CFFF ROM unused or monitor ROM | |
| 145 | ||
| 146 | ********* GTIA ******************************** | |
| 147 | D000 hposp0 player 0 horz position | |
| 148 | D001 hposp1 player 1 horz position | |
| 149 | D002 hposp2 player 2 horz position | |
| 150 | D003 hposp3 player 3 horz position | |
| 151 | D004 hposm0 missile 0 horz position | |
| 152 | D005 hposm1 missile 0 horz position | |
| 153 | D006 hposm2 missile 0 horz position | |
| 154 | D007 hposm3 missile 0 horz position | |
| 155 | D008 sizep0 size player 0 | |
| 156 | D009 sizep1 size player 0 | |
| 157 | D00A sizep2 size player 0 | |
| 158 | D00B sizep3 size player 0 | |
| 159 | D00C sizem size missiles | |
| 160 | D00D grafp0 graphics data for player 0 | |
| 161 | D00E grafp1 graphics data for player 1 | |
| 162 | D00F grafp2 graphics data for player 2 | |
| 163 | D010 grafp3 graphics data for player 3 | |
| 164 | D011 grafm graphics data for missiles | |
| 165 | D012 colpm0 color for player/missile 0 | |
| 166 | D013 colpm1 color for player/missile 1 | |
| 167 | D014 colpm2 color for player/missile 2 | |
| 168 | D015 colpm3 color for player/missile 3 | |
| 169 | D016 colpf0 color 0 playfield | |
| 170 | D017 colpf1 color 1 playfield | |
| 171 | D018 colpf2 color 2 playfield | |
| 172 | D019 colpf3 color 3 playfield | |
| 173 | D01A colbk background playfield | |
| 174 | D01B prior priority select | |
| 175 | D01C vdelay delay until vertical retrace | |
| 176 | D01D gractl graphics control | |
| 177 | D01E hitclr clear collisions | |
| 178 | D01F wcons write console (speaker) | |
| 179 | D020-D0FF repeated 7 times | |
| 180 | ||
| 181 | D100-D1FF xff unused | |
| 182 | ||
| 183 | ********* POKEY ******************************** | |
| 184 | D200 audf1 frequency audio chan #1 | |
| 185 | D201 audc1 control audio chan #1 | |
| 186 | D202 audf2 frequency audio chan #2 | |
| 187 | D203 audc2 control audio chan #2 | |
| 188 | D204 audf3 frequency audio chan #3 | |
| 189 | D205 audc3 control audio chan #3 | |
| 190 | D206 audf4 frequency audio chan #4 | |
| 191 | D207 audc4 control audio chan #4 | |
| 192 | D208 audctl audio control | |
| 193 | D209 stimer start timer | |
| 194 | D20A skres sk reset | |
| 195 | D20B potgo start pot AD conversion | |
| 196 | D20C xff unused | |
| 197 | D20D serout serial output | |
| 198 | D20E irqen IRQ enable | |
| 199 | D20F skctl sk control | |
| 200 | D210-D2FF repeated 15 times | |
| 201 | ||
| 202 | ********* PIO ******************************** | |
| 203 | D300 porta write pio port A (output or mask) | |
| 204 | D301 portb write pio port B (output or mask) | |
| 205 | D302 pactl write pio port A control | |
| 206 | D303 pbctl write pio port B control | |
| 207 | D304-D3FF repeated | |
| 208 | ||
| 209 | ********* ANTIC ******************************** | |
| 210 | D400 dmactl write DMA control | |
| 211 | D401 chactl write character control | |
| 212 | D402 dlistl write display list lo | |
| 213 | D403 dlisth write display list hi | |
| 214 | D404 hscrol write horz scroll | |
| 215 | D405 vscrol write vert scroll | |
| 216 | D406 xff unused | |
| 217 | D407 pmbash player/missile base addr hi | |
| 218 | D408 xff unused | |
| 219 | D409 chbash character generator base addr hi | |
| 220 | D40A wsync wait for hsync | |
| 221 | D40B xff unused | |
| 222 | D40C xff unused | |
| 223 | D40D xff unused | |
| 224 | D40E nmien NMI enable | |
| 225 | D40F nmires NMI reset | |
| 226 | ||
| 227 | D500-D7FF xff unused memory | |
| 228 | ||
| 229 | D800-DFFF ROM floating point ROM | |
| 230 | E000-FFFF ROM BIOS ROM | |
| 231 | ******************************************************************************/ | |
| 232 | ||
| 233 | /************************************************************** | |
| 234 | * | |
| 235 | * Memory maps | |
| 236 | * | |
| 237 | **************************************************************/ | |
| 238 | ||
| 239 | ||
| 240 | static ADDRESS_MAP_START(a400_mem, AS_PROGRAM, 8) | |
| 241 | AM_RANGE(0x0000, 0x9fff) AM_NOP /* RAM installed at runtime */ | |
| 242 | AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("a000") | |
| 243 | AM_RANGE(0xc000, 0xcfff) AM_ROM | |
| 244 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 245 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 246 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 247 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 248 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 249 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 250 | AM_RANGE(0xd800, 0xffff) AM_ROM | |
| 251 | ADDRESS_MAP_END | |
| 252 | ||
| 253 | ||
| 254 | static ADDRESS_MAP_START(a800_mem, AS_PROGRAM, 8) | |
| 255 | AM_RANGE(0x0000, 0x7fff) AM_RAMBANK("0000") | |
| 256 | AM_RANGE(0x8000, 0x9fff) AM_RAMBANK("8000") | |
| 257 | AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("a000") | |
| 258 | AM_RANGE(0xc000, 0xcfff) AM_ROM | |
| 259 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 260 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 261 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 262 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 263 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 264 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 265 | AM_RANGE(0xd800, 0xffff) AM_ROM | |
| 266 | ADDRESS_MAP_END | |
| 267 | ||
| 268 | ||
| 269 | static ADDRESS_MAP_START(a600xl_mem, AS_PROGRAM, 8) | |
| 270 | AM_RANGE(0x0000, 0x3fff) AM_RAM | |
| 271 | AM_RANGE(0x5000, 0x57ff) AM_ROM AM_REGION("maincpu", 0x5000) /* self test */ | |
| 272 | AM_RANGE(0xa000, 0xbfff) AM_ROM /* BASIC */ | |
| 273 | AM_RANGE(0xc000, 0xcfff) AM_ROM /* OS */ | |
| 274 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 275 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 276 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 277 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 278 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 279 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 280 | AM_RANGE(0xd800, 0xffff) AM_ROM /* OS */ | |
| 281 | ADDRESS_MAP_END | |
| 282 | ||
| 283 | ||
| 284 | static ADDRESS_MAP_START(a800xl_mem, AS_PROGRAM, 8) | |
| 285 | AM_RANGE(0x0000, 0x4fff) AM_RAM | |
| 286 | AM_RANGE(0x5000, 0x57ff) AM_RAMBANK("bank2") | |
| 287 | AM_RANGE(0x5800, 0x9fff) AM_RAM | |
| 288 | AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("bank1") | |
| 289 | AM_RANGE(0xc000, 0xcfff) AM_RAMBANK("bank3") | |
| 290 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 291 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 292 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 293 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 294 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 295 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 296 | AM_RANGE(0xd800, 0xffff) AM_RAMBANK("bank4") | |
| 297 | ADDRESS_MAP_END | |
| 298 | ||
| 299 | static ADDRESS_MAP_START(xegs_mem, AS_PROGRAM, 8) | |
| 300 | AM_RANGE(0x0000, 0x4fff) AM_RAM | |
| 301 | AM_RANGE(0x5000, 0x57ff) AM_RAMBANK("bank2") | |
| 302 | AM_RANGE(0x5800, 0x7fff) AM_RAM | |
| 303 | AM_RANGE(0x8000, 0x9fff) AM_ROMBANK("bank0") | |
| 304 | AM_RANGE(0xa000, 0xbfff) AM_ROMBANK("bank1") | |
| 305 | AM_RANGE(0xc000, 0xcfff) AM_RAMBANK("bank3") | |
| 306 | AM_RANGE(0xd000, 0xd0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 307 | AM_RANGE(0xd100, 0xd1ff) AM_NOP | |
| 308 | AM_RANGE(0xd200, 0xd2ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 309 | AM_RANGE(0xd300, 0xd3ff) AM_DEVREADWRITE_MODERN("pia", pia6821_device, read_alt, write_alt) | |
| 310 | AM_RANGE(0xd400, 0xd4ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 311 | AM_RANGE(0xd500, 0xd7ff) AM_NOP | |
| 312 | AM_RANGE(0xd800, 0xffff) AM_RAMBANK("bank4") | |
| 313 | ADDRESS_MAP_END | |
| 314 | ||
| 315 | ||
| 316 | static ADDRESS_MAP_START(a5200_mem, AS_PROGRAM, 8) | |
| 317 | AM_RANGE(0x0000, 0x3fff) AM_RAM | |
| 318 | AM_RANGE(0x4000, 0xbfff) AM_ROM | |
| 319 | AM_RANGE(0xc000, 0xc0ff) AM_READWRITE(atari_gtia_r, atari_gtia_w) | |
| 320 | AM_RANGE(0xd400, 0xd5ff) AM_READWRITE(atari_antic_r, atari_antic_w) | |
| 321 | AM_RANGE(0xe800, 0xe8ff) AM_DEVREADWRITE("pokey", pokey_r, pokey_w) | |
| 322 | AM_RANGE(0xf800, 0xffff) AM_ROM | |
| 323 | ADDRESS_MAP_END | |
| 324 | ||
| 325 | ||
| 326 | #ifdef MESS | |
| 327 | int atari_input_disabled(running_machine &machine) | |
| 328 | { | |
| 329 | return 0; | |
| 330 | } | |
| 331 | #endif | |
| 332 | ||
| 333 | /************************************************************** | |
| 334 | * | |
| 335 | * Input ports | |
| 336 | * | |
| 337 | **************************************************************/ | |
| 338 | ||
| 339 | ||
| 340 | #define JOYSTICK_DELTA 10 | |
| 341 | #define JOYSTICK_SENSITIVITY 200 | |
| 342 | ||
| 343 | static INPUT_PORTS_START( atari_artifacting ) | |
| 344 | PORT_START("artifacts") | |
| 345 | PORT_CONFNAME(0x40, 0x00, "Television Artifacts" ) | |
| 346 | PORT_CONFSETTING(0x00, DEF_STR( Off ) ) | |
| 347 | PORT_CONFSETTING(0x40, DEF_STR( On ) ) | |
| 348 | INPUT_PORTS_END | |
| 349 | ||
| 350 | ||
| 351 | ||
| 352 | static INPUT_PORTS_START( atari_console ) | |
| 353 | PORT_START("console") | |
| 354 | PORT_BIT(0x04, 0x04, IPT_KEYBOARD) PORT_NAME("CONS.2: Option") PORT_CODE(KEYCODE_F3) | |
| 355 | PORT_BIT(0x02, 0x02, IPT_KEYBOARD) PORT_NAME("CONS.1: Select") PORT_CODE(KEYCODE_F2) | |
| 356 | PORT_BIT(0x01, 0x01, IPT_KEYBOARD) PORT_NAME("CONS.0: Start") PORT_CODE(KEYCODE_F1) | |
| 357 | INPUT_PORTS_END | |
| 358 | ||
| 359 | ||
| 360 | ||
| 361 | static INPUT_PORTS_START( atari_digital_joystick2 ) | |
| 362 | PORT_START("djoy_0_1") /* IN1 digital joystick #1 + #2 (PIA port A) */ | |
| 363 | PORT_BIT(0x01, 0x01, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(1) | |
| 364 | PORT_BIT(0x02, 0x02, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(1) | |
| 365 | PORT_BIT(0x04, 0x04, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(1) | |
| 366 | PORT_BIT(0x08, 0x08, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(1) | |
| 367 | PORT_BIT(0x10, 0x10, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(2) | |
| 368 | PORT_BIT(0x20, 0x20, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) | |
| 369 | PORT_BIT(0x40, 0x40, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(2) | |
| 370 | PORT_BIT(0x80, 0x80, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) | |
| 371 | ||
| 372 | PORT_START("djoy_2_3") /* IN2 digital joystick #3 + #4 (PIA port B) */ | |
| 373 | PORT_BIT(0x01, 0x01, IPT_UNUSED) | |
| 374 | PORT_BIT(0x02, 0x02, IPT_UNUSED) | |
| 375 | PORT_BIT(0x04, 0x04, IPT_UNUSED) | |
| 376 | PORT_BIT(0x08, 0x08, IPT_UNUSED) | |
| 377 | PORT_BIT(0x10, 0x10, IPT_UNUSED) | |
| 378 | PORT_BIT(0x20, 0x20, IPT_UNUSED) | |
| 379 | PORT_BIT(0x40, 0x40, IPT_UNUSED) | |
| 380 | PORT_BIT(0x80, 0x80, IPT_UNUSED) | |
| 381 | ||
| 382 | PORT_START("djoy_b") /* IN3 digital joystick buttons (GTIA button bits) */ | |
| 383 | PORT_BIT(0x01, 0x01, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 384 | PORT_BIT(0x02, 0x02, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 385 | PORT_BIT(0x04, 0x04, IPT_UNUSED) | |
| 386 | PORT_BIT(0x08, 0x08, IPT_UNUSED) | |
| 387 | PORT_BIT(0x10, 0x10, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 388 | PORT_BIT(0x20, 0x20, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 389 | PORT_BIT(0x40, 0x40, IPT_UNUSED) | |
| 390 | PORT_BIT(0x80, 0x80, IPT_UNUSED) | |
| 391 | INPUT_PORTS_END | |
| 392 | ||
| 393 | ||
| 394 | ||
| 395 | static INPUT_PORTS_START( atari_digital_joystick4 ) | |
| 396 | PORT_START("djoy_0_1") /* digital joystick #1 + #2 (PIA port A) */ | |
| 397 | PORT_BIT(0x01, 0x01, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(1) | |
| 398 | PORT_BIT(0x02, 0x02, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(1) | |
| 399 | PORT_BIT(0x04, 0x04, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(1) | |
| 400 | PORT_BIT(0x08, 0x08, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(1) | |
| 401 | PORT_BIT(0x10, 0x10, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(2) | |
| 402 | PORT_BIT(0x20, 0x20, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) | |
| 403 | PORT_BIT(0x40, 0x40, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(2) | |
| 404 | PORT_BIT(0x80, 0x80, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) | |
| 405 | ||
| 406 | PORT_START("djoy_2_3") /* digital joystick #3 + #4 (PIA port B) */ | |
| 407 | PORT_BIT(0x01, 0x01, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(3) | |
| 408 | PORT_BIT(0x02, 0x02, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(3) | |
| 409 | PORT_BIT(0x04, 0x04, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(3) | |
| 410 | PORT_BIT(0x08, 0x08, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(3) | |
| 411 | PORT_BIT(0x10, 0x10, IPT_JOYSTICK_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(4) | |
| 412 | PORT_BIT(0x20, 0x20, IPT_JOYSTICK_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(4) | |
| 413 | PORT_BIT(0x40, 0x40, IPT_JOYSTICK_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(4) | |
| 414 | PORT_BIT(0x80, 0x80, IPT_JOYSTICK_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(4) | |
| 415 | ||
| 416 | PORT_START("djoy_b") /* digital joystick buttons (GTIA button bits) */ | |
| 417 | PORT_BIT(0x01, 0x01, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 418 | PORT_BIT(0x02, 0x02, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 419 | PORT_BIT(0x04, 0x04, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON3) PORT_PLAYER(3) | |
| 420 | PORT_BIT(0x08, 0x08, IPT_BUTTON1) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON4) PORT_PLAYER(4) | |
| 421 | PORT_BIT(0x10, 0x10, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) | |
| 422 | PORT_BIT(0x20, 0x20, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) | |
| 423 | PORT_BIT(0x40, 0x40, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON3) PORT_PLAYER(3) | |
| 424 | PORT_BIT(0x80, 0x80, IPT_BUTTON2) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(JOYCODE_BUTTON4) PORT_PLAYER(4) | |
| 425 | INPUT_PORTS_END | |
| 426 | ||
| 427 | ||
| 428 | ||
| 429 | /* 2009-04 FP: | |
| 430 | Small note about natural keyboard support: currently, | |
| 431 | - "Break" is mapped to 'F1' | |
| 432 | - "Clear" is mapped to 'F2' | |
| 433 | - "Atari" is mapped to 'F3' */ | |
| 434 | ||
| 435 | static INPUT_PORTS_START( atari_keyboard ) | |
| 436 | PORT_START("keyboard_0") | |
| 437 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') | |
| 438 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') | |
| 439 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') | |
| 440 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(F1)) | |
| 441 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 442 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') | |
| 443 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('+') PORT_CHAR('\\') | |
| 444 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*') PORT_CHAR('^') | |
| 445 | ||
| 446 | PORT_START("keyboard_1") | |
| 447 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') | |
| 448 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) // None! | |
| 449 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') | |
| 450 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') | |
| 451 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) | |
| 452 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') | |
| 453 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('-') PORT_CHAR('_') | |
| 454 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('=') PORT_CHAR('|') | |
| 455 | ||
| 456 | PORT_START("keyboard_2") | |
| 457 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') | |
| 458 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 459 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') | |
| 460 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 461 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 462 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') | |
| 463 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') | |
| 464 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') | |
| 465 | ||
| 466 | PORT_START("keyboard_3") | |
| 467 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') | |
| 468 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 469 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') | |
| 470 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') | |
| 471 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Escape") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) | |
| 472 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') | |
| 473 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('\"') | |
| 474 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') | |
| 475 | ||
| 476 | PORT_START("keyboard_4") | |
| 477 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('[') | |
| 478 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') | |
| 479 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(']') | |
| 480 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') | |
| 481 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 482 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') | |
| 483 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') | |
| 484 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Atari") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(F3)) | |
| 485 | ||
| 486 | PORT_START("keyboard_5") | |
| 487 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') | |
| 488 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 489 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') | |
| 490 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') | |
| 491 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) | |
| 492 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') | |
| 493 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') | |
| 494 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') | |
| 495 | ||
| 496 | PORT_START("keyboard_6") | |
| 497 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') | |
| 498 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 499 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') | |
| 500 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') | |
| 501 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("BackS Delete") PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(DEL)) | |
| 502 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('@') | |
| 503 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("< Clear") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('<') PORT_CHAR(UCHAR_MAMEKEY(F2)) | |
| 504 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("> Insert") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('>') PORT_CHAR(UCHAR_MAMEKEY(INSERT)) | |
| 505 | ||
| 506 | PORT_START("keyboard_7") | |
| 507 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') | |
| 508 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') | |
| 509 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') | |
| 510 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 511 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) | |
| 512 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') | |
| 513 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') | |
| 514 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') | |
| 515 | ||
| 516 | PORT_START("fake") | |
| 517 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) | |
| 518 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) | |
| 519 | INPUT_PORTS_END | |
| 520 | ||
| 521 | ||
| 522 | static INPUT_PORTS_START( atari_analog_paddles ) | |
| 523 | PORT_START("analog_0") /* IN8 analog in #1 */ | |
| 524 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) PORT_REVERSE | |
| 525 | ||
| 526 | PORT_START("analog_1") /* IN9 analog in #2 */ | |
| 527 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) PORT_REVERSE | |
| 528 | ||
| 529 | PORT_START("analog_2") /* IN10 analog in #3 */ | |
| 530 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(3) PORT_REVERSE | |
| 531 | ||
| 532 | PORT_START("analog_3") /* IN11 analog in #4 */ | |
| 533 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(4) PORT_REVERSE | |
| 534 | ||
| 535 | PORT_START("analog_4") /* IN12 analog in #5 */ | |
| 536 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(5) */ | |
| 537 | ||
| 538 | PORT_START("analog_5") /* IN13 analog in #6 */ | |
| 539 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(6) */ | |
| 540 | ||
| 541 | PORT_START("analog_6") /* IN14 analog in #7 */ | |
| 542 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(7) */ | |
| 543 | ||
| 544 | PORT_START("analog_7") /* IN15 analog in #8 */ | |
| 545 | PORT_BIT(0xff, 0x74, IPT_PADDLE) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_REVERSE /* PORT_PLAYER(8) */ | |
| 546 | INPUT_PORTS_END | |
| 547 | ||
| 548 | ||
| 549 | ||
| 550 | static INPUT_PORTS_START( a800 ) | |
| 551 | PORT_INCLUDE( atari_artifacting ) | |
| 552 | PORT_INCLUDE( atari_console ) | |
| 553 | PORT_INCLUDE( atari_digital_joystick4 ) | |
| 554 | PORT_INCLUDE( atari_keyboard ) | |
| 555 | PORT_INCLUDE( atari_analog_paddles ) | |
| 556 | INPUT_PORTS_END | |
| 557 | ||
| 558 | ||
| 559 | ||
| 560 | static INPUT_PORTS_START( a800xl ) | |
| 561 | PORT_INCLUDE( atari_artifacting ) | |
| 562 | PORT_INCLUDE( atari_console ) | |
| 563 | PORT_INCLUDE( atari_digital_joystick2 ) | |
| 564 | PORT_INCLUDE( atari_keyboard ) | |
| 565 | PORT_INCLUDE( atari_analog_paddles ) | |
| 566 | INPUT_PORTS_END | |
| 567 | ||
| 568 | ||
| 569 | ||
| 570 | static INPUT_PORTS_START( a5200 ) | |
| 571 | PORT_INCLUDE( atari_artifacting ) | |
| 572 | ||
| 573 | PORT_START("djoy_b") /* lower/upper buttons */ | |
| 574 | PORT_BIT(0x01, 0x01, IPT_BUTTON1) PORT_PLAYER(1) | |
| 575 | PORT_BIT(0x02, 0x02, IPT_BUTTON1) PORT_PLAYER(2) | |
| 576 | PORT_BIT(0x04, 0x04, IPT_BUTTON1) PORT_PLAYER(3) | |
| 577 | PORT_BIT(0x08, 0x08, IPT_BUTTON1) PORT_PLAYER(4) | |
| 578 | PORT_BIT(0x10, 0x10, IPT_BUTTON2) PORT_PLAYER(1) | |
| 579 | PORT_BIT(0x20, 0x20, IPT_BUTTON2) PORT_PLAYER(2) | |
| 580 | PORT_BIT(0x40, 0x40, IPT_BUTTON2) PORT_PLAYER(3) | |
| 581 | PORT_BIT(0x80, 0x80, IPT_BUTTON2) PORT_PLAYER(4) | |
| 582 | ||
| 583 | PORT_START("keypad_0") | |
| 584 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("(Break)") PORT_CODE(KEYCODE_PAUSE) // is this correct? | |
| 585 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[#]") PORT_CODE(KEYCODE_ENTER_PAD) | |
| 586 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[0]") PORT_CODE(KEYCODE_0_PAD) | |
| 587 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[*]") PORT_CODE(KEYCODE_PLUS_PAD) | |
| 588 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 589 | ||
| 590 | PORT_START("keypad_1") | |
| 591 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F3) | |
| 592 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[9]") PORT_CODE(KEYCODE_9_PAD) | |
| 593 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[8]") PORT_CODE(KEYCODE_8_PAD) | |
| 594 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[7]") PORT_CODE(KEYCODE_7_PAD) | |
| 595 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 596 | ||
| 597 | PORT_START("keypad_2") | |
| 598 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(DEF_STR(Pause)) PORT_CODE(KEYCODE_F2) | |
| 599 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[6]") PORT_CODE(KEYCODE_6_PAD) | |
| 600 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[5]") PORT_CODE(KEYCODE_5_PAD) | |
| 601 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[4]") PORT_CODE(KEYCODE_4_PAD) | |
| 602 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 603 | ||
| 604 | PORT_START("keypad_3") | |
| 605 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_START) PORT_NAME("Start") | |
| 606 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[3]") PORT_CODE(KEYCODE_3_PAD) | |
| 607 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[2]") PORT_CODE(KEYCODE_2_PAD) | |
| 608 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("[1]") PORT_CODE(KEYCODE_1_PAD) | |
| 609 | PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED) | |
| 610 | ||
| 611 | PORT_START("analog_0") | |
| 612 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) | |
| 613 | ||
| 614 | PORT_START("analog_1") | |
| 615 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(1) | |
| 616 | ||
| 617 | PORT_START("analog_2") | |
| 618 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) | |
| 619 | ||
| 620 | PORT_START("analog_3") | |
| 621 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(2) | |
| 622 | ||
| 623 | PORT_START("analog_4") | |
| 624 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(3) | |
| 625 | ||
| 626 | PORT_START("analog_5") | |
| 627 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(3) | |
| 628 | ||
| 629 | PORT_START("analog_6") | |
| 630 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(4) | |
| 631 | ||
| 632 | PORT_START("analog_7") | |
| 633 | PORT_BIT(0xff, 0x72, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0x00,0xe4) PORT_PLAYER(4) | |
| 634 | ||
| 635 | INPUT_PORTS_END | |
| 636 | ||
| 637 | ||
| 638 | /************************************************************** | |
| 639 | * | |
| 640 | * Palette | |
| 641 | * | |
| 642 | **************************************************************/ | |
| 643 | ||
| 644 | static const UINT8 atari_palette[256*3] = | |
| 645 | { | |
| 646 | /* Grey */ | |
| 647 | 0x00,0x00,0x00, 0x25,0x25,0x25, 0x34,0x34,0x34, 0x4e,0x4e,0x4e, | |
| 648 | 0x68,0x68,0x68, 0x75,0x75,0x75, 0x8e,0x8e,0x8e, 0xa4,0xa4,0xa4, | |
| 649 | 0xb8,0xb8,0xb8, 0xc5,0xc5,0xc5, 0xd0,0xd0,0xd0, 0xd7,0xd7,0xd7, | |
| 650 | 0xe1,0xe1,0xe1, 0xea,0xea,0xea, 0xf4,0xf4,0xf4, 0xff,0xff,0xff, | |
| 651 | /* Gold */ | |
| 652 | 0x41,0x20,0x00, 0x54,0x28,0x00, 0x76,0x37,0x00, 0x9a,0x50,0x00, | |
| 653 | 0xc3,0x68,0x06, 0xe4,0x7b,0x07, 0xff,0x91,0x1a, 0xff,0xab,0x1d, | |
| 654 | 0xff,0xc5,0x1f, 0xff,0xd0,0x3b, 0xff,0xd8,0x4c, 0xff,0xe6,0x51, | |
| 655 | 0xff,0xf4,0x56, 0xff,0xf9,0x70, 0xff,0xff,0x90, 0xff,0xff,0xaa, | |
| 656 | /* Orange */ | |
| 657 | 0x45,0x19,0x04, 0x72,0x1e,0x11, 0x9f,0x24,0x1e, 0xb3,0x3a,0x20, | |
| 658 | 0xc8,0x51,0x20, 0xe3,0x69,0x20, 0xfc,0x81,0x20, 0xfd,0x8c,0x25, | |
| 659 | 0xfe,0x98,0x2c, 0xff,0xae,0x38, 0xff,0xb9,0x46, 0xff,0xbf,0x51, | |
| 660 | 0xff,0xc6,0x6d, 0xff,0xd5,0x87, 0xff,0xe4,0x98, 0xff,0xe6,0xab, | |
| 661 | /* Red-Orange */ | |
| 662 | 0x5d,0x1f,0x0c, 0x7a,0x24,0x0d, 0x98,0x2c,0x0e, 0xb0,0x2f,0x0f, | |
| 663 | 0xbf,0x36,0x24, 0xd3,0x4e,0x2a, 0xe7,0x62,0x3e, 0xf3,0x6e,0x4a, | |
| 664 | 0xfd,0x78,0x54, 0xff,0x8a,0x6a, 0xff,0x98,0x7c, 0xff,0xa4,0x8b, | |
| 665 | 0xff,0xb3,0x9e, 0xff,0xc2,0xb2, 0xff,0xd0,0xc3, 0xff,0xda,0xd0, | |
| 666 | /* Pink */ | |
| 667 | 0x4a,0x17,0x00, 0x72,0x1f,0x00, 0xa8,0x13,0x00, 0xc8,0x21,0x0a, | |
| 668 | 0xdf,0x25,0x12, 0xec,0x3b,0x24, 0xfa,0x52,0x36, 0xfc,0x61,0x48, | |
| 669 | 0xff,0x70,0x5f, 0xff,0x7e,0x7e, 0xff,0x8f,0x8f, 0xff,0x9d,0x9e, | |
| 670 | 0xff,0xab,0xad, 0xff,0xb9,0xbd, 0xff,0xc7,0xce, 0xff,0xca,0xde, | |
| 671 | /* Purple */ | |
| 672 | 0x49,0x00,0x36, 0x66,0x00,0x4b, 0x80,0x03,0x5f, 0x95,0x0f,0x74, | |
| 673 | 0xaa,0x22,0x88, 0xba,0x3d,0x99, 0xca,0x4d,0xa9, 0xd7,0x5a,0xb6, | |
| 674 | 0xe4,0x67,0xc3, 0xef,0x72,0xce, 0xfb,0x7e,0xda, 0xff,0x8d,0xe1, | |
| 675 | 0xff,0x9d,0xe5, 0xff,0xa5,0xe7, 0xff,0xaf,0xea, 0xff,0xb8,0xec, | |
| 676 | /* Purple-Blue */ | |
| 677 | 0x48,0x03,0x6c, 0x5c,0x04,0x88, 0x65,0x0d,0x90, 0x7b,0x23,0xa7, | |
| 678 | 0x93,0x3b,0xbf, 0x9d,0x45,0xc9, 0xa7,0x4f,0xd3, 0xb2,0x5a,0xde, | |
| 679 | 0xbd,0x65,0xe9, 0xc5,0x6d,0xf1, 0xce,0x76,0xfa, 0xd5,0x83,0xff, | |
| 680 | 0xda,0x90,0xff, 0xde,0x9c,0xff, 0xe2,0xa9,0xff, 0xe6,0xb6,0xff, | |
| 681 | /* Blue 1 */ | |
| 682 | 0x05,0x1e,0x81, 0x06,0x26,0xa5, 0x08,0x2f,0xca, 0x26,0x3d,0xd4, | |
| 683 | 0x44,0x4c,0xde, 0x4f,0x5a,0xec, 0x5a,0x68,0xff, 0x65,0x75,0xff, | |
| 684 | 0x71,0x83,0xff, 0x80,0x91,0xff, 0x90,0xa0,0xff, 0x97,0xa9,0xff, | |
| 685 | 0x9f,0xb2,0xff, 0xaf,0xbe,0xff, 0xc0,0xcb,0xff, 0xcd,0xd3,0xff, | |
| 686 | /* Blue 2 */ | |
| 687 | 0x0b,0x07,0x79, 0x20,0x1c,0x8e, 0x35,0x31,0xa3, 0x46,0x42,0xb4, | |
| 688 | 0x57,0x53,0xc5, 0x61,0x5d,0xcf, 0x6d,0x69,0xdb, 0x7b,0x77,0xe9, | |
| 689 | 0x89,0x85,0xf7, 0x91,0x8d,0xff, 0x9c,0x98,0xff, 0xa7,0xa4,0xff, | |
| 690 | 0xb2,0xaf,0xff, 0xbb,0xb8,0xff, 0xc3,0xc1,0xff, 0xd3,0xd1,0xff, | |
| 691 | /* Light-Blue */ | |
| 692 | 0x1d,0x29,0x5a, 0x1d,0x38,0x76, 0x1d,0x48,0x92, 0x1d,0x5c,0xac, | |
| 693 | 0x1d,0x71,0xc6, 0x32,0x86,0xcf, 0x48,0x9b,0xd9, 0x4e,0xa8,0xec, | |
| 694 | 0x55,0xb6,0xff, 0x69,0xca,0xff, 0x74,0xcb,0xff, 0x82,0xd3,0xff, | |
| 695 | 0x8d,0xda,0xff, 0x9f,0xd4,0xff, 0xb4,0xe2,0xff, 0xc0,0xeb,0xff, | |
| 696 | /* Turquoise */ | |
| 697 | 0x00,0x4b,0x59, 0x00,0x5d,0x6e, 0x00,0x6f,0x84, 0x00,0x84,0x9c, | |
| 698 | 0x00,0x99,0xbf, 0x00,0xab,0xca, 0x00,0xbc,0xde, 0x00,0xd0,0xf5, | |
| 699 | 0x10,0xdc,0xff, 0x3e,0xe1,0xff, 0x64,0xe7,0xff, 0x76,0xea,0xff, | |
| 700 | 0x8b,0xed,0xff, 0x9a,0xef,0xff, 0xb1,0xf3,0xff, 0xc7,0xf6,0xff, | |
| 701 | /* Green-Blue */ | |
| 702 | 0x00,0x48,0x00, 0x00,0x54,0x00, 0x03,0x6b,0x03, 0x0e,0x76,0x0e, | |
| 703 | 0x18,0x80,0x18, 0x27,0x92,0x27, 0x36,0xa4,0x36, 0x4e,0xb9,0x4e, | |
| 704 | 0x51,0xcd,0x51, 0x72,0xda,0x72, 0x7c,0xe4,0x7c, 0x85,0xed,0x85, | |
| 705 | 0x99,0xf2,0x99, 0xb3,0xf7,0xb3, 0xc3,0xf9,0xc3, 0xcd,0xfc,0xcd, | |
| 706 | /* Green */ | |
| 707 | 0x16,0x40,0x00, 0x1c,0x53,0x00, 0x23,0x66,0x00, 0x28,0x78,0x00, | |
| 708 | 0x2e,0x8c,0x00, 0x3a,0x98,0x0c, 0x47,0xa5,0x19, 0x51,0xaf,0x23, | |
| 709 | 0x5c,0xba,0x2e, 0x71,0xcf,0x43, 0x85,0xe3,0x57, 0x8d,0xeb,0x5f, | |
| 710 | 0x97,0xf5,0x69, 0xa0,0xfe,0x72, 0xb1,0xff,0x8a, 0xbc,0xff,0x9a, | |
| 711 | /* Yellow-Green */ | |
| 712 | 0x2c,0x35,0x00, 0x38,0x44,0x00, 0x44,0x52,0x00, 0x49,0x56,0x00, | |
| 713 | 0x60,0x71,0x00, 0x6c,0x7f,0x00, 0x79,0x8d,0x0a, 0x8b,0x9f,0x1c, | |
| 714 | 0x9e,0xb2,0x2f, 0xab,0xbf,0x3c, 0xb8,0xcc,0x49, 0xc2,0xd6,0x53, | |
| 715 | 0xcd,0xe1,0x53, 0xdb,0xef,0x6c, 0xe8,0xfc,0x79, 0xf2,0xff,0xab, | |
| 716 | /* Orange-Green */ | |
| 717 | 0x46,0x3a,0x09, 0x4d,0x3f,0x09, 0x54,0x45,0x09, 0x6c,0x58,0x09, | |
| 718 | 0x90,0x76,0x09, 0xab,0x8b,0x0a, 0xc1,0xa1,0x20, 0xd0,0xb0,0x2f, | |
| 719 | 0xde,0xbe,0x3d, 0xe6,0xc6,0x45, 0xed,0xcd,0x4c, 0xf5,0xd8,0x62, | |
| 720 | 0xfb,0xe2,0x76, 0xfc,0xee,0x98, 0xfd,0xf3,0xa9, 0xfd,0xf3,0xbe, | |
| 721 | /* Light-Orange */ | |
| 722 | 0x40,0x1a,0x02, 0x58,0x1f,0x05, 0x70,0x24,0x08, 0x8d,0x3a,0x13, | |
| 723 | 0xab,0x51,0x1f, 0xb5,0x64,0x27, 0xbf,0x77,0x30, 0xd0,0x85,0x3a, | |
| 724 | 0xe1,0x93,0x44, 0xed,0xa0,0x4e, 0xf9,0xad,0x58, 0xfc,0xb7,0x5c, | |
| 725 | 0xff,0xc1,0x60, 0xff,0xca,0x69, 0xff,0xcf,0x7e, 0xff,0xda,0x96 | |
| 726 | }; | |
| 727 | ||
| 728 | ||
| 729 | /* Initialise the palette */ | |
| 730 | static PALETTE_INIT( mess_atari ) | |
| 731 | { | |
| 732 | int i; | |
| 733 | ||
| 734 | for ( i = 0; i < sizeof(atari_palette) / 3; i++ ) | |
| 735 | { | |
| 736 | palette_set_color_rgb(machine, i, atari_palette[i*3], atari_palette[i*3+1], atari_palette[i*3+2]); | |
| 737 | } | |
| 738 | } | |
| 739 | ||
| 740 | /************************************************************** | |
| 741 | * | |
| 742 | * Memory banking | |
| 743 | * | |
| 744 | **************************************************************/ | |
| 745 | ||
| 746 | static void a800xl_mmu(running_machine &machine, UINT8 new_mmu) | |
| 747 | { | |
| 748 | UINT8 *base = machine.region("maincpu")->base(); | |
| 749 | UINT8 *base1, *base2, *base3, *base4; | |
| 750 | ||
| 751 | /* check if memory C000-FFFF changed */ | |
| 752 | if( new_mmu & 0x01 ) | |
| 753 | { | |
| 754 | logerror("%s MMU BIOS ROM\n", machine.system().name); | |
| 755 | base3 = base + 0x14000; /* 8K lo BIOS */ | |
| 756 | base4 = base + 0x15800; /* 4K FP ROM + 8K hi BIOS */ | |
| 757 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xc000, 0xcfff, "bank3"); | |
| 758 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xc000, 0xcfff); | |
| 759 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xd800, 0xffff, "bank4"); | |
| 760 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xd800, 0xffff); | |
| 761 | } | |
| 762 | else | |
| 763 | { | |
| 764 | logerror("%s MMU BIOS RAM\n", machine.system().name); | |
| 765 | base3 = base + 0x0c000; /* 8K RAM */ | |
| 766 | base4 = base + 0x0d800; /* 4K RAM + 8K RAM */ | |
| 767 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xc000, 0xcfff, "bank3"); | |
| 768 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xd800, 0xffff, "bank4"); | |
| 769 | } | |
| 770 | memory_set_bankptr(machine, "bank3", base3); | |
| 771 | memory_set_bankptr(machine, "bank4", base4); | |
| 772 | ||
| 773 | /* check if BASIC changed */ | |
| 774 | if( new_mmu & 0x02 ) | |
| 775 | { | |
| 776 | logerror("%s MMU BASIC RAM\n", machine.system().name); | |
| 777 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xa000, 0xbfff, "bank1"); | |
| 778 | base1 = base + 0x0a000; /* 8K RAM */ | |
| 779 | } | |
| 780 | else | |
| 781 | { | |
| 782 | logerror("%s MMU BASIC ROM\n", machine.system().name); | |
| 783 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xbfff, "bank1"); | |
| 784 | machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0xa000, 0xbfff); | |
| 785 | base1 = base + 0x10000; /* 8K BASIC */ | |
| 786 | } | |
| 787 | ||
| 788 | memory_set_bankptr(machine, "bank1", base1); | |
| 789 | ||
| 790 | /* check if self-test ROM changed */ | |
| 791 | if( new_mmu & 0x80 ) | |
| 792 | { | |
| 793 | logerror("%s MMU SELFTEST RAM\n", machine.system().name); | |
| 794 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x5000, 0x57ff, "bank2"); | |
| 795 | base2 = base + 0x05000; /* 0x0800 bytes */ | |
| 796 | } | |
| 797 | else | |
| 798 | { | |
| 799 | logerror("%s MMU SELFTEST ROM\n", machine.system().name); | |
| 800 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x5000, 0x57ff, "bank2"); | |
| 801 | machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0x5000, 0x57ff); | |
| 802 | base2 = base + 0x15000; /* 0x0800 bytes */ | |
| 803 | } | |
| 804 | memory_set_bankptr(machine, "bank2", base2); | |
| 805 | } | |
| 806 | ||
| 807 | /* BASIC was available in a separate cart, so we don't test it */ | |
| 808 | static void a1200xl_mmu(running_machine &machine, UINT8 new_mmu) | |
| 809 | { | |
| 810 | UINT8 *base = machine.region("maincpu")->base(); | |
| 811 | UINT8 *base2, *base3, *base4; | |
| 812 | ||
| 813 | /* check if memory C000-FFFF changed */ | |
| 814 | if( new_mmu & 0x01 ) | |
| 815 | { | |
| 816 | logerror("%s MMU BIOS ROM\n", machine.system().name); | |
| 817 | base3 = base + 0x14000; /* 8K lo BIOS */ | |
| 818 | base4 = base + 0x15800; /* 4K FP ROM + 8K hi BIOS */ | |
| 819 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xc000, 0xcfff, "bank3"); | |
| 820 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xc000, 0xcfff); | |
| 821 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xd800, 0xffff, "bank4"); | |
| 822 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xd800, 0xffff); | |
| 823 | } | |
| 824 | else | |
| 825 | { | |
| 826 | logerror("%s MMU BIOS RAM\n", machine.system().name); | |
| 827 | base3 = base + 0x0c000; /* 8K RAM */ | |
| 828 | base4 = base + 0x0d800; /* 4K RAM + 8K RAM */ | |
| 829 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xc000, 0xcfff, "bank3"); | |
| 830 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xd800, 0xffff, "bank4"); | |
| 831 | } | |
| 832 | memory_set_bankptr(machine, "bank3", base3); | |
| 833 | memory_set_bankptr(machine, "bank4", base4); | |
| 834 | ||
| 835 | /* check if self-test ROM changed */ | |
| 836 | if( new_mmu & 0x80 ) | |
| 837 | { | |
| 838 | logerror("%s MMU SELFTEST RAM\n", machine.system().name); | |
| 839 | base2 = base + 0x05000; /* 0x0800 bytes */ | |
| 840 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x5000, 0x57ff, "bank2"); | |
| 841 | } | |
| 842 | else | |
| 843 | { | |
| 844 | logerror("%s MMU SELFTEST ROM\n", machine.system().name); | |
| 845 | base2 = base + 0x15000; /* 0x0800 bytes */ | |
| 846 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x5000, 0x57ff, "bank2"); | |
| 847 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x5000, 0x57ff); | |
| 848 | } | |
| 849 | memory_set_bankptr(machine, "bank2", base2); | |
| 850 | } | |
| 851 | ||
| 852 | static void xegs_mmu(running_machine &machine, UINT8 new_mmu) | |
| 853 | { | |
| 854 | UINT8 *base = machine.region("maincpu")->base(); | |
| 855 | UINT8 *base2, *base3, *base4; | |
| 856 | ||
| 857 | /* check if memory C000-FFFF changed */ | |
| 858 | if( new_mmu & 0x01 ) | |
| 859 | { | |
| 860 | logerror("%s MMU BIOS ROM\n", machine.system().name); | |
| 861 | base3 = base + 0x14000; /* 8K lo BIOS */ | |
| 862 | base4 = base + 0x15800; /* 4K FP ROM + 8K hi BIOS */ | |
| 863 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xc000, 0xcfff, "bank3"); | |
| 864 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xc000, 0xcfff); | |
| 865 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xd800, 0xffff, "bank4"); | |
| 866 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xd800, 0xffff); | |
| 867 | } | |
| 868 | else | |
| 869 | { | |
| 870 | logerror("%s MMU BIOS RAM\n", machine.system().name); | |
| 871 | base3 = base + 0x0c000; /* 8K RAM */ | |
| 872 | base4 = base + 0x0d800; /* 4K RAM + 8K RAM */ | |
| 873 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xc000, 0xcfff, "bank3"); | |
| 874 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xd800, 0xffff, "bank4"); | |
| 875 | } | |
| 876 | memory_set_bankptr(machine, "bank3", base3); | |
| 877 | memory_set_bankptr(machine, "bank4", base4); | |
| 878 | ||
| 879 | ||
| 880 | /* check if self-test ROM changed */ | |
| 881 | if( new_mmu & 0x80 ) | |
| 882 | { | |
| 883 | logerror("%s MMU SELFTEST RAM\n", machine.system().name); | |
| 884 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x5000, 0x57ff, "bank2"); | |
| 885 | base2 = base + 0x05000; /* 0x0800 bytes */ | |
| 886 | } | |
| 887 | else | |
| 888 | { | |
| 889 | logerror("%s MMU SELFTEST ROM\n", machine.system().name); | |
| 890 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x5000, 0x57ff, "bank2"); | |
| 891 | machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0x5000, 0x57ff); | |
| 892 | base2 = base + 0x15000; /* 0x0800 bytes */ | |
| 893 | } | |
| 894 | memory_set_bankptr(machine, "bank2", base2); | |
| 895 | } | |
| 896 | ||
| 897 | /************************************************************** | |
| 898 | * | |
| 899 | * PIA interface | |
| 900 | * | |
| 901 | **************************************************************/ | |
| 902 | ||
| 903 | static WRITE8_DEVICE_HANDLER(a1200xl_pia_pb_w) { a1200xl_mmu(device->machine(), data); } | |
| 904 | static WRITE8_DEVICE_HANDLER(a800xl_pia_pb_w) | |
| 905 | { | |
| 906 | if (downcast<pia6821_device *>(device)->port_b_z_mask() != 0xff) | |
| 907 | a800xl_mmu(device->machine(), data); | |
| 908 | } | |
| 909 | ||
| 910 | static WRITE8_DEVICE_HANDLER(xegs_pia_pb_w) | |
| 911 | { | |
| 912 | if (downcast<pia6821_device *>(device)->port_b_z_mask() != 0xff) | |
| 913 | xegs_mmu(device->machine(), data); | |
| 914 | } | |
| 915 | ||
| 916 | static const pokey_interface atari_pokey_interface = | |
| 917 | { | |
| 918 | { | |
| 919 | DEVCB_INPUT_PORT("analog_0"), | |
| 920 | DEVCB_INPUT_PORT("analog_1"), | |
| 921 | DEVCB_INPUT_PORT("analog_2"), | |
| 922 | DEVCB_INPUT_PORT("analog_3"), | |
| 923 | DEVCB_INPUT_PORT("analog_4"), | |
| 924 | DEVCB_INPUT_PORT("analog_5"), | |
| 925 | DEVCB_INPUT_PORT("analog_6"), | |
| 926 | DEVCB_INPUT_PORT("analog_7") | |
| 927 | }, | |
| 928 | DEVCB_NULL, | |
| 929 | DEVCB_DEVICE_HANDLER("fdc", atari_serin_r), | |
| 930 | DEVCB_DEVICE_HANDLER("fdc", atari_serout_w), | |
| 931 | atari_interrupt_cb, | |
| 932 | }; | |
| 933 | ||
| 934 | ||
| 935 | static const pia6821_interface atari_pia_interface = | |
| 936 | { | |
| 937 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 938 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 939 | DEVCB_NULL, /* line CA1 in */ | |
| 940 | DEVCB_NULL, /* line CB1 in */ | |
| 941 | DEVCB_NULL, /* line CA2 in */ | |
| 942 | DEVCB_NULL, /* line CB2 in */ | |
| 943 | DEVCB_NULL, /* port A out */ | |
| 944 | DEVCB_NULL, /* port B out */ | |
| 945 | DEVCB_NULL, /* line CA2 out */ | |
| 946 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 947 | DEVCB_NULL, /* IRQA */ | |
| 948 | DEVCB_NULL /* IRQB */ | |
| 949 | }; | |
| 950 | ||
| 951 | static const pia6821_interface a600xl_pia_interface = | |
| 952 | { | |
| 953 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 954 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 955 | DEVCB_NULL, /* line CA1 in */ | |
| 956 | DEVCB_NULL, /* line CB1 in */ | |
| 957 | DEVCB_NULL, /* line CA2 in */ | |
| 958 | DEVCB_NULL, /* line CB2 in */ | |
| 959 | DEVCB_NULL, /* port A out */ | |
| 960 | DEVCB_HANDLER(a600xl_pia_pb_w), /* port B out */ | |
| 961 | DEVCB_NULL, /* line CA2 out */ | |
| 962 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 963 | DEVCB_NULL, /* IRQA */ | |
| 964 | DEVCB_NULL /* IRQB */ | |
| 965 | }; | |
| 966 | ||
| 967 | static const pia6821_interface a1200xl_pia_interface = | |
| 968 | { | |
| 969 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 970 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 971 | DEVCB_NULL, /* line CA1 in */ | |
| 972 | DEVCB_NULL, /* line CB1 in */ | |
| 973 | DEVCB_NULL, /* line CA2 in */ | |
| 974 | DEVCB_NULL, /* line CB2 in */ | |
| 975 | DEVCB_NULL, /* port A out */ | |
| 976 | DEVCB_HANDLER(a1200xl_pia_pb_w), /* port B out */ | |
| 977 | DEVCB_NULL, /* line CA2 out */ | |
| 978 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 979 | DEVCB_NULL, /* IRQA */ | |
| 980 | DEVCB_NULL /* IRQB */ | |
| 981 | }; | |
| 982 | ||
| 983 | static const pia6821_interface a800xl_pia_interface = | |
| 984 | { | |
| 985 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 986 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 987 | DEVCB_NULL, /* line CA1 in */ | |
| 988 | DEVCB_NULL, /* line CB1 in */ | |
| 989 | DEVCB_NULL, /* line CA2 in */ | |
| 990 | DEVCB_NULL, /* line CB2 in */ | |
| 991 | DEVCB_NULL, /* port A out */ | |
| 992 | DEVCB_HANDLER(a800xl_pia_pb_w), /* port B out */ | |
| 993 | DEVCB_NULL, /* line CA2 out */ | |
| 994 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 995 | DEVCB_NULL, /* IRQA */ | |
| 996 | DEVCB_NULL /* IRQB */ | |
| 997 | }; | |
| 998 | ||
| 999 | static const pia6821_interface xegs_pia_interface = | |
| 1000 | { | |
| 1001 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 1002 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 1003 | DEVCB_NULL, /* line CA1 in */ | |
| 1004 | DEVCB_NULL, /* line CB1 in */ | |
| 1005 | DEVCB_NULL, /* line CA2 in */ | |
| 1006 | DEVCB_NULL, /* line CB2 in */ | |
| 1007 | DEVCB_NULL, /* port A out */ | |
| 1008 | DEVCB_HANDLER(xegs_pia_pb_w), /* port B out */ | |
| 1009 | DEVCB_NULL, /* line CA2 out */ | |
| 1010 | DEVCB_DEVICE_LINE("fdc",atarifdc_pia_cb2_w), /* port CB2 out */ | |
| 1011 | DEVCB_NULL, /* IRQA */ | |
| 1012 | DEVCB_NULL /* IRQB */ | |
| 1013 | }; | |
| 1014 | ||
| 1015 | // FIXME: should there be anything connected where other system have the fdc? | |
| 1016 | static const pokey_interface a5200_pokey_interface = | |
| 1017 | { | |
| 1018 | { | |
| 1019 | DEVCB_INPUT_PORT("analog_0"), | |
| 1020 | DEVCB_INPUT_PORT("analog_1"), | |
| 1021 | DEVCB_INPUT_PORT("analog_2"), | |
| 1022 | DEVCB_INPUT_PORT("analog_3"), | |
| 1023 | DEVCB_INPUT_PORT("analog_4"), | |
| 1024 | DEVCB_INPUT_PORT("analog_5"), | |
| 1025 | DEVCB_INPUT_PORT("analog_6"), | |
| 1026 | DEVCB_INPUT_PORT("analog_7") | |
| 1027 | }, | |
| 1028 | DEVCB_NULL, | |
| 1029 | DEVCB_NULL, // FIXME: is there anything connected here? | |
| 1030 | DEVCB_NULL, // FIXME: is there anything connected here? | |
| 1031 | atari_interrupt_cb, | |
| 1032 | }; | |
| 1033 | ||
| 1034 | static const pia6821_interface a5200_pia_interface = | |
| 1035 | { | |
| 1036 | DEVCB_HANDLER(atari_pia_pa_r), /* port A in */ | |
| 1037 | DEVCB_HANDLER(atari_pia_pb_r), /* port B in */ | |
| 1038 | DEVCB_NULL, /* line CA1 in */ | |
| 1039 | DEVCB_NULL, /* line CB1 in */ | |
| 1040 | DEVCB_NULL, /* line CA2 in */ | |
| 1041 | DEVCB_NULL, /* line CB2 in */ | |
| 1042 | DEVCB_NULL, /* port A out */ | |
| 1043 | DEVCB_NULL, /* port B out */ | |
| 1044 | DEVCB_NULL, /* line CA2 out */ | |
| 1045 | DEVCB_NULL, /* port CB2 out */ // FIXME: is there anything connected here | |
| 1046 | DEVCB_NULL, /* IRQA */ | |
| 1047 | DEVCB_NULL /* IRQB */ | |
| 1048 | }; | |
| 1049 | ||
| 1050 | ||
| 1051 | /************************************************************** | |
| 1052 | * | |
| 1053 | * Machine drivers | |
| 1054 | * | |
| 1055 | **************************************************************/ | |
| 1056 | ||
| 1057 | static MACHINE_CONFIG_FRAGMENT( a400_cartslot ) | |
| 1058 | MCFG_CARTSLOT_ADD("cart1") | |
| 1059 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1060 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1061 | MCFG_CARTSLOT_LOAD(a800_cart) | |
| 1062 | MCFG_CARTSLOT_UNLOAD(a800_cart) | |
| 1063 | MCFG_CARTSLOT_INTERFACE("a800_cart") | |
| 1064 | MACHINE_CONFIG_END | |
| 1065 | ||
| 1066 | static MACHINE_CONFIG_FRAGMENT( a800_cartslot ) | |
| 1067 | MCFG_CARTSLOT_ADD("cart1") | |
| 1068 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1069 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1070 | MCFG_CARTSLOT_LOAD(a800_cart) | |
| 1071 | MCFG_CARTSLOT_UNLOAD(a800_cart) | |
| 1072 | MCFG_CARTSLOT_INTERFACE("a800_cart") | |
| 1073 | ||
| 1074 | MCFG_CARTSLOT_ADD("cart2") | |
| 1075 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1076 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1077 | MCFG_CARTSLOT_LOAD(a800_cart_right) | |
| 1078 | MCFG_CARTSLOT_UNLOAD(a800_cart_right) | |
| 1079 | MCFG_CARTSLOT_INTERFACE("a800_cart") | |
| 1080 | MACHINE_CONFIG_END | |
| 1081 | ||
| 1082 | static MACHINE_CONFIG_START( atari_common_nodac, driver_device ) | |
| 1083 | /* basic machine hardware */ | |
| 1084 | MCFG_CPU_ADD("maincpu", M6502, FREQ_17_EXACT) | |
| 1085 | ||
| 1086 | /* video hardware */ | |
| 1087 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 1088 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1)) | |
| 1089 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 1090 | MCFG_SCREEN_VISIBLE_AREA(MIN_X, MAX_X, MIN_Y, MAX_Y) | |
| 1091 | MCFG_PALETTE_LENGTH(sizeof(atari_palette) / 3) | |
| 1092 | MCFG_PALETTE_INIT(mess_atari) | |
| 1093 | MCFG_SCREEN_UPDATE(atari) | |
| 1094 | ||
| 1095 | MCFG_VIDEO_START(atari) | |
| 1096 | ||
| 1097 | MCFG_PIA6821_ADD( "pia", atari_pia_interface ) | |
| 1098 | ||
| 1099 | /* sound hardware */ | |
| 1100 | MCFG_SPEAKER_STANDARD_MONO("mono") | |
| 1101 | MCFG_SOUND_ADD("pokey", POKEY, FREQ_17_EXACT) | |
| 1102 | MCFG_SOUND_CONFIG(atari_pokey_interface) | |
| 1103 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) | |
| 1104 | ||
| 1105 | /* internal ram */ | |
| 1106 | MCFG_RAM_ADD(RAM_TAG) | |
| 1107 | MCFG_RAM_DEFAULT_SIZE("40K") | |
| 1108 | MACHINE_CONFIG_END | |
| 1109 | ||
| 1110 | ||
| 1111 | static MACHINE_CONFIG_DERIVED( atari_common, atari_common_nodac ) | |
| 1112 | MCFG_SOUND_ADD("dac", DAC, 0) | |
| 1113 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) | |
| 1114 | ||
| 1115 | MCFG_ATARI_FDC_ADD("fdc") | |
| 1116 | MACHINE_CONFIG_END | |
| 1117 | ||
| 1118 | ||
| 1119 | static MACHINE_CONFIG_DERIVED( a400, atari_common ) | |
| 1120 | ||
| 1121 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1122 | MCFG_CPU_PROGRAM_MAP(a400_mem) | |
| 1123 | MCFG_CPU_VBLANK_INT_HACK(a400_interrupt, TOTAL_LINES_60HZ) | |
| 1124 | ||
| 1125 | MCFG_MACHINE_START( a400 ) | |
| 1126 | ||
| 1127 | MCFG_SCREEN_MODIFY("screen") | |
| 1128 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1129 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1130 | ||
| 1131 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1132 | ||
| 1133 | /* software lists */ | |
| 1134 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1135 | MACHINE_CONFIG_END | |
| 1136 | ||
| 1137 | ||
| 1138 | static MACHINE_CONFIG_DERIVED( a400pal, atari_common ) | |
| 1139 | ||
| 1140 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1141 | MCFG_CPU_PROGRAM_MAP(a400_mem) | |
| 1142 | MCFG_CPU_VBLANK_INT_HACK(a400_interrupt, TOTAL_LINES_50HZ) | |
| 1143 | ||
| 1144 | MCFG_MACHINE_START( a400 ) | |
| 1145 | ||
| 1146 | MCFG_SCREEN_MODIFY("screen") | |
| 1147 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_50HZ) | |
| 1148 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_50HZ) | |
| 1149 | ||
| 1150 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1151 | ||
| 1152 | /* software lists */ | |
| 1153 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1154 | MACHINE_CONFIG_END | |
| 1155 | ||
| 1156 | ||
| 1157 | static MACHINE_CONFIG_DERIVED( a800, atari_common ) | |
| 1158 | ||
| 1159 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1160 | MCFG_CPU_PROGRAM_MAP(a800_mem) | |
| 1161 | MCFG_CPU_VBLANK_INT_HACK(a800_interrupt, TOTAL_LINES_60HZ) | |
| 1162 | ||
| 1163 | MCFG_MACHINE_START( a800 ) | |
| 1164 | ||
| 1165 | MCFG_SCREEN_MODIFY("screen") | |
| 1166 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1167 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1168 | ||
| 1169 | MCFG_FRAGMENT_ADD(a800_cartslot) | |
| 1170 | ||
| 1171 | /* software lists */ | |
| 1172 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1173 | MACHINE_CONFIG_END | |
| 1174 | ||
| 1175 | ||
| 1176 | static MACHINE_CONFIG_DERIVED( a800pal, atari_common ) | |
| 1177 | ||
| 1178 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1179 | MCFG_CPU_PROGRAM_MAP(a800_mem) | |
| 1180 | MCFG_CPU_VBLANK_INT_HACK(a800_interrupt, TOTAL_LINES_50HZ) | |
| 1181 | ||
| 1182 | MCFG_MACHINE_START( a800 ) | |
| 1183 | ||
| 1184 | MCFG_SCREEN_MODIFY("screen") | |
| 1185 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_50HZ) | |
| 1186 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_50HZ) | |
| 1187 | ||
| 1188 | MCFG_FRAGMENT_ADD(a800_cartslot) | |
| 1189 | ||
| 1190 | /* software lists */ | |
| 1191 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1192 | MACHINE_CONFIG_END | |
| 1193 | ||
| 1194 | ||
| 1195 | static MACHINE_CONFIG_DERIVED( a600xl, atari_common ) | |
| 1196 | ||
| 1197 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1198 | MCFG_CPU_PROGRAM_MAP(a600xl_mem) // FIXME? | |
| 1199 | MCFG_CPU_VBLANK_INT_HACK(a800xl_interrupt, TOTAL_LINES_60HZ) | |
| 1200 | ||
| 1201 | MCFG_PIA6821_MODIFY( "pia", a600xl_pia_interface ) | |
| 1202 | ||
| 1203 | MCFG_MACHINE_START( a800xl ) // FIXME? | |
| 1204 | ||
| 1205 | MCFG_SCREEN_MODIFY("screen") | |
| 1206 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1207 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1208 | ||
| 1209 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1210 | ||
| 1211 | /* software lists */ | |
| 1212 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1213 | ||
| 1214 | /* internal ram */ | |
| 1215 | MCFG_RAM_MODIFY(RAM_TAG) | |
| 1216 | MCFG_RAM_DEFAULT_SIZE("16K") | |
| 1217 | MACHINE_CONFIG_END | |
| 1218 | ||
| 1219 | ||
| 1220 | static MACHINE_CONFIG_DERIVED( a800xl, atari_common ) | |
| 1221 | ||
| 1222 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1223 | MCFG_CPU_PROGRAM_MAP(a800xl_mem) | |
| 1224 | MCFG_CPU_VBLANK_INT_HACK(a800xl_interrupt, TOTAL_LINES_60HZ) | |
| 1225 | ||
| 1226 | MCFG_PIA6821_MODIFY( "pia", a800xl_pia_interface ) | |
| 1227 | ||
| 1228 | MCFG_MACHINE_START( a800xl ) | |
| 1229 | ||
| 1230 | MCFG_SCREEN_MODIFY("screen") | |
| 1231 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1232 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1233 | ||
| 1234 | MCFG_FRAGMENT_ADD(a400_cartslot) | |
| 1235 | ||
| 1236 | /* software lists */ | |
| 1237 | MCFG_SOFTWARE_LIST_ADD("cart_list","a800") | |
| 1238 | MACHINE_CONFIG_END | |
| 1239 | ||
| 1240 | static MACHINE_CONFIG_DERIVED( a800xlpal, a800xl ) | |
| 1241 | ||
| 1242 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1243 | MCFG_CPU_CLOCK( 1773000 ) | |
| 1244 | MCFG_CPU_VBLANK_INT_HACK(a800xl_interrupt, TOTAL_LINES_50HZ) | |
| 1245 | MCFG_SCREEN_MODIFY("screen") | |
| 1246 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_50HZ) | |
| 1247 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_50HZ) | |
| 1248 | ||
| 1249 | MCFG_SOUND_MODIFY("pokey") | |
| 1250 | MCFG_SOUND_CLOCK(1773000) | |
| 1251 | MACHINE_CONFIG_END | |
| 1252 | ||
| 1253 | static MACHINE_CONFIG_DERIVED( a1200xl, a800xl ) | |
| 1254 | ||
| 1255 | MCFG_PIA6821_MODIFY( "pia", a1200xl_pia_interface ) | |
| 1256 | MACHINE_CONFIG_END | |
| 1257 | ||
| 1258 | static MACHINE_CONFIG_DERIVED( xegs, a800xl ) | |
| 1259 | ||
| 1260 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1261 | MCFG_CPU_PROGRAM_MAP(xegs_mem) | |
| 1262 | ||
| 1263 | MCFG_MACHINE_START( xegs ) | |
| 1264 | ||
| 1265 | MCFG_PIA6821_MODIFY( "pia", xegs_pia_interface ) | |
| 1266 | ||
| 1267 | MCFG_DEVICE_REMOVE("cart1") | |
| 1268 | MCFG_DEVICE_REMOVE("cart_list") | |
| 1269 | ||
| 1270 | MCFG_CARTSLOT_ADD("cart1") | |
| 1271 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 1272 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1273 | MCFG_CARTSLOT_LOAD(xegs_cart) | |
| 1274 | MCFG_CARTSLOT_UNLOAD(xegs_cart) | |
| 1275 | MCFG_CARTSLOT_INTERFACE("xegs_cart") | |
| 1276 | ||
| 1277 | /* software lists */ | |
| 1278 | MCFG_SOFTWARE_LIST_ADD("cart_list","xegs") | |
| 1279 | MACHINE_CONFIG_END | |
| 1280 | ||
| 1281 | ||
| 1282 | static MACHINE_CONFIG_DERIVED( a5200, atari_common_nodac ) | |
| 1283 | ||
| 1284 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 1285 | MCFG_CPU_PROGRAM_MAP(a5200_mem) | |
| 1286 | MCFG_CPU_VBLANK_INT_HACK(a5200_interrupt, TOTAL_LINES_60HZ) | |
| 1287 | ||
| 1288 | MCFG_DEVICE_REMOVE("pokey") | |
| 1289 | MCFG_SOUND_ADD("pokey", POKEY, FREQ_17_EXACT) | |
| 1290 | MCFG_SOUND_CONFIG(a5200_pokey_interface) | |
| 1291 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) | |
| 1292 | ||
| 1293 | MCFG_PIA6821_MODIFY( "pia", a5200_pia_interface ) | |
| 1294 | ||
| 1295 | MCFG_MACHINE_START( a5200 ) | |
| 1296 | ||
| 1297 | MCFG_SCREEN_MODIFY( "screen" ) | |
| 1298 | MCFG_SCREEN_REFRESH_RATE(FRAME_RATE_60HZ) | |
| 1299 | MCFG_SCREEN_SIZE(HWIDTH*8, TOTAL_LINES_60HZ) | |
| 1300 | ||
| 1301 | MCFG_CARTSLOT_ADD("cart") | |
| 1302 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin,a52") | |
| 1303 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1304 | MCFG_CARTSLOT_LOAD(a5200_cart) | |
| 1305 | MCFG_CARTSLOT_UNLOAD(a5200_cart) | |
| 1306 | MCFG_CARTSLOT_INTERFACE("a5200_cart") | |
| 1307 | ||
| 1308 | /* Software lists */ | |
| 1309 | MCFG_SOFTWARE_LIST_ADD("cart_list","a5200") | |
| 1310 | ||
| 1311 | /* internal ram */ | |
| 1312 | MCFG_RAM_MODIFY(RAM_TAG) | |
| 1313 | MCFG_RAM_DEFAULT_SIZE("16K") | |
| 1314 | MACHINE_CONFIG_END | |
| 1315 | ||
| 1316 | ||
| 1317 | /************************************************************** | |
| 1318 | * | |
| 1319 | * ROM loading | |
| 1320 | * | |
| 1321 | **************************************************************/ | |
| 1322 | ||
| 1323 | ROM_START(a400) | |
| 1324 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1325 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1326 | ROM_SYSTEM_BIOS(0, "default", "OS Rev. B") | |
| 1327 | ROMX_LOAD( "co12499b.rom", 0xe000, 0x1000, BAD_DUMP CRC(d818f3e8) SHA1(bcdec2188f6a6a5bfc1df4e383bd828d34b5c4ac), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1328 | ROMX_LOAD( "co14599b.rom", 0xf000, 0x1000, BAD_DUMP CRC(c1690a9b) SHA1(c5248e8565574fd39ae1c3f4f356aa4cac07df95), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1329 | ROM_SYSTEM_BIOS(1, "reva", "OS Rev. A") | |
| 1330 | ROMX_LOAD( "co12499a.rom", 0xe000, 0x1000, BAD_DUMP CRC(29f64e17) SHA1(abf7ec488c6b600f1b7f30bdc7f8a2bf6a727675), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1331 | ROMX_LOAD( "co14599a.rom", 0xf000, 0x1000, BAD_DUMP CRC(bc533f0c) SHA1(e217148495fa747fe5488132d8d22533e68c7e58), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1332 | ||
| 1333 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1334 | ROM_END | |
| 1335 | ||
| 1336 | ROM_START(a400pal) | |
| 1337 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1338 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1339 | ROM_LOAD( "co15199.rom", 0xe000, 0x1000, BAD_DUMP CRC(8e547f56) SHA1(1bd746ea798b723bfb18495a7facca113183d713) ) // Rev. A - CRC and label waiting for confirmation | |
| 1340 | ROM_LOAD( "co15299.rom", 0xf000, 0x1000, BAD_DUMP CRC(be55b413) SHA1(d88afae49b08e75943d0258cb580e5d34756414a) ) // Rev. A - CRC and label waiting for confirmation | |
| 1341 | ||
| 1342 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1343 | ROM_END | |
| 1344 | ||
| 1345 | ROM_START(a800) | |
| 1346 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1347 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1348 | ROM_SYSTEM_BIOS(0, "default", "OS Rev. B") | |
| 1349 | ROMX_LOAD( "co12499b.rom", 0xe000, 0x1000, BAD_DUMP CRC(d818f3e8) SHA1(bcdec2188f6a6a5bfc1df4e383bd828d34b5c4ac), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1350 | ROMX_LOAD( "co14599b.rom", 0xf000, 0x1000, BAD_DUMP CRC(c1690a9b) SHA1(c5248e8565574fd39ae1c3f4f356aa4cac07df95), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1351 | ROM_SYSTEM_BIOS(1, "reva", "OS Rev. A") | |
| 1352 | ROMX_LOAD( "co12499a.rom", 0xe000, 0x1000, BAD_DUMP CRC(29f64e17) SHA1(abf7ec488c6b600f1b7f30bdc7f8a2bf6a727675), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1353 | ROMX_LOAD( "co14599a.rom", 0xf000, 0x1000, BAD_DUMP CRC(bc533f0c) SHA1(e217148495fa747fe5488132d8d22533e68c7e58), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1354 | ||
| 1355 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1356 | ||
| 1357 | ROM_REGION(0x2000, "rslot", ROMREGION_ERASEFF) | |
| 1358 | ROM_END | |
| 1359 | ||
| 1360 | ROM_START(a800pal) | |
| 1361 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 2 * 8K for cartridges */ | |
| 1362 | ROM_LOAD( "co12399b.rom", 0xd800, 0x0800, CRC(6a5d766e) SHA1(01a6044f7a81d409c938e7dfde0a1af5832229d2) ) | |
| 1363 | ROM_LOAD( "co15199.rom", 0xe000, 0x1000, BAD_DUMP CRC(8e547f56) SHA1(1bd746ea798b723bfb18495a7facca113183d713) ) // Rev. A - CRC and label waiting for confirmation | |
| 1364 | ROM_LOAD( "co15299.rom", 0xf000, 0x1000, BAD_DUMP CRC(be55b413) SHA1(d88afae49b08e75943d0258cb580e5d34756414a) ) // Rev. A - CRC and label waiting for confirmation | |
| 1365 | ||
| 1366 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1367 | ||
| 1368 | ROM_REGION(0x2000, "rslot", ROMREGION_ERASEFF) | |
| 1369 | ROM_END | |
| 1370 | ||
| 1371 | ROM_START(a1200xl) | |
| 1372 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1373 | ROM_SYSTEM_BIOS(0, "default", "OS Rev. 11") | |
| 1374 | ROMX_LOAD( "co60616b.rom", 0x14000, 0x2000, BAD_DUMP CRC(6e29ec8d) SHA1(3f9c06d6b4d261f3d5bf4354e3cff0c17b9347b9), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1375 | ROMX_LOAD( "co60617b.rom", 0x16000, 0x2000, BAD_DUMP CRC(d73ce29a) SHA1(64790242d902643fe0c40dd842749f1fe461831b), ROM_BIOS(1) ) // CRC and label waiting for confirmation | |
| 1376 | ROM_SYSTEM_BIOS(1, "rev10", "OS Rev. 10") | |
| 1377 | ROMX_LOAD( "co60616a.rom", 0x14000, 0x2000, BAD_DUMP CRC(0391386b) SHA1(7c176657c88b89b8a69bf021fa8e0939efc0dff2), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1378 | ROMX_LOAD( "co60617a.rom", 0x16000, 0x2000, BAD_DUMP CRC(b502f1e7) SHA1(6688db57d97fa570aef5c15cef3e5fb2688879c2), ROM_BIOS(2) ) // CRC and label waiting for confirmation | |
| 1379 | ||
| 1380 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1381 | ROM_END | |
| 1382 | ||
| 1383 | ROM_START(a600xl) | |
| 1384 | ROM_REGION(0x10000, "maincpu", 0) | |
| 1385 | ROM_LOAD( "co60302a.rom", 0xa000, 0x2000, CRC(f0202fb3) SHA1(7ad88dd99ff4a6ee66f6d162074db6f8bef7a9b6) ) // Rev. B | |
| 1386 | ROM_LOAD( "co62024.rom", 0xc000, 0x4000, CRC(643bcc98) SHA1(881d030656b40bbe48f15a696b28f22c0b752ab0) ) // Rev. 1 | |
| 1387 | ||
| 1388 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1389 | ROM_END | |
| 1390 | ||
| 1391 | ROM_START(a800xl) | |
| 1392 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1393 | ROM_FILL( 0, 0x10000, 0x00 ) | |
| 1394 | ROM_LOAD( "co60302a.rom", 0x10000, 0x2000, CRC(f0202fb3) SHA1(7ad88dd99ff4a6ee66f6d162074db6f8bef7a9b6) ) // Rev. B | |
| 1395 | ROM_LOAD( "co61598b.rom", 0x14000, 0x4000, CRC(1f9cd270) SHA1(ae4f523ba08b6fd59f3cae515a2b2410bbd98f55) ) // Rev. 2 | |
| 1396 | ||
| 1397 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1398 | ROM_END | |
| 1399 | ||
| 1400 | #define rom_a800xlp rom_a800xl | |
| 1401 | ||
| 1402 | ROM_START(a65xe) | |
| 1403 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1404 | ROM_LOAD( "co24947a.rom", 0x10000, 0x2000, CRC(7d684184) SHA1(3693c9cb9bf3b41bae1150f7a8264992468fc8c0) ) // Rev. C | |
| 1405 | ROM_LOAD( "co61598b.rom", 0x14000, 0x4000, CRC(1f9cd270) SHA1(ae4f523ba08b6fd59f3cae515a2b2410bbd98f55) ) // Rev. 2 | |
| 1406 | ||
| 1407 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1408 | ROM_END | |
| 1409 | ||
| 1410 | ROM_START(a65xea) | |
| 1411 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1412 | ROM_LOAD( "basic_ar.rom", 0x10000, 0x2000, CRC(c899f4d6) SHA1(043df191d1fe402e792266a108e147ffcda35130) ) // is this correct? or shall we use Rev. C? | |
| 1413 | // ROM_LOAD( "c101700.rom", 0x14000, 0x4000, CRC(7f9a76c8) SHA1(57eb6d87850a763f11767f53d4eaede186f831a2) ) // this was from Savetz and has wrong bits! | |
| 1414 | ROM_LOAD( "c101700.rom", 0x14000, 0x4000, CRC(45f47988) SHA1(a36b8b20f657580f172749bb0625c08706ed824c) ) // Rev. 3B ? | |
| 1415 | ||
| 1416 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1417 | ROM_END | |
| 1418 | ||
| 1419 | ROM_START(a130xe) | |
| 1420 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1421 | ROM_LOAD( "co24947a.rom", 0x10000, 0x2000, CRC(7d684184) SHA1(3693c9cb9bf3b41bae1150f7a8264992468fc8c0) ) // Rev. C | |
| 1422 | ROM_LOAD( "co61598b.rom", 0x14000, 0x4000, CRC(1f9cd270) SHA1(ae4f523ba08b6fd59f3cae515a2b2410bbd98f55) ) // Rev. 2 | |
| 1423 | ||
| 1424 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1425 | ROM_END | |
| 1426 | ||
| 1427 | ROM_START(a800xe) | |
| 1428 | ROM_REGION(0x18000, "maincpu", 0) | |
| 1429 | ROM_LOAD( "co24947a.rom", 0x10000, 0x2000, CRC(7d684184) SHA1(3693c9cb9bf3b41bae1150f7a8264992468fc8c0) ) // Rev. C | |
| 1430 | ROM_LOAD( "c300717.rom", 0x14000, 0x4000, CRC(29f133f7) SHA1(f03b9b93000ee84abb9cf8d6367241006f172182) ) // Rev. 3 | |
| 1431 | ||
| 1432 | ROM_REGION(0x10000, "lslot", ROMREGION_ERASEFF) | |
| 1433 | ROM_END | |
| 1434 | ||
| 1435 | ROM_START(xegs) | |
| 1436 | ROM_REGION(0x1a000, "maincpu", 0) | |
| 1437 | ROM_LOAD( "c101687.rom", 0x10000, 0x8000, CRC(d50260d1) SHA1(0e0625ab2473f8431640df3ac8af61925760b9b9) ) // Rev. C + Rev. 4 + Missile Command | |
| 1438 | ||
| 1439 | ROM_REGION(0x20000, "user1", ROMREGION_ERASE00) | |
| 1440 | ROM_END | |
| 1441 | ||
| 1442 | ||
| 1443 | ROM_START(a5200) | |
| 1444 | ROM_REGION(0x14000, "maincpu", 0) /* 64K for the CPU + 16K for cartridges */ | |
| 1445 | ROM_SYSTEM_BIOS(0, "default", "a5200") | |
| 1446 | ROMX_LOAD( "5200.rom", 0xf800, 0x0800, CRC(4248d3e3) SHA1(6ad7a1e8c9fad486fbec9498cb48bf5bc3adc530), ROM_BIOS(1) ) | |
| 1447 | ROM_SYSTEM_BIOS(1, "alt", "a5200 (alt)") | |
| 1448 | ROMX_LOAD( "5200a.rom", 0xf800, 0x0800, CRC(c2ba2613) SHA1(1d2a3f00109d75d2d79fecb565775eb95b7d04d5), ROM_BIOS(2) ) | |
| 1449 | ROM_END | |
| 1450 | ||
| 1451 | /************************************************************** | |
| 1452 | * | |
| 1453 | * Driver initializations | |
| 1454 | * | |
| 1455 | **************************************************************/ | |
| 1456 | ||
| 1457 | static DRIVER_INIT( a800xl ) | |
| 1458 | { | |
| 1459 | a800xl_mmu(machine, 0xff); | |
| 1460 | } | |
| 1461 | ||
| 1462 | static DRIVER_INIT( xegs ) | |
| 1463 | { | |
| 1464 | xegs_mmu(machine, 0xff); | |
| 1465 | } | |
| 1466 | ||
| 1467 | static DRIVER_INIT( a600xl ) | |
| 1468 | { | |
| 1469 | UINT8 *rom = machine.region("maincpu")->base(); | |
| 1470 | memcpy( rom + 0x5000, rom + 0xd000, 0x800 ); | |
| 1471 | } | |
| 1472 | ||
| 1473 | /************************************************************** | |
| 1474 | * | |
| 1475 | * Game driver(s) | |
| 1476 | * | |
| 1477 | **************************************************************/ | |
| 1478 | ||
| 1479 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 1480 | COMP ( 1979, a400, 0, 0, a400, a800, 0, "Atari", "Atari 400 (NTSC)", 0) | |
| 1481 | COMP ( 1979, a400pal, a400, 0, a400pal, a800, 0, "Atari", "Atari 400 (PAL)", 0) | |
| 1482 | COMP ( 1979, a800, 0, 0, a800, a800, 0, "Atari", "Atari 800 (NTSC)", 0) | |
| 1483 | COMP ( 1979, a800pal, a800, 0, a800pal, a800, 0, "Atari", "Atari 800 (PAL)", 0) | |
| 1484 | COMP ( 1982, a1200xl, a800, 0, a1200xl, a800xl, a800xl, "Atari", "Atari 1200XL", GAME_NOT_WORKING ) // 64k RAM | |
| 1485 | COMP ( 1983, a600xl, a800xl, 0, a600xl, a800xl, a600xl, "Atari", "Atari 600XL", GAME_NOT_WORKING ) // 16k RAM | |
| 1486 | COMP ( 1983, a800xl, 0, 0, a800xl, a800xl, a800xl, "Atari", "Atari 800XL (NTSC)",GAME_IMPERFECT_GRAPHICS ) // 64k RAM | |
| 1487 | COMP ( 1983, a800xlp, a800xl, 0, a800xlpal, a800xl, a800xl, "Atari", "Atari 800XL (PAL)", GAME_IMPERFECT_GRAPHICS ) // 64k RAM | |
| 1488 | COMP ( 1986, a65xe, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 65XE", GAME_NOT_WORKING ) // 64k RAM | |
| 1489 | COMP ( 1986, a65xea, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 65XE (Arabic)", GAME_NOT_WORKING ) | |
| 1490 | COMP ( 1986, a130xe, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 130XE", GAME_NOT_WORKING ) // 128k RAM | |
| 1491 | COMP ( 1986, a800xe, a800xl, 0, a800xl, a800xl, a800xl, "Atari", "Atari 800XE", GAME_NOT_WORKING ) // 64k RAM | |
| 1492 | COMP ( 1987, xegs, 0, 0, xegs, a800xl, xegs, "Atari", "Atari XE Game System", GAME_NOT_WORKING ) // 64k RAM | |
| 1493 | ||
| 1494 | CONS ( 1982, a5200, 0, 0, a5200, a5200, 0, "Atari", "Atari 5200", 0) |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | Commodore Amiga - (c) 1985, Commodore Business Machines Co. | |
| 3 | ||
| 4 | Preliminary driver by: | |
| 5 | ||
| 6 | Ernesto Corvi | |
| 7 | ||
| 8 | Note 1: The 'fast-mem' memory detector in Kickstart 1.2 expects to | |
| 9 | see the custom chips at the end of any present fast memory (mapped | |
| 10 | from $C00000 onwards). I assume this is a bug, given that the routine | |
| 11 | was entirely rewritten for Kickstart 1.3. So the strategy is, for | |
| 12 | any machine that can run Kickstart 1.2 (a500,a1000 and a2000), we | |
| 13 | map a mirror of the custom chips right after any fast-mem we mapped. | |
| 14 | If we didn't map any, then we still put a mirror, but where fast-mem | |
| 15 | would commence ($C00000). | |
| 16 | ||
| 17 | ***************************************************************************/ | |
| 18 | ||
| 19 | /* Core includes */ | |
| 20 | #include "emu.h" | |
| 21 | #include "includes/amiga.h" | |
| 22 | ||
| 23 | /* Components */ | |
| 24 | #include "cpu/m68000/m68000.h" | |
| 25 | #include "cpu/m6502/m6502.h" | |
| 26 | #include "machine/6525tpi.h" | |
| 27 | #include "machine/6526cia.h" | |
| 28 | #include "machine/amigafdc.h" | |
| 29 | #include "machine/amigakbd.h" | |
| 30 | #include "machine/amigacd.h" | |
| 31 | #include "machine/amigacrt.h" | |
| 32 | #include "machine/msm6242.h" | |
| 33 | #include "machine/ctronics.h" | |
| 34 | #include "machine/nvram.h" | |
| 35 | #include "sound/cdda.h" | |
| 36 | ||
| 37 | /* Devices */ | |
| 38 | #include "imagedev/chd_cd.h" | |
| 39 | #include "imagedev/cartslot.h" | |
| 40 | ||
| 41 | ||
| 42 | static READ8_DEVICE_HANDLER( amiga_cia_0_portA_r ); | |
| 43 | static READ8_DEVICE_HANDLER( amiga_cia_0_cdtv_portA_r ); | |
| 44 | static WRITE8_DEVICE_HANDLER( amiga_cia_0_portA_w ); | |
| 45 | ||
| 46 | /*************************************************************************** | |
| 47 | Battery Backed-Up Clock (MSM6264) | |
| 48 | ***************************************************************************/ | |
| 49 | ||
| 50 | static READ16_HANDLER( amiga_clock_r ) | |
| 51 | { | |
| 52 | device_t *rtc = space->machine().device("rtc"); | |
| 53 | return msm6242_r(rtc, offset / 2); | |
| 54 | } | |
| 55 | ||
| 56 | ||
| 57 | static WRITE16_HANDLER( amiga_clock_w ) | |
| 58 | { | |
| 59 | device_t *rtc = space->machine().device("rtc"); | |
| 60 | msm6242_w(rtc, offset / 2, data); | |
| 61 | } | |
| 62 | ||
| 63 | ||
| 64 | /*************************************************************************** | |
| 65 | CENTRONICS PORT | |
| 66 | ***************************************************************************/ | |
| 67 | ||
| 68 | static READ8_DEVICE_HANDLER( amiga_cia_1_porta_r ) | |
| 69 | { | |
| 70 | UINT8 result = 0; | |
| 71 | ||
| 72 | /* centronics status is stored in PA0 to PA2 */ | |
| 73 | result |= centronics_busy_r(device) << 0; | |
| 74 | result |= !centronics_pe_r(device) << 1; | |
| 75 | result |= centronics_vcc_r(device) << 2; | |
| 76 | ||
| 77 | /* PA3 to PA7 store the serial line status (not emulated) */ | |
| 78 | ||
| 79 | return result; | |
| 80 | } | |
| 81 | ||
| 82 | static const centronics_interface amiga_centronics_config = | |
| 83 | { | |
| 84 | FALSE, | |
| 85 | DEVCB_DEVICE_LINE("cia_0", mos6526_flag_w), | |
| 86 | DEVCB_NULL, | |
| 87 | DEVCB_NULL | |
| 88 | }; | |
| 89 | ||
| 90 | ||
| 91 | /*************************************************************************** | |
| 92 | Address maps | |
| 93 | ***************************************************************************/ | |
| 94 | ||
| 95 | static ADDRESS_MAP_START(amiga_mem, AS_PROGRAM, 16) | |
| 96 | ADDRESS_MAP_UNMAP_HIGH | |
| 97 | AM_RANGE(0x000000, 0x07ffff) AM_MIRROR(0x80000) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(amiga_state, m_chip_ram, m_chip_ram_size) | |
| 98 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) | |
| 99 | AM_RANGE(0xc00000, 0xc7ffff) AM_RAM /* slow-mem */ | |
| 100 | AM_RANGE(0xc80000, 0xcfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) /* see Note 1 above */ | |
| 101 | AM_RANGE(0xdf0000, 0xdfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) AM_BASE_MEMBER(amiga_state, m_custom_regs) /* Custom Chips */ | |
| 102 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE(amiga_autoconfig_r, amiga_autoconfig_w) | |
| 103 | AM_RANGE(0xf80000, 0xffffff) AM_ROM AM_REGION("user1", 0) /* System ROM - mirror */ | |
| 104 | ADDRESS_MAP_END | |
| 105 | ||
| 106 | static ADDRESS_MAP_START(keyboard_mem, AS_PROGRAM, 8) | |
| 107 | AM_RANGE(0x0000, 0x003f) AM_RAM /* internal user ram */ | |
| 108 | AM_RANGE(0x0040, 0x007f) AM_NOP /* unassigned */ | |
| 109 | AM_RANGE(0x0080, 0x0080) AM_NOP /* port a */ | |
| 110 | AM_RANGE(0x0081, 0x0081) AM_NOP /* port b */ | |
| 111 | AM_RANGE(0x0082, 0x0082) AM_NOP /* port c */ | |
| 112 | AM_RANGE(0x0083, 0x0083) AM_NOP /* port d */ | |
| 113 | AM_RANGE(0x0084, 0x0085) AM_NOP /* latch */ | |
| 114 | AM_RANGE(0x0086, 0x0087) AM_NOP /* count */ | |
| 115 | AM_RANGE(0x0088, 0x0088) AM_NOP /* upper latch & transfer latch to counter */ | |
| 116 | AM_RANGE(0x0089, 0x0089) AM_NOP /* clear pa0 pos edge detected */ | |
| 117 | AM_RANGE(0x008a, 0x008a) AM_NOP /* clear pa1 neg edge detected */ | |
| 118 | AM_RANGE(0x008b, 0x008e) AM_NOP /* unassigned */ | |
| 119 | AM_RANGE(0x008f, 0x008f) AM_NOP /* control register */ | |
| 120 | AM_RANGE(0x0090, 0x07ff) AM_NOP /* unassigned */ | |
| 121 | AM_RANGE(0x0800, 0x0fff) AM_ROM AM_REGION("keyboard", 0) /* internal mask rom */ | |
| 122 | ADDRESS_MAP_END | |
| 123 | ||
| 124 | ||
| 125 | /* | |
| 126 | * CDTV memory map (source: http://www.l8r.net/technical/cdtv-technical.html) | |
| 127 | * | |
| 128 | * 000000-0FFFFF Chip memory | |
| 129 | * 100000-1FFFFF Space for extra chip memory (Megachip) | |
| 130 | * 200000-9FFFFF Space for AutoConfig memory | |
| 131 | * A00000-BFFFFF CIA chips | |
| 132 | * C00000-C7FFFF Space for slow-fast memory | |
| 133 | * C80000-DBFFFF Space | |
| 134 | * DC0000-DC7FFF Power backed-up real time clock | |
| 135 | * DC8000-DC87FF Non-volatile RAM | |
| 136 | * DC8800-DCFFFF Space in non-volatile RAM decoded area | |
| 137 | * DD0000-DEFFFF Space | |
| 138 | * DF0000-DFFFFF Custom chips | |
| 139 | * E00000-E7FFFF Memory card address space for front panel memory card | |
| 140 | * E80000-E8FFFF AutoConfig configuration space | |
| 141 | * E90000-E9FFFF First AutoConfig device, used by DMAC | |
| 142 | * EA0000-EFFFFF Space for other AutoConfig devices | |
| 143 | * F00000-F3FFFF CDTV ROM | |
| 144 | * F40000-F7FFFF Space in CDTV ROM decoded area | |
| 145 | * F80000-FBFFFF Space in Kickstart ROM decoded area (used by Kickstart 2) | |
| 146 | * FC0000-FFFFFF Kickstart ROM | |
| 147 | * | |
| 148 | */ | |
| 149 | ||
| 150 | static ADDRESS_MAP_START(cdtv_mem, AS_PROGRAM, 16) | |
| 151 | AM_RANGE(0x000000, 0x0fffff) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(amiga_state, m_chip_ram, m_chip_ram_size) | |
| 152 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) | |
| 153 | AM_RANGE(0xdc0000, 0xdc003f) AM_READWRITE(amiga_clock_r, amiga_clock_w) | |
| 154 | AM_RANGE(0xdc8000, 0xdc87ff) AM_RAM AM_SHARE("nvram") | |
| 155 | AM_RANGE(0xdf0000, 0xdfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) AM_BASE_MEMBER(amiga_state, m_custom_regs) /* Custom Chips */ | |
| 156 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE(amiga_autoconfig_r, amiga_autoconfig_w) | |
| 157 | AM_RANGE(0xf00000, 0xffffff) AM_ROM AM_REGION("user1", 0) /* CDTV & System ROM */ | |
| 158 | ADDRESS_MAP_END | |
| 159 | ||
| 160 | static ADDRESS_MAP_START(cdtv_rcmcu_mem, AS_PROGRAM, 8) | |
| 161 | AM_RANGE(0x0000, 0x003f) AM_RAM /* internal user ram */ | |
| 162 | AM_RANGE(0x0040, 0x007f) AM_NOP /* unassigned */ | |
| 163 | AM_RANGE(0x0080, 0x0080) AM_NOP /* port a */ | |
| 164 | AM_RANGE(0x0081, 0x0081) AM_NOP /* port b */ | |
| 165 | AM_RANGE(0x0082, 0x0082) AM_NOP /* port c */ | |
| 166 | AM_RANGE(0x0083, 0x0083) AM_NOP /* port d */ | |
| 167 | AM_RANGE(0x0084, 0x0085) AM_NOP /* latch */ | |
| 168 | AM_RANGE(0x0086, 0x0087) AM_NOP /* count */ | |
| 169 | AM_RANGE(0x0088, 0x0088) AM_NOP /* upper latch & transfer latch to counter */ | |
| 170 | AM_RANGE(0x0089, 0x0089) AM_NOP /* clear pa0 pos edge detected */ | |
| 171 | AM_RANGE(0x008a, 0x008a) AM_NOP /* clear pa1 neg edge detected */ | |
| 172 | AM_RANGE(0x008b, 0x008e) AM_NOP /* unassigned */ | |
| 173 | AM_RANGE(0x008f, 0x008f) AM_NOP /* control register */ | |
| 174 | AM_RANGE(0x0090, 0x07ff) AM_NOP /* unassigned */ | |
| 175 | AM_RANGE(0x0800, 0x0fff) AM_ROM AM_REGION("rcmcu", 0) /* internal mask rom */ | |
| 176 | ADDRESS_MAP_END | |
| 177 | ||
| 178 | static ADDRESS_MAP_START(a1000_mem, AS_PROGRAM, 16) | |
| 179 | AM_RANGE(0x000000, 0x03ffff) AM_MIRROR(0xc0000) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(amiga_state, m_chip_ram, m_chip_ram_size) | |
| 180 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE(amiga_cia_r, amiga_cia_w) | |
| 181 | AM_RANGE(0xc00000, 0xc3ffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) /* See Note 1 above */ | |
| 182 | AM_RANGE(0xdf0000, 0xdfffff) AM_READWRITE(amiga_custom_r, amiga_custom_w) AM_BASE_MEMBER(amiga_state, m_custom_regs) /* Custom Chips */ | |
| 183 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE(amiga_autoconfig_r, amiga_autoconfig_w) | |
| 184 | AM_RANGE(0xf80000, 0xfbffff) AM_ROM AM_REGION("user1", 0) /* Bootstrap ROM */ | |
| 185 | AM_RANGE(0xfc0000, 0xffffff) AM_RAMBANK("bank2") /* Writable Control Store RAM */ | |
| 186 | ADDRESS_MAP_END | |
| 187 | ||
| 188 | ||
| 189 | /*************************************************************************** | |
| 190 | Inputs | |
| 191 | ***************************************************************************/ | |
| 192 | ||
| 193 | static INPUT_PORTS_START( amiga_common ) | |
| 194 | PORT_START("input") | |
| 195 | PORT_CONFNAME( 0x20, 0x00, "Input Port 0 Device") | |
| 196 | PORT_CONFSETTING( 0x00, "Mouse" ) | |
| 197 | PORT_CONFSETTING( 0x20, DEF_STR(Joystick) ) | |
| 198 | PORT_CONFNAME( 0x10, 0x10, "Input Port 1 Device") | |
| 199 | PORT_CONFSETTING( 0x00, "Mouse" ) | |
| 200 | PORT_CONFSETTING( 0x10, DEF_STR(Joystick) ) | |
| 201 | ||
| 202 | PORT_START("CIA0PORTA") | |
| 203 | PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_SPECIAL ) | |
| 204 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) | |
| 205 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) | |
| 206 | ||
| 207 | PORT_START("JOY0DAT") | |
| 208 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P1JOY") | |
| 209 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 210 | ||
| 211 | PORT_START("JOY1DAT") | |
| 212 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P2JOY") | |
| 213 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 214 | ||
| 215 | PORT_START("POTGO") | |
| 216 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 217 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) | |
| 218 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 219 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) | |
| 220 | PORT_BIT( 0xaaff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 221 | ||
| 222 | PORT_START("P1JOY") | |
| 223 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) | |
| 224 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) | |
| 225 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) | |
| 226 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) | |
| 227 | ||
| 228 | PORT_START("P2JOY") | |
| 229 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) | |
| 230 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) | |
| 231 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) | |
| 232 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) | |
| 233 | ||
| 234 | PORT_START("P0MOUSEX") | |
| 235 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 236 | ||
| 237 | PORT_START("P0MOUSEY") | |
| 238 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 239 | ||
| 240 | PORT_START("P1MOUSEX") | |
| 241 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 242 | ||
| 243 | PORT_START("P1MOUSEY") | |
| 244 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 245 | ||
| 246 | PORT_INCLUDE( amiga_us_keyboard ) | |
| 247 | ||
| 248 | INPUT_PORTS_END | |
| 249 | ||
| 250 | ||
| 251 | static INPUT_PORTS_START( amiga ) | |
| 252 | PORT_START("hardware") | |
| 253 | PORT_CONFNAME( 0x08, 0x08, "Battery backed-up RTC") | |
| 254 | PORT_CONFSETTING( 0x00, "Not Installed" ) | |
| 255 | PORT_CONFSETTING( 0x08, "Installed" ) | |
| 256 | ||
| 257 | PORT_INCLUDE( amiga_common ) | |
| 258 | INPUT_PORTS_END | |
| 259 | ||
| 260 | ||
| 261 | /* TODO: Support for the CDTV remote control */ | |
| 262 | static INPUT_PORTS_START( cdtv ) | |
| 263 | PORT_INCLUDE( amiga_common ) | |
| 264 | INPUT_PORTS_END | |
| 265 | ||
| 266 | /*************************************************************************** | |
| 267 | Machine drivers | |
| 268 | ***************************************************************************/ | |
| 269 | ||
| 270 | static MACHINE_START( cdtv ) | |
| 271 | { | |
| 272 | MACHINE_START_CALL( amigacd ); | |
| 273 | } | |
| 274 | ||
| 275 | ||
| 276 | static MACHINE_RESET( cdtv ) | |
| 277 | { | |
| 278 | MACHINE_RESET_CALL( amiga ); | |
| 279 | ||
| 280 | /* initialize the cdrom controller */ | |
| 281 | MACHINE_RESET_CALL( amigacd ); | |
| 282 | } | |
| 283 | ||
| 284 | static const mos6526_interface cia_0_ntsc_intf = | |
| 285 | { | |
| 286 | 60, /* tod_clock */ | |
| 287 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 288 | DEVCB_DEVICE_LINE("centronics", centronics_strobe_w), /* pc_func */ | |
| 289 | DEVCB_NULL, | |
| 290 | DEVCB_NULL, | |
| 291 | DEVCB_HANDLER(amiga_cia_0_portA_r), | |
| 292 | DEVCB_HANDLER(amiga_cia_0_portA_w), /* port A */ | |
| 293 | DEVCB_NULL, | |
| 294 | DEVCB_DEVICE_HANDLER("centronics", centronics_data_w) /* port B */ | |
| 295 | }; | |
| 296 | ||
| 297 | static const mos6526_interface cia_0_pal_intf = | |
| 298 | { | |
| 299 | 50, /* tod_clock */ | |
| 300 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 301 | DEVCB_DEVICE_LINE("centronics", centronics_strobe_w), /* pc_func */ | |
| 302 | DEVCB_NULL, | |
| 303 | DEVCB_NULL, | |
| 304 | DEVCB_HANDLER(amiga_cia_0_portA_r), | |
| 305 | DEVCB_HANDLER(amiga_cia_0_portA_w), /* port A */ | |
| 306 | DEVCB_NULL, | |
| 307 | DEVCB_DEVICE_HANDLER("centronics", centronics_data_w) /* port B */ | |
| 308 | }; | |
| 309 | ||
| 310 | static const mos6526_interface cia_1_intf = | |
| 311 | { | |
| 312 | 0, /* tod_clock */ | |
| 313 | DEVCB_LINE(amiga_cia_1_irq), /* irq_func */ | |
| 314 | DEVCB_NULL, /* pc_func */ | |
| 315 | DEVCB_NULL, | |
| 316 | DEVCB_NULL, | |
| 317 | DEVCB_DEVICE_HANDLER("centronics", amiga_cia_1_porta_r), | |
| 318 | DEVCB_NULL, /* port A */ | |
| 319 | DEVCB_NULL, | |
| 320 | DEVCB_DEVICE_HANDLER("fdc", amiga_fdc_control_w) /* port B */ | |
| 321 | }; | |
| 322 | ||
| 323 | static const mos6526_interface cia_0_cdtv_intf = | |
| 324 | { | |
| 325 | 0, /* tod_clock */ | |
| 326 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 327 | DEVCB_DEVICE_LINE("centronics", centronics_strobe_w), /* pc_func */ | |
| 328 | DEVCB_NULL, | |
| 329 | DEVCB_NULL, | |
| 330 | DEVCB_HANDLER(amiga_cia_0_cdtv_portA_r), | |
| 331 | DEVCB_HANDLER(amiga_cia_0_portA_w), /* port A */ | |
| 332 | DEVCB_NULL, | |
| 333 | DEVCB_DEVICE_HANDLER("centronics", centronics_data_w) /* port B */ | |
| 334 | }; | |
| 335 | ||
| 336 | static const mos6526_interface cia_1_cdtv_intf = | |
| 337 | { | |
| 338 | 0, /* tod_clock */ | |
| 339 | DEVCB_LINE(amiga_cia_1_irq), /* irq_func */ | |
| 340 | DEVCB_NULL, /* pc_func */ | |
| 341 | DEVCB_NULL, | |
| 342 | DEVCB_NULL, | |
| 343 | DEVCB_DEVICE_HANDLER("centronics", amiga_cia_1_porta_r), | |
| 344 | DEVCB_NULL, /* port A */ | |
| 345 | DEVCB_NULL, | |
| 346 | DEVCB_NULL /* port B */ | |
| 347 | }; | |
| 348 | ||
| 349 | static const tpi6525_interface cdtv_tpi_intf = | |
| 350 | { | |
| 351 | DEVCB_LINE(amigacd_tpi6525_irq), | |
| 352 | DEVCB_NULL, | |
| 353 | DEVCB_NULL, | |
| 354 | DEVCB_NULL, | |
| 355 | DEVCB_HANDLER(amigacd_tpi6525_portb_w), | |
| 356 | DEVCB_HANDLER(amigacd_tpi6525_portc_r), | |
| 357 | DEVCB_NULL, | |
| 358 | DEVCB_NULL, | |
| 359 | DEVCB_NULL | |
| 360 | }; | |
| 361 | ||
| 362 | ||
| 363 | static MACHINE_CONFIG_FRAGMENT( amiga_cartslot ) | |
| 364 | MCFG_CARTSLOT_ADD("cart") | |
| 365 | MCFG_CARTSLOT_EXTENSION_LIST("rom,bin") | |
| 366 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 367 | MACHINE_CONFIG_END | |
| 368 | ||
| 369 | static MACHINE_CONFIG_START( ntsc, amiga_state ) | |
| 370 | /* basic machine hardware */ | |
| 371 | MCFG_CPU_ADD("maincpu", M68000, AMIGA_68000_NTSC_CLOCK) | |
| 372 | MCFG_CPU_PROGRAM_MAP(amiga_mem) | |
| 373 | ||
| 374 | MCFG_CPU_ADD("keyboard", M6502, XTAL_1MHz) /* 1 MHz? */ | |
| 375 | MCFG_CPU_PROGRAM_MAP(keyboard_mem) | |
| 376 | ||
| 377 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 378 | MCFG_SCREEN_REFRESH_RATE(59.997) | |
| 379 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 380 | ||
| 381 | MCFG_MACHINE_RESET( amiga ) | |
| 382 | ||
| 383 | /* video hardware */ | |
| 384 | MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) | |
| 385 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 386 | MCFG_SCREEN_SIZE(228*4, 262) | |
| 387 | MCFG_SCREEN_VISIBLE_AREA(214, (228*4)-1, 34, 262-1) | |
| 388 | MCFG_SCREEN_UPDATE(amiga) | |
| 389 | ||
| 390 | MCFG_PALETTE_LENGTH(4096) | |
| 391 | MCFG_PALETTE_INIT( amiga ) | |
| 392 | ||
| 393 | MCFG_VIDEO_START(amiga) | |
| 394 | ||
| 395 | /* devices */ | |
| 396 | MCFG_MSM6242_ADD("rtc") | |
| 397 | MCFG_CENTRONICS_ADD("centronics", amiga_centronics_config) | |
| 398 | ||
| 399 | /* sound hardware */ | |
| 400 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 401 | ||
| 402 | MCFG_SOUND_ADD("amiga", AMIGA, 3579545) | |
| 403 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.50) | |
| 404 | MCFG_SOUND_ROUTE(1, "rspeaker", 0.50) | |
| 405 | MCFG_SOUND_ROUTE(2, "rspeaker", 0.50) | |
| 406 | MCFG_SOUND_ROUTE(3, "lspeaker", 0.50) | |
| 407 | ||
| 408 | /* cia */ | |
| 409 | MCFG_MOS8520_ADD("cia_0", AMIGA_68000_NTSC_CLOCK / 10, cia_0_ntsc_intf) | |
| 410 | MCFG_MOS8520_ADD("cia_1", AMIGA_68000_NTSC_CLOCK, cia_1_intf) | |
| 411 | ||
| 412 | MCFG_AMIGA_FDC_ADD("fdc") | |
| 413 | MACHINE_CONFIG_END | |
| 414 | ||
| 415 | static MACHINE_CONFIG_DERIVED( a1000n, ntsc ) | |
| 416 | MCFG_CPU_MODIFY("maincpu") | |
| 417 | MCFG_CPU_PROGRAM_MAP(a1000_mem) | |
| 418 | MACHINE_CONFIG_END | |
| 419 | ||
| 420 | static MACHINE_CONFIG_DERIVED( a500n, ntsc ) | |
| 421 | MCFG_FRAGMENT_ADD(amiga_cartslot) | |
| 422 | MACHINE_CONFIG_END | |
| 423 | ||
| 424 | ||
| 425 | static MACHINE_CONFIG_DERIVED( cdtv, ntsc ) | |
| 426 | MCFG_CPU_REPLACE("maincpu", M68000, CDTV_CLOCK_X1 / 4) | |
| 427 | MCFG_CPU_PROGRAM_MAP(cdtv_mem) | |
| 428 | ||
| 429 | MCFG_DEVICE_REMOVE("keyboard") | |
| 430 | ||
| 431 | MCFG_CPU_ADD("rcmcu", M6502, XTAL_1MHz) /* 1 MHz? */ | |
| 432 | MCFG_CPU_PROGRAM_MAP(cdtv_rcmcu_mem) | |
| 433 | MCFG_DEVICE_DISABLE() | |
| 434 | ||
| 435 | // MCFG_CPU_ADD("lcd", LC6554, XTAL_4MHz) /* 4 MHz? */ | |
| 436 | // MCFG_CPU_PROGRAM_MAP(cdtv_lcd_mem) | |
| 437 | ||
| 438 | MCFG_MACHINE_START( cdtv ) | |
| 439 | MCFG_MACHINE_RESET( cdtv ) | |
| 440 | ||
| 441 | MCFG_NVRAM_ADD_0FILL("nvram") | |
| 442 | ||
| 443 | MCFG_SOUND_ADD( "cdda", CDDA, 0 ) | |
| 444 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.0 ) | |
| 445 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.0 ) | |
| 446 | ||
| 447 | /* cdrom */ | |
| 448 | MCFG_CDROM_ADD( "cdrom" ) | |
| 449 | MCFG_CDROM_INTERFACE("cdrom") | |
| 450 | MCFG_SOFTWARE_LIST_ADD("cd_list", "cdtv") | |
| 451 | ||
| 452 | MCFG_TPI6525_ADD("tpi6525", cdtv_tpi_intf) | |
| 453 | ||
| 454 | /* cia */ | |
| 455 | MCFG_DEVICE_REMOVE("cia_0") | |
| 456 | MCFG_DEVICE_REMOVE("cia_1") | |
| 457 | MCFG_MOS8520_ADD("cia_0", CDTV_CLOCK_X1 / 40, cia_0_cdtv_intf) | |
| 458 | MCFG_MOS8520_ADD("cia_1", CDTV_CLOCK_X1 / 4, cia_1_cdtv_intf) | |
| 459 | MACHINE_CONFIG_END | |
| 460 | ||
| 461 | ||
| 462 | static MACHINE_CONFIG_DERIVED( pal, ntsc ) | |
| 463 | ||
| 464 | /* adjust for PAL specs */ | |
| 465 | MCFG_CPU_MODIFY("maincpu") | |
| 466 | MCFG_CPU_CLOCK( AMIGA_68000_PAL_CLOCK) | |
| 467 | ||
| 468 | MCFG_SCREEN_MODIFY("screen") | |
| 469 | MCFG_SCREEN_REFRESH_RATE(50) | |
| 470 | MCFG_SCREEN_SIZE(228*4, 312) | |
| 471 | MCFG_SCREEN_VISIBLE_AREA(214, (228*4)-1, 34, 312-1) | |
| 472 | ||
| 473 | /* cia */ | |
| 474 | MCFG_DEVICE_REMOVE("cia_0") | |
| 475 | MCFG_MOS8520_ADD("cia_0", AMIGA_68000_PAL_CLOCK / 10, cia_0_pal_intf) | |
| 476 | MACHINE_CONFIG_END | |
| 477 | ||
| 478 | static MACHINE_CONFIG_DERIVED( a500p, pal ) | |
| 479 | MCFG_FRAGMENT_ADD(amiga_cartslot) | |
| 480 | MACHINE_CONFIG_END | |
| 481 | ||
| 482 | static MACHINE_CONFIG_DERIVED( a1000p, pal ) | |
| 483 | MCFG_CPU_MODIFY("maincpu") | |
| 484 | MCFG_CPU_PROGRAM_MAP(a1000_mem) | |
| 485 | MACHINE_CONFIG_END | |
| 486 | ||
| 487 | /*************************************************************************** | |
| 488 | ||
| 489 | Amiga specific stuff | |
| 490 | ||
| 491 | ***************************************************************************/ | |
| 492 | ||
| 493 | ||
| 494 | static READ8_DEVICE_HANDLER( amiga_cia_0_portA_r ) | |
| 495 | { | |
| 496 | UINT8 ret = input_port_read(device->machine(), "CIA0PORTA") & 0xc0; /* Gameport 1 and 0 buttons */ | |
| 497 | ret |= amiga_fdc_status_r(device->machine().device("fdc")); | |
| 498 | return ret; | |
| 499 | } | |
| 500 | ||
| 501 | ||
| 502 | static READ8_DEVICE_HANDLER( amiga_cia_0_cdtv_portA_r ) | |
| 503 | { | |
| 504 | return input_port_read(device->machine(), "CIA0PORTA") & 0xc0; /* Gameport 1 and 0 buttons */ | |
| 505 | } | |
| 506 | ||
| 507 | ||
| 508 | static WRITE8_DEVICE_HANDLER( amiga_cia_0_portA_w ) | |
| 509 | { | |
| 510 | amiga_state *state = device->machine().driver_data<amiga_state>(); | |
| 511 | /* switch banks as appropriate */ | |
| 512 | memory_set_bank(device->machine(), "bank1", data & 1); | |
| 513 | ||
| 514 | /* swap the write handlers between ROM and bank 1 based on the bit */ | |
| 515 | if ((data & 1) == 0) { | |
| 516 | UINT32 mirror_mask = state->m_chip_ram_size; | |
| 517 | ||
| 518 | while( (mirror_mask<<1) < 0x100000 ) { | |
| 519 | mirror_mask |= ( mirror_mask << 1 ); | |
| 520 | } | |
| 521 | ||
| 522 | /* overlay disabled, map RAM on 0x000000 */ | |
| 523 | device->machine().device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x000000, state->m_chip_ram_size - 1, 0, mirror_mask, "bank1"); | |
| 524 | ||
| 525 | /* if there is a cart region, check for cart overlay */ | |
| 526 | if (device->machine().region("user2")->base() != NULL) | |
| 527 | amiga_cart_check_overlay(device->machine()); | |
| 528 | } | |
| 529 | else | |
| 530 | /* overlay enabled, map Amiga system ROM on 0x000000 */ | |
| 531 | device->machine().device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x000000, state->m_chip_ram_size - 1); | |
| 532 | ||
| 533 | set_led_status( device->machine(), 0, ( data & 2 ) ? 0 : 1 ); /* bit 2 = Power Led on Amiga */ | |
| 534 | output_set_value("power_led", ( data & 2 ) ? 0 : 1); | |
| 535 | } | |
| 536 | ||
| 537 | static UINT16 amiga_read_joy0dat(running_machine &machine) | |
| 538 | { | |
| 539 | if ( input_port_read(machine, "input") & 0x20 ) { | |
| 540 | /* Joystick */ | |
| 541 | return input_port_read_safe(machine, "JOY0DAT", 0xffff); | |
| 542 | } else { | |
| 543 | /* Mouse */ | |
| 544 | int input; | |
| 545 | input = ( input_port_read(machine, "P0MOUSEX") & 0xff ); | |
| 546 | input |= ( input_port_read(machine, "P0MOUSEY") & 0xff ) << 8; | |
| 547 | return input; | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | static UINT16 amiga_read_joy1dat(running_machine &machine) | |
| 552 | { | |
| 553 | if ( input_port_read(machine, "input") & 0x10 ) { | |
| 554 | /* Joystick */ | |
| 555 | return input_port_read_safe(machine, "JOY1DAT", 0xffff); | |
| 556 | } else { | |
| 557 | /* Mouse */ | |
| 558 | int input; | |
| 559 | input = ( input_port_read(machine, "P1MOUSEX") & 0xff ); | |
| 560 | input |= ( input_port_read(machine, "P1MOUSEY") & 0xff ) << 8; | |
| 561 | return input; | |
| 562 | } | |
| 563 | } | |
| 564 | ||
| 565 | static UINT16 amiga_read_dskbytr(running_machine &machine) | |
| 566 | { | |
| 567 | return amiga_fdc_get_byte(machine.device("fdc")); | |
| 568 | } | |
| 569 | ||
| 570 | static void amiga_write_dsklen(running_machine &machine, UINT16 data) | |
| 571 | { | |
| 572 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 573 | if ( data & 0x8000 ) { | |
| 574 | if ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) | |
| 575 | amiga_fdc_setup_dma(machine.device("fdc")); | |
| 576 | } | |
| 577 | } | |
| 578 | ||
| 579 | ||
| 580 | static void amiga_reset(running_machine &machine) | |
| 581 | { | |
| 582 | if (input_port_read(machine, "hardware") & 0x08) | |
| 583 | { | |
| 584 | /* Install RTC */ | |
| 585 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0xdc0000, 0xdc003f, FUNC(amiga_clock_r), FUNC(amiga_clock_w)); | |
| 586 | } | |
| 587 | else | |
| 588 | { | |
| 589 | /* No RTC support */ | |
| 590 | machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_readwrite(0xdc0000, 0xdc003f); | |
| 591 | } | |
| 592 | } | |
| 593 | ||
| 594 | static DRIVER_INIT( amiga ) | |
| 595 | { | |
| 596 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 597 | static const amiga_machine_interface amiga_intf = | |
| 598 | { | |
| 599 | ANGUS_CHIP_RAM_MASK, | |
| 600 | amiga_read_joy0dat, amiga_read_joy1dat, /* joy0dat_r & joy1dat_r */ | |
| 601 | NULL, /* potgo_w */ | |
| 602 | amiga_read_dskbytr, amiga_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 603 | NULL, /* serdat_w */ | |
| 604 | NULL, /* scanline0_callback */ | |
| 605 | amiga_reset, /* reset_callback */ | |
| 606 | amiga_cart_nmi, /* nmi_callback */ | |
| 607 | 0 /* flags */ | |
| 608 | }; | |
| 609 | ||
| 610 | amiga_machine_config(machine, &amiga_intf); | |
| 611 | ||
| 612 | /* set up memory */ | |
| 613 | memory_configure_bank(machine, "bank1", 0, 1, state->m_chip_ram, 0); | |
| 614 | memory_configure_bank(machine, "bank1", 1, 1, machine.region("user1")->base(), 0); | |
| 615 | ||
| 616 | /* initialize cartridge (if present) */ | |
| 617 | amiga_cart_init(machine); | |
| 618 | ||
| 619 | /* initialize keyboard */ | |
| 620 | amigakbd_init(machine); | |
| 621 | } | |
| 622 | ||
| 623 | #ifdef UNUSED_FUNCTION | |
| 624 | static DRIVER_INIT( amiga_ecs ) | |
| 625 | { | |
| 626 | static const amiga_machine_interface amiga_intf = | |
| 627 | { | |
| 628 | ECS_CHIP_RAM_MASK, | |
| 629 | amiga_cia_0_portA_r, NULL, /* CIA0 port A & B read */ | |
| 630 | amiga_cia_0_portA_w, NULL, /* CIA0 port A & B write */ | |
| 631 | NULL, NULL, /* CIA1 port A & B read */ | |
| 632 | NULL, amiga_fdc_control_w, /* CIA1 port A & B write */ | |
| 633 | amiga_read_joy0dat, amiga_read_joy1dat, /* joy0dat_r & joy1dat_r */ | |
| 634 | NULL, /* potgo_w */ | |
| 635 | amiga_read_dskbytr, amiga_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 636 | NULL, /* serdat_w */ | |
| 637 | NULL, /* scanline0_callback */ | |
| 638 | amiga_reset, /* reset_callback */ | |
| 639 | amiga_cart_nmi, /* nmi_callback */ | |
| 640 | 0 /* flags */ | |
| 641 | }; | |
| 642 | ||
| 643 | amiga_machine_config(machine, &amiga_intf); | |
| 644 | ||
| 645 | /* set up memory */ | |
| 646 | memory_configure_bank(1, 0, 1, state->m_chip_ram, 0); | |
| 647 | memory_configure_bank(1, 1, 1, machine.region("user1")->base(), 0); | |
| 648 | ||
| 649 | /* initialize Action Replay (if present) */ | |
| 650 | amiga_cart_init(machine); | |
| 651 | ||
| 652 | /* initialize keyboard */ | |
| 653 | amigakbd_init(machine); | |
| 654 | } | |
| 655 | #endif | |
| 656 | ||
| 657 | static DRIVER_INIT( cdtv ) | |
| 658 | { | |
| 659 | amiga_state *state = machine.driver_data<amiga_state>(); | |
| 660 | static const amiga_machine_interface amiga_intf = | |
| 661 | { | |
| 662 | ECS_CHIP_RAM_MASK, | |
| 663 | amiga_read_joy0dat, amiga_read_joy1dat, /* joy0dat_r & joy1dat_r */ | |
| 664 | NULL, /* potgo_w */ | |
| 665 | amiga_read_dskbytr, amiga_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 666 | NULL, /* serdat_w */ | |
| 667 | NULL, /* scanline0_callback */ | |
| 668 | NULL, /* reset_callback */ | |
| 669 | NULL, /* nmi_callback */ | |
| 670 | 0 /* flags */ | |
| 671 | }; | |
| 672 | ||
| 673 | amiga_machine_config(machine, &amiga_intf); | |
| 674 | ||
| 675 | /* set up memory */ | |
| 676 | memory_configure_bank(machine, "bank1", 0, 1, state->m_chip_ram, 0); | |
| 677 | memory_configure_bank(machine, "bank1", 1, 1, machine.region("user1")->base(), 0); | |
| 678 | ||
| 679 | /* initialize keyboard - in cdtv we can use a standard Amiga keyboard*/ | |
| 680 | amigakbd_init(machine); | |
| 681 | } | |
| 682 | ||
| 683 | ||
| 684 | /*************************************************************************** | |
| 685 | ROM DEFINITIONS | |
| 686 | ***************************************************************************/ | |
| 687 | ||
| 688 | ROM_START( a500n ) | |
| 689 | ROM_REGION16_BE(0x080000, "user1", 0) | |
| 690 | ROM_DEFAULT_BIOS("kick13") | |
| 691 | ROM_SYSTEM_BIOS(0, "kick12", "Kickstart 1.2 (33.180)") | |
| 692 | ROMX_LOAD("315093-01.u6", 0x000000, 0x040000, CRC(a6ce1636) SHA1(11f9e62cf299f72184835b7b2a70a16333fc0d88), ROM_GROUPWORD | ROM_BIOS(1)) | |
| 693 | ROM_SYSTEM_BIOS(1, "kick13", "Kickstart 1.3 (34.5)") | |
| 694 | ROMX_LOAD("315093-02.u6", 0x000000, 0x040000, CRC(c4f0f55f) SHA1(891e9a547772fe0c6c19b610baf8bc4ea7fcb785), ROM_GROUPWORD | ROM_BIOS(2)) | |
| 695 | ROM_COPY("user1", 0x000000, 0x040000, 0x040000) | |
| 696 | ROM_SYSTEM_BIOS(2, "kick204", "Kickstart 2.04 (37.175)") | |
| 697 | ROMX_LOAD("390979-01.u6", 0x000000, 0x080000, CRC(c3bdb240) SHA1(c5839f5cb98a7a8947065c3ed2f14f5f42e334a1), ROM_GROUPWORD | ROM_BIOS(3)) /* identical to 363968.01 */ | |
| 698 | ROM_SYSTEM_BIOS(3, "kick31", "Kickstart 3.1 (40.63)") | |
| 699 | ROMX_LOAD("kick40063.u6", 0x000000, 0x080000, CRC(fc24ae0d) SHA1(3b7f1493b27e212830f989f26ca76c02049f09ca), ROM_GROUPWORD | ROM_BIOS(4)) /* part number? */ | |
| 700 | ||
| 701 | /* action replay cartridge */ | |
| 702 | ROM_REGION16_BE(0x080000, "user2", ROMREGION_ERASEFF ) | |
| 703 | ROM_CART_LOAD("cart", 0x0000, 0x080000, ROM_NOMIRROR | ROM_OPTIONAL) | |
| 704 | ||
| 705 | /* keyboard controller, mos 6500/1 mcu */ | |
| 706 | ROM_REGION(0x800, "keyboard", 0) | |
| 707 | ROM_LOAD("328191-02.ic1", 0x000, 0x800, NO_DUMP) | |
| 708 | ROM_END | |
| 709 | ||
| 710 | #define rom_a500p rom_a500n | |
| 711 | ||
| 712 | ||
| 713 | ROM_START( a1000n ) | |
| 714 | ROM_REGION16_BE(0x080000, "user1", 0) | |
| 715 | ROM_LOAD16_BYTE("252179-01.u5n", 0x000000, 0x001000, CRC(42553bc4) SHA1(8855a97f7a44e3f62d1c88d938fee1f4c606af5b)) | |
| 716 | ROM_LOAD16_BYTE("252180-01.u5p", 0x000001, 0x001000, CRC(8e5b9a37) SHA1(d10f1564b99f5ffe108fa042362e877f569de2c3)) | |
| 717 | ||
| 718 | /* keyboard controller, mos 6500/1 mcu */ | |
| 719 | ROM_REGION(0x800, "keyboard", 0) | |
| 720 | ROM_LOAD("328191-01.bin", 0x000, 0x800, NO_DUMP) | |
| 721 | ROM_END | |
| 722 | ||
| 723 | #define rom_a1000p rom_a1000n | |
| 724 | ||
| 725 | ||
| 726 | ROM_START( cdtv ) | |
| 727 | ROM_REGION16_BE(0x100000, "user1", 0) | |
| 728 | ROM_LOAD16_BYTE("391008-01.u34", 0x000000, 0x020000, CRC(791cb14b) SHA1(277a1778924496353ffe56be68063d2a334360e4)) | |
| 729 | ROM_LOAD16_BYTE("391009-01.u35", 0x000001, 0x020000, CRC(accbbc2e) SHA1(41b06d1679c6e6933c3378b7626025f7641ebc5c)) | |
| 730 | ROM_COPY("user1", 0x000000, 0x040000, 0x040000) | |
| 731 | ROMX_LOAD( "315093-02.u13", 0x080000, 0x040000, CRC(c4f0f55f) SHA1(891e9a547772fe0c6c19b610baf8bc4ea7fcb785), ROM_GROUPWORD) | |
| 732 | ROM_COPY("user1", 0x080000, 0x0c0000, 0x040000) | |
| 733 | ||
| 734 | /* remote control input converter, mos 6500/1 mcu */ | |
| 735 | ROM_REGION(0x800, "rcmcu", 0) | |
| 736 | ROM_LOAD("252609-02.u75", 0x000, 0x800, NO_DUMP) | |
| 737 | ||
| 738 | /* lcd controller, sanyo lc6554h */ | |
| 739 | ROM_REGION(0x1000, "lcd", 0) | |
| 740 | ROM_LOAD("252608-01.u62", 0x000, 0x1000, NO_DUMP) | |
| 741 | ROM_END | |
| 742 | ||
| 743 | /*************************************************************************** | |
| 744 | GAME DRIVERS | |
| 745 | ***************************************************************************/ | |
| 746 | ||
| 747 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 748 | COMP( 1985, a1000n, 0, 0, a1000n, amiga, amiga, "Commodore Business Machines", "Amiga 1000 (NTSC)", GAME_IMPERFECT_GRAPHICS ) | |
| 749 | COMP( 1985, a1000p, a1000n, 0, a1000p, amiga, amiga, "Commodore Business Machines", "Amiga 1000 (PAL)", GAME_IMPERFECT_GRAPHICS ) | |
| 750 | COMP( 1987, a500n, 0, 0, a500n, amiga, amiga, "Commodore Business Machines", "Amiga 500 (NTSC, OCS)", GAME_IMPERFECT_GRAPHICS ) | |
| 751 | COMP( 1987, a500p, a500n, 0, a500p, amiga, amiga, "Commodore Business Machines", "Amiga 500 (PAL, OCS)", GAME_IMPERFECT_GRAPHICS ) | |
| 752 | COMP( 1991, cdtv, 0, 0, cdtv, cdtv, cdtv, "Commodore Business Machines", "CDTV (NTSC)", GAME_IMPERFECT_GRAPHICS ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Acorn Archimedes 7000/7000+ | |
| 4 | ||
| 5 | preliminary driver by Angelo Salese, | |
| 6 | based on work by Tomasz Slanina and Tom Walker | |
| 7 | ||
| 8 | ??? | |
| 9 | bp (0382827C) (second trigger) | |
| 10 | do R13 = SR13 | |
| 11 | ||
| 12 | ****************************************************************************/ | |
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | #include "cpu/arm7/arm7.h" | |
| 16 | #include "cpu/arm7/arm7core.h" | |
| 17 | ||
| 18 | ||
| 19 | class a7000_state : public driver_device | |
| 20 | { | |
| 21 | public: | |
| 22 | a7000_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 23 | : driver_device(mconfig, type, tag) { } | |
| 24 | ||
| 25 | UINT8 m_vidc20_pal_index; | |
| 26 | UINT16 m_vidc20_horz_reg[0x10]; | |
| 27 | UINT16 m_vidc20_vert_reg[0x10]; | |
| 28 | UINT8 m_vidc20_bpp_mode; | |
| 29 | emu_timer *m_flyback_timer; | |
| 30 | UINT16 m_timer_in[2]; | |
| 31 | UINT16 m_timer_out[2]; | |
| 32 | int m_timer_counter[2]; | |
| 33 | emu_timer *m_IOMD_timer[2]; | |
| 34 | UINT8 m_IRQ_status_A; | |
| 35 | UINT8 m_IRQ_mask_A; | |
| 36 | UINT8 m_IOMD_IO_ctrl; | |
| 37 | UINT8 m_IOMD_keyb_ctrl; | |
| 38 | UINT16 m_io_id; | |
| 39 | UINT8 m_viddma_status; | |
| 40 | UINT32 m_viddma_addr_start; | |
| 41 | UINT32 m_viddma_addr_end; | |
| 42 | UINT8 m_t0readinc; | |
| 43 | UINT8 m_t1readinc; | |
| 44 | }; | |
| 45 | ||
| 46 | ||
| 47 | /* | |
| 48 | * | |
| 49 | * VIDC20 chip emulation | |
| 50 | * | |
| 51 | */ | |
| 52 | ||
| 53 | ||
| 54 | static const char *const vidc20_regnames[] = | |
| 55 | { | |
| 56 | "Video Palette", // 0 | |
| 57 | "Video Palette Address", // 1 | |
| 58 | "RESERVED", // 2 | |
| 59 | "LCD offset", // 3 | |
| 60 | "Border Colour", // 4 | |
| 61 | "Cursor Palette Logical Colour 1", // 5 | |
| 62 | "Cursor Palette Logical Colour 2", // 6 | |
| 63 | "Cursor Palette Logical Colour 3", // 7 | |
| 64 | "Horizontal", // 8 | |
| 65 | "Vertical", // 9 | |
| 66 | "Stereo Image", // A | |
| 67 | "Sound", // B | |
| 68 | "External", // C | |
| 69 | "Frequency Synthesis", // D | |
| 70 | "Control", // E | |
| 71 | "Data Control" // F | |
| 72 | }; | |
| 73 | ||
| 74 | static const char *const vidc20_horz_regnames[] = | |
| 75 | { | |
| 76 | "Horizontal Cycle", // 0x80 HCR | |
| 77 | "Horizontal Sync Width", // 0x81 HSWR | |
| 78 | "Horizontal Border Start", // 0x82 HBSR | |
| 79 | "Horizontal Display Start", // 0x83 HDSR | |
| 80 | "Horizontal Display End", // 0x84 HDER | |
| 81 | "Horizontal Border End", // 0x85 HBER | |
| 82 | "Horizontal Cursor Start", // 0x86 HCSR | |
| 83 | "Horizontal Interlace", // 0x87 HIR | |
| 84 | "Horizontal Counter TEST", // 0x88 | |
| 85 | "Horizontal <UNDEFINED>", // 0x89 | |
| 86 | "Horizontal <UNDEFINED>", // 0x8a | |
| 87 | "Horizontal <UNDEFINED>", // 0x8b | |
| 88 | "Horizontal All TEST", // 0x8c | |
| 89 | "Horizontal <UNDEFINED>", // 0x8d | |
| 90 | "Horizontal <UNDEFINED>", // 0x8e | |
| 91 | "Horizontal <UNDEFINED>" // 0x8f | |
| 92 | }; | |
| 93 | ||
| 94 | #define HCR 0 | |
| 95 | #define HSWR 1 | |
| 96 | #define HBSR 2 | |
| 97 | #define HDSR 3 | |
| 98 | #define HDER 4 | |
| 99 | #define HBER 5 | |
| 100 | #define HCSR 6 | |
| 101 | #define HIR 7 | |
| 102 | ||
| 103 | static const char *const vidc20_vert_regnames[] = | |
| 104 | { | |
| 105 | "Vertical Cycle", // 0x90 VCR | |
| 106 | "Vertical Sync Width", // 0x91 VSWR | |
| 107 | "Vertical Border Start", // 0x92 VBSR | |
| 108 | "Vertical Display Start", // 0x93 VDSR | |
| 109 | "Vertical Display End", // 0x94 VDER | |
| 110 | "Vertical Border End", // 0x95 VBER | |
| 111 | "Vertical Cursor Start", // 0x96 VCSR | |
| 112 | "Vertical Cursor End", // 0x97 VCER | |
| 113 | "Vertical Counter TEST", // 0x98 | |
| 114 | "Horizontal <UNDEFINED>", // 0x99 | |
| 115 | "Vertical Counter Increment TEST", // 0x9a | |
| 116 | "Horizontal <UNDEFINED>", // 0x9b | |
| 117 | "Vertical All TEST", // 0x9c | |
| 118 | "Horizontal <UNDEFINED>", // 0x9d | |
| 119 | "Horizontal <UNDEFINED>", // 0x9e | |
| 120 | "Horizontal <UNDEFINED>" // 0x9f | |
| 121 | }; | |
| 122 | ||
| 123 | #define VCR 0 | |
| 124 | #define VSWR 1 | |
| 125 | #define VBSR 2 | |
| 126 | #define VDSR 3 | |
| 127 | #define VDER 4 | |
| 128 | #define VBER 5 | |
| 129 | #define VCSR 6 | |
| 130 | #define VCER 7 | |
| 131 | ||
| 132 | static void vidc20_dynamic_screen_change(running_machine &machine) | |
| 133 | { | |
| 134 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 135 | /* sanity checks - first pass */ | |
| 136 | /* | |
| 137 | total cycles + border start/end | |
| 138 | */ | |
| 139 | if(state->m_vidc20_horz_reg[HCR] && state->m_vidc20_horz_reg[HBSR] && state->m_vidc20_horz_reg[HBER] && | |
| 140 | state->m_vidc20_vert_reg[VCR] && state->m_vidc20_vert_reg[VBSR] && state->m_vidc20_vert_reg[VBER]) | |
| 141 | { | |
| 142 | /* sanity checks - second pass */ | |
| 143 | /* | |
| 144 | total cycles > border end > border start | |
| 145 | */ | |
| 146 | if((state->m_vidc20_horz_reg[HCR] > state->m_vidc20_horz_reg[HBER]) && | |
| 147 | (state->m_vidc20_horz_reg[HBER] > state->m_vidc20_horz_reg[HBSR]) && | |
| 148 | (state->m_vidc20_vert_reg[VCR] > state->m_vidc20_vert_reg[VBER]) && | |
| 149 | (state->m_vidc20_vert_reg[VBER] > state->m_vidc20_vert_reg[VBSR])) | |
| 150 | { | |
| 151 | /* finally ready to change the resolution */ | |
| 152 | int hblank_period,vblank_period; | |
| 153 | rectangle visarea = machine.primary_screen->visible_area(); | |
| 154 | hblank_period = (state->m_vidc20_horz_reg[HCR] & 0x3ffc); | |
| 155 | vblank_period = (state->m_vidc20_vert_reg[VCR] & 0x3fff); | |
| 156 | /* note that we use the border registers as the visible area */ | |
| 157 | visarea.min_x = (state->m_vidc20_horz_reg[HBSR] & 0x3ffe); | |
| 158 | visarea.max_x = (state->m_vidc20_horz_reg[HBER] & 0x3ffe)-1; | |
| 159 | visarea.min_y = (state->m_vidc20_vert_reg[VBSR] & 0x1fff); | |
| 160 | visarea.max_y = (state->m_vidc20_vert_reg[VBER] & 0x1fff)-1; | |
| 161 | ||
| 162 | machine.primary_screen->configure(hblank_period, vblank_period, visarea, machine.primary_screen->frame_period().attoseconds ); | |
| 163 | logerror("VIDC20: successfully changed the screen to:\n Display Size = %d x %d\n Border Size %d x %d\n Cycle Period %d x %d\n", | |
| 164 | (state->m_vidc20_horz_reg[HDER]-state->m_vidc20_horz_reg[HDSR]),(state->m_vidc20_vert_reg[VDER]-state->m_vidc20_vert_reg[VDSR]), | |
| 165 | (state->m_vidc20_horz_reg[HBER]-state->m_vidc20_horz_reg[HBSR]),(state->m_vidc20_vert_reg[VBER]-state->m_vidc20_vert_reg[VBSR]), | |
| 166 | hblank_period,vblank_period); | |
| 167 | } | |
| 168 | } | |
| 169 | } | |
| 170 | ||
| 171 | static WRITE32_HANDLER( a7000_vidc20_w ) | |
| 172 | { | |
| 173 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 174 | int reg = data >> 28; | |
| 175 | ||
| 176 | switch(reg) | |
| 177 | { | |
| 178 | case 0: // Video Palette | |
| 179 | { | |
| 180 | int r,g,b; | |
| 181 | ||
| 182 | r = (data & 0x0000ff) >> 0; | |
| 183 | g = (data & 0x00ff00) >> 8; | |
| 184 | b = (data & 0xff0000) >> 16; | |
| 185 | ||
| 186 | palette_set_color_rgb(space->machine(),state->m_vidc20_pal_index & 0xff,r,g,b); | |
| 187 | ||
| 188 | /* auto-increment & wrap-around */ | |
| 189 | state->m_vidc20_pal_index++; | |
| 190 | state->m_vidc20_pal_index &= 0xff; | |
| 191 | } | |
| 192 | break; | |
| 193 | case 1: // Video Palette Address | |
| 194 | { | |
| 195 | // according to RPCEmu, these mustn't be set | |
| 196 | if (data & 0x0fffff00) | |
| 197 | return; | |
| 198 | ||
| 199 | state->m_vidc20_pal_index = data & 0xff; | |
| 200 | } | |
| 201 | break; | |
| 202 | ||
| 203 | case 4: // Border Color | |
| 204 | { | |
| 205 | int r,g,b; | |
| 206 | ||
| 207 | r = (data & 0x0000ff) >> 0; | |
| 208 | g = (data & 0x00ff00) >> 8; | |
| 209 | b = (data & 0xff0000) >> 16; | |
| 210 | ||
| 211 | palette_set_color_rgb(space->machine(),0x100,r,g,b); | |
| 212 | } | |
| 213 | break; | |
| 214 | case 5: // Cursor Palette Logical Colour n | |
| 215 | case 6: | |
| 216 | case 7: | |
| 217 | { | |
| 218 | int r,g,b; | |
| 219 | int cursor_index = 0x100 + reg - 4; // 0x101,0x102 and 0x103 (plus 0x100 of above, 2bpp) | |
| 220 | ||
| 221 | r = (data & 0x0000ff) >> 0; | |
| 222 | g = (data & 0x00ff00) >> 8; | |
| 223 | b = (data & 0xff0000) >> 16; | |
| 224 | ||
| 225 | palette_set_color_rgb(space->machine(),cursor_index,r,g,b); | |
| 226 | } | |
| 227 | break; | |
| 228 | case 8: // Horizontal | |
| 229 | { | |
| 230 | int horz_reg; | |
| 231 | ||
| 232 | horz_reg = (data >> 24) & 0xf; | |
| 233 | state->m_vidc20_horz_reg[horz_reg] = data & 0x3fff; | |
| 234 | if(horz_reg == 0 || horz_reg == 2 || horz_reg == 5) | |
| 235 | vidc20_dynamic_screen_change(space->machine()); | |
| 236 | ||
| 237 | // logerror("VIDC20: %s Register write = %08x (%d)\n",vidc20_horz_regnames[horz_reg],val,val); | |
| 238 | } | |
| 239 | break; | |
| 240 | case 9: // Vertical | |
| 241 | { | |
| 242 | int vert_reg; | |
| 243 | ||
| 244 | vert_reg = (data >> 24) & 0xf; | |
| 245 | state->m_vidc20_vert_reg[vert_reg] = data & 0x1fff; | |
| 246 | if(vert_reg == 0 || vert_reg == 2 || vert_reg == 5) | |
| 247 | vidc20_dynamic_screen_change(space->machine()); | |
| 248 | ||
| 249 | if(vert_reg == 4) | |
| 250 | { | |
| 251 | if(state->m_vidc20_vert_reg[VDER] != 0) | |
| 252 | state->m_flyback_timer->adjust(space->machine().primary_screen->time_until_pos(state->m_vidc20_vert_reg[VDER])); | |
| 253 | else | |
| 254 | state->m_flyback_timer->adjust(attotime::never); | |
| 255 | } | |
| 256 | ||
| 257 | // logerror("VIDC20: %s Register write = %08x (%d)\n",vidc20_vert_regnames[vert_reg],val,val); | |
| 258 | ||
| 259 | } | |
| 260 | break; | |
| 261 | case 0x0e: // Control | |
| 262 | { | |
| 263 | state->m_vidc20_bpp_mode = (data & 0xe0) >> 5; | |
| 264 | } | |
| 265 | break; | |
| 266 | default: logerror("VIDC20: %s Register write = %08x\n",vidc20_regnames[reg],data & 0xfffffff); | |
| 267 | } | |
| 268 | } | |
| 269 | ||
| 270 | static VIDEO_START( a7000 ) | |
| 271 | { | |
| 272 | } | |
| 273 | ||
| 274 | static SCREEN_UPDATE( a7000 ) | |
| 275 | { | |
| 276 | a7000_state *state = screen->machine().driver_data<a7000_state>(); | |
| 277 | int x_size,y_size,x_start,y_start; | |
| 278 | int x,y,xi; | |
| 279 | UINT32 count; | |
| 280 | UINT8 *vram = screen->machine().region("vram")->base(); | |
| 281 | ||
| 282 | bitmap_fill(bitmap, cliprect, screen->machine().pens[0x100]); | |
| 283 | ||
| 284 | x_size = (state->m_vidc20_horz_reg[HDER]-state->m_vidc20_horz_reg[HDSR]); | |
| 285 | y_size = (state->m_vidc20_vert_reg[VDER]-state->m_vidc20_vert_reg[VDSR]); | |
| 286 | x_start = state->m_vidc20_horz_reg[HDSR]; | |
| 287 | y_start = state->m_vidc20_vert_reg[VDSR]; | |
| 288 | ||
| 289 | /* check if display is enabled */ | |
| 290 | if(x_size <= 0 || y_size <= 0) | |
| 291 | return 0; | |
| 292 | ||
| 293 | // popmessage("%d",state->m_vidc20_bpp_mode); | |
| 294 | ||
| 295 | count = 0; | |
| 296 | ||
| 297 | switch(state->m_vidc20_bpp_mode) | |
| 298 | { | |
| 299 | case 0: /* 1 bpp */ | |
| 300 | { | |
| 301 | for(y=0;y<y_size;y++) | |
| 302 | { | |
| 303 | for(x=0;x<x_size;x+=8) | |
| 304 | { | |
| 305 | for(xi=0;xi<8;xi++) | |
| 306 | *BITMAP_ADDR32(bitmap, y+y_start, x+xi+x_start) = screen->machine().pens[(vram[count]>>(xi))&1]; | |
| 307 | ||
| 308 | count++; | |
| 309 | } | |
| 310 | } | |
| 311 | } | |
| 312 | break; | |
| 313 | case 1: /* 2 bpp */ | |
| 314 | { | |
| 315 | for(y=0;y<y_size;y++) | |
| 316 | { | |
| 317 | for(x=0;x<x_size;x+=4) | |
| 318 | { | |
| 319 | for(xi=0;xi<4;xi++) | |
| 320 | *BITMAP_ADDR32(bitmap, y+y_start, x+xi+x_start) = screen->machine().pens[(vram[count]>>(xi*2))&3]; | |
| 321 | ||
| 322 | count++; | |
| 323 | } | |
| 324 | } | |
| 325 | } | |
| 326 | break; | |
| 327 | case 2: /* 4 bpp */ | |
| 328 | { | |
| 329 | for(y=0;y<y_size;y++) | |
| 330 | { | |
| 331 | for(x=0;x<x_size;x+=2) | |
| 332 | { | |
| 333 | for(xi=0;xi<2;xi++) | |
| 334 | *BITMAP_ADDR32(bitmap, y+y_start, x+xi+x_start) = screen->machine().pens[(vram[count]>>(xi*4))&0xf]; | |
| 335 | ||
| 336 | count++; | |
| 337 | } | |
| 338 | } | |
| 339 | } | |
| 340 | break; | |
| 341 | case 3: /* 8 bpp */ | |
| 342 | { | |
| 343 | for(y=0;y<y_size;y++) | |
| 344 | { | |
| 345 | for(x=0;x<x_size;x++) | |
| 346 | { | |
| 347 | *BITMAP_ADDR32(bitmap, y+y_start, x+x_start) = screen->machine().pens[(vram[count])&0xff]; | |
| 348 | ||
| 349 | count++; | |
| 350 | } | |
| 351 | } | |
| 352 | } | |
| 353 | break; | |
| 354 | case 4: /* 16 bpp */ | |
| 355 | { | |
| 356 | for(y=0;y<y_size;y++) | |
| 357 | { | |
| 358 | for(x=0;x<x_size;x++) | |
| 359 | { | |
| 360 | int r,g,b,pen; | |
| 361 | ||
| 362 | pen = ((vram[count]<<8)|(vram[count+1]))&0xffff; | |
| 363 | r = (pen & 0x000f); | |
| 364 | g = (pen & 0x00f0) >> 4; | |
| 365 | b = (pen & 0x0f00) >> 8; | |
| 366 | r = (r << 4) | (r & 0xf); | |
| 367 | g = (g << 4) | (g & 0xf); | |
| 368 | b = (b << 4) | (b & 0xf); | |
| 369 | ||
| 370 | *BITMAP_ADDR32(bitmap, y+y_start, x+x_start) = b | g << 8 | r << 16; | |
| 371 | ||
| 372 | count+=2; | |
| 373 | } | |
| 374 | } | |
| 375 | } | |
| 376 | break; | |
| 377 | case 6: /* 32 bpp */ | |
| 378 | { | |
| 379 | for(y=0;y<y_size;y++) | |
| 380 | { | |
| 381 | for(x=0;x<x_size;x++) | |
| 382 | { | |
| 383 | int r,g,b,pen; | |
| 384 | ||
| 385 | pen = ((vram[count]<<24)|(vram[count+1]<<16)|(vram[count+2]<<8)|(vram[count+3]<<0)); | |
| 386 | r = (pen & 0x0000ff); | |
| 387 | g = (pen & 0x00ff00) >> 8; | |
| 388 | b = (pen & 0xff0000) >> 16; | |
| 389 | ||
| 390 | *BITMAP_ADDR32(bitmap, y+y_start, x+x_start) = b | g << 8 | r << 16; | |
| 391 | ||
| 392 | count+=4; | |
| 393 | } | |
| 394 | } | |
| 395 | } | |
| 396 | break; | |
| 397 | default: | |
| 398 | //fatalerror("VIDC20 %08x BPP mode not supported\n",state->m_vidc20_bpp_mode); | |
| 399 | break; | |
| 400 | } | |
| 401 | ||
| 402 | return 0; | |
| 403 | } | |
| 404 | ||
| 405 | /* | |
| 406 | * | |
| 407 | * IOMD / ARM7500 / ARM7500FE chip emulation | |
| 408 | * | |
| 409 | */ | |
| 410 | ||
| 411 | /* TODO: some of these registers are actually ARM7500 specific */ | |
| 412 | static const char *const iomd_regnames[] = | |
| 413 | { | |
| 414 | "I/O Control", // 0x000 IOCR | |
| 415 | "Keyboard Data", // 0x004 KBDDAT | |
| 416 | "Keyboard Control", // 0x008 KBDCR | |
| 417 | "General Purpose I/O Lines", // 0x00c IOLINES | |
| 418 | "IRQA Status", // 0x010 IRQSTA | |
| 419 | "IRQA Request/clear", // 0x014 IRQRQA | |
| 420 | "IRQA Mask", // 0x018 IRQMSKA | |
| 421 | "Enter SUSPEND Mode", // 0x01c SUSMODE | |
| 422 | "IRQB Status", // 0x020 IRQSTB | |
| 423 | "IRQB Request/clear", // 0x024 IRQRQB | |
| 424 | "IRQB Mask", // 0x028 IRQMSKB | |
| 425 | "Enter STOP Mode", // 0x02c STOPMODE | |
| 426 | "FIQ Status", // 0x030 FIQST | |
| 427 | "FIQ Request/clear", // 0x034 FIQRQ | |
| 428 | "FIQ Mask", // 0x038 FIQMSK | |
| 429 | "Clock divider control", // 0x03c CLKCTL | |
| 430 | "Timer 0 Low Bits", // 0x040 T0LOW | |
| 431 | "Timer 0 High Bits", // 0x044 T0HIGH | |
| 432 | "Timer 0 Go Command", // 0x048 T0GO | |
| 433 | "Timer 0 Latch Command", // 0x04c T0LATCH | |
| 434 | "Timer 1 Low Bits", // 0x050 T1LOW | |
| 435 | "Timer 1 High Bits", // 0x054 T1HIGH | |
| 436 | "Timer 1 Go Command", // 0x058 T1GO | |
| 437 | "Timer 1 Latch Command", // 0x05c T1LATCH | |
| 438 | "IRQC Status", // 0x060 IRQSTC | |
| 439 | "IRQC Request/clear", // 0x064 IRQRQC | |
| 440 | "IRQC Mask", // 0x068 IRQMSKC | |
| 441 | "LCD and IIS Control Bits", // 0x06c VIDIMUX | |
| 442 | "IRQD Status", // 0x070 IRQSTD | |
| 443 | "IRQD Request/clear", // 0x074 IRQRQD | |
| 444 | "IRQD Mask", // 0x078 IRQMSKD | |
| 445 | "<RESERVED>", // 0x07c | |
| 446 | "ROM Control Bank 0", // 0x080 ROMCR0 | |
| 447 | "ROM Control Bank 1", // 0x084 ROMCR1 | |
| 448 | "DRAM Control (IOMD)", // 0x088 DRAMCR | |
| 449 | "VRAM and Refresh Control", // 0x08c VREFCR | |
| 450 | "Flyback Line Size", // 0x090 FSIZE | |
| 451 | "Chip ID no. Low Byte", // 0x094 ID0 | |
| 452 | "Chip ID no. High Byte", // 0x098 ID1 | |
| 453 | "Chip Version Number", // 0x09c VERSION | |
| 454 | "Mouse X Position", // 0x0a0 MOUSEX | |
| 455 | "Mouse Y Position", // 0x0a4 MOUSEY | |
| 456 | "Mouse Data", // 0x0a8 MSEDAT | |
| 457 | "Mouse Control", // 0x0ac MSECR | |
| 458 | "<RESERVED>", // 0x0b0 | |
| 459 | "<RESERVED>", // 0x0b4 | |
| 460 | "<RESERVED>", // 0x0b8 | |
| 461 | "<RESERVED>", // 0x0bc | |
| 462 | "DACK Timing Control", // 0x0c0 DMATCR | |
| 463 | "I/O Timing Control", // 0x0c4 IOTCR | |
| 464 | "Expansion Card Timing", // 0x0c8 ECTCR | |
| 465 | "DMA External Control", // 0x0cc DMAEXT (IOMD) / ASTCR (ARM7500) | |
| 466 | "DRAM Width Control", // 0x0d0 DRAMWID | |
| 467 | "Force CAS/RAS Lines Low", // 0x0d4 SELFREF | |
| 468 | "<RESERVED>", // 0x0d8 | |
| 469 | "<RESERVED>", // 0x0dc | |
| 470 | "A to D IRQ Control", // 0x0e0 ATODICR | |
| 471 | "A to D IRQ Status", // 0x0e4 ATODCC | |
| 472 | "A to D IRQ Converter Control", // 0x0e8 ATODICR | |
| 473 | "A to D IRQ Counter 1", // 0x0ec ATODCNT1 | |
| 474 | "A to D IRQ Counter 2", // 0x0f0 ATODCNT2 | |
| 475 | "A to D IRQ Counter 3", // 0x0f4 ATODCNT3 | |
| 476 | "A to D IRQ Counter 4", // 0x0f8 ATODCNT4 | |
| 477 | "<RESERVED>", // 0x0fc | |
| 478 | "I/O DMA 0 CurA", // 0x100 IO0CURA | |
| 479 | "I/O DMA 0 EndA", // 0x104 IO0ENDA | |
| 480 | "I/O DMA 0 CurB", // 0x108 IO0CURB | |
| 481 | "I/O DMA 0 EndB", // 0x10c IO0ENDB | |
| 482 | "I/O DMA 0 Control", // 0x110 IO0CR | |
| 483 | "I/O DMA 0 Status", // 0x114 IO0ST | |
| 484 | "<RESERVED>", // 0x118 | |
| 485 | "<RESERVED>", // 0x11c | |
| 486 | "I/O DMA 1 CurA", // 0x120 IO1CURA | |
| 487 | "I/O DMA 1 EndA", // 0x124 IO1ENDA | |
| 488 | "I/O DMA 1 CurB", // 0x128 IO1CURB | |
| 489 | "I/O DMA 1 EndB", // 0x12c IO1ENDB | |
| 490 | "I/O DMA 1 Control", // 0x130 IO1CR | |
| 491 | "I/O DMA 1 Status", // 0x134 IO1ST | |
| 492 | "<RESERVED>", // 0x138 | |
| 493 | "<RESERVED>", // 0x13c | |
| 494 | "I/O DMA 2 CurA", // 0x140 IO2CURA | |
| 495 | "I/O DMA 2 EndA", // 0x144 IO2ENDA | |
| 496 | "I/O DMA 2 CurB", // 0x148 IO2CURB | |
| 497 | "I/O DMA 2 EndB", // 0x14c IO2ENDB | |
| 498 | "I/O DMA 2 Control", // 0x150 IO2CR | |
| 499 | "I/O DMA 2 Status", // 0x154 IO2ST | |
| 500 | "<RESERVED>", // 0x158 | |
| 501 | "<RESERVED>", // 0x15c | |
| 502 | "I/O DMA 3 CurA", // 0x160 IO3CURA | |
| 503 | "I/O DMA 3 EndA", // 0x164 IO3ENDA | |
| 504 | "I/O DMA 3 CurB", // 0x168 IO3CURB | |
| 505 | "I/O DMA 3 EndB", // 0x16c IO3ENDB | |
| 506 | "I/O DMA 3 Control", // 0x170 IO3CR | |
| 507 | "I/O DMA 3 Status", // 0x174 IO3ST | |
| 508 | "<RESERVED>", // 0x178 | |
| 509 | "<RESERVED>", // 0x17c | |
| 510 | "Sound DMA 0 CurA", // 0x180 SD0CURA | |
| 511 | "Sound DMA 0 EndA", // 0x184 SD0ENDA | |
| 512 | "Sound DMA 0 CurB", // 0x188 SD0CURB | |
| 513 | "Sound DMA 0 EndB", // 0x18c SD0ENDB | |
| 514 | "Sound DMA 0 Control", // 0x190 SD0CR | |
| 515 | "Sound DMA 0 Status", // 0x194 SD0ST | |
| 516 | "<RESERVED>", // 0x198 | |
| 517 | "<RESERVED>", // 0x19c | |
| 518 | "Sound DMA 1 CurA", // 0x1a0 SD1CURA | |
| 519 | "Sound DMA 1 EndA", // 0x1a4 SD1ENDA | |
| 520 | "Sound DMA 1 CurB", // 0x1a8 SD1CURB | |
| 521 | "Sound DMA 1 EndB", // 0x1ac SD1ENDB | |
| 522 | "Sound DMA 1 Control", // 0x1b0 SD1CR | |
| 523 | "Sound DMA 1 Status", // 0x1b4 SD1ST | |
| 524 | "<RESERVED>", // 0x1b8 | |
| 525 | "<RESERVED>", // 0x1bc | |
| 526 | "Cursor DMA Current", // 0x1c0 CURSCUR | |
| 527 | "Cursor DMA Init", // 0x1c4 CURSINIT | |
| 528 | "Duplex LCD Current B", // 0x1c8 VIDCURB | |
| 529 | "<RESERVED>", // 0x1cc | |
| 530 | "Video DMA Current", // 0x1d0 VIDCUR | |
| 531 | "Video DMA End", // 0x1d4 VIDEND | |
| 532 | "Video DMA Start", // 0x1d8 VIDSTART | |
| 533 | "Video DMA Init", // 0x1dc VIDINIT | |
| 534 | "Video DMA Control", // 0x1e0 VIDCR | |
| 535 | "<RESERVED>", // 0x1e4 | |
| 536 | "Duplex LCD Init B", // 0x1e8 VIDINITB | |
| 537 | "<RESERVED>", // 0x1ec | |
| 538 | "DMA IRQ Status", // 0x1f0 DMAST | |
| 539 | "DMA IRQ Request", // 0x1f4 DMARQ | |
| 540 | "DMA IRQ Mask", // 0x1f8 DMAMSK | |
| 541 | "<RESERVED>" // 0x1fc | |
| 542 | }; | |
| 543 | ||
| 544 | #define IOMD_IOCR 0x000/4 | |
| 545 | #define IOMD_KBDDAT 0x004/4 | |
| 546 | #define IOMD_KBDCR 0x008/4 | |
| 547 | ||
| 548 | #define IOMD_IRQSTA 0x010/4 | |
| 549 | #define IOMD_IRQRQA 0x014/4 | |
| 550 | #define IOMD_IRQMSKA 0x018/4 | |
| 551 | ||
| 552 | #define IOMD_T0LOW 0x040/4 | |
| 553 | #define IOMD_T0HIGH 0x044/4 | |
| 554 | #define IOMD_T0GO 0x048/4 | |
| 555 | #define IOMD_T0LATCH 0x04c/4 | |
| 556 | ||
| 557 | #define IOMD_T1LOW 0x050/4 | |
| 558 | #define IOMD_T1HIGH 0x054/4 | |
| 559 | #define IOMD_T1GO 0x058/4 | |
| 560 | #define IOMD_T1LATCH 0x05c/4 | |
| 561 | ||
| 562 | #define IOMD_ID0 0x094/4 | |
| 563 | #define IOMD_ID1 0x098/4 | |
| 564 | #define IOMD_VERSION 0x09c/4 | |
| 565 | ||
| 566 | #define IOMD_VIDCUR 0x1d0/4 | |
| 567 | #define IOMD_VIDEND 0x1d4/4 | |
| 568 | #define IOMD_VIDSTART 0x1d8/4 | |
| 569 | #define IOMD_VIDINIT 0x1dc/4 | |
| 570 | #define IOMD_VIDCR 0x1e0/4 | |
| 571 | ||
| 572 | ||
| 573 | ||
| 574 | static void fire_iomd_timer(a7000_state *state, int timer) | |
| 575 | { | |
| 576 | int timer_count = state->m_timer_counter[timer]; | |
| 577 | int val = timer_count / 2; // correct? | |
| 578 | ||
| 579 | if(val==0) | |
| 580 | state->m_IOMD_timer[timer]->adjust(attotime::never); | |
| 581 | else | |
| 582 | state->m_IOMD_timer[timer]->adjust(attotime::from_usec(val), 0, attotime::from_usec(val)); | |
| 583 | } | |
| 584 | ||
| 585 | static TIMER_CALLBACK( IOMD_timer0_callback ) | |
| 586 | { | |
| 587 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 588 | state->m_IRQ_status_A|=0x20; | |
| 589 | if(state->m_IRQ_mask_A&0x20) | |
| 590 | { | |
| 591 | generic_pulse_irq_line(machine.device("maincpu"), ARM7_IRQ_LINE); | |
| 592 | } | |
| 593 | } | |
| 594 | ||
| 595 | static TIMER_CALLBACK( IOMD_timer1_callback ) | |
| 596 | { | |
| 597 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 598 | state->m_IRQ_status_A|=0x40; | |
| 599 | if(state->m_IRQ_mask_A&0x40) | |
| 600 | { | |
| 601 | generic_pulse_irq_line(machine.device("maincpu"), ARM7_IRQ_LINE); | |
| 602 | } | |
| 603 | } | |
| 604 | ||
| 605 | static TIMER_CALLBACK( flyback_timer_callback ) | |
| 606 | { | |
| 607 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 608 | state->m_IRQ_status_A|=0x08; | |
| 609 | if(state->m_IRQ_mask_A&0x08) | |
| 610 | { | |
| 611 | generic_pulse_irq_line(machine.device("maincpu"), ARM7_IRQ_LINE); | |
| 612 | } | |
| 613 | ||
| 614 | state->m_flyback_timer->adjust(machine.primary_screen->time_until_pos(state->m_vidc20_vert_reg[VDER])); | |
| 615 | } | |
| 616 | ||
| 617 | static void viddma_transfer_start(address_space *space) | |
| 618 | { | |
| 619 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 620 | UINT32 src = state->m_viddma_addr_start; | |
| 621 | UINT32 dst = 0; | |
| 622 | UINT32 size = state->m_viddma_addr_end; | |
| 623 | UINT32 dma_index; | |
| 624 | UINT8 *vram = space->machine().region("vram")->base(); | |
| 625 | ||
| 626 | /* TODO: this should actually be a qword transfer */ | |
| 627 | for(dma_index = 0;dma_index < size;dma_index++) | |
| 628 | { | |
| 629 | vram[dst] = space->read_byte(src); | |
| 630 | ||
| 631 | src++; | |
| 632 | dst++; | |
| 633 | } | |
| 634 | } | |
| 635 | ||
| 636 | static READ32_HANDLER( a7000_iomd_r ) | |
| 637 | { | |
| 638 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 639 | // if(offset != IOMD_KBDCR) | |
| 640 | // logerror("IOMD: %s Register (%04x) read\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4); | |
| 641 | ||
| 642 | ||
| 643 | switch(offset) | |
| 644 | { | |
| 645 | case IOMD_IOCR: | |
| 646 | { | |
| 647 | UINT8 flyback; | |
| 648 | int vert_pos; | |
| 649 | ||
| 650 | vert_pos = space->machine().primary_screen->vpos(); | |
| 651 | flyback = (vert_pos <= state->m_vidc20_vert_reg[VDSR] || vert_pos >= state->m_vidc20_vert_reg[VDER]) ? 0x80 : 0x00; | |
| 652 | ||
| 653 | return state->m_IOMD_IO_ctrl | 0x34 | flyback; | |
| 654 | } | |
| 655 | case IOMD_KBDCR: return state->m_IOMD_keyb_ctrl | 0x80; //IOMD Keyb status | |
| 656 | ||
| 657 | /* | |
| 658 | 1--- ---- always high | |
| 659 | -x-- ---- Timer 1 | |
| 660 | --x- ---- Timer 0 | |
| 661 | ---x ---- Power On Reset | |
| 662 | ---- x--- Flyback | |
| 663 | ---- -x-- nINT1 | |
| 664 | ---- --0- always low | |
| 665 | ---- ---x INT2 | |
| 666 | */ | |
| 667 | case IOMD_IRQSTA: return (state->m_IRQ_status_A & ~2) | 0x80; | |
| 668 | case IOMD_IRQRQA: return (state->m_IRQ_status_A & state->m_IRQ_mask_A) | 0x80; | |
| 669 | case IOMD_IRQMSKA: return (state->m_IRQ_mask_A); | |
| 670 | ||
| 671 | case IOMD_T0LOW: return state->m_timer_out[0] & 0xff; | |
| 672 | case IOMD_T0HIGH: return (state->m_timer_out[0] >> 8) & 0xff; | |
| 673 | ||
| 674 | case IOMD_T1LOW: return state->m_timer_out[1] & 0xff; | |
| 675 | case IOMD_T1HIGH: return (state->m_timer_out[1] >> 8) & 0xff; | |
| 676 | ||
| 677 | case IOMD_ID0: return state->m_io_id & 0xff; // IOMD ID low | |
| 678 | case IOMD_ID1: return (state->m_io_id >> 8) & 0xff; // IOMD ID high | |
| 679 | case IOMD_VERSION: return 0; | |
| 680 | ||
| 681 | case IOMD_VIDEND: return (state->m_viddma_addr_end & 0x00fffff8); //bits 31:24 undefined | |
| 682 | case IOMD_VIDSTART: return (state->m_viddma_addr_start & 0x1ffffff8); //bits 31, 30, 29 undefined | |
| 683 | case IOMD_VIDCR: return (state->m_viddma_status & 0xa0) | 0x50; //bit 6 = DRAM mode, bit 4 = QWORD transfer | |
| 684 | ||
| 685 | default: logerror("IOMD: %s Register (%04x) read\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4); break; | |
| 686 | } | |
| 687 | ||
| 688 | return 0; | |
| 689 | } | |
| 690 | ||
| 691 | static WRITE32_HANDLER( a7000_iomd_w ) | |
| 692 | { | |
| 693 | a7000_state *state = space->machine().driver_data<a7000_state>(); | |
| 694 | // logerror("IOMD: %s Register (%04x) write = %08x\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4,data); | |
| 695 | ||
| 696 | switch(offset) | |
| 697 | { | |
| 698 | case IOMD_IOCR: state->m_IOMD_IO_ctrl = data & ~0xf4; break; | |
| 699 | ||
| 700 | case IOMD_KBDCR: | |
| 701 | state->m_IOMD_keyb_ctrl = data & ~0xf4; | |
| 702 | //keyboard_ctrl_write(data & 0x08); | |
| 703 | break; | |
| 704 | ||
| 705 | case IOMD_IRQRQA: state->m_IRQ_status_A &= ~data; break; | |
| 706 | case IOMD_IRQMSKA: state->m_IRQ_mask_A = (data & ~2) | 0x80; break; | |
| 707 | ||
| 708 | case IOMD_T0LOW: state->m_timer_in[0] = (state->m_timer_in[0] & 0xff00) | (data & 0xff); break; | |
| 709 | case IOMD_T0HIGH: state->m_timer_in[0] = (state->m_timer_in[0] & 0x00ff) | ((data & 0xff) << 8); break; | |
| 710 | case IOMD_T0GO: | |
| 711 | state->m_timer_counter[0] = state->m_timer_in[0]; | |
| 712 | fire_iomd_timer(state,0); | |
| 713 | break; | |
| 714 | case IOMD_T0LATCH: | |
| 715 | { | |
| 716 | state->m_t0readinc^=1; | |
| 717 | state->m_timer_out[0] = state->m_timer_counter[0]; | |
| 718 | if(state->m_t0readinc) | |
| 719 | { | |
| 720 | state->m_timer_counter[0]--; | |
| 721 | if(state->m_timer_counter[0] < 0) | |
| 722 | state->m_timer_counter[0]+= state->m_timer_in[0]; | |
| 723 | } | |
| 724 | } | |
| 725 | break; | |
| 726 | ||
| 727 | case IOMD_T1LOW: state->m_timer_in[1] = (state->m_timer_in[1] & 0xff00) | (data & 0xff); break; | |
| 728 | case IOMD_T1HIGH: state->m_timer_in[1] = (state->m_timer_in[1] & 0x00ff) | ((data & 0xff) << 8); break; | |
| 729 | case IOMD_T1GO: | |
| 730 | state->m_timer_counter[1] = state->m_timer_in[1]; | |
| 731 | fire_iomd_timer(state,1); | |
| 732 | break; | |
| 733 | case IOMD_T1LATCH: | |
| 734 | { | |
| 735 | state->m_t1readinc^=1; | |
| 736 | state->m_timer_out[1] = state->m_timer_counter[1]; | |
| 737 | if(state->m_t1readinc) | |
| 738 | { | |
| 739 | state->m_timer_counter[1]--; | |
| 740 | if(state->m_timer_counter[1] < 0) | |
| 741 | state->m_timer_counter[1]+= state->m_timer_in[1]; | |
| 742 | } | |
| 743 | } | |
| 744 | break; | |
| 745 | ||
| 746 | case IOMD_VIDEND: state->m_viddma_addr_end = data & 0x00fffff8; //bits 31:24 unused | |
| 747 | case IOMD_VIDSTART: state->m_viddma_addr_start = data & 0x1ffffff8; //bits 31, 30, 29 unused | |
| 748 | case IOMD_VIDCR: | |
| 749 | state->m_viddma_status = data & 0xa0; if(data & 0x20) { viddma_transfer_start(space); } | |
| 750 | break; | |
| 751 | ||
| 752 | ||
| 753 | default: logerror("IOMD: %s Register (%04x) write = %08x\n",iomd_regnames[offset & (0x1ff >> 2)],offset*4,data); | |
| 754 | } | |
| 755 | } | |
| 756 | ||
| 757 | static ADDRESS_MAP_START( a7000_mem, AS_PROGRAM, 32) | |
| 758 | AM_RANGE(0x00000000, 0x003fffff) AM_MIRROR(0x00800000) AM_ROM AM_REGION("user1", 0x0) | |
| 759 | // AM_RANGE(0x01000000, 0x01ffffff) AM_NOP //expansion ROM | |
| 760 | // AM_RANGE(0x02000000, 0x02ffffff) AM_RAM //VRAM | |
| 761 | // I/O 03000000 - 033fffff | |
| 762 | // AM_RANGE(0x03010000, 0x03011fff) //Super IO | |
| 763 | // AM_RANGE(0x03012000, 0x03029fff) //FDC | |
| 764 | // AM_RANGE(0x0302b000, 0x0302bfff) //Network podule | |
| 765 | // AM_RANGE(0x03040000, 0x0304ffff) //podule space 0,1,2,3 | |
| 766 | // AM_RANGE(0x03070000, 0x0307ffff) //podule space 4,5,6,7 | |
| 767 | AM_RANGE(0x03200000, 0x032001ff) AM_READWRITE(a7000_iomd_r,a7000_iomd_w) //IOMD Registers //mirrored at 0x03000000-0x1ff? | |
| 768 | // AM_RANGE(0x03310000, 0x03310003) //Mouse Buttons | |
| 769 | ||
| 770 | AM_RANGE(0x03400000, 0x037fffff) AM_WRITE(a7000_vidc20_w) | |
| 771 | // AM_RANGE(0x08000000, 0x08ffffff) AM_MIRROR(0x07000000) //EASI space | |
| 772 | AM_RANGE(0x10000000, 0x13ffffff) AM_RAM //SIMM 0 bank 0 | |
| 773 | AM_RANGE(0x14000000, 0x17ffffff) AM_RAM //SIMM 0 bank 1 | |
| 774 | // AM_RANGE(0x18000000, 0x18ffffff) AM_MIRROR(0x03000000) AM_RAM //SIMM 1 bank 0 | |
| 775 | // AM_RANGE(0x1c000000, 0x1cffffff) AM_MIRROR(0x03000000) AM_RAM //SIMM 1 bank 1 | |
| 776 | ADDRESS_MAP_END | |
| 777 | ||
| 778 | ||
| 779 | /* Input ports */ | |
| 780 | static INPUT_PORTS_START( a7000 ) | |
| 781 | INPUT_PORTS_END | |
| 782 | ||
| 783 | static MACHINE_START(a7000) | |
| 784 | { | |
| 785 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 786 | state->m_IOMD_timer[0] = machine.scheduler().timer_alloc(FUNC(IOMD_timer0_callback)); | |
| 787 | state->m_IOMD_timer[1] = machine.scheduler().timer_alloc(FUNC(IOMD_timer1_callback)); | |
| 788 | state->m_flyback_timer = machine.scheduler().timer_alloc(FUNC(flyback_timer_callback)); | |
| 789 | ||
| 790 | state->m_io_id = 0xd4e7; | |
| 791 | } | |
| 792 | ||
| 793 | static MACHINE_RESET(a7000) | |
| 794 | { | |
| 795 | a7000_state *state = machine.driver_data<a7000_state>(); | |
| 796 | state->m_IOMD_IO_ctrl = 0x0b | 0x34; //bit 0,1 and 3 set high on reset plus 2,4,5 always high | |
| 797 | // state->m_IRQ_status_A = 0x10; // set POR bit ON | |
| 798 | state->m_IRQ_mask_A = 0x00; | |
| 799 | ||
| 800 | state->m_IOMD_keyb_ctrl = 0x00; | |
| 801 | ||
| 802 | state->m_IOMD_timer[0]->adjust( attotime::never); | |
| 803 | state->m_IOMD_timer[1]->adjust( attotime::never); | |
| 804 | state->m_flyback_timer->adjust( attotime::never); | |
| 805 | } | |
| 806 | ||
| 807 | static MACHINE_CONFIG_START( a7000, a7000_state ) | |
| 808 | ||
| 809 | /* Basic machine hardware */ | |
| 810 | MCFG_CPU_ADD( "maincpu", ARM7, XTAL_32MHz ) | |
| 811 | MCFG_CPU_PROGRAM_MAP(a7000_mem) | |
| 812 | ||
| 813 | MCFG_MACHINE_START( a7000 ) | |
| 814 | MCFG_MACHINE_RESET( a7000 ) | |
| 815 | ||
| 816 | /* video hardware */ | |
| 817 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 818 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 819 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 820 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 821 | MCFG_SCREEN_SIZE(1900, 1080) //max available size | |
| 822 | MCFG_SCREEN_VISIBLE_AREA(0, 1900-1, 0, 1080-1) | |
| 823 | MCFG_SCREEN_UPDATE(a7000) | |
| 824 | MCFG_PALETTE_LENGTH(0x200) | |
| 825 | // MCFG_PALETTE_INIT(black_and_white) | |
| 826 | ||
| 827 | MCFG_VIDEO_START(a7000) | |
| 828 | MACHINE_CONFIG_END | |
| 829 | ||
| 830 | static MACHINE_CONFIG_DERIVED( a7000p, a7000 ) | |
| 831 | ||
| 832 | MCFG_CPU_MODIFY("maincpu") | |
| 833 | MCFG_CPU_CLOCK(XTAL_48MHz) | |
| 834 | MACHINE_CONFIG_END | |
| 835 | ||
| 836 | ROM_START(a7000) | |
| 837 | ROM_REGION( 0x800000, "user1", ROMREGION_ERASEFF ) | |
| 838 | ROM_LOAD( "rom1.bin", 0x000000, 0x100000, CRC(ff0e3d12) SHA1(fa489bebede3d13dc43cddec5b5c9b6829a28914) ) | |
| 839 | ROM_LOAD( "rom2.bin", 0x100000, 0x100000, CRC(4ae4fd8b) SHA1(1b30d5905d5364dfa48bad69257b0ef8190e9bf6) ) | |
| 840 | ROM_LOAD( "rom3.bin", 0x200000, 0x100000, CRC(3108fb2b) SHA1(865b01583f3fb5f4ed5e9201676db327cdeb40b3) ) | |
| 841 | ROM_LOAD( "rom4.bin", 0x300000, 0x100000, CRC(55a51980) SHA1(a7191727edd5babf679ebbdea6585833a1fb34e6) ) | |
| 842 | ||
| 843 | ROM_REGION( 0x800000, "vram", ROMREGION_ERASE00 ) | |
| 844 | ROM_END | |
| 845 | ||
| 846 | ROM_START(a7000p) | |
| 847 | ROM_REGION( 0x800000, "user1", ROMREGION_ERASEFF ) | |
| 848 | ROM_LOAD( "riscos-3.71.rom", 0x000000, 0x400000, CRC(211cf888) SHA1(c5fe0645e48894fb4b245abeefdc9a65d659af59)) | |
| 849 | ||
| 850 | ROM_REGION( 0x800000, "vram", ROMREGION_ERASE00 ) | |
| 851 | ROM_END | |
| 852 | ||
| 853 | /*************************************************************************** | |
| 854 | ||
| 855 | Game driver(s) | |
| 856 | ||
| 857 | ***************************************************************************/ | |
| 858 | ||
| 859 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 860 | COMP( 1995, a7000, 0, 0, a7000, a7000, 0, "Acorn", "Archimedes A7000", GAME_NOT_WORKING | GAME_NO_SOUND ) | |
| 861 | COMP( 1997, a7000p, a7000, 0, a7000p, a7000, 0, "Acorn", "Archimedes A7000+", GAME_NOT_WORKING | GAME_NO_SOUND ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Neo-Geo AES hardware | |
| 4 | ||
| 5 | Credits (from MAME neogeo.c, since this is just a minor edit of that driver): | |
| 6 | * This driver was made possible by the research done by | |
| 7 | Charles MacDonald. For a detailed description of the Neo-Geo | |
| 8 | hardware, please visit his page at: | |
| 9 | http://cgfm2.emuviews.com/temp/mvstech.txt | |
| 10 | * Presented to you by the Shin Emu Keikaku team. | |
| 11 | * The following people have all spent probably far | |
| 12 | too much time on this: | |
| 13 | AVDB | |
| 14 | Bryan McPhail | |
| 15 | Fuzz | |
| 16 | Ernesto Corvi | |
| 17 | Andrew Prime | |
| 18 | Zsolt Vasvari | |
| 19 | ||
| 20 | MESS cartridge support by R. Belmont based on work by Michael Zapf | |
| 21 | ||
| 22 | Current status: | |
| 23 | - Cartridges run. | |
| 24 | ||
| 25 | ToDo : | |
| 26 | - Change input code to allow selection of the mahjong panel in PORT_CATEGORY. | |
| 27 | - Clean up code, to reduce duplication of MAME source | |
| 28 | ||
| 29 | ****************************************************************************/ | |
| 30 | ||
| 31 | #include "emu.h" | |
| 32 | #include "cpu/m68000/m68000.h" | |
| 33 | #include "includes/neogeo.h" | |
| 34 | #include "machine/pd4990a.h" | |
| 35 | #include "cpu/z80/z80.h" | |
| 36 | #include "sound/2610intf.h" | |
| 37 | #include "imagedev/aescart.h" | |
| 38 | #include "imagedev/cartslot.h" | |
| 39 | #ifdef MESS | |
| 40 | #include "neogeo.lh" | |
| 41 | #else | |
| 42 | extern const char layout_neogeo[]; | |
| 43 | #endif | |
| 44 | ||
| 45 | ||
| 46 | // CD-ROM / DMA control registers | |
| 47 | typedef struct | |
| 48 | { | |
| 49 | UINT8 area_sel; | |
| 50 | UINT8 pcm_bank_sel; | |
| 51 | UINT8 spr_bank_sel; | |
| 52 | UINT32 addr_source; // target if in fill mode | |
| 53 | UINT32 addr_target; | |
| 54 | UINT16 fill_word; | |
| 55 | UINT32 word_count; | |
| 56 | UINT16 dma_mode[10]; | |
| 57 | } neocd_ctrl_t; | |
| 58 | ||
| 59 | class ng_aes_state : public neogeo_state | |
| 60 | { | |
| 61 | public: | |
| 62 | ng_aes_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 63 | : neogeo_state(mconfig, type, tag) { } | |
| 64 | ||
| 65 | UINT8 *m_memcard_data; | |
| 66 | neocd_ctrl_t m_neocd_ctrl; | |
| 67 | }; | |
| 68 | ||
| 69 | ||
| 70 | ||
| 71 | #define LOG_VIDEO_SYSTEM (0) | |
| 72 | #define LOG_CPU_COMM (0) | |
| 73 | #define LOG_MAIN_CPU_BANKING (1) | |
| 74 | #define LOG_AUDIO_CPU_BANKING (1) | |
| 75 | ||
| 76 | #define NEOCD_AREA_SPR 0 | |
| 77 | #define NEOCD_AREA_PCM 1 | |
| 78 | #define NEOCD_AREA_AUDIO 4 | |
| 79 | #define NEOCD_AREA_FIX 5 | |
| 80 | ||
| 81 | /************************************* | |
| 82 | * | |
| 83 | * Global variables | |
| 84 | * | |
| 85 | *************************************/ | |
| 86 | ||
| 87 | //static UINT16 *save_ram; | |
| 88 | ||
| 89 | UINT16* neocd_work_ram; | |
| 90 | ||
| 91 | /************************************* | |
| 92 | * | |
| 93 | * Forward declarations | |
| 94 | * | |
| 95 | *************************************/ | |
| 96 | ||
| 97 | //static void set_output_latch(running_machine &machine, UINT8 data); | |
| 98 | //static void set_output_data(running_machine &machine, UINT8 data); | |
| 99 | ||
| 100 | ||
| 101 | /************************************* | |
| 102 | * | |
| 103 | * Main CPU interrupt generation | |
| 104 | * | |
| 105 | *************************************/ | |
| 106 | ||
| 107 | #define IRQ2CTRL_ENABLE (0x10) | |
| 108 | #define IRQ2CTRL_LOAD_RELATIVE (0x20) | |
| 109 | #define IRQ2CTRL_AUTOLOAD_VBLANK (0x40) | |
| 110 | #define IRQ2CTRL_AUTOLOAD_REPEAT (0x80) | |
| 111 | ||
| 112 | ||
| 113 | static void adjust_display_position_interrupt_timer( running_machine &machine ) | |
| 114 | { | |
| 115 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 116 | ||
| 117 | if ((state->m_display_counter + 1) != 0) | |
| 118 | { | |
| 119 | attotime period = (attotime::from_hz(NEOGEO_PIXEL_CLOCK) * (state->m_display_counter + 1)); | |
| 120 | if (LOG_VIDEO_SYSTEM) logerror("adjust_display_position_interrupt_timer current y: %02x current x: %02x target y: %x target x: %x\n", machine.primary_screen->vpos(), machine.primary_screen->hpos(), (state->m_display_counter + 1) / NEOGEO_HTOTAL, (state->m_display_counter + 1) % NEOGEO_HTOTAL); | |
| 121 | ||
| 122 | state->m_display_position_interrupt_timer->adjust(period); | |
| 123 | } | |
| 124 | } | |
| 125 | ||
| 126 | #ifdef MESS | |
| 127 | void neogeo_set_display_position_interrupt_control( running_machine &machine, UINT16 data ) | |
| 128 | { | |
| 129 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 130 | state->m_display_position_interrupt_control = data; | |
| 131 | } | |
| 132 | ||
| 133 | ||
| 134 | void neogeo_set_display_counter_msb( address_space *space, UINT16 data ) | |
| 135 | { | |
| 136 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 137 | ||
| 138 | state->m_display_counter = (state->m_display_counter & 0x0000ffff) | ((UINT32)data << 16); | |
| 139 | ||
| 140 | if (LOG_VIDEO_SYSTEM) logerror("PC %06x: set_display_counter %08x\n", cpu_get_pc(&space->device()), state->m_display_counter); | |
| 141 | } | |
| 142 | ||
| 143 | ||
| 144 | void neogeo_set_display_counter_lsb( address_space *space, UINT16 data ) | |
| 145 | { | |
| 146 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 147 | ||
| 148 | state->m_display_counter = (state->m_display_counter & 0xffff0000) | data; | |
| 149 | ||
| 150 | if (LOG_VIDEO_SYSTEM) logerror("PC %06x: set_display_counter %08x\n", cpu_get_pc(&space->device()), state->m_display_counter); | |
| 151 | ||
| 152 | if (state->m_display_position_interrupt_control & IRQ2CTRL_LOAD_RELATIVE) | |
| 153 | { | |
| 154 | if (LOG_VIDEO_SYSTEM) logerror("AUTOLOAD_RELATIVE "); | |
| 155 | adjust_display_position_interrupt_timer(space->machine()); | |
| 156 | } | |
| 157 | } | |
| 158 | #endif | |
| 159 | ||
| 160 | static void update_interrupts( running_machine &machine ) | |
| 161 | { | |
| 162 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 163 | ||
| 164 | if(strcmp((char*)machine.system().name,"aes") != 0) | |
| 165 | { // raster and vblank IRQs are swapped on the NeoCD. | |
| 166 | cputag_set_input_line(machine, "maincpu", 2, state->m_vblank_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 167 | cputag_set_input_line(machine, "maincpu", 1, state->m_display_position_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 168 | cputag_set_input_line(machine, "maincpu", 3, state->m_irq3_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 169 | } | |
| 170 | else | |
| 171 | { | |
| 172 | cputag_set_input_line(machine, "maincpu", 1, state->m_vblank_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 173 | cputag_set_input_line(machine, "maincpu", 2, state->m_display_position_interrupt_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 174 | cputag_set_input_line(machine, "maincpu", 3, state->m_irq3_pending ? ASSERT_LINE : CLEAR_LINE); | |
| 175 | } | |
| 176 | } | |
| 177 | ||
| 178 | #ifdef MESS | |
| 179 | void neogeo_acknowledge_interrupt( running_machine &machine, UINT16 data ) | |
| 180 | { | |
| 181 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 182 | ||
| 183 | if (data & 0x01) | |
| 184 | state->m_irq3_pending = 0; | |
| 185 | if (data & 0x02) | |
| 186 | state->m_display_position_interrupt_pending = 0; | |
| 187 | if (data & 0x04) | |
| 188 | state->m_vblank_interrupt_pending = 0; | |
| 189 | ||
| 190 | update_interrupts(machine); | |
| 191 | } | |
| 192 | #endif | |
| 193 | ||
| 194 | static TIMER_CALLBACK( display_position_interrupt_callback ) | |
| 195 | { | |
| 196 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 197 | ||
| 198 | if (LOG_VIDEO_SYSTEM) logerror("--- Scanline @ %d,%d\n", machine.primary_screen->vpos(), machine.primary_screen->hpos()); | |
| 199 | ||
| 200 | if (state->m_display_position_interrupt_control & IRQ2CTRL_ENABLE) | |
| 201 | { | |
| 202 | if (LOG_VIDEO_SYSTEM) logerror("*** Scanline interrupt (IRQ2) *** y: %02x x: %02x\n", machine.primary_screen->vpos(), machine.primary_screen->hpos()); | |
| 203 | state->m_display_position_interrupt_pending = 1; | |
| 204 | ||
| 205 | update_interrupts(machine); | |
| 206 | } | |
| 207 | ||
| 208 | if (state->m_display_position_interrupt_control & IRQ2CTRL_AUTOLOAD_REPEAT) | |
| 209 | { | |
| 210 | if (LOG_VIDEO_SYSTEM) logerror("AUTOLOAD_REPEAT "); | |
| 211 | adjust_display_position_interrupt_timer(machine); | |
| 212 | } | |
| 213 | } | |
| 214 | ||
| 215 | ||
| 216 | static TIMER_CALLBACK( display_position_vblank_callback ) | |
| 217 | { | |
| 218 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 219 | ||
| 220 | if (state->m_display_position_interrupt_control & IRQ2CTRL_AUTOLOAD_VBLANK) | |
| 221 | { | |
| 222 | if (LOG_VIDEO_SYSTEM) logerror("AUTOLOAD_VBLANK "); | |
| 223 | adjust_display_position_interrupt_timer(machine); | |
| 224 | } | |
| 225 | ||
| 226 | /* set timer for next screen */ | |
| 227 | state->m_display_position_vblank_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, NEOGEO_VBLANK_RELOAD_HPOS)); | |
| 228 | } | |
| 229 | ||
| 230 | ||
| 231 | static TIMER_CALLBACK( vblank_interrupt_callback ) | |
| 232 | { | |
| 233 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 234 | ||
| 235 | if (LOG_VIDEO_SYSTEM) logerror("+++ VBLANK @ %d,%d\n", machine.primary_screen->vpos(), machine.primary_screen->hpos()); | |
| 236 | ||
| 237 | /* add a timer tick to the pd4990a */ | |
| 238 | upd4990a_addretrace(state->m_upd4990a); | |
| 239 | ||
| 240 | state->m_vblank_interrupt_pending = 1; | |
| 241 | ||
| 242 | update_interrupts(machine); | |
| 243 | ||
| 244 | /* set timer for next screen */ | |
| 245 | state->m_vblank_interrupt_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, 0)); | |
| 246 | } | |
| 247 | ||
| 248 | ||
| 249 | static void create_interrupt_timers( running_machine &machine ) | |
| 250 | { | |
| 251 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 252 | state->m_display_position_interrupt_timer = machine.scheduler().timer_alloc(FUNC(display_position_interrupt_callback)); | |
| 253 | state->m_display_position_vblank_timer = machine.scheduler().timer_alloc(FUNC(display_position_vblank_callback)); | |
| 254 | state->m_vblank_interrupt_timer = machine.scheduler().timer_alloc(FUNC(vblank_interrupt_callback)); | |
| 255 | } | |
| 256 | ||
| 257 | ||
| 258 | static void start_interrupt_timers( running_machine &machine ) | |
| 259 | { | |
| 260 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 261 | state->m_vblank_interrupt_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, 0)); | |
| 262 | state->m_display_position_vblank_timer->adjust(machine.primary_screen->time_until_pos(NEOGEO_VBSTART, NEOGEO_VBLANK_RELOAD_HPOS)); | |
| 263 | } | |
| 264 | ||
| 265 | ||
| 266 | ||
| 267 | /************************************* | |
| 268 | * | |
| 269 | * Audio CPU interrupt generation | |
| 270 | * | |
| 271 | *************************************/ | |
| 272 | ||
| 273 | static void audio_cpu_irq(device_t *device, int assert) | |
| 274 | { | |
| 275 | neogeo_state *state = device->machine().driver_data<neogeo_state>(); | |
| 276 | device_set_input_line(state->m_audiocpu, 0, assert ? ASSERT_LINE : CLEAR_LINE); | |
| 277 | } | |
| 278 | ||
| 279 | ||
| 280 | static void audio_cpu_assert_nmi(running_machine &machine) | |
| 281 | { | |
| 282 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 283 | device_set_input_line(state->m_audiocpu, INPUT_LINE_NMI, ASSERT_LINE); | |
| 284 | } | |
| 285 | ||
| 286 | ||
| 287 | static WRITE8_HANDLER( audio_cpu_clear_nmi_w ) | |
| 288 | { | |
| 289 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 290 | device_set_input_line(state->m_audiocpu, INPUT_LINE_NMI, CLEAR_LINE); | |
| 291 | } | |
| 292 | ||
| 293 | ||
| 294 | ||
| 295 | /************************************* | |
| 296 | * | |
| 297 | * Input ports / Controllers | |
| 298 | * | |
| 299 | *************************************/ | |
| 300 | ||
| 301 | static void select_controller( running_machine &machine, UINT8 data ) | |
| 302 | { | |
| 303 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 304 | state->m_controller_select = data; | |
| 305 | } | |
| 306 | ||
| 307 | ||
| 308 | #if 0 | |
| 309 | static CUSTOM_INPUT( multiplexed_controller_r ) | |
| 310 | { | |
| 311 | int port = (FPTR)param; | |
| 312 | ||
| 313 | static const char *const cntrl[2][2] = | |
| 314 | { | |
| 315 | { "IN0-0", "IN0-1" }, { "IN1-0", "IN1-1" } | |
| 316 | }; | |
| 317 | ||
| 318 | return input_port_read_safe(field.machine(), cntrl[port][controller_select & 0x01], 0x00); | |
| 319 | } | |
| 320 | ||
| 321 | ||
| 322 | static CUSTOM_INPUT( mahjong_controller_r ) | |
| 323 | { | |
| 324 | UINT32 ret; | |
| 325 | ||
| 326 | /* | |
| 327 | cpu #0 (PC=00C18B9A): unmapped memory word write to 00380000 = 0012 & 00FF | |
| 328 | cpu #0 (PC=00C18BB6): unmapped memory word write to 00380000 = 001B & 00FF | |
| 329 | cpu #0 (PC=00C18D54): unmapped memory word write to 00380000 = 0024 & 00FF | |
| 330 | cpu #0 (PC=00C18D6C): unmapped memory word write to 00380000 = 0009 & 00FF | |
| 331 | cpu #0 (PC=00C18C40): unmapped memory word write to 00380000 = 0000 & 00FF | |
| 332 | */ | |
| 333 | switch (controller_select) | |
| 334 | { | |
| 335 | default: | |
| 336 | case 0x00: ret = 0x0000; break; /* nothing? */ | |
| 337 | case 0x09: ret = input_port_read(field.machine(), "MAHJONG1"); break; | |
| 338 | case 0x12: ret = input_port_read(field.machine(), "MAHJONG2"); break; | |
| 339 | case 0x1b: ret = input_port_read(field.machine(), "MAHJONG3"); break; /* player 1 normal inputs? */ | |
| 340 | case 0x24: ret = input_port_read(field.machine(), "MAHJONG4"); break; | |
| 341 | } | |
| 342 | ||
| 343 | return ret; | |
| 344 | } | |
| 345 | ||
| 346 | #endif | |
| 347 | ||
| 348 | static WRITE16_HANDLER( io_control_w ) | |
| 349 | { | |
| 350 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 351 | switch (offset) | |
| 352 | { | |
| 353 | case 0x00: select_controller(space->machine(), data & 0x00ff); break; | |
| 354 | // case 0x18: set_output_latch(space->machine(), data & 0x00ff); break; | |
| 355 | // case 0x20: set_output_data(space->machine(), data & 0x00ff); break; | |
| 356 | case 0x28: upd4990a_control_16_w(state->m_upd4990a, 0, data, mem_mask); break; | |
| 357 | // case 0x30: break; // coin counters | |
| 358 | // case 0x31: break; // coin counters | |
| 359 | // case 0x32: break; // coin lockout | |
| 360 | // case 0x33: break; // coui lockout | |
| 361 | ||
| 362 | default: | |
| 363 | logerror("PC: %x Unmapped I/O control write. Offset: %x Data: %x\n", cpu_get_pc(&space->device()), offset, data); | |
| 364 | break; | |
| 365 | } | |
| 366 | } | |
| 367 | ||
| 368 | ||
| 369 | ||
| 370 | /************************************* | |
| 371 | * | |
| 372 | * Unmapped memory access | |
| 373 | * | |
| 374 | *************************************/ | |
| 375 | #ifdef MESS | |
| 376 | READ16_HANDLER( neogeo_unmapped_r ) | |
| 377 | { | |
| 378 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 379 | UINT16 ret; | |
| 380 | ||
| 381 | /* unmapped memory returns the last word on the data bus, which is almost always the opcode | |
| 382 | of the next instruction due to prefetch */ | |
| 383 | ||
| 384 | /* prevent recursion */ | |
| 385 | if (state->m_recurse) | |
| 386 | ret = 0xffff; | |
| 387 | else | |
| 388 | { | |
| 389 | state->m_recurse = 1; | |
| 390 | ret = space->read_word(cpu_get_pc(&space->device())); | |
| 391 | state->m_recurse = 0; | |
| 392 | } | |
| 393 | ||
| 394 | return ret; | |
| 395 | } | |
| 396 | #endif | |
| 397 | ||
| 398 | ||
| 399 | ||
| 400 | /************************************* | |
| 401 | * | |
| 402 | * uPD4990A calendar chip | |
| 403 | * | |
| 404 | *************************************/ | |
| 405 | #if 0 | |
| 406 | static void calendar_init(running_machine &machine) | |
| 407 | { | |
| 408 | /* set the celander IC to 'right now' */ | |
| 409 | system_time systime; | |
| 410 | system_tm time; | |
| 411 | ||
| 412 | machine.base_datetime(&systime); | |
| 413 | time = systime.local_time; | |
| 414 | ||
| 415 | pd4990a.seconds = ((time.second / 10) << 4) + (time.second % 10); | |
| 416 | pd4990a.minutes = ((time.minute / 10) << 4) + (time.minute % 10); | |
| 417 | pd4990a.hours = ((time.hour / 10) <<4 ) + (time.hour % 10); | |
| 418 | pd4990a.days = ((time.mday / 10) << 4) + (time.mday % 10); | |
| 419 | pd4990a.month = time.month + 1; | |
| 420 | pd4990a.year = ((((time.year - 1900) % 100) / 10) << 4) + ((time.year - 1900) % 10); | |
| 421 | pd4990a.weekday = time.weekday; | |
| 422 | } | |
| 423 | ||
| 424 | ||
| 425 | static void calendar_clock(void) | |
| 426 | { | |
| 427 | // pd4990a_addretrace(); | |
| 428 | } | |
| 429 | #endif | |
| 430 | ||
| 431 | static CUSTOM_INPUT( get_calendar_status ) | |
| 432 | { | |
| 433 | neogeo_state *state = field.machine().driver_data<neogeo_state>(); | |
| 434 | return (upd4990a_databit_r(state->m_upd4990a, 0) << 1) | upd4990a_testbit_r(state->m_upd4990a, 0); | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | ||
| 439 | /************************************* | |
| 440 | * | |
| 441 | * NVRAM (Save RAM) | |
| 442 | * | |
| 443 | *************************************/ | |
| 444 | #if 0 | |
| 445 | static NVRAM_HANDLER( neogeo ) | |
| 446 | { | |
| 447 | if (read_or_write) | |
| 448 | /* save the SRAM settings */ | |
| 449 | mame_fwrite(file, save_ram, 0x2000); | |
| 450 | else | |
| 451 | { | |
| 452 | /* load the SRAM settings */ | |
| 453 | if (file) | |
| 454 | mame_fread(file, save_ram, 0x2000); | |
| 455 | else | |
| 456 | memset(save_ram, 0, 0x10000); | |
| 457 | } | |
| 458 | } | |
| 459 | ||
| 460 | ||
| 461 | static void set_save_ram_unlock( running_machine &machine, UINT8 data ) | |
| 462 | { | |
| 463 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 464 | state->m_save_ram_unlocked = data; | |
| 465 | } | |
| 466 | ||
| 467 | ||
| 468 | static WRITE16_HANDLER( save_ram_w ) | |
| 469 | { | |
| 470 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 471 | ||
| 472 | if (state->m_save_ram_unlocked) | |
| 473 | COMBINE_DATA(&save_ram[offset]); | |
| 474 | } | |
| 475 | #endif | |
| 476 | ||
| 477 | ||
| 478 | /************************************* | |
| 479 | * | |
| 480 | * Memory card | |
| 481 | * | |
| 482 | *************************************/ | |
| 483 | ||
| 484 | #define MEMCARD_SIZE 0x0800 | |
| 485 | ||
| 486 | static CUSTOM_INPUT( get_memcard_status ) | |
| 487 | { | |
| 488 | /* D0 and D1 are memcard presence indicators, D2 indicates memcard | |
| 489 | write protect status (we are always write enabled) */ | |
| 490 | if(strcmp((char*)field.machine().system().name,"aes") != 0) | |
| 491 | return 0x00; // On the Neo Geo CD, the memory card is internal and therefore always present. | |
| 492 | else | |
| 493 | return (memcard_present(field.machine()) == -1) ? 0x07 : 0x00; | |
| 494 | } | |
| 495 | ||
| 496 | static READ16_HANDLER( memcard_r ) | |
| 497 | { | |
| 498 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 499 | UINT16 ret; | |
| 500 | ||
| 501 | if (memcard_present(space->machine()) != -1) | |
| 502 | ret = state->m_memcard_data[offset] | 0xff00; | |
| 503 | else | |
| 504 | ret = 0xffff; | |
| 505 | ||
| 506 | return ret; | |
| 507 | } | |
| 508 | ||
| 509 | ||
| 510 | static WRITE16_HANDLER( memcard_w ) | |
| 511 | { | |
| 512 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 513 | if (ACCESSING_BITS_0_7) | |
| 514 | { | |
| 515 | if (memcard_present(space->machine()) != -1) | |
| 516 | state->m_memcard_data[offset] = data; | |
| 517 | } | |
| 518 | } | |
| 519 | ||
| 520 | /* The NeoCD has an 8kB internal memory card, instead of memcard slots like the MVS and AES */ | |
| 521 | static READ16_HANDLER( neocd_memcard_r ) | |
| 522 | { | |
| 523 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 524 | return state->m_memcard_data[offset] | 0xff00; | |
| 525 | } | |
| 526 | ||
| 527 | ||
| 528 | static WRITE16_HANDLER( neocd_memcard_w ) | |
| 529 | { | |
| 530 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 531 | if (ACCESSING_BITS_0_7) | |
| 532 | { | |
| 533 | state->m_memcard_data[offset] = data; | |
| 534 | } | |
| 535 | } | |
| 536 | ||
| 537 | static MEMCARD_HANDLER( neogeo ) | |
| 538 | { | |
| 539 | ng_aes_state *state = machine.driver_data<ng_aes_state>(); | |
| 540 | switch (action) | |
| 541 | { | |
| 542 | case MEMCARD_CREATE: | |
| 543 | memset(state->m_memcard_data, 0, MEMCARD_SIZE); | |
| 544 | file.write(state->m_memcard_data, MEMCARD_SIZE); | |
| 545 | break; | |
| 546 | ||
| 547 | case MEMCARD_INSERT: | |
| 548 | file.read(state->m_memcard_data, MEMCARD_SIZE); | |
| 549 | break; | |
| 550 | ||
| 551 | case MEMCARD_EJECT: | |
| 552 | file.write(state->m_memcard_data, MEMCARD_SIZE); | |
| 553 | break; | |
| 554 | } | |
| 555 | } | |
| 556 | ||
| 557 | ||
| 558 | ||
| 559 | /************************************* | |
| 560 | * | |
| 561 | * Inter-CPU communications | |
| 562 | * | |
| 563 | *************************************/ | |
| 564 | ||
| 565 | static WRITE16_HANDLER( audio_command_w ) | |
| 566 | { | |
| 567 | /* accessing the LSB only is not mapped */ | |
| 568 | if (mem_mask != 0x00ff) | |
| 569 | { | |
| 570 | soundlatch_w(space, 0, data >> 8); | |
| 571 | ||
| 572 | audio_cpu_assert_nmi(space->machine()); | |
| 573 | ||
| 574 | /* boost the interleave to let the audio CPU read the command */ | |
| 575 | space->machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(50)); | |
| 576 | ||
| 577 | if (LOG_CPU_COMM) logerror("MAIN CPU PC %06x: audio_command_w %04x - %04x\n", cpu_get_pc(&space->device()), data, mem_mask); | |
| 578 | } | |
| 579 | } | |
| 580 | ||
| 581 | ||
| 582 | static READ8_HANDLER( audio_command_r ) | |
| 583 | { | |
| 584 | UINT8 ret = soundlatch_r(space, 0); | |
| 585 | ||
| 586 | if (LOG_CPU_COMM) logerror(" AUD CPU PC %04x: audio_command_r %02x\n", cpu_get_pc(&space->device()), ret); | |
| 587 | ||
| 588 | /* this is a guess */ | |
| 589 | audio_cpu_clear_nmi_w(space, 0, 0); | |
| 590 | ||
| 591 | return ret; | |
| 592 | } | |
| 593 | ||
| 594 | ||
| 595 | static WRITE8_HANDLER( audio_result_w ) | |
| 596 | { | |
| 597 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 598 | ||
| 599 | if (LOG_CPU_COMM && (state->m_audio_result != data)) logerror(" AUD CPU PC %04x: audio_result_w %02x\n", cpu_get_pc(&space->device()), data); | |
| 600 | ||
| 601 | state->m_audio_result = data; | |
| 602 | } | |
| 603 | ||
| 604 | ||
| 605 | static CUSTOM_INPUT( get_audio_result ) | |
| 606 | { | |
| 607 | neogeo_state *state = field.machine().driver_data<neogeo_state>(); | |
| 608 | UINT32 ret = state->m_audio_result; | |
| 609 | ||
| 610 | // if (LOG_CPU_COMM) logerror("MAIN CPU PC %06x: audio_result_r %02x\n", cpu_get_pc(field.machine().device("maincpu")), ret); | |
| 611 | ||
| 612 | return ret; | |
| 613 | } | |
| 614 | ||
| 615 | ||
| 616 | ||
| 617 | /************************************* | |
| 618 | * | |
| 619 | * Main CPU banking | |
| 620 | * | |
| 621 | *************************************/ | |
| 622 | ||
| 623 | static void _set_main_cpu_vector_table_source( running_machine &machine ) | |
| 624 | { | |
| 625 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 626 | memory_set_bank(machine, NEOGEO_BANK_VECTORS, state->m_main_cpu_vector_table_source); | |
| 627 | } | |
| 628 | ||
| 629 | ||
| 630 | static void set_main_cpu_vector_table_source( running_machine &machine, UINT8 data ) | |
| 631 | { | |
| 632 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 633 | state->m_main_cpu_vector_table_source = data; | |
| 634 | ||
| 635 | _set_main_cpu_vector_table_source(machine); | |
| 636 | } | |
| 637 | ||
| 638 | ||
| 639 | static void _set_main_cpu_bank_address( running_machine &machine ) | |
| 640 | { | |
| 641 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 642 | memory_set_bankptr(machine, NEOGEO_BANK_CARTRIDGE, &machine.region("maincpu")->base()[state->m_main_cpu_bank_address]); | |
| 643 | } | |
| 644 | ||
| 645 | #ifdef MESS | |
| 646 | void neogeo_set_main_cpu_bank_address( address_space *space, UINT32 bank_address ) | |
| 647 | { | |
| 648 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 649 | ||
| 650 | if (LOG_MAIN_CPU_BANKING) logerror("MAIN CPU PC %06x: neogeo_set_main_cpu_bank_address %06x\n", cpu_get_pc(&space->device()), bank_address); | |
| 651 | ||
| 652 | state->m_main_cpu_bank_address = bank_address; | |
| 653 | ||
| 654 | _set_main_cpu_bank_address(space->machine()); | |
| 655 | } | |
| 656 | #endif | |
| 657 | ||
| 658 | static WRITE16_HANDLER( main_cpu_bank_select_w ) | |
| 659 | { | |
| 660 | UINT32 bank_address; | |
| 661 | UINT32 len = space->machine().region("maincpu")->bytes(); | |
| 662 | ||
| 663 | if ((len <= 0x100000) && (data & 0x07)) | |
| 664 | logerror("PC %06x: warning: bankswitch to %02x but no banks available\n", cpu_get_pc(&space->device()), data); | |
| 665 | else | |
| 666 | { | |
| 667 | bank_address = ((data & 0x07) + 1) * 0x100000; | |
| 668 | ||
| 669 | if (bank_address >= len) | |
| 670 | { | |
| 671 | logerror("PC %06x: warning: bankswitch to empty bank %02x\n", cpu_get_pc(&space->device()), data); | |
| 672 | bank_address = 0x100000; | |
| 673 | } | |
| 674 | ||
| 675 | neogeo_set_main_cpu_bank_address(space, bank_address); | |
| 676 | } | |
| 677 | } | |
| 678 | ||
| 679 | ||
| 680 | static void main_cpu_banking_init( running_machine &machine ) | |
| 681 | { | |
| 682 | address_space *mainspace = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 683 | ||
| 684 | /* create vector banks */ | |
| 685 | memory_configure_bank(machine, NEOGEO_BANK_VECTORS, 0, 1, machine.region("mainbios")->base(), 0); | |
| 686 | memory_configure_bank(machine, NEOGEO_BANK_VECTORS, 1, 1, machine.region("maincpu")->base(), 0); | |
| 687 | ||
| 688 | /* set initial main CPU bank */ | |
| 689 | if (machine.region("maincpu")->bytes() > 0x100000) | |
| 690 | neogeo_set_main_cpu_bank_address(mainspace, 0x100000); | |
| 691 | else | |
| 692 | neogeo_set_main_cpu_bank_address(mainspace, 0x000000); | |
| 693 | } | |
| 694 | ||
| 695 | ||
| 696 | ||
| 697 | /************************************* | |
| 698 | * | |
| 699 | * Audio CPU banking | |
| 700 | * | |
| 701 | *************************************/ | |
| 702 | ||
| 703 | static void set_audio_cpu_banking( running_machine &machine ) | |
| 704 | { | |
| 705 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 706 | int region; | |
| 707 | ||
| 708 | for (region = 0; region < 4; region++) | |
| 709 | memory_set_bank(machine, NEOGEO_BANK_AUDIO_CPU_CART_BANK + region, state->m_audio_cpu_banks[region]); | |
| 710 | } | |
| 711 | ||
| 712 | ||
| 713 | static void audio_cpu_bank_select( address_space *space, int region, UINT8 bank ) | |
| 714 | { | |
| 715 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 716 | ||
| 717 | if (LOG_AUDIO_CPU_BANKING) logerror("Audio CPU PC %03x: audio_cpu_bank_select: Region: %d Bank: %02x\n", cpu_get_pc(&space->device()), region, bank); | |
| 718 | ||
| 719 | state->m_audio_cpu_banks[region] = bank; | |
| 720 | ||
| 721 | set_audio_cpu_banking(space->machine()); | |
| 722 | } | |
| 723 | ||
| 724 | ||
| 725 | static READ8_HANDLER( audio_cpu_bank_select_f000_f7ff_r ) | |
| 726 | { | |
| 727 | audio_cpu_bank_select(space, 0, offset >> 8); | |
| 728 | ||
| 729 | return 0; | |
| 730 | } | |
| 731 | ||
| 732 | ||
| 733 | static READ8_HANDLER( audio_cpu_bank_select_e000_efff_r ) | |
| 734 | { | |
| 735 | audio_cpu_bank_select(space, 1, offset >> 8); | |
| 736 | ||
| 737 | return 0; | |
| 738 | } | |
| 739 | ||
| 740 | ||
| 741 | static READ8_HANDLER( audio_cpu_bank_select_c000_dfff_r ) | |
| 742 | { | |
| 743 | audio_cpu_bank_select(space, 2, offset >> 8); | |
| 744 | ||
| 745 | return 0; | |
| 746 | } | |
| 747 | ||
| 748 | ||
| 749 | static READ8_HANDLER( audio_cpu_bank_select_8000_bfff_r ) | |
| 750 | { | |
| 751 | audio_cpu_bank_select(space, 3, offset >> 8); | |
| 752 | ||
| 753 | return 0; | |
| 754 | } | |
| 755 | ||
| 756 | ||
| 757 | static void _set_audio_cpu_rom_source( address_space *space ) | |
| 758 | { | |
| 759 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 760 | ||
| 761 | /* if (!machine.region("audiobios")->base()) */ | |
| 762 | state->m_audio_cpu_rom_source = 1; | |
| 763 | ||
| 764 | memory_set_bank(space->machine(), NEOGEO_BANK_AUDIO_CPU_MAIN_BANK, state->m_audio_cpu_rom_source); | |
| 765 | ||
| 766 | /* reset CPU if the source changed -- this is a guess */ | |
| 767 | if (state->m_audio_cpu_rom_source != state->m_audio_cpu_rom_source_last) | |
| 768 | { | |
| 769 | state->m_audio_cpu_rom_source_last = state->m_audio_cpu_rom_source; | |
| 770 | ||
| 771 | cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_RESET, PULSE_LINE); | |
| 772 | ||
| 773 | if (LOG_AUDIO_CPU_BANKING) logerror("Audio CPU PC %03x: selectign %s ROM\n", cpu_get_pc(&space->device()), state->m_audio_cpu_rom_source ? "CARTRIDGE" : "BIOS"); | |
| 774 | } | |
| 775 | } | |
| 776 | ||
| 777 | ||
| 778 | static void set_audio_cpu_rom_source( address_space *space, UINT8 data ) | |
| 779 | { | |
| 780 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 781 | state->m_audio_cpu_rom_source = data; | |
| 782 | ||
| 783 | _set_audio_cpu_rom_source(space); | |
| 784 | } | |
| 785 | ||
| 786 | ||
| 787 | static void audio_cpu_banking_init( running_machine &machine ) | |
| 788 | { | |
| 789 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 790 | int region; | |
| 791 | int bank; | |
| 792 | UINT8 *rgn; | |
| 793 | UINT32 address_mask; | |
| 794 | ||
| 795 | /* audio bios/cartridge selection */ | |
| 796 | if (machine.region("audiobios")->base()) | |
| 797 | memory_configure_bank(machine, NEOGEO_BANK_AUDIO_CPU_MAIN_BANK, 0, 1, machine.region("audiobios")->base(), 0); | |
| 798 | memory_configure_bank(machine, NEOGEO_BANK_AUDIO_CPU_MAIN_BANK, 1, 1, machine.region("audiocpu")->base(), 0); | |
| 799 | ||
| 800 | /* audio banking */ | |
| 801 | address_mask = machine.region("audiocpu")->bytes() - 0x10000 - 1; | |
| 802 | ||
| 803 | rgn = machine.region("audiocpu")->base(); | |
| 804 | for (region = 0; region < 4; region++) | |
| 805 | { | |
| 806 | for (bank = 0; bank < 0x100; bank++) | |
| 807 | { | |
| 808 | UINT32 bank_address = 0x10000 + (((bank << (11 + region)) & 0x3ffff) & address_mask); | |
| 809 | memory_configure_bank(machine, NEOGEO_BANK_AUDIO_CPU_CART_BANK + region, bank, 1, &rgn[bank_address], 0); | |
| 810 | } | |
| 811 | } | |
| 812 | ||
| 813 | /* set initial audio banks -- | |
| 814 | how does this really work, or is it even neccessary? */ | |
| 815 | state->m_audio_cpu_banks[0] = 0x1e; | |
| 816 | state->m_audio_cpu_banks[1] = 0x0e; | |
| 817 | state->m_audio_cpu_banks[2] = 0x06; | |
| 818 | state->m_audio_cpu_banks[3] = 0x02; | |
| 819 | ||
| 820 | set_audio_cpu_banking(machine); | |
| 821 | ||
| 822 | state->m_audio_cpu_rom_source_last = 0; | |
| 823 | set_audio_cpu_rom_source(machine.device("maincpu")->memory().space(AS_PROGRAM), 0); | |
| 824 | } | |
| 825 | ||
| 826 | ||
| 827 | ||
| 828 | /************************************* | |
| 829 | * | |
| 830 | * System control register | |
| 831 | * | |
| 832 | *************************************/ | |
| 833 | ||
| 834 | static WRITE16_HANDLER( system_control_w ) | |
| 835 | { | |
| 836 | if (ACCESSING_BITS_0_7) | |
| 837 | { | |
| 838 | UINT8 bit = (offset >> 3) & 0x01; | |
| 839 | ||
| 840 | switch (offset & 0x07) | |
| 841 | { | |
| 842 | default: | |
| 843 | case 0x00: neogeo_set_screen_dark(space->machine(), bit); break; | |
| 844 | case 0x01: set_main_cpu_vector_table_source(space->machine(), bit); | |
| 845 | set_audio_cpu_rom_source(space, bit); /* this is a guess */ | |
| 846 | break; | |
| 847 | case 0x05: neogeo_set_fixed_layer_source(space->machine(), bit); break; | |
| 848 | // case 0x06: set_save_ram_unlock(space->machine(), bit); break; | |
| 849 | case 0x07: neogeo_set_palette_bank(space->machine(), bit); break; | |
| 850 | ||
| 851 | case 0x02: /* unknown - HC32 middle pin 1 */ | |
| 852 | case 0x03: /* unknown - uPD4990 pin ? */ | |
| 853 | case 0x04: /* unknown - HC32 middle pin 10 */ | |
| 854 | logerror("PC: %x Unmapped system control write. Offset: %x Data: %x\n", cpu_get_pc(&space->device()), offset & 0x07, bit); | |
| 855 | break; | |
| 856 | } | |
| 857 | ||
| 858 | if (LOG_VIDEO_SYSTEM && ((offset & 0x07) != 0x06)) logerror("PC: %x System control write. Offset: %x Data: %x\n", cpu_get_pc(&space->device()), offset & 0x07, bit); | |
| 859 | } | |
| 860 | } | |
| 861 | ||
| 862 | /* | |
| 863 | * CD-ROM / DMA control | |
| 864 | * | |
| 865 | * DMA | |
| 866 | ||
| 867 | FF0061 Write 0x40 means start DMA transfer | |
| 868 | FF0064 Source address (in copy mode), Target address (in filll mode) | |
| 869 | FF0068 Target address (in copy mode) | |
| 870 | FF006C Fill word | |
| 871 | FF0070 Words count | |
| 872 | FF007E \ | |
| 873 | ...... | DMA programming words? NeoGeoCD uses Sanyo Puppet LC8359 chip to | |
| 874 | FF008E / interface with CD, and do DMA transfers | |
| 875 | ||
| 876 | Memory access control | |
| 877 | ||
| 878 | FF011C DIP SWITCH (Region code) | |
| 879 | FF0105 Area Selector (5 = FIX, 0 = SPR, 4 = Z80, 1 = PCM) | |
| 880 | FF01A1 Sprite bank selector | |
| 881 | FF01A3 PCM bank selector | |
| 882 | FF0120 Prepare sprite area for transfer | |
| 883 | FF0122 Prepare PCM area for transfer | |
| 884 | FF0126 Prepare Z80 area for transfer | |
| 885 | FF0128 Prepare Fix area for transfer | |
| 886 | FF0140 Terminate work on Spr Area (Sprites must be decoded here) | |
| 887 | FF0142 Terminate work on Pcm Area | |
| 888 | FF0146 Terminate work on Z80 Area (Z80 needs to be reset) | |
| 889 | FF0148 Terminate work on Fix Area | |
| 890 | ||
| 891 | CD-ROM: | |
| 892 | 0xff0102 == 0xF0 start cd transfer | |
| 893 | int m=bcd(fast_r8(0x10f6c8)); | |
| 894 | int s=bcd(fast_r8(0x10f6c9)); | |
| 895 | int f=bcd(fast_r8(0x10f6ca)); | |
| 896 | int seccount=fast_r16(0x10f688); | |
| 897 | ||
| 898 | inisec=((m*60)+s)*75+f; | |
| 899 | inisec-=150; | |
| 900 | dstaddr=0x111204; // this must come from somewhere | |
| 901 | ||
| 902 | the value @ 0x10f688 is decremented each time a sector is read until it's 0. | |
| 903 | ||
| 904 | * | |
| 905 | */ | |
| 906 | ||
| 907 | static void neocd_do_dma(address_space* space) | |
| 908 | { | |
| 909 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 910 | // TODO: Proper DMA timing and control | |
| 911 | int count; | |
| 912 | // UINT16 word; | |
| 913 | ||
| 914 | switch(state->m_neocd_ctrl.dma_mode[0]) | |
| 915 | { | |
| 916 | case 0xffdd: | |
| 917 | for(count=0;count<state->m_neocd_ctrl.word_count;count++) | |
| 918 | { | |
| 919 | //word = space->read_word(state->m_neocd_ctrl.addr_source); | |
| 920 | space->write_word(state->m_neocd_ctrl.addr_source+(count*2),state->m_neocd_ctrl.fill_word); | |
| 921 | } | |
| 922 | logerror("CTRL: DMA word-fill transfer of %i bytes\n",count*2); | |
| 923 | break; | |
| 924 | case 0xfef5: | |
| 925 | for(count=0;count<state->m_neocd_ctrl.word_count;count++) | |
| 926 | { | |
| 927 | //word = space->read_word(state->m_neocd_ctrl.addr_source); | |
| 928 | space->write_word(state->m_neocd_ctrl.addr_source+(count*4),(state->m_neocd_ctrl.addr_source+(count*4)) >> 16); | |
| 929 | space->write_word(state->m_neocd_ctrl.addr_source+(count*4)+2,(state->m_neocd_ctrl.addr_source+(count*4)) & 0xffff); | |
| 930 | } | |
| 931 | logerror("CTRL: DMA mode 2 transfer of %i bytes\n",count*4); | |
| 932 | break; | |
| 933 | case 0xcffd: | |
| 934 | for(count=0;count<state->m_neocd_ctrl.word_count;count++) | |
| 935 | { | |
| 936 | //word = space->read_word(state->m_neocd_ctrl.addr_source); | |
| 937 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8),((state->m_neocd_ctrl.addr_source+(count*8)) >> 24) | 0xff00); | |
| 938 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8)+2,((state->m_neocd_ctrl.addr_source+(count*8)) >> 16) | 0xff00); | |
| 939 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8)+4,((state->m_neocd_ctrl.addr_source+(count*8)) >> 8) | 0xff00); | |
| 940 | space->write_word(state->m_neocd_ctrl.addr_source+(count*8)+6,(state->m_neocd_ctrl.addr_source+(count*8)) | 0xff00); | |
| 941 | } | |
| 942 | logerror("CTRL: DMA mode 3 transfer of %i bytes\n",count*8); | |
| 943 | break; | |
| 944 | default: | |
| 945 | logerror("CTRL: Unknown DMA transfer mode %04x\n",state->m_neocd_ctrl.dma_mode[0]); | |
| 946 | } | |
| 947 | } | |
| 948 | ||
| 949 | static READ16_HANDLER( neocd_control_r ) | |
| 950 | { | |
| 951 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 952 | ||
| 953 | switch(offset) | |
| 954 | { | |
| 955 | case 0x64/2: // source address, high word | |
| 956 | return (state->m_neocd_ctrl.addr_source >> 16) & 0xffff; | |
| 957 | case 0x66/2: // source address, low word | |
| 958 | return state->m_neocd_ctrl.addr_source & 0xffff; | |
| 959 | case 0x68/2: // target address, high word | |
| 960 | return (state->m_neocd_ctrl.addr_target >> 16) & 0xffff; | |
| 961 | case 0x6a/2: // target address, low word | |
| 962 | return state->m_neocd_ctrl.addr_target & 0xffff; | |
| 963 | case 0x6c/2: // fill word | |
| 964 | return state->m_neocd_ctrl.fill_word; | |
| 965 | case 0x70/2: // word count | |
| 966 | return (state->m_neocd_ctrl.word_count >> 16) & 0xffff; | |
| 967 | case 0x72/2: | |
| 968 | return state->m_neocd_ctrl.word_count & 0xffff; | |
| 969 | case 0x7e/2: // DMA parameters | |
| 970 | case 0x80/2: | |
| 971 | case 0x82/2: | |
| 972 | case 0x84/2: | |
| 973 | case 0x86/2: | |
| 974 | case 0x88/2: | |
| 975 | case 0x8a/2: | |
| 976 | case 0x8c/2: | |
| 977 | case 0x8e/2: | |
| 978 | return state->m_neocd_ctrl.dma_mode[offset-(0x7e/2)]; | |
| 979 | break; | |
| 980 | case 0x105/2: | |
| 981 | return state->m_neocd_ctrl.area_sel; | |
| 982 | case 0x11c/2: | |
| 983 | logerror("CTRL: Read region code.\n"); | |
| 984 | return 0x0600; // we'll just force USA region for now | |
| 985 | case 0x1a0/2: | |
| 986 | return state->m_neocd_ctrl.spr_bank_sel; | |
| 987 | break; | |
| 988 | case 0x1a2/2: | |
| 989 | return state->m_neocd_ctrl.pcm_bank_sel; | |
| 990 | break; | |
| 991 | default: | |
| 992 | logerror("CTRL: Read offset %04x\n",offset); | |
| 993 | } | |
| 994 | ||
| 995 | return 0; | |
| 996 | } | |
| 997 | ||
| 998 | static WRITE16_HANDLER( neocd_control_w ) | |
| 999 | { | |
| 1000 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 1001 | switch(offset) | |
| 1002 | { | |
| 1003 | case 0x60/2: // Start DMA transfer | |
| 1004 | if((data & 0xff) == 0x40) | |
| 1005 | neocd_do_dma(space); | |
| 1006 | break; | |
| 1007 | case 0x64/2: // source address, high word | |
| 1008 | state->m_neocd_ctrl.addr_source = (state->m_neocd_ctrl.addr_source & 0x0000ffff) | (data << 16); | |
| 1009 | logerror("CTRL: Set source address to %08x\n",state->m_neocd_ctrl.addr_source); | |
| 1010 | break; | |
| 1011 | case 0x66/2: // source address, low word | |
| 1012 | state->m_neocd_ctrl.addr_source = (state->m_neocd_ctrl.addr_source & 0xffff0000) | data; | |
| 1013 | logerror("CTRL: Set source address to %08x\n",state->m_neocd_ctrl.addr_source); | |
| 1014 | break; | |
| 1015 | case 0x68/2: // target address, high word | |
| 1016 | state->m_neocd_ctrl.addr_target = (state->m_neocd_ctrl.addr_target & 0x0000ffff) | (data << 16); | |
| 1017 | logerror("CTRL: Set target address to %08x\n",state->m_neocd_ctrl.addr_target); | |
| 1018 | break; | |
| 1019 | case 0x6a/2: // target address, low word | |
| 1020 | state->m_neocd_ctrl.addr_target = (state->m_neocd_ctrl.addr_target & 0xffff0000) | data; | |
| 1021 | logerror("CTRL: Set target address to %08x\n",state->m_neocd_ctrl.addr_target); | |
| 1022 | break; | |
| 1023 | case 0x6c/2: // fill word | |
| 1024 | state->m_neocd_ctrl.fill_word = data; | |
| 1025 | logerror("CTRL: Set fill word to %04x\n",data); | |
| 1026 | break; | |
| 1027 | case 0x70/2: // word count | |
| 1028 | state->m_neocd_ctrl.word_count = (state->m_neocd_ctrl.word_count & 0x0000ffff) | (data << 16); | |
| 1029 | logerror("CTRL: Set word count to %i\n",state->m_neocd_ctrl.word_count); | |
| 1030 | break; | |
| 1031 | case 0x72/2: // word count (low word) | |
| 1032 | state->m_neocd_ctrl.word_count = (state->m_neocd_ctrl.word_count & 0xffff0000) | data; | |
| 1033 | logerror("CTRL: Set word count to %i\n",state->m_neocd_ctrl.word_count); | |
| 1034 | break; | |
| 1035 | case 0x7e/2: // DMA parameters | |
| 1036 | case 0x80/2: | |
| 1037 | case 0x82/2: | |
| 1038 | case 0x84/2: | |
| 1039 | case 0x86/2: | |
| 1040 | case 0x88/2: | |
| 1041 | case 0x8a/2: | |
| 1042 | case 0x8c/2: | |
| 1043 | case 0x8e/2: | |
| 1044 | state->m_neocd_ctrl.dma_mode[offset-(0x7e/2)] = data; | |
| 1045 | logerror("CTRL: DMA parameter %i set to %04x\n",offset-(0x7e/2),data); | |
| 1046 | break; | |
| 1047 | case 0x104/2: | |
| 1048 | state->m_neocd_ctrl.area_sel = data & 0x00ff; | |
| 1049 | logerror("CTRL: 0xExxxxx set to area %i\n",data & 0xff); | |
| 1050 | break; | |
| 1051 | case 0x140/2: // end sprite transfer | |
| 1052 | video_reset_neogeo(space->machine()); | |
| 1053 | break; | |
| 1054 | case 0x142/2: // end PCM transfer | |
| 1055 | break; | |
| 1056 | case 0x146/2: // end Z80 transfer | |
| 1057 | cputag_set_input_line(space->machine(),"audiocpu",INPUT_LINE_RESET,PULSE_LINE); | |
| 1058 | break; | |
| 1059 | case 0x148/2: // end FIX transfer | |
| 1060 | video_reset_neogeo(space->machine()); | |
| 1061 | break; | |
| 1062 | case 0x1a0/2: | |
| 1063 | state->m_neocd_ctrl.spr_bank_sel = data & 0xff; | |
| 1064 | logerror("CTRL: Sprite area set to bank %i\n",data & 0xff); | |
| 1065 | break; | |
| 1066 | case 0x1a2/2: | |
| 1067 | state->m_neocd_ctrl.pcm_bank_sel = data & 0xff; | |
| 1068 | logerror("CTRL: PCM area set to bank %i\n",data & 0xff); | |
| 1069 | break; | |
| 1070 | default: | |
| 1071 | logerror("CTRL: Write offset %04x, data %04x\n",offset*2,data); | |
| 1072 | } | |
| 1073 | } | |
| 1074 | ||
| 1075 | /* | |
| 1076 | * Handling NeoCD banked RAM | |
| 1077 | * When the Z80 space is banked in to 0xe00000, only the low byte of each word is used | |
| 1078 | */ | |
| 1079 | ||
| 1080 | static READ16_HANDLER(neocd_transfer_r) | |
| 1081 | { | |
| 1082 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 1083 | UINT16 ret = 0x0000; | |
| 1084 | UINT8* Z80 = space->machine().region("audiocpu")->base(); | |
| 1085 | UINT8* PCM = space->machine().region("ymsnd")->base(); | |
| 1086 | UINT8* FIX = space->machine().region("fixed")->base(); | |
| 1087 | UINT16* SPR = (UINT16*)space->machine().region("sprites")->base(); | |
| 1088 | ||
| 1089 | switch(state->m_neocd_ctrl.area_sel) | |
| 1090 | { | |
| 1091 | case NEOCD_AREA_AUDIO: | |
| 1092 | ret = Z80[offset & 0xffff] | 0xff00; | |
| 1093 | break; | |
| 1094 | case NEOCD_AREA_PCM: | |
| 1095 | ret = PCM[offset + (0x100000*state->m_neocd_ctrl.pcm_bank_sel)] | 0xff00; | |
| 1096 | break; | |
| 1097 | case NEOCD_AREA_SPR: | |
| 1098 | ret = SPR[offset + (0x80000*state->m_neocd_ctrl.spr_bank_sel)]; | |
| 1099 | break; | |
| 1100 | case NEOCD_AREA_FIX: | |
| 1101 | ret = FIX[offset & 0x1ffff] | 0xff00; | |
| 1102 | break; | |
| 1103 | } | |
| 1104 | ||
| 1105 | return ret; | |
| 1106 | } | |
| 1107 | ||
| 1108 | static WRITE16_HANDLER(neocd_transfer_w) | |
| 1109 | { | |
| 1110 | ng_aes_state *state = space->machine().driver_data<ng_aes_state>(); | |
| 1111 | UINT8* Z80 = space->machine().region("audiocpu")->base(); | |
| 1112 | UINT8* PCM = space->machine().region("ymsnd")->base(); | |
| 1113 | UINT8* FIX = space->machine().region("fixed")->base(); | |
| 1114 | UINT16* SPR = (UINT16*)space->machine().region("sprites")->base(); | |
| 1115 | ||
| 1116 | switch(state->m_neocd_ctrl.area_sel) | |
| 1117 | { | |
| 1118 | case NEOCD_AREA_AUDIO: | |
| 1119 | Z80[offset & 0xffff] = data & 0xff; | |
| 1120 | break; | |
| 1121 | case NEOCD_AREA_PCM: | |
| 1122 | PCM[offset + (0x100000*state->m_neocd_ctrl.pcm_bank_sel)] = data & 0xff; | |
| 1123 | break; | |
| 1124 | case NEOCD_AREA_SPR: | |
| 1125 | COMBINE_DATA(SPR+(offset + (0x80000*state->m_neocd_ctrl.spr_bank_sel))); | |
| 1126 | break; | |
| 1127 | case NEOCD_AREA_FIX: | |
| 1128 | FIX[offset & 0x1ffff] = data & 0xff; | |
| 1129 | break; | |
| 1130 | } | |
| 1131 | ||
| 1132 | } | |
| 1133 | ||
| 1134 | /* | |
| 1135 | * Handling selectable controller types | |
| 1136 | */ | |
| 1137 | ||
| 1138 | static READ16_HANDLER( aes_in0_r ) | |
| 1139 | { | |
| 1140 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 1141 | UINT32 ret = 0xffff; | |
| 1142 | UINT32 ctrl = input_port_read(space->machine(),"CTRLSEL"); | |
| 1143 | ||
| 1144 | switch(ctrl & 0x0f) | |
| 1145 | { | |
| 1146 | case 0x00: | |
| 1147 | ret = 0xffff; | |
| 1148 | break; | |
| 1149 | case 0x01: | |
| 1150 | ret = input_port_read(space->machine(),"IN0"); | |
| 1151 | break; | |
| 1152 | case 0x02: | |
| 1153 | switch (state->m_controller_select) | |
| 1154 | { | |
| 1155 | case 0x09: ret = input_port_read(space->machine(), "MJ01_P1"); break; | |
| 1156 | case 0x12: ret = input_port_read(space->machine(), "MJ02_P1"); break; | |
| 1157 | case 0x1b: ret = input_port_read(space->machine(), "MJ03_P1"); break; /* player 1 normal inputs? */ | |
| 1158 | case 0x24: ret = input_port_read(space->machine(), "MJ04_P1"); break; | |
| 1159 | default: | |
| 1160 | ret = input_port_read(space->machine(),"IN0"); | |
| 1161 | break; | |
| 1162 | } | |
| 1163 | break; | |
| 1164 | } | |
| 1165 | ||
| 1166 | return ret; | |
| 1167 | } | |
| 1168 | ||
| 1169 | static READ16_HANDLER( aes_in1_r ) | |
| 1170 | { | |
| 1171 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 1172 | UINT32 ret = 0xffff; | |
| 1173 | UINT32 ctrl = input_port_read(space->machine(),"CTRLSEL"); | |
| 1174 | ||
| 1175 | switch(ctrl & 0xf0) | |
| 1176 | { | |
| 1177 | case 0x00: | |
| 1178 | ret = 0xffff; | |
| 1179 | break; | |
| 1180 | case 0x10: | |
| 1181 | ret = input_port_read(space->machine(),"IN1"); | |
| 1182 | break; | |
| 1183 | case 0x20: | |
| 1184 | switch (state->m_controller_select) | |
| 1185 | { | |
| 1186 | case 0x09: ret = input_port_read(space->machine(), "MJ01_P2"); break; | |
| 1187 | case 0x12: ret = input_port_read(space->machine(), "MJ02_P2"); break; | |
| 1188 | case 0x1b: ret = input_port_read(space->machine(), "MJ03_P2"); break; /* player 2 normal inputs? */ | |
| 1189 | case 0x24: ret = input_port_read(space->machine(), "MJ04_P2"); break; | |
| 1190 | default: | |
| 1191 | ret = input_port_read(space->machine(),"IN1"); | |
| 1192 | break; | |
| 1193 | } | |
| 1194 | break; | |
| 1195 | } | |
| 1196 | ||
| 1197 | return ret; | |
| 1198 | } | |
| 1199 | ||
| 1200 | ||
| 1201 | static READ16_HANDLER(aes_in2_r) | |
| 1202 | { | |
| 1203 | UINT32 in2 = input_port_read(space->machine(),"IN2"); | |
| 1204 | UINT32 ret = in2; | |
| 1205 | UINT32 sel = input_port_read(space->machine(),"CTRLSEL"); | |
| 1206 | neogeo_state *state = space->machine().driver_data<neogeo_state>(); | |
| 1207 | ||
| 1208 | if((sel & 0x02) && (state->m_controller_select == 0x24)) | |
| 1209 | ret ^= 0x0200; | |
| 1210 | ||
| 1211 | if((sel & 0x20) && (state->m_controller_select == 0x24)) | |
| 1212 | ret ^= 0x0800; | |
| 1213 | ||
| 1214 | return ret; | |
| 1215 | } | |
| 1216 | ||
| 1217 | ||
| 1218 | /************************************* | |
| 1219 | * | |
| 1220 | * Machine initialization | |
| 1221 | * | |
| 1222 | *************************************/ | |
| 1223 | ||
| 1224 | static void aes_postload(neogeo_state *state) | |
| 1225 | { | |
| 1226 | _set_main_cpu_bank_address(state->machine()); | |
| 1227 | _set_main_cpu_vector_table_source(state->machine()); | |
| 1228 | set_audio_cpu_banking(state->machine()); | |
| 1229 | _set_audio_cpu_rom_source(state->machine().device("maincpu")->memory().space(AS_PROGRAM)); | |
| 1230 | } | |
| 1231 | ||
| 1232 | static void common_machine_start(running_machine &machine) | |
| 1233 | { | |
| 1234 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 1235 | ||
| 1236 | /* set the BIOS bank */ | |
| 1237 | memory_set_bankptr(machine, NEOGEO_BANK_BIOS, machine.region("mainbios")->base()); | |
| 1238 | ||
| 1239 | /* set the initial main CPU bank */ | |
| 1240 | main_cpu_banking_init(machine); | |
| 1241 | ||
| 1242 | /* set the initial audio CPU ROM banks */ | |
| 1243 | audio_cpu_banking_init(machine); | |
| 1244 | ||
| 1245 | create_interrupt_timers(machine); | |
| 1246 | ||
| 1247 | /* start with an IRQ3 - but NOT on a reset */ | |
| 1248 | state->m_irq3_pending = 1; | |
| 1249 | ||
| 1250 | /* get devices */ | |
| 1251 | state->m_maincpu = machine.device("maincpu"); | |
| 1252 | state->m_audiocpu = machine.device("audiocpu"); | |
| 1253 | state->m_upd4990a = machine.device("upd4990a"); | |
| 1254 | ||
| 1255 | /* register state save */ | |
| 1256 | state->save_item(NAME(state->m_display_position_interrupt_control)); | |
| 1257 | state->save_item(NAME(state->m_display_counter)); | |
| 1258 | state->save_item(NAME(state->m_vblank_interrupt_pending)); | |
| 1259 | state->save_item(NAME(state->m_display_position_interrupt_pending)); | |
| 1260 | state->save_item(NAME(state->m_irq3_pending)); | |
| 1261 | state->save_item(NAME(state->m_audio_result)); | |
| 1262 | state->save_item(NAME(state->m_controller_select)); | |
| 1263 | state->save_item(NAME(state->m_main_cpu_bank_address)); | |
| 1264 | state->save_item(NAME(state->m_main_cpu_vector_table_source)); | |
| 1265 | state->save_item(NAME(state->m_audio_cpu_banks)); | |
| 1266 | state->save_item(NAME(state->m_audio_cpu_rom_source)); | |
| 1267 | state->save_item(NAME(state->m_audio_cpu_rom_source_last)); | |
| 1268 | state->save_item(NAME(state->m_save_ram_unlocked)); | |
| 1269 | state->save_item(NAME(state->m_output_data)); | |
| 1270 | state->save_item(NAME(state->m_output_latch)); | |
| 1271 | state->save_item(NAME(state->m_el_value)); | |
| 1272 | state->save_item(NAME(state->m_led1_value)); | |
| 1273 | state->save_item(NAME(state->m_led2_value)); | |
| 1274 | state->save_item(NAME(state->m_recurse)); | |
| 1275 | ||
| 1276 | machine.save().register_postload(save_prepost_delegate(FUNC(aes_postload), state)); | |
| 1277 | } | |
| 1278 | ||
| 1279 | static MACHINE_START( neogeo ) | |
| 1280 | { | |
| 1281 | ng_aes_state *state = machine.driver_data<ng_aes_state>(); | |
| 1282 | common_machine_start(machine); | |
| 1283 | ||
| 1284 | /* initialize the memcard data structure */ | |
| 1285 | state->m_memcard_data = auto_alloc_array_clear(machine, UINT8, MEMCARD_SIZE); | |
| 1286 | state->save_pointer(NAME(state->m_memcard_data), 0x0800); | |
| 1287 | } | |
| 1288 | ||
| 1289 | static MACHINE_START(neocd) | |
| 1290 | { | |
| 1291 | ng_aes_state *state = machine.driver_data<ng_aes_state>(); | |
| 1292 | UINT8* ROM = machine.region("mainbios")->base(); | |
| 1293 | UINT8* RAM = machine.region("maincpu")->base(); | |
| 1294 | UINT8* Z80bios = machine.region("audiobios")->base(); | |
| 1295 | UINT8* FIXbios = machine.region("fixedbios")->base(); | |
| 1296 | int x; | |
| 1297 | ||
| 1298 | common_machine_start(machine); | |
| 1299 | ||
| 1300 | /* initialize the memcard data structure */ | |
| 1301 | /* NeoCD doesn't have memcard slots, rather, it has a larger internal memory which works the same */ | |
| 1302 | state->m_memcard_data = auto_alloc_array_clear(machine, UINT8, 0x2000); | |
| 1303 | state->save_pointer(NAME(state->m_memcard_data), 0x2000); | |
| 1304 | ||
| 1305 | // copy initial 68k vectors into RAM | |
| 1306 | memcpy(RAM,ROM,0x80); | |
| 1307 | ||
| 1308 | // copy Z80 code into Z80 space (from 0x20000) | |
| 1309 | for(x=0;x<0x10000;x+=2) | |
| 1310 | { | |
| 1311 | Z80bios[x] = ROM[x+0x20001]; | |
| 1312 | Z80bios[x+1] = ROM[x+0x20000]; | |
| 1313 | } | |
| 1314 | ||
| 1315 | // copy fixed tiles into FIX space (from 0x70000) | |
| 1316 | memcpy(FIXbios,ROM+0x70000,0x10000); | |
| 1317 | } | |
| 1318 | ||
| 1319 | //static DEVICE_IMAGE_LOAD(aes_cart) | |
| 1320 | //{ | |
| 1321 | // else | |
| 1322 | // return IMAGE_INIT_FAIL; | |
| 1323 | ||
| 1324 | // return IMAGE_INIT_PASS; | |
| 1325 | //} | |
| 1326 | ||
| 1327 | /************************************* | |
| 1328 | * | |
| 1329 | * Machine reset | |
| 1330 | * | |
| 1331 | *************************************/ | |
| 1332 | ||
| 1333 | static MACHINE_RESET( neogeo ) | |
| 1334 | { | |
| 1335 | neogeo_state *state = machine.driver_data<neogeo_state>(); | |
| 1336 | offs_t offs; | |
| 1337 | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); | |
| 1338 | ||
| 1339 | /* reset system control registers */ | |
| 1340 | for (offs = 0; offs < 8; offs++) | |
| 1341 | system_control_w(space, offs, 0, 0x00ff); | |
| 1342 | ||
| 1343 | machine.device("maincpu")->reset(); | |
| 1344 | ||
| 1345 | neogeo_reset_rng(machine); | |
| 1346 | ||
| 1347 | start_interrupt_timers(machine); | |
| 1348 | ||
| 1349 | /* trigger the IRQ3 that was set by MACHINE_START */ | |
| 1350 | update_interrupts(machine); | |
| 1351 | ||
| 1352 | state->m_recurse = 0; | |
| 1353 | ||
| 1354 | /* AES apparently always uses the cartridge's fixed bank mode */ | |
| 1355 | neogeo_set_fixed_layer_source(machine,1); | |
| 1356 | } | |
| 1357 | ||
| 1358 | ||
| 1359 | ||
| 1360 | /************************************* | |
| 1361 | * | |
| 1362 | * Main CPU memory handlers | |
| 1363 | * | |
| 1364 | *************************************/ | |
| 1365 | ||
| 1366 | static ADDRESS_MAP_START( main_map, AS_PROGRAM, 16 ) | |
| 1367 | AM_RANGE(0x000000, 0x00007f) AM_ROMBANK(NEOGEO_BANK_VECTORS) | |
| 1368 | AM_RANGE(0x000080, 0x0fffff) AM_ROM | |
| 1369 | AM_RANGE(0x100000, 0x10ffff) AM_MIRROR(0x0f0000) AM_RAM | |
| 1370 | /* some games have protection devices in the 0x200000 region, it appears to map to cart space, not surprising, the ROM is read here too */ | |
| 1371 | AM_RANGE(0x200000, 0x2fffff) AM_ROMBANK(NEOGEO_BANK_CARTRIDGE) | |
| 1372 | AM_RANGE(0x2ffff0, 0x2fffff) AM_WRITE(main_cpu_bank_select_w) | |
| 1373 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ff7e) AM_READ(aes_in0_r) | |
| 1374 | AM_RANGE(0x300080, 0x300081) AM_MIRROR(0x01ff7e) AM_READ_PORT("IN4") | |
| 1375 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ffe0) AM_READ(neogeo_unmapped_r) AM_WRITENOP // AES has no watchdog | |
| 1376 | AM_RANGE(0x320000, 0x320001) AM_MIRROR(0x01fffe) AM_READ_PORT("IN3") AM_WRITE(audio_command_w) | |
| 1377 | AM_RANGE(0x340000, 0x340001) AM_MIRROR(0x01fffe) AM_READ(aes_in1_r) | |
| 1378 | AM_RANGE(0x360000, 0x37ffff) AM_READ(neogeo_unmapped_r) | |
| 1379 | AM_RANGE(0x380000, 0x380001) AM_MIRROR(0x01fffe) AM_READ(aes_in2_r) | |
| 1380 | AM_RANGE(0x380000, 0x38007f) AM_MIRROR(0x01ff80) AM_WRITE(io_control_w) | |
| 1381 | AM_RANGE(0x3a0000, 0x3a001f) AM_MIRROR(0x01ffe0) AM_READWRITE(neogeo_unmapped_r, system_control_w) | |
| 1382 | AM_RANGE(0x3c0000, 0x3c0007) AM_MIRROR(0x01fff8) AM_READ(neogeo_video_register_r) | |
| 1383 | AM_RANGE(0x3c0000, 0x3c000f) AM_MIRROR(0x01fff0) AM_WRITE(neogeo_video_register_w) | |
| 1384 | AM_RANGE(0x3e0000, 0x3fffff) AM_READ(neogeo_unmapped_r) | |
| 1385 | AM_RANGE(0x400000, 0x401fff) AM_MIRROR(0x3fe000) AM_READWRITE(neogeo_paletteram_r, neogeo_paletteram_w) | |
| 1386 | AM_RANGE(0x800000, 0x800fff) AM_READWRITE(memcard_r, memcard_w) | |
| 1387 | AM_RANGE(0xc00000, 0xc1ffff) AM_MIRROR(0x0e0000) AM_ROMBANK(NEOGEO_BANK_BIOS) | |
| 1388 | AM_RANGE(0xd00000, 0xd0ffff) AM_MIRROR(0x0f0000) AM_READ(neogeo_unmapped_r) //AM_RAM_WRITE(save_ram_w) AM_BASE(&save_ram) | |
| 1389 | AM_RANGE(0xe00000, 0xffffff) AM_READ(neogeo_unmapped_r) | |
| 1390 | ADDRESS_MAP_END | |
| 1391 | ||
| 1392 | static ADDRESS_MAP_START( neocd_main_map, AS_PROGRAM, 16 ) | |
| 1393 | AM_RANGE(0x000000, 0x00007f) AM_RAMBANK(NEOGEO_BANK_VECTORS) | |
| 1394 | AM_RANGE(0x000080, 0x0fffff) AM_RAM | |
| 1395 | AM_RANGE(0x100000, 0x10ffff) AM_MIRROR(0x0f0000) AM_RAM AM_BASE(&neocd_work_ram) | |
| 1396 | /* some games have protection devices in the 0x200000 region, it appears to map to cart space, not surprising, the ROM is read here too */ | |
| 1397 | AM_RANGE(0x200000, 0x2fffff) AM_ROMBANK(NEOGEO_BANK_CARTRIDGE) | |
| 1398 | AM_RANGE(0x2ffff0, 0x2fffff) AM_WRITE(main_cpu_bank_select_w) | |
| 1399 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ff7e) AM_READ(aes_in0_r) | |
| 1400 | AM_RANGE(0x300080, 0x300081) AM_MIRROR(0x01ff7e) AM_READ_PORT("IN4") | |
| 1401 | AM_RANGE(0x300000, 0x300001) AM_MIRROR(0x01ffe0) AM_READ(neogeo_unmapped_r) AM_WRITENOP // AES has no watchdog | |
| 1402 | AM_RANGE(0x320000, 0x320001) AM_MIRROR(0x01fffe) AM_READ_PORT("IN3") AM_WRITE(audio_command_w) | |
| 1403 | AM_RANGE(0x340000, 0x340001) AM_MIRROR(0x01fffe) AM_READ(aes_in1_r) | |
| 1404 | AM_RANGE(0x360000, 0x37ffff) AM_READ(neogeo_unmapped_r) | |
| 1405 | AM_RANGE(0x380000, 0x380001) AM_MIRROR(0x01fffe) AM_READ(aes_in2_r) | |
| 1406 | AM_RANGE(0x380000, 0x38007f) AM_MIRROR(0x01ff80) AM_WRITE(io_control_w) | |
| 1407 | AM_RANGE(0x3a0000, 0x3a001f) AM_MIRROR(0x01ffe0) AM_READWRITE(neogeo_unmapped_r, system_control_w) | |
| 1408 | AM_RANGE(0x3c0000, 0x3c0007) AM_MIRROR(0x01fff8) AM_READ(neogeo_video_register_r) | |
| 1409 | AM_RANGE(0x3c0000, 0x3c000f) AM_MIRROR(0x01fff0) AM_WRITE(neogeo_video_register_w) | |
| 1410 | AM_RANGE(0x3e0000, 0x3fffff) AM_READ(neogeo_unmapped_r) | |
| 1411 | AM_RANGE(0x400000, 0x401fff) AM_MIRROR(0x3fe000) AM_READWRITE(neogeo_paletteram_r, neogeo_paletteram_w) | |
| 1412 | AM_RANGE(0x800000, 0x803fff) AM_READWRITE(neocd_memcard_r, neocd_memcard_w) | |
| 1413 | AM_RANGE(0xc00000, 0xcfffff) AM_ROMBANK(NEOGEO_BANK_BIOS) | |
| 1414 | AM_RANGE(0xd00000, 0xd0ffff) AM_MIRROR(0x0f0000) AM_READ(neogeo_unmapped_r) //AM_RAM_WRITE(save_ram_w) AM_BASE(&save_ram) | |
| 1415 | AM_RANGE(0xe00000, 0xefffff) AM_READWRITE(neocd_transfer_r,neocd_transfer_w) | |
| 1416 | AM_RANGE(0xf00000, 0xfeffff) AM_READ(neogeo_unmapped_r) | |
| 1417 | AM_RANGE(0xff0000, 0xff01ff) AM_READWRITE(neocd_control_r, neocd_control_w) // CDROM / DMA | |
| 1418 | AM_RANGE(0xff0200, 0xffffff) AM_READ(neogeo_unmapped_r) | |
| 1419 | ADDRESS_MAP_END | |
| 1420 | ||
| 1421 | ||
| 1422 | /************************************* | |
| 1423 | * | |
| 1424 | * Audio CPU memory handlers | |
| 1425 | * | |
| 1426 | *************************************/ | |
| 1427 | ||
| 1428 | static ADDRESS_MAP_START( audio_map, AS_PROGRAM, 8 ) | |
| 1429 | AM_RANGE(0x0000, 0x7fff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_MAIN_BANK) | |
| 1430 | AM_RANGE(0x8000, 0xbfff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 3) | |
| 1431 | AM_RANGE(0xc000, 0xdfff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 2) | |
| 1432 | AM_RANGE(0xe000, 0xefff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 1) | |
| 1433 | AM_RANGE(0xf000, 0xf7ff) AM_ROMBANK(NEOGEO_BANK_AUDIO_CPU_CART_BANK + 0) | |
| 1434 | AM_RANGE(0xf800, 0xffff) AM_RAM | |
| 1435 | ADDRESS_MAP_END | |
| 1436 | ||
| 1437 | ||
| 1438 | ||
| 1439 | /************************************* | |
| 1440 | * | |
| 1441 | * Audio CPU port handlers | |
| 1442 | * | |
| 1443 | *************************************/ | |
| 1444 | ||
| 1445 | static ADDRESS_MAP_START( audio_io_map, AS_IO, 8 ) | |
| 1446 | /*AM_RANGE(0x00, 0x00) AM_MIRROR(0xff00) AM_READWRITE(audio_command_r, audio_cpu_clear_nmi_w);*/ /* may not and NMI clear */ | |
| 1447 | AM_RANGE(0x00, 0x00) AM_MIRROR(0xff00) AM_READ(audio_command_r) | |
| 1448 | AM_RANGE(0x04, 0x07) AM_MIRROR(0xff00) AM_DEVREADWRITE("ymsnd", ym2610_r, ym2610_w) | |
| 1449 | AM_RANGE(0x08, 0x08) AM_MIRROR(0xff00) /* write - NMI enable / acknowledge? (the data written doesn't matter) */ | |
| 1450 | AM_RANGE(0x08, 0x08) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_f000_f7ff_r) | |
| 1451 | AM_RANGE(0x09, 0x09) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_e000_efff_r) | |
| 1452 | AM_RANGE(0x0a, 0x0a) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_c000_dfff_r) | |
| 1453 | AM_RANGE(0x0b, 0x0b) AM_MIRROR(0xfff0) AM_MASK(0xfff0) AM_READ(audio_cpu_bank_select_8000_bfff_r) | |
| 1454 | AM_RANGE(0x0c, 0x0c) AM_MIRROR(0xff00) AM_WRITE(audio_result_w) | |
| 1455 | AM_RANGE(0x18, 0x18) AM_MIRROR(0xff00) /* write - NMI disable? (the data written doesn't matter) */ | |
| 1456 | ADDRESS_MAP_END | |
| 1457 | ||
| 1458 | ||
| 1459 | ||
| 1460 | /************************************* | |
| 1461 | * | |
| 1462 | * Audio interface | |
| 1463 | * | |
| 1464 | *************************************/ | |
| 1465 | ||
| 1466 | static const ym2610_interface ym2610_config = | |
| 1467 | { | |
| 1468 | audio_cpu_irq | |
| 1469 | }; | |
| 1470 | ||
| 1471 | ||
| 1472 | ||
| 1473 | /************************************* | |
| 1474 | * | |
| 1475 | * Standard Neo-Geo DIPs and | |
| 1476 | * input port definition | |
| 1477 | * | |
| 1478 | *************************************/ | |
| 1479 | ||
| 1480 | #define STANDARD_DIPS \ | |
| 1481 | PORT_DIPNAME( 0x0001, 0x0001, "Test Switch" ) PORT_DIPLOCATION("SW:1") \ | |
| 1482 | PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) \ | |
| 1483 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1484 | PORT_DIPNAME( 0x0002, 0x0002, "Coin Chutes?" ) PORT_DIPLOCATION("SW:2") \ | |
| 1485 | PORT_DIPSETTING( 0x0000, "1?" ) \ | |
| 1486 | PORT_DIPSETTING( 0x0002, "2?" ) \ | |
| 1487 | PORT_DIPNAME( 0x0004, 0x0004, "Autofire (in some games)" ) PORT_DIPLOCATION("SW:3") \ | |
| 1488 | PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) \ | |
| 1489 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1490 | PORT_DIPNAME( 0x0018, 0x0018, "COMM Setting (Cabinet No.)" ) PORT_DIPLOCATION("SW:4,5") \ | |
| 1491 | PORT_DIPSETTING( 0x0018, "1" ) \ | |
| 1492 | PORT_DIPSETTING( 0x0008, "2" ) \ | |
| 1493 | PORT_DIPSETTING( 0x0010, "3" ) \ | |
| 1494 | PORT_DIPSETTING( 0x0000, "4" ) \ | |
| 1495 | PORT_DIPNAME( 0x0020, 0x0020, "COMM Setting (Link Enable)" ) PORT_DIPLOCATION("SW:6") \ | |
| 1496 | PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) \ | |
| 1497 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1498 | PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW:7") \ | |
| 1499 | PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) \ | |
| 1500 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) \ | |
| 1501 | PORT_DIPNAME( 0x0080, 0x0080, "Freeze" ) PORT_DIPLOCATION("SW:8") \ | |
| 1502 | PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) \ | |
| 1503 | PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1504 | ||
| 1505 | #define STANDARD_IN2 \ | |
| 1506 | PORT_START("IN2") \ | |
| 1507 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) \ | |
| 1508 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_START1 ) \ | |
| 1509 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("1P Select") PORT_CODE(KEYCODE_5) PORT_PLAYER(1) \ | |
| 1510 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_START2 ) \ | |
| 1511 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("2P Select") PORT_CODE(KEYCODE_6) PORT_PLAYER(2) \ | |
| 1512 | PORT_BIT( 0x7000, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(get_memcard_status, NULL) \ | |
| 1513 | PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* Matrimelee expects this bit to be active high when on an AES */ | |
| 1514 | ||
| 1515 | #define STANDARD_IN3 \ | |
| 1516 | PORT_START("IN3") \ | |
| 1517 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED ) /* Coin 1 - AES has no coin slots, it's a console */ \ | |
| 1518 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) /* Coin 2 - AES has no coin slots, it's a console */ \ | |
| 1519 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNUSED ) /* Service Coin - not used, AES is a console */ \ | |
| 1520 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* having this ACTIVE_HIGH causes you to start with 2 credits using USA bios roms */ \ | |
| 1521 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* having this ACTIVE_HIGH causes you to start with 2 credits using USA bios roms */ \ | |
| 1522 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_SPECIAL ) /* what is this? */ \ | |
| 1523 | PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(get_calendar_status, NULL) \ | |
| 1524 | PORT_BIT( 0xff00, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(get_audio_result, NULL) | |
| 1525 | ||
| 1526 | ||
| 1527 | #define STANDARD_IN4 \ | |
| 1528 | PORT_START("IN4") \ | |
| 1529 | PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1530 | PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1531 | PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1532 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1533 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1534 | PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_UNKNOWN ) \ | |
| 1535 | PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_SPECIAL ) /* what is this? - is 0 for 1 or 2 slot MVS (and AES?)*/ \ | |
| 1536 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Enter BIOS") PORT_CODE(KEYCODE_F2) \ | |
| 1537 | PORT_BIT( 0xff00, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1538 | ||
| 1539 | static INPUT_PORTS_START( controller ) | |
| 1540 | PORT_START("IN0") | |
| 1541 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1542 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1543 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1544 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1545 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1546 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1547 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1548 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1549 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_CATEGORY (1) | |
| 1550 | ||
| 1551 | ||
| 1552 | PORT_START("IN1") | |
| 1553 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1554 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1555 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1556 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1557 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1558 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1559 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1560 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1561 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_CATEGORY (2) | |
| 1562 | INPUT_PORTS_END | |
| 1563 | ||
| 1564 | static INPUT_PORTS_START( mjpanel ) | |
| 1565 | PORT_START("MJ01_P1") | |
| 1566 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1567 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_A ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1568 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_B ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1569 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_C ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1570 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_D ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1571 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_E ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1572 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_F ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1573 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_G ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1574 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1575 | ||
| 1576 | PORT_START("MJ02_P1") | |
| 1577 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1578 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_H ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1579 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_I ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1580 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_J ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1581 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_K ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1582 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_L ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1583 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_M ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1584 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_N ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1585 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1586 | ||
| 1587 | PORT_START("MJ03_P1") | |
| 1588 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1589 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1590 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1591 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1592 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1593 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1594 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1595 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1596 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1597 | ||
| 1598 | PORT_START("MJ04_P1") | |
| 1599 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1600 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1601 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1602 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1603 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1604 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) PORT_PLAYER(1) PORT_CATEGORY (3) | |
| 1605 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1606 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1607 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1608 | ||
| 1609 | PORT_START("MJ01_P2") | |
| 1610 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1611 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_A ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1612 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_B ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1613 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_C ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1614 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_D ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1615 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_E ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1616 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_F ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1617 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_G ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1618 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1619 | ||
| 1620 | PORT_START("MJ02_P2") | |
| 1621 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1622 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_H ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1623 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_I ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1624 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_J ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1625 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_K ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1626 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_L ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1627 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_MAHJONG_M ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1628 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_MAHJONG_N ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1629 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1630 | ||
| 1631 | PORT_START("MJ03_P2") | |
| 1632 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1633 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1634 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1635 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1636 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1637 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1638 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1639 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1640 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1641 | ||
| 1642 | PORT_START("MJ04_P2") | |
| 1643 | PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 1644 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1645 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1646 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1647 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1648 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) PORT_PLAYER(2) PORT_CATEGORY (4) | |
| 1649 | PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1650 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1651 | PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) | |
| 1652 | ||
| 1653 | INPUT_PORTS_END | |
| 1654 | ||
| 1655 | static INPUT_PORTS_START( aes ) | |
| 1656 | // was there anyting in place of dipswitch in the home console? | |
| 1657 | /* PORT_START("IN0") | |
| 1658 | PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 1659 | // PORT_DIPNAME( 0x0001, 0x0001, "Test Switch" ) PORT_DIPLOCATION("SW:1") | |
| 1660 | // PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) | |
| 1661 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1662 | // PORT_DIPNAME( 0x0002, 0x0002, "Coin Chutes?" ) PORT_DIPLOCATION("SW:2") | |
| 1663 | // PORT_DIPSETTING( 0x0000, "1?" ) | |
| 1664 | // PORT_DIPSETTING( 0x0002, "2?" ) | |
| 1665 | // PORT_DIPNAME( 0x0004, 0x0000, "Mahjong Control Panel (or Auto Fire)" ) PORT_DIPLOCATION("SW:3") | |
| 1666 | // PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) | |
| 1667 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1668 | // PORT_DIPNAME( 0x0018, 0x0018, "COMM Setting (Cabinet No.)" ) PORT_DIPLOCATION("SW:4,5") | |
| 1669 | // PORT_DIPSETTING( 0x0018, "1" ) | |
| 1670 | // PORT_DIPSETTING( 0x0008, "2" ) | |
| 1671 | // PORT_DIPSETTING( 0x0010, "3" ) | |
| 1672 | // PORT_DIPSETTING( 0x0000, "4" ) | |
| 1673 | // PORT_DIPNAME( 0x0020, 0x0020, "COMM Setting (Link Enable)" ) PORT_DIPLOCATION("SW:6") | |
| 1674 | // PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) | |
| 1675 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1676 | // PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW:7") | |
| 1677 | // PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) | |
| 1678 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1679 | // PORT_DIPNAME( 0x0080, 0x0080, "Freeze" ) PORT_DIPLOCATION("SW:8") | |
| 1680 | // PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) | |
| 1681 | // PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| 1682 | PORT_BIT( 0xff00, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(aes_controller_r, NULL) */ | |
| 1683 | ||
| 1684 | PORT_START("CTRLSEL") /* Select Controller Type */ | |
| 1685 | PORT_CATEGORY_CLASS( 0x0f, 0x01, "P1 Controller") | |
| 1686 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 0 ) | |
| 1687 | PORT_CATEGORY_ITEM( 0x01, "NeoGeo Controller", 1 ) | |
| 1688 | PORT_CATEGORY_ITEM( 0x02, "NeoGeo Mahjong Panel", 3 ) | |
| 1689 | PORT_CATEGORY_CLASS( 0xf0, 0x10, "P2 Controller") | |
| 1690 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 0 ) | |
| 1691 | PORT_CATEGORY_ITEM( 0x10, "NeoGeo Controller", 2 ) | |
| 1692 | PORT_CATEGORY_ITEM( 0x20, "NeoGeo Mahjong Panel", 4 ) | |
| 1693 | ||
| 1694 | PORT_INCLUDE( controller ) | |
| 1695 | ||
| 1696 | PORT_INCLUDE( mjpanel ) | |
| 1697 | ||
| 1698 | // were some of these present in the AES?!? | |
| 1699 | STANDARD_IN2 | |
| 1700 | ||
| 1701 | STANDARD_IN3 | |
| 1702 | ||
| 1703 | STANDARD_IN4 | |
| 1704 | INPUT_PORTS_END | |
| 1705 | ||
| 1706 | ||
| 1707 | ||
| 1708 | /************************************* | |
| 1709 | * | |
| 1710 | * Machine driver | |
| 1711 | * | |
| 1712 | *************************************/ | |
| 1713 | ||
| 1714 | static MACHINE_CONFIG_START( neogeo, ng_aes_state ) | |
| 1715 | ||
| 1716 | /* basic machine hardware */ | |
| 1717 | MCFG_CPU_ADD("maincpu", M68000, NEOGEO_MAIN_CPU_CLOCK) | |
| 1718 | MCFG_CPU_PROGRAM_MAP(main_map) | |
| 1719 | ||
| 1720 | MCFG_CPU_ADD("audiocpu", Z80, NEOGEO_AUDIO_CPU_CLOCK) | |
| 1721 | MCFG_CPU_PROGRAM_MAP(audio_map) | |
| 1722 | MCFG_CPU_IO_MAP(audio_io_map) | |
| 1723 | ||
| 1724 | MCFG_MACHINE_START(neogeo) | |
| 1725 | MCFG_MACHINE_RESET(neogeo) | |
| 1726 | ||
| 1727 | /* video hardware */ | |
| 1728 | MCFG_VIDEO_START(neogeo) | |
| 1729 | MCFG_VIDEO_RESET(neogeo) | |
| 1730 | MCFG_DEFAULT_LAYOUT(layout_neogeo) | |
| 1731 | ||
| 1732 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 1733 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 1734 | MCFG_SCREEN_RAW_PARAMS(NEOGEO_PIXEL_CLOCK, NEOGEO_HTOTAL, NEOGEO_HBEND, NEOGEO_HBSTART, NEOGEO_VTOTAL, NEOGEO_VBEND, NEOGEO_VBSTART) | |
| 1735 | MCFG_SCREEN_UPDATE(neogeo) | |
| 1736 | ||
| 1737 | /* audio hardware */ | |
| 1738 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 1739 | ||
| 1740 | MCFG_SOUND_ADD("ymsnd", YM2610, NEOGEO_YM2610_CLOCK) | |
| 1741 | MCFG_SOUND_CONFIG(ym2610_config) | |
| 1742 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.60) | |
| 1743 | MCFG_SOUND_ROUTE(0, "rspeaker", 0.60) | |
| 1744 | MCFG_SOUND_ROUTE(1, "lspeaker", 1.0) | |
| 1745 | MCFG_SOUND_ROUTE(2, "rspeaker", 1.0) | |
| 1746 | ||
| 1747 | /* NEC uPD4990A RTC */ | |
| 1748 | MCFG_UPD4990A_ADD("upd4990a") | |
| 1749 | MACHINE_CONFIG_END | |
| 1750 | ||
| 1751 | static MACHINE_CONFIG_DERIVED( aes, neogeo ) | |
| 1752 | ||
| 1753 | MCFG_MEMCARD_HANDLER(neogeo) | |
| 1754 | ||
| 1755 | MCFG_AES_CARTRIDGE_ADD("aes_multicart") | |
| 1756 | // MCFG_CARTSLOT_ADD("cart") | |
| 1757 | // MCFG_CARTSLOT_MANDATORY | |
| 1758 | ||
| 1759 | // MCFG_CARTSLOT_LOAD(aes_cart) | |
| 1760 | ||
| 1761 | MCFG_SOFTWARE_LIST_ADD("cart_list","aes") | |
| 1762 | MACHINE_CONFIG_END | |
| 1763 | ||
| 1764 | static MACHINE_CONFIG_DERIVED( neocd, neogeo ) | |
| 1765 | ||
| 1766 | MCFG_CPU_MODIFY("maincpu") | |
| 1767 | MCFG_CPU_PROGRAM_MAP(neocd_main_map) | |
| 1768 | ||
| 1769 | MCFG_MACHINE_START(neocd) | |
| 1770 | MACHINE_CONFIG_END | |
| 1771 | ||
| 1772 | /************************************* | |
| 1773 | * | |
| 1774 | * Driver initalization | |
| 1775 | * | |
| 1776 | *************************************/ | |
| 1777 | ||
| 1778 | static DRIVER_INIT( neogeo ) | |
| 1779 | { | |
| 1780 | } | |
| 1781 | ||
| 1782 | ||
| 1783 | ROM_START( aes ) | |
| 1784 | ROM_REGION16_BE( 0x80000, "mainbios", 0 ) | |
| 1785 | ROM_SYSTEM_BIOS( 0, "jap-aes", "Japan AES" ) | |
| 1786 | ROMX_LOAD("neo-po.bin", 0x00000, 0x020000, CRC(16d0c132) SHA1(4e4a440cae46f3889d20234aebd7f8d5f522e22c), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(1)) /* AES Console (Japan) Bios */ | |
| 1787 | ROM_SYSTEM_BIOS( 1, "asia-aes", "Asia AES" ) | |
| 1788 | ROMX_LOAD("neo-epo.bin", 0x00000, 0x020000, CRC(d27a71f1) SHA1(1b3b22092f30c4d1b2c15f04d1670eb1e9fbea07), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(2)) /* AES Console (Asia?) Bios */ | |
| 1789 | // ROM_SYSTEM_BIOS( 2, "uni-bios_2_3","Universe Bios (Hack, Ver. 2.3)" ) | |
| 1790 | // ROMX_LOAD( "uni-bios_2_3.rom", 0x00000, 0x020000, CRC(27664eb5) SHA1(5b02900a3ccf3df168bdcfc98458136fd2b92ac0), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(3) ) /* Universe Bios v2.3 (hack) */ | |
| 1791 | ||
| 1792 | ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF ) | |
| 1793 | ||
| 1794 | ROM_REGION( 0x20000, "audiobios", 0 ) | |
| 1795 | ROM_LOAD( "sm1.sm1", 0x00000, 0x20000, CRC(94416d67) SHA1(42f9d7ddd6c0931fd64226a60dc73602b2819dcf) ) | |
| 1796 | ||
| 1797 | ROM_REGION( 0x90000, "audiocpu", ROMREGION_ERASEFF ) | |
| 1798 | ||
| 1799 | ROM_REGION( 0x20000, "zoomy", 0 ) | |
| 1800 | ROM_LOAD( "000-lo.lo", 0x00000, 0x20000, CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) ) | |
| 1801 | ||
| 1802 | ROM_REGION( 0x20000, "fixedbios", 0 ) | |
| 1803 | ROM_LOAD( "sfix.sfix", 0x000000, 0x20000, CRC(c2ea0cfd) SHA1(fd4a618cdcdbf849374f0a50dd8efe9dbab706c3) ) | |
| 1804 | ||
| 1805 | ROM_REGION( 0x20000, "fixed", ROMREGION_ERASEFF ) | |
| 1806 | ||
| 1807 | ROM_REGION( 0x1000000, "ymsnd", ROMREGION_ERASEFF ) | |
| 1808 | ||
| 1809 | ROM_REGION( 0x1000000, "ymsnd.deltat", ROMREGION_ERASEFF ) | |
| 1810 | ||
| 1811 | ROM_REGION( 0x900000, "sprites", ROMREGION_ERASEFF ) | |
| 1812 | ROM_END | |
| 1813 | ||
| 1814 | ROM_START( neocd ) | |
| 1815 | ROM_REGION16_BE( 0x100000, "mainbios", 0 ) | |
| 1816 | ROM_LOAD16_WORD_SWAP( "top-sp1.bin", 0x00000, 0x80000, CRC(19f0ad1a) SHA1(b3e2f8467e9a642c122428d075024a9bd1fe0679) ) | |
| 1817 | ||
| 1818 | ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF ) | |
| 1819 | ||
| 1820 | ROM_REGION( 0x100000, "audiobios", ROMREGION_ERASEFF ) | |
| 1821 | ||
| 1822 | ROM_REGION( 0x10000, "audiocpu", ROMREGION_ERASEFF ) | |
| 1823 | ||
| 1824 | ROM_REGION( 0x20000, "zoomy", 0 ) | |
| 1825 | ROM_LOAD( "000-lo.lo", 0x00000, 0x20000, CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) ) | |
| 1826 | ||
| 1827 | ROM_REGION( 0x20000, "fixedbios", ROMREGION_ERASEFF ) | |
| 1828 | ||
| 1829 | ROM_REGION( 0x20000, "fixed", ROMREGION_ERASEFF ) | |
| 1830 | ||
| 1831 | ROM_REGION( 0x400000, "ymsnd", ROMREGION_ERASEFF ) | |
| 1832 | ||
| 1833 | // NO_DELTAT_REGION | |
| 1834 | ||
| 1835 | ROM_REGION( 0x400000, "sprites", ROMREGION_ERASEFF ) | |
| 1836 | ROM_END | |
| 1837 | ||
| 1838 | ROM_START( neocdz ) | |
| 1839 | ROM_REGION16_BE( 0x100000, "mainbios", 0 ) | |
| 1840 | ROM_LOAD16_WORD_SWAP( "neocd.bin", 0x00000, 0x80000, CRC(df9de490) SHA1(7bb26d1e5d1e930515219cb18bcde5b7b23e2eda) ) | |
| 1841 | ||
| 1842 | ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF ) | |
| 1843 | ||
| 1844 | ROM_REGION( 0x20000, "audiobios", ROMREGION_ERASEFF ) | |
| 1845 | ||
| 1846 | ROM_REGION( 0x10000, "audiocpu", ROMREGION_ERASEFF ) | |
| 1847 | ||
| 1848 | ROM_REGION( 0x20000, "zoomy", 0 ) | |
| 1849 | ROM_LOAD( "000-lo.lo", 0x00000, 0x20000, CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) ) | |
| 1850 | ||
| 1851 | ROM_REGION( 0x20000, "fixedbios", ROMREGION_ERASEFF ) | |
| 1852 | ||
| 1853 | ROM_REGION( 0x20000, "fixed", ROMREGION_ERASEFF ) | |
| 1854 | ||
| 1855 | ROM_REGION( 0x400000, "ymsnd", ROMREGION_ERASEFF ) | |
| 1856 | ||
| 1857 | // NO_DELTAT_REGION | |
| 1858 | ||
| 1859 | ROM_REGION( 0x400000, "sprites", ROMREGION_ERASEFF ) | |
| 1860 | ROM_END | |
| 1861 | ||
| 1862 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 1863 | CONS( 1990, aes, 0, 0, aes, aes, neogeo, "SNK", "Neo-Geo AES", 0) | |
| 1864 | CONS( 1994, neocd, aes, 0, neocd, aes, neogeo, "SNK", "Neo-Geo CD", GAME_NOT_WORKING ) | |
| 1865 | CONS( 1996, neocdz, aes, 0, neocd, aes, neogeo, "SNK", "Neo-Geo CDZ", GAME_NOT_WORKING ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | Amiga 1200 | |
| 3 | ||
| 4 | Preliminary MAME driver by Mariusz Wojcieszek | |
| 5 | CD-ROM controller by Ernesto Corvi | |
| 6 | Borrowed by incog for MESS | |
| 7 | ||
| 8 | 2009-05 Fabio Priuli: | |
| 9 | Amiga 1200 support is just sketched (I basically took cd32 and removed Akiko). I connected | |
| 10 | the floppy drive in the same way as in amiga.c but it seems to be not working, since I | |
| 11 | tried to load WB3.1 with no success. However, this problem may be due to anything: maybe | |
| 12 | the floppy code must be connected elsewhere, or the .adf image is broken, or I made some | |
| 13 | stupid mistake in the CIA interfaces. | |
| 14 | Later, it could be wise to re-factor this source and merge the non-AGA code with | |
| 15 | mess/drivers/amiga.c | |
| 16 | */ | |
| 17 | ||
| 18 | #include "emu.h" | |
| 19 | #include "cpu/m68000/m68000.h" | |
| 20 | #include "machine/6526cia.h" | |
| 21 | #include "machine/i2cmem.h" | |
| 22 | #include "machine/amigafdc.h" | |
| 23 | #include "machine/amigakbd.h" | |
| 24 | ||
| 25 | #include "includes/amiga.h" | |
| 26 | #include "includes/cd32.h" | |
| 27 | ||
| 28 | ||
| 29 | ||
| 30 | class ami1200_state : public cd32_state | |
| 31 | { | |
| 32 | public: | |
| 33 | ami1200_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 34 | : cd32_state(mconfig, type, tag) { } | |
| 35 | ||
| 36 | UINT16 potgo_value; | |
| 37 | int cd32_shifter[2]; | |
| 38 | int oldstate[2]; | |
| 39 | }; | |
| 40 | ||
| 41 | ||
| 42 | ||
| 43 | #define A1200PAL_XTAL_X1 XTAL_28_37516MHz | |
| 44 | #define A1200PAL_XTAL_X2 XTAL_4_433619MHz | |
| 45 | ||
| 46 | ||
| 47 | ||
| 48 | static void handle_cd32_joystick_cia(ami1200_state *state, UINT8 pra, UINT8 dra); | |
| 49 | ||
| 50 | static WRITE32_HANDLER( aga_overlay_w ) | |
| 51 | { | |
| 52 | if (ACCESSING_BITS_16_23) | |
| 53 | { | |
| 54 | data = (data >> 16) & 1; | |
| 55 | ||
| 56 | /* switch banks as appropriate */ | |
| 57 | memory_set_bank(space->machine(), "bank1", data & 1); | |
| 58 | ||
| 59 | /* swap the write handlers between ROM and bank 1 based on the bit */ | |
| 60 | if ((data & 1) == 0) | |
| 61 | /* overlay disabled, map RAM on 0x000000 */ | |
| 62 | space->install_write_bank(0x000000, 0x1fffff, "bank1"); | |
| 63 | else | |
| 64 | /* overlay enabled, map Amiga system ROM on 0x000000 */ | |
| 65 | space->unmap_write(0x000000, 0x1fffff); | |
| 66 | } | |
| 67 | } | |
| 68 | ||
| 69 | /************************************* | |
| 70 | * | |
| 71 | * CIA-A port A access: | |
| 72 | * | |
| 73 | * PA7 = game port 1, pin 6 (fire) | |
| 74 | * PA6 = game port 0, pin 6 (fire) | |
| 75 | * PA5 = /RDY (disk ready) | |
| 76 | * PA4 = /TK0 (disk track 00) | |
| 77 | * PA3 = /WPRO (disk write protect) | |
| 78 | * PA2 = /CHNG (disk change) | |
| 79 | * PA1 = /LED (LED, 0=bright / audio filter control) | |
| 80 | * PA0 = MUTE | |
| 81 | * | |
| 82 | *************************************/ | |
| 83 | ||
| 84 | static WRITE8_DEVICE_HANDLER( ami1200_cia_0_porta_w ) | |
| 85 | { | |
| 86 | ami1200_state *state = device->machine().driver_data<ami1200_state>(); | |
| 87 | ||
| 88 | /* bit 2 = Power Led on Amiga */ | |
| 89 | set_led_status(device->machine(), 0, !BIT(data, 1)); | |
| 90 | ||
| 91 | handle_cd32_joystick_cia(state, data, mos6526_r(device, 2)); | |
| 92 | } | |
| 93 | ||
| 94 | /************************************* | |
| 95 | * | |
| 96 | * CIA-A port B access: | |
| 97 | * | |
| 98 | * PB7 = parallel data 7 | |
| 99 | * PB6 = parallel data 6 | |
| 100 | * PB5 = parallel data 5 | |
| 101 | * PB4 = parallel data 4 | |
| 102 | * PB3 = parallel data 3 | |
| 103 | * PB2 = parallel data 2 | |
| 104 | * PB1 = parallel data 1 | |
| 105 | * PB0 = parallel data 0 | |
| 106 | * | |
| 107 | *************************************/ | |
| 108 | ||
| 109 | static READ8_DEVICE_HANDLER( ami1200_cia_0_portb_r ) | |
| 110 | { | |
| 111 | /* parallel port */ | |
| 112 | logerror("%s:CIA0_portb_r\n", device->machine().describe_context()); | |
| 113 | return 0xff; | |
| 114 | } | |
| 115 | ||
| 116 | static WRITE8_DEVICE_HANDLER( ami1200_cia_0_portb_w ) | |
| 117 | { | |
| 118 | /* parallel port */ | |
| 119 | logerror("%s:CIA0_portb_w(%02x)\n", device->machine().describe_context(), data); | |
| 120 | } | |
| 121 | ||
| 122 | static ADDRESS_MAP_START( a1200_map, AS_PROGRAM, 32 ) | |
| 123 | ADDRESS_MAP_UNMAP_HIGH | |
| 124 | AM_RANGE(0x000000, 0x1fffff) AM_RAMBANK("bank1") AM_BASE_SIZE_MEMBER(cd32_state, m_chip_ram, m_chip_ram_size) | |
| 125 | AM_RANGE(0xbfa000, 0xbfa003) AM_WRITE(aga_overlay_w) | |
| 126 | AM_RANGE(0xbfd000, 0xbfefff) AM_READWRITE16(amiga_cia_r, amiga_cia_w, 0xffffffff) | |
| 127 | AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE16(amiga_custom_r, amiga_custom_w, 0xffffffff) AM_BASE_MEMBER(cd32_state, m_custom_regs) | |
| 128 | AM_RANGE(0xe80000, 0xe8ffff) AM_READWRITE16(amiga_autoconfig_r, amiga_autoconfig_w, 0xffffffff) | |
| 129 | AM_RANGE(0xf80000, 0xffffff) AM_ROM AM_REGION("user1", 0) /* Kickstart */ | |
| 130 | ADDRESS_MAP_END | |
| 131 | ||
| 132 | ||
| 133 | //int cd32_input_port_val = 0; | |
| 134 | //int cd32_input_select = 0; | |
| 135 | ||
| 136 | static void cd32_potgo_w(running_machine &machine, UINT16 data) | |
| 137 | { | |
| 138 | ami1200_state *state = machine.driver_data<ami1200_state>(); | |
| 139 | int i; | |
| 140 | ||
| 141 | state->m_potgo_value = state->m_potgo_value & 0x5500; | |
| 142 | state->m_potgo_value |= data & 0xaa00; | |
| 143 | ||
| 144 | for (i = 0; i < 8; i += 2) | |
| 145 | { | |
| 146 | UINT16 dir = 0x0200 << i; | |
| 147 | if (data & dir) | |
| 148 | { | |
| 149 | UINT16 d = 0x0100 << i; | |
| 150 | state->m_potgo_value &= ~d; | |
| 151 | state->m_potgo_value |= data & d; | |
| 152 | } | |
| 153 | } | |
| 154 | for (i = 0; i < 2; i++) | |
| 155 | { | |
| 156 | UINT16 p5dir = 0x0200 << (i * 4); /* output enable P5 */ | |
| 157 | UINT16 p5dat = 0x0100 << (i * 4); /* data P5 */ | |
| 158 | if ((state->m_potgo_value & p5dir) && (state->m_potgo_value & p5dat)) | |
| 159 | state->m_cd32_shifter[i] = 8; | |
| 160 | } | |
| 161 | } | |
| 162 | ||
| 163 | static void handle_cd32_joystick_cia(ami1200_state *state, UINT8 pra, UINT8 dra) | |
| 164 | { | |
| 165 | int i; | |
| 166 | ||
| 167 | for (i = 0; i < 2; i++) | |
| 168 | { | |
| 169 | UINT8 but = 0x40 << i; | |
| 170 | UINT16 p5dir = 0x0200 << (i * 4); /* output enable P5 */ | |
| 171 | UINT16 p5dat = 0x0100 << (i * 4); /* data P5 */ | |
| 172 | if (!(state->m_potgo_value & p5dir) || !(state->m_potgo_value & p5dat)) | |
| 173 | { | |
| 174 | if ((dra & but) && (pra & but) != state->m_oldstate[i]) | |
| 175 | { | |
| 176 | if (!(pra & but)) | |
| 177 | { | |
| 178 | state->m_cd32_shifter[i]--; | |
| 179 | if (state->m_cd32_shifter[i] < 0) | |
| 180 | state->m_cd32_shifter[i] = 0; | |
| 181 | } | |
| 182 | } | |
| 183 | } | |
| 184 | state->m_oldstate[i] = pra & but; | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | ||
| 189 | static INPUT_PORTS_START( a1200 ) | |
| 190 | PORT_START("CIA0PORTA") | |
| 191 | PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_SPECIAL ) | |
| 192 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) | |
| 193 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) | |
| 194 | ||
| 195 | PORT_START("CIA0PORTB") | |
| 196 | PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 197 | ||
| 198 | PORT_START("JOY0DAT") | |
| 199 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P1JOY") | |
| 200 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 201 | ||
| 202 | PORT_START("JOY1DAT") | |
| 203 | PORT_BIT( 0x0303, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(amiga_joystick_convert, "P2JOY") | |
| 204 | PORT_BIT( 0xfcfc, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 205 | ||
| 206 | PORT_START("POTGO") | |
| 207 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 208 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) | |
| 209 | PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 210 | PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) | |
| 211 | PORT_BIT( 0xaaff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 212 | ||
| 213 | PORT_START("P1JOY") | |
| 214 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) | |
| 215 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) | |
| 216 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) | |
| 217 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) | |
| 218 | ||
| 219 | PORT_START("P2JOY") | |
| 220 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) | |
| 221 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) | |
| 222 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) | |
| 223 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) | |
| 224 | ||
| 225 | PORT_START("P0MOUSEX") | |
| 226 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 227 | ||
| 228 | PORT_START("P0MOUSEY") | |
| 229 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) | |
| 230 | ||
| 231 | PORT_START("P1MOUSEX") | |
| 232 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 233 | ||
| 234 | PORT_START("P1MOUSEY") | |
| 235 | PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(2) | |
| 236 | ||
| 237 | PORT_INCLUDE( amiga_us_keyboard ) | |
| 238 | INPUT_PORTS_END | |
| 239 | ||
| 240 | ||
| 241 | /************************************* | |
| 242 | * | |
| 243 | * Sound definitions | |
| 244 | * | |
| 245 | *************************************/ | |
| 246 | ||
| 247 | static READ8_DEVICE_HANDLER( a1200_cia_0_portA_r ) | |
| 248 | { | |
| 249 | UINT8 ret = input_port_read(device->machine(), "CIA0PORTA") & 0xc0; /* Gameport 1 and 0 buttons */ | |
| 250 | ret |= amiga_fdc_status_r(device->machine().device("fdc")); | |
| 251 | return ret; | |
| 252 | } | |
| 253 | ||
| 254 | ||
| 255 | static const mos6526_interface a1200_cia_0_intf = | |
| 256 | { | |
| 257 | 0, /* tod_clock */ | |
| 258 | DEVCB_LINE(amiga_cia_0_irq), /* irq_func */ | |
| 259 | DEVCB_NULL, /* pc_func */ | |
| 260 | DEVCB_NULL, | |
| 261 | DEVCB_NULL, | |
| 262 | DEVCB_HANDLER(a1200_cia_0_portA_r), | |
| 263 | DEVCB_HANDLER(ami1200_cia_0_porta_w), /* port A */ | |
| 264 | DEVCB_HANDLER(ami1200_cia_0_portb_r), | |
| 265 | DEVCB_HANDLER(ami1200_cia_0_portb_w) /* port B */ | |
| 266 | }; | |
| 267 | ||
| 268 | static const mos6526_interface a1200_cia_1_intf = | |
| 269 | { | |
| 270 | 0, /* tod_clock */ | |
| 271 | DEVCB_LINE(amiga_cia_1_irq), /* irq_func */ | |
| 272 | DEVCB_NULL, /* pc_func */ | |
| 273 | DEVCB_NULL, | |
| 274 | DEVCB_NULL, | |
| 275 | DEVCB_NULL, | |
| 276 | DEVCB_NULL, /* port A */ | |
| 277 | DEVCB_NULL, | |
| 278 | DEVCB_DEVICE_HANDLER("fdc", amiga_fdc_control_w) /* port B */ | |
| 279 | }; | |
| 280 | ||
| 281 | ||
| 282 | static MACHINE_CONFIG_START( a1200n, ami1200_state ) | |
| 283 | ||
| 284 | /* basic machine hardware */ | |
| 285 | MCFG_CPU_ADD("maincpu", M68EC020, AMIGA_68EC020_NTSC_CLOCK) /* 14.3 Mhz */ | |
| 286 | MCFG_CPU_PROGRAM_MAP(a1200_map) | |
| 287 | ||
| 288 | // MCFG_CPU_ADD("keyboard_mpu", MC68HC05) | |
| 289 | ||
| 290 | MCFG_MACHINE_RESET(amiga) | |
| 291 | ||
| 292 | /* video hardware */ | |
| 293 | MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) | |
| 294 | ||
| 295 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 296 | MCFG_SCREEN_REFRESH_RATE(59.997) | |
| 297 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 298 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 299 | MCFG_SCREEN_SIZE(512*2, 312) | |
| 300 | MCFG_SCREEN_VISIBLE_AREA((129-8-8)*2, (449+8-1+8)*2, 44-8, 300+8-1) | |
| 301 | MCFG_SCREEN_UPDATE(amiga_aga) | |
| 302 | ||
| 303 | MCFG_VIDEO_START(amiga_aga) | |
| 304 | ||
| 305 | /* sound hardware */ | |
| 306 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 307 | ||
| 308 | MCFG_SOUND_ADD("amiga", AMIGA, XTAL_28_63636MHz/8) | |
| 309 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.25) | |
| 310 | MCFG_SOUND_ROUTE(1, "rspeaker", 0.25) | |
| 311 | MCFG_SOUND_ROUTE(2, "rspeaker", 0.25) | |
| 312 | MCFG_SOUND_ROUTE(3, "lspeaker", 0.25) | |
| 313 | ||
| 314 | /* cia */ | |
| 315 | MCFG_MOS8520_ADD("cia_0", AMIGA_68EC020_NTSC_CLOCK / 10, a1200_cia_0_intf) | |
| 316 | MCFG_MOS8520_ADD("cia_1", AMIGA_68EC020_NTSC_CLOCK / 10, a1200_cia_1_intf) | |
| 317 | ||
| 318 | MCFG_AMIGA_FDC_ADD("fdc") | |
| 319 | MACHINE_CONFIG_END | |
| 320 | ||
| 321 | static MACHINE_CONFIG_DERIVED( a1200p, a1200n ) | |
| 322 | ||
| 323 | /* adjust for PAL specs */ | |
| 324 | MCFG_CPU_MODIFY("maincpu") | |
| 325 | MCFG_CPU_CLOCK(A1200PAL_XTAL_X1/2) /* 14.18758 MHz */ | |
| 326 | ||
| 327 | /* video hardware */ | |
| 328 | MCFG_SCREEN_MODIFY("screen") | |
| 329 | MCFG_SCREEN_REFRESH_RATE(50) | |
| 330 | ||
| 331 | /* sound hardware */ | |
| 332 | MCFG_SOUND_MODIFY("amiga") | |
| 333 | MCFG_SOUND_CLOCK(A1200PAL_XTAL_X1/8) /* 3.546895 MHz */ | |
| 334 | ||
| 335 | /* cia */ | |
| 336 | MCFG_DEVICE_MODIFY("cia_0") | |
| 337 | MCFG_DEVICE_CLOCK(A1200PAL_XTAL_X1/20) | |
| 338 | MCFG_DEVICE_MODIFY("cia_1") | |
| 339 | MCFG_DEVICE_CLOCK(A1200PAL_XTAL_X1/20) | |
| 340 | MACHINE_CONFIG_END | |
| 341 | ||
| 342 | ||
| 343 | /*************************************************************************** | |
| 344 | ROM DEFINITIONS | |
| 345 | ***************************************************************************/ | |
| 346 | ||
| 347 | ROM_START( a1200n ) | |
| 348 | ROM_REGION32_BE(0x080000, "user1", 0) | |
| 349 | ROM_DEFAULT_BIOS("kick31") | |
| 350 | ROM_SYSTEM_BIOS(0, "kick30", "Kickstart 3.0 (39.106)") | |
| 351 | ROMX_LOAD("391523-01.u6a", 0x000000, 0x040000, CRC(c742a412) SHA1(999eb81c65dfd07a71ee19315d99c7eb858ab186), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 352 | ROMX_LOAD("391524-01.u6b", 0x000002, 0x040000, CRC(d55c6ec6) SHA1(3341108d3a402882b5ef9d3b242cbf3c8ab1a3e9), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(1)) | |
| 353 | ROM_SYSTEM_BIOS(1, "kick31", "Kickstart 3.1 (40.068)") | |
| 354 | ROMX_LOAD("391773-01.u6a", 0x000000, 0x040000, CRC(08dbf275) SHA1(b8800f5f909298109ea69690b1b8523fa22ddb37), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) // ROM_LOAD32_WORD_SWAP! | |
| 355 | ROMX_LOAD("391774-01.u6b", 0x000002, 0x040000, CRC(16c07bf8) SHA1(90e331be1970b0e53f53a9b0390b51b59b3869c2), ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(2)) | |
| 356 | ||
| 357 | // COMMODORE | 391508-01 REV0 | KEYBOARD MPU | |
| 358 | ROM_REGION(0x1040, "keyboard_rev0", 0) | |
| 359 | ROM_LOAD("391508-01.u13", 0x0000, 0x1040, NO_DUMP) | |
| 360 | ||
| 361 | // Amiga Tech REV1 Keyboard MPU | |
| 362 | ROM_REGION(0x2f40, "keyboard_rev1", 0) | |
| 363 | ROM_LOAD("391508-02.u13", 0x0000, 0x2f40, NO_DUMP) | |
| 364 | ROM_END | |
| 365 | ||
| 366 | #define rom_a1200p rom_a1200n | |
| 367 | ||
| 368 | ||
| 369 | /***************************************************************************************************/ | |
| 370 | ||
| 371 | // these come directly from amiga.c | |
| 372 | ||
| 373 | static UINT16 a1200_read_dskbytr(running_machine &machine) | |
| 374 | { | |
| 375 | return amiga_fdc_get_byte(machine.device("fdc")); | |
| 376 | } | |
| 377 | ||
| 378 | static void a1200_write_dsklen(running_machine &machine, UINT16 data) | |
| 379 | { | |
| 380 | cd32_state *state = machine.driver_data<cd32_state>(); | |
| 381 | if ( data & 0x8000 ) | |
| 382 | { | |
| 383 | if ( CUSTOM_REG(REG_DSKLEN) & 0x8000 ) | |
| 384 | amiga_fdc_setup_dma(machine.device("fdc")); | |
| 385 | } | |
| 386 | } | |
| 387 | ||
| 388 | ||
| 389 | static DRIVER_INIT( a1200 ) | |
| 390 | { | |
| 391 | cd32_state *state = machine.driver_data<cd32_state>(); | |
| 392 | static const amiga_machine_interface cd32_intf = | |
| 393 | { | |
| 394 | AGA_CHIP_RAM_MASK, | |
| 395 | NULL, NULL, /* joy0dat_r & joy1dat_r */ | |
| 396 | cd32_potgo_w, /* potgo_w */ | |
| 397 | a1200_read_dskbytr, a1200_write_dsklen, /* dskbytr_r & dsklen_w */ | |
| 398 | NULL, /* serdat_w */ | |
| 399 | NULL, /* scanline0_callback */ | |
| 400 | NULL, /* reset_callback */ | |
| 401 | NULL, /* nmi_callback */ | |
| 402 | FLAGS_AGA_CHIPSET /* flags */ | |
| 403 | }; | |
| 404 | ||
| 405 | /* configure our Amiga setup */ | |
| 406 | amiga_machine_config(machine, &cd32_intf); | |
| 407 | ||
| 408 | /* set up memory */ | |
| 409 | memory_configure_bank(machine, "bank1", 0, 1, state->m_chip_ram, 0); | |
| 410 | memory_configure_bank(machine, "bank1", 1, 1, machine.region("user1")->base(), 0); | |
| 411 | ||
| 412 | /* initialize keyboard */ | |
| 413 | amigakbd_init(machine); | |
| 414 | } | |
| 415 | ||
| 416 | ||
| 417 | /***************************************************************************************************/ | |
| 418 | ||
| 419 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 420 | COMP( 1992, a1200n, 0, 0, a1200n, a1200, a1200, "Commodore Business Machines", "Amiga 1200 (NTSC)" , GAME_NOT_WORKING ) | |
| 421 | COMP( 1992, a1200p, a1200n, 0, a1200p, a1200, a1200, "Commodore Business Machines", "Amiga 1200 (PAL)" , GAME_NOT_WORKING ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | nes.c | |
| 4 | ||
| 5 | Driver file to handle emulation of the Nintendo Entertainment System (Famicom). | |
| 6 | ||
| 7 | MESS driver by Brad Oliver (bradman@pobox.com), NES sound code by Matt Conte. | |
| 8 | Based in part on the old xNes code, by Nicolas Hamel, Chuck Mason, Brad Oliver, | |
| 9 | Richard Bannister and Jeff Mitchell. | |
| 10 | ||
| 11 | ***************************************************************************/ | |
| 12 | ||
| 13 | #include "emu.h" | |
| 14 | #include "video/ppu2c0x.h" | |
| 15 | #include "machine/nes_mmc.h" | |
| 16 | #include "includes/nes.h" | |
| 17 | #include "cpu/m6502/m6502.h" | |
| 18 | #include "imagedev/cartslot.h" | |
| 19 | #include "sound/nes_apu.h" | |
| 20 | #include "imagedev/flopdrv.h" | |
| 21 | #include "formats/nes_dsk.h" | |
| 22 | ||
| 23 | ||
| 24 | static READ8_DEVICE_HANDLER( psg_4015_r ) | |
| 25 | { | |
| 26 | return nes_psg_r(device, 0x15); | |
| 27 | } | |
| 28 | ||
| 29 | static WRITE8_DEVICE_HANDLER( psg_4015_w ) | |
| 30 | { | |
| 31 | nes_psg_w(device, 0x15, data); | |
| 32 | } | |
| 33 | ||
| 34 | static WRITE8_DEVICE_HANDLER( psg_4017_w ) | |
| 35 | { | |
| 36 | nes_psg_w(device, 0x17, data); | |
| 37 | } | |
| 38 | ||
| 39 | static WRITE8_HANDLER(nes_vh_sprite_dma_w) | |
| 40 | { | |
| 41 | nes_state *state = space->machine().driver_data<nes_state>(); | |
| 42 | ppu2c0x_spriteram_dma(space, state->m_ppu, data); | |
| 43 | } | |
| 44 | ||
| 45 | static ADDRESS_MAP_START( nes_map, AS_PROGRAM, 8 ) | |
| 46 | AM_RANGE(0x0000, 0x07ff) AM_RAM AM_MIRROR(0x1800) /* RAM */ | |
| 47 | AM_RANGE(0x2000, 0x3fff) AM_DEVREADWRITE("ppu", ppu2c0x_r, ppu2c0x_w) /* PPU registers */ | |
| 48 | AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("nessound", nes_psg_r, nes_psg_w) /* PSG primary registers */ | |
| 49 | AM_RANGE(0x4014, 0x4014) AM_WRITE(nes_vh_sprite_dma_w) /* stupid address space hole */ | |
| 50 | AM_RANGE(0x4015, 0x4015) AM_DEVREADWRITE("nessound", psg_4015_r, psg_4015_w) /* PSG status / first control register */ | |
| 51 | AM_RANGE(0x4016, 0x4016) AM_READWRITE(nes_IN0_r, nes_IN0_w) /* IN0 - input port 1 */ | |
| 52 | AM_RANGE(0x4017, 0x4017) AM_READ(nes_IN1_r) /* IN1 - input port 2 */ | |
| 53 | AM_RANGE(0x4017, 0x4017) AM_DEVWRITE("nessound", psg_4017_w) /* PSG second control register */ | |
| 54 | AM_RANGE(0x4100, 0x5fff) AM_READWRITE(nes_low_mapper_r, nes_low_mapper_w) /* Perform unholy acts on the machine */ | |
| 55 | ADDRESS_MAP_END | |
| 56 | ||
| 57 | ||
| 58 | static INPUT_PORTS_START( nes_controllers ) | |
| 59 | PORT_START("CTRLSEL") /* Select Controller Type */ | |
| 60 | PORT_CATEGORY_CLASS( 0x000f, 0x0001, "P1 Controller") | |
| 61 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 62 | PORT_CATEGORY_ITEM( 0x0001, "Gamepad", 1 ) | |
| 63 | PORT_CATEGORY_ITEM( 0x0002, "Zapper", 5 ) | |
| 64 | PORT_CATEGORY_ITEM( 0x0006, "Crazy Climber pad", 10 ) | |
| 65 | PORT_CATEGORY_CLASS( 0x00f0, 0x0010, "P2 Controller") | |
| 66 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 67 | PORT_CATEGORY_ITEM( 0x0010, "Gamepad", 2 ) | |
| 68 | PORT_CATEGORY_ITEM( 0x0030, "Zapper", 6 ) | |
| 69 | PORT_CATEGORY_ITEM( 0x0040, "Arkanoid paddle", 7 ) | |
| 70 | // PORT_CATEGORY_ITEM( 0x0050, "Family Trainer", 11 ) | |
| 71 | PORT_CATEGORY_CLASS( 0x0f00, 0x0000, "P3 Controller") | |
| 72 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 73 | PORT_CATEGORY_ITEM( 0x0100, "Gamepad", 3 ) | |
| 74 | PORT_CATEGORY_CLASS( 0xf000, 0x0000, "P4 Controller") | |
| 75 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 76 | PORT_CATEGORY_ITEM( 0x1000, "Gamepad", 4 ) | |
| 77 | ||
| 78 | PORT_START("PAD1") /* Joypad 1 */ | |
| 79 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 A") PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 80 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 B") PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 81 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 82 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 83 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 84 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 85 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 86 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(1) PORT_PLAYER(1) | |
| 87 | ||
| 88 | PORT_START("PAD2") /* Joypad 2 */ | |
| 89 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 A") PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 90 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 B") PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 91 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 92 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 93 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 94 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 95 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 96 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(2) PORT_PLAYER(2) | |
| 97 | ||
| 98 | PORT_START("PAD3") /* Joypad 3 */ | |
| 99 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3 A") PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 100 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3 B") PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 101 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 102 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 103 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 104 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 105 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 106 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(3) PORT_PLAYER(3) | |
| 107 | ||
| 108 | PORT_START("PAD4") /* Joypad 4 */ | |
| 109 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4 A") PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 110 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4 B") PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 111 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 112 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 113 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 114 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 115 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 116 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CATEGORY(4) PORT_PLAYER(4) | |
| 117 | ||
| 118 | PORT_START("ZAPPER1_X") /* P1 zapper */ | |
| 119 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_CATEGORY(5) PORT_PLAYER(1) | |
| 120 | PORT_START("ZAPPER1_Y") /* P1 zapper */ | |
| 121 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_CATEGORY(5) PORT_PLAYER(1) | |
| 122 | PORT_START("ZAPPER1_T") /* P1 zapper trigger */ | |
| 123 | PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P1 Lightgun Trigger") PORT_CATEGORY(5) PORT_PLAYER(1) | |
| 124 | ||
| 125 | PORT_START("ZAPPER2_X") /* P2 zapper */ | |
| 126 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255 ) PORT_CATEGORY(6) PORT_PLAYER(2) | |
| 127 | PORT_START("ZAPPER2_Y") /* P2 zapper */ | |
| 128 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255 ) PORT_CATEGORY(6) PORT_PLAYER(2) | |
| 129 | PORT_START("ZAPPER2_T") /* P2 zapper trigger */ | |
| 130 | PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P2 Lightgun Trigger") PORT_CATEGORY(6) PORT_PLAYER(2) | |
| 131 | ||
| 132 | PORT_START("PADDLE") /* Arkanoid paddle */ | |
| 133 | PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(3) PORT_MINMAX(0x62,0xf2) PORT_CATEGORY(7) | |
| 134 | ||
| 135 | PORT_START("CC_LEFT") | |
| 136 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 137 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 138 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 139 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 140 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_UP ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 141 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_DOWN ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 142 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 143 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 144 | ||
| 145 | PORT_START("CC_RIGHT") | |
| 146 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 147 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 148 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 149 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 150 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_UP ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 151 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_DOWN ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 152 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_LEFT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 153 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_RIGHT ) PORT_CATEGORY(10) PORT_PLAYER(1) | |
| 154 | ||
| 155 | INPUT_PORTS_END | |
| 156 | ||
| 157 | static INPUT_PORTS_START( nes ) | |
| 158 | PORT_INCLUDE( nes_controllers ) | |
| 159 | ||
| 160 | PORT_START("CONFIG") /* configuration */ | |
| 161 | PORT_CONFNAME( 0x01, 0x00, "Draw Top/Bottom 8 Lines") | |
| 162 | PORT_CONFSETTING( 0x01, DEF_STR(No) ) | |
| 163 | PORT_CONFSETTING( 0x00, DEF_STR(Yes) ) | |
| 164 | PORT_CONFNAME( 0x02, 0x00, "Enforce 8 Sprites/line") | |
| 165 | PORT_CONFSETTING( 0x02, DEF_STR(No) ) | |
| 166 | PORT_CONFSETTING( 0x00, DEF_STR(Yes) ) | |
| 167 | INPUT_PORTS_END | |
| 168 | ||
| 169 | static INPUT_PORTS_START( famicom ) | |
| 170 | PORT_INCLUDE( nes_controllers ) | |
| 171 | ||
| 172 | PORT_START("FLIPDISK") /* fake keys */ | |
| 173 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Change Disk Side") | |
| 174 | INPUT_PORTS_END | |
| 175 | ||
| 176 | static INPUT_PORTS_START( fc_keyboard ) | |
| 177 | PORT_START("FCKEY0") | |
| 178 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) | |
| 179 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) | |
| 180 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[') | |
| 181 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']') | |
| 182 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Kana") | |
| 183 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_RSHIFT) | |
| 184 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') | |
| 185 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Stop") PORT_CODE(KEYCODE_BACKSPACE) | |
| 186 | ||
| 187 | PORT_START("FCKEY1") | |
| 188 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) | |
| 189 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') | |
| 190 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') | |
| 191 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(';') | |
| 192 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CHAR('_') | |
| 193 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CHAR('/') | |
| 194 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') | |
| 195 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^') | |
| 196 | ||
| 197 | PORT_START("FCKEY2") | |
| 198 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) | |
| 199 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_O) PORT_CHAR('O') | |
| 200 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_L) PORT_CHAR('L') | |
| 201 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_K) PORT_CHAR('K') | |
| 202 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') | |
| 203 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') | |
| 204 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_P) PORT_CHAR('P') | |
| 205 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_0) PORT_CHAR('0') | |
| 206 | ||
| 207 | PORT_START("FCKEY3") | |
| 208 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) | |
| 209 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_I) PORT_CHAR('I') | |
| 210 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_U) PORT_CHAR('U') | |
| 211 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_J) PORT_CHAR('J') | |
| 212 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_M) PORT_CHAR('M') | |
| 213 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_N) PORT_CHAR('N') | |
| 214 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_9) PORT_CHAR('9') | |
| 215 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_8) PORT_CHAR('8') | |
| 216 | ||
| 217 | PORT_START("FCKEY4") | |
| 218 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) | |
| 219 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') | |
| 220 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_G) PORT_CHAR('G') | |
| 221 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_H) PORT_CHAR('H') | |
| 222 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_B) PORT_CHAR('B') | |
| 223 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_V) PORT_CHAR('V') | |
| 224 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_7) PORT_CHAR('7') | |
| 225 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_6) PORT_CHAR('6') | |
| 226 | ||
| 227 | PORT_START("FCKEY5") | |
| 228 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) | |
| 229 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_T) PORT_CHAR('T') | |
| 230 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_R) PORT_CHAR('R') | |
| 231 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_D) PORT_CHAR('D') | |
| 232 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F) PORT_CHAR('F') | |
| 233 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_C) PORT_CHAR('C') | |
| 234 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_5) PORT_CHAR('5') | |
| 235 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_4) PORT_CHAR('4') | |
| 236 | ||
| 237 | PORT_START("FCKEY6") | |
| 238 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) | |
| 239 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_W) PORT_CHAR('W') | |
| 240 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_S) PORT_CHAR('S') | |
| 241 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_A) PORT_CHAR('A') | |
| 242 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_X) PORT_CHAR('X') | |
| 243 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') | |
| 244 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_E) PORT_CHAR('E') | |
| 245 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_3) PORT_CHAR('3') | |
| 246 | ||
| 247 | PORT_START("FCKEY7") | |
| 248 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) | |
| 249 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(ESC)) | |
| 250 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') | |
| 251 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) | |
| 252 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) | |
| 253 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Grph") PORT_CODE(KEYCODE_LALT) | |
| 254 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_1) PORT_CHAR('1') | |
| 255 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_2) PORT_CHAR('2') | |
| 256 | ||
| 257 | PORT_START("FCKEY8") | |
| 258 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Clr") | |
| 259 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) | |
| 260 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) | |
| 261 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) | |
| 262 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) | |
| 263 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') | |
| 264 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Del") PORT_CODE(KEYCODE_DEL) | |
| 265 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(8) PORT_NAME("Ins") PORT_CODE(KEYCODE_INSERT) | |
| 266 | ||
| 267 | INPUT_PORTS_END | |
| 268 | ||
| 269 | static INPUT_PORTS_START( subor_keyboard ) | |
| 270 | PORT_START("SUBKEY0") | |
| 271 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_4) PORT_CHAR('4') | |
| 272 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_G) PORT_CHAR('G') | |
| 273 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F) PORT_CHAR('F') | |
| 274 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_C) PORT_CHAR('C') | |
| 275 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) | |
| 276 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_E) PORT_CHAR('E') | |
| 277 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_5) PORT_CHAR('5') | |
| 278 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_V) PORT_CHAR('V') | |
| 279 | ||
| 280 | PORT_START("SUBKEY1") | |
| 281 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_2) PORT_CHAR('2') | |
| 282 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_D) PORT_CHAR('D') | |
| 283 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_S) PORT_CHAR('S') | |
| 284 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) | |
| 285 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) | |
| 286 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_W) PORT_CHAR('W') | |
| 287 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_3) PORT_CHAR('3') | |
| 288 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_X) PORT_CHAR('X') | |
| 289 | ||
| 290 | PORT_START("SUBKEY2") | |
| 291 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) | |
| 292 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) | |
| 293 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("NEXT") | |
| 294 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) | |
| 295 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) | |
| 296 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("PRIOR") | |
| 297 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) | |
| 298 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) | |
| 299 | ||
| 300 | PORT_START("SUBKEY3") | |
| 301 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_9) PORT_CHAR('9') | |
| 302 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_I) PORT_CHAR('I') | |
| 303 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_L) PORT_CHAR('L') | |
| 304 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') | |
| 305 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) | |
| 306 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_O) PORT_CHAR('O') | |
| 307 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_0) PORT_CHAR('0') | |
| 308 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') | |
| 309 | ||
| 310 | PORT_START("SUBKEY4") | |
| 311 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') | |
| 312 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) | |
| 313 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) | |
| 314 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) | |
| 315 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) | |
| 316 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') | |
| 317 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') | |
| 318 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) | |
| 319 | ||
| 320 | PORT_START("SUBKEY5") | |
| 321 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') | |
| 322 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) | |
| 323 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') | |
| 324 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') | |
| 325 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) | |
| 326 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_A) PORT_CHAR('A') | |
| 327 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_1) PORT_CHAR('1') | |
| 328 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) | |
| 329 | ||
| 330 | PORT_START("SUBKEY6") | |
| 331 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_7) PORT_CHAR('7') | |
| 332 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') | |
| 333 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_K) PORT_CHAR('K') | |
| 334 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_M) PORT_CHAR('M') | |
| 335 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) | |
| 336 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_U) PORT_CHAR('U') | |
| 337 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_8) PORT_CHAR('8') | |
| 338 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_J) PORT_CHAR('J') | |
| 339 | ||
| 340 | PORT_START("SUBKEY7") | |
| 341 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') | |
| 342 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') | |
| 343 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') | |
| 344 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') | |
| 345 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) | |
| 346 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_P) PORT_CHAR('P') | |
| 347 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') | |
| 348 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) | |
| 349 | ||
| 350 | PORT_START("SUBKEY8") | |
| 351 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_T) PORT_CHAR('T') | |
| 352 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_H) PORT_CHAR('H') | |
| 353 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_N) PORT_CHAR('N') | |
| 354 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') | |
| 355 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) | |
| 356 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_R) PORT_CHAR('R') | |
| 357 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_6) PORT_CHAR('6') | |
| 358 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_B) PORT_CHAR('B') | |
| 359 | ||
| 360 | PORT_START("SUBKEY9") | |
| 361 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CATEGORY(9) | |
| 362 | ||
| 363 | PORT_START("SUBKEY10") | |
| 364 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("LMENU") | |
| 365 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) | |
| 366 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) | |
| 367 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) | |
| 368 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) | |
| 369 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) | |
| 370 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) | |
| 371 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) | |
| 372 | ||
| 373 | PORT_START("SUBKEY11") | |
| 374 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_MINUS_PAD)PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) | |
| 375 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) | |
| 376 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) | |
| 377 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) | |
| 378 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) | |
| 379 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) | |
| 380 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_SLASH_PAD)PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) | |
| 381 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) | |
| 382 | ||
| 383 | PORT_START("SUBKEY12") | |
| 384 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') | |
| 385 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) | |
| 386 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("PAUSE") | |
| 387 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("SPACE2") | |
| 388 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) | |
| 389 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) | |
| 390 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) | |
| 391 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CATEGORY(9) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) | |
| 392 | ||
| 393 | INPUT_PORTS_END | |
| 394 | ||
| 395 | static INPUT_PORTS_START( famikey ) | |
| 396 | PORT_INCLUDE( famicom ) | |
| 397 | PORT_INCLUDE( fc_keyboard ) | |
| 398 | PORT_INCLUDE( subor_keyboard ) | |
| 399 | ||
| 400 | PORT_MODIFY("CTRLSEL") /* Select Controller Type */ | |
| 401 | PORT_CATEGORY_CLASS( 0x000f, 0x0004, "P1 Controller") | |
| 402 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 403 | PORT_CATEGORY_ITEM( 0x0001, "Gamepad", 1 ) | |
| 404 | PORT_CATEGORY_ITEM( 0x0002, "Zapper", 5 ) | |
| 405 | PORT_CATEGORY_ITEM( 0x0006, "Crazy Climber pad", 10 ) | |
| 406 | PORT_CATEGORY_ITEM( 0x0007, "FC Keyboard", 8 ) | |
| 407 | PORT_CATEGORY_ITEM( 0x0008, "Subor Keyboard", 9 ) | |
| 408 | PORT_CATEGORY_CLASS( 0x00f0, 0x0010, "P2 Controller") | |
| 409 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 410 | PORT_CATEGORY_ITEM( 0x0010, "Gamepad", 2 ) | |
| 411 | PORT_CATEGORY_ITEM( 0x0030, "Zapper", 6 ) | |
| 412 | PORT_CATEGORY_ITEM( 0x0040, "Arkanoid paddle", 7 ) | |
| 413 | // PORT_CATEGORY_ITEM( 0x0050, "Family Trainer", 11 ) | |
| 414 | PORT_CATEGORY_CLASS( 0x0f00, 0x0000, "P3 Controller") | |
| 415 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 416 | PORT_CATEGORY_ITEM( 0x0100, "Gamepad", 3 ) | |
| 417 | PORT_CATEGORY_CLASS( 0xf000, 0x0000, "P4 Controller") | |
| 418 | PORT_CATEGORY_ITEM( 0x0000, "Unconnected", 0 ) | |
| 419 | PORT_CATEGORY_ITEM( 0x1000, "Gamepad", 4 ) | |
| 420 | INPUT_PORTS_END | |
| 421 | ||
| 422 | #ifdef UNUSED_FUNCTION | |
| 423 | /* This layout is not changed at runtime */ | |
| 424 | gfx_layout nes_vram_charlayout = | |
| 425 | { | |
| 426 | 8,8, /* 8*8 characters */ | |
| 427 | 512, /* 512 characters */ | |
| 428 | 2, /* 2 bits per pixel */ | |
| 429 | { 8*8, 0 }, /* the two bitplanes are separated */ | |
| 430 | { 0, 1, 2, 3, 4, 5, 6, 7 }, | |
| 431 | { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, | |
| 432 | 16*8 /* every char takes 16 consecutive bytes */ | |
| 433 | }; | |
| 434 | #endif | |
| 435 | ||
| 436 | static const nes_interface nes_apu_interface = | |
| 437 | { | |
| 438 | "maincpu" | |
| 439 | }; | |
| 440 | ||
| 441 | ||
| 442 | static void ppu_nmi(device_t *device, int *ppu_regs) | |
| 443 | { | |
| 444 | cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_NMI, PULSE_LINE); | |
| 445 | } | |
| 446 | ||
| 447 | ||
| 448 | static const ppu2c0x_interface nes_ppu_interface = | |
| 449 | { | |
| 450 | 0, | |
| 451 | 0, | |
| 452 | PPU_MIRROR_NONE, | |
| 453 | ppu_nmi | |
| 454 | }; | |
| 455 | ||
| 456 | static const floppy_config nes_floppy_config = | |
| 457 | { | |
| 458 | DEVCB_NULL, | |
| 459 | DEVCB_NULL, | |
| 460 | DEVCB_NULL, | |
| 461 | DEVCB_NULL, | |
| 462 | DEVCB_NULL, | |
| 463 | FLOPPY_STANDARD_5_25_DSHD, | |
| 464 | FLOPPY_OPTIONS_NAME(nes_only), | |
| 465 | NULL | |
| 466 | }; | |
| 467 | ||
| 468 | ||
| 469 | static MACHINE_CONFIG_START( nes, nes_state ) | |
| 470 | /* basic machine hardware */ | |
| 471 | MCFG_CPU_ADD("maincpu", N2A03, NTSC_CLOCK) | |
| 472 | MCFG_CPU_PROGRAM_MAP(nes_map) | |
| 473 | ||
| 474 | MCFG_MACHINE_START( nes ) | |
| 475 | MCFG_MACHINE_RESET( nes ) | |
| 476 | ||
| 477 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 478 | MCFG_SCREEN_REFRESH_RATE(60.098) | |
| 479 | // This isn't used so much to calulate the vblank duration (the PPU code tracks that manually) but to determine | |
| 480 | // the number of cycles in each scanline for the PPU scanline timer. Since the PPU has 20 vblank scanlines + 2 | |
| 481 | // non-rendering scanlines, we compensate. This ends up being 2500 cycles for the non-rendering portion, 2273 | |
| 482 | // cycles for the actual vblank period. | |
| 483 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((113.66/(NTSC_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_NTSC-PPU_VBLANK_FIRST_SCANLINE+1+2))) | |
| 484 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 485 | MCFG_SCREEN_SIZE(32*8, 262) | |
| 486 | MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 30*8-1) | |
| 487 | MCFG_SCREEN_UPDATE(nes) | |
| 488 | ||
| 489 | MCFG_PALETTE_INIT(nes) | |
| 490 | MCFG_VIDEO_START(nes) | |
| 491 | ||
| 492 | MCFG_PALETTE_LENGTH(4*16*8) | |
| 493 | ||
| 494 | MCFG_PPU2C02_ADD( "ppu", nes_ppu_interface ) | |
| 495 | ||
| 496 | /* sound hardware */ | |
| 497 | MCFG_SPEAKER_STANDARD_MONO("mono") | |
| 498 | MCFG_SOUND_ADD("nessound", NES, NTSC_CLOCK) | |
| 499 | MCFG_SOUND_CONFIG(nes_apu_interface) | |
| 500 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) | |
| 501 | ||
| 502 | MCFG_CARTSLOT_ADD("cart") | |
| 503 | MCFG_CARTSLOT_EXTENSION_LIST("nes,unf") | |
| 504 | MCFG_CARTSLOT_MANDATORY | |
| 505 | MCFG_CARTSLOT_INTERFACE("nes_cart") | |
| 506 | MCFG_CARTSLOT_LOAD(nes_cart) | |
| 507 | MCFG_CARTSLOT_PARTIALHASH(nes_partialhash) | |
| 508 | MCFG_SOFTWARE_LIST_ADD("cart_list","nes") | |
| 509 | MACHINE_CONFIG_END | |
| 510 | ||
| 511 | static MACHINE_CONFIG_DERIVED( nespal, nes ) | |
| 512 | ||
| 513 | /* basic machine hardware */ | |
| 514 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 515 | MCFG_CPU_CLOCK( PAL_CLOCK ) | |
| 516 | ||
| 517 | MCFG_DEVICE_REMOVE( "ppu" ) | |
| 518 | MCFG_PPU2C07_ADD( "ppu", nes_ppu_interface ) | |
| 519 | ||
| 520 | /* video hardware */ | |
| 521 | MCFG_SCREEN_MODIFY("screen") | |
| 522 | MCFG_SCREEN_REFRESH_RATE(53.355) | |
| 523 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2))) | |
| 524 | MCFG_VIDEO_START(nes) | |
| 525 | ||
| 526 | /* sound hardware */ | |
| 527 | MCFG_SOUND_REPLACE("nessound", NES, PAL_CLOCK) | |
| 528 | MCFG_SOUND_CONFIG(nes_apu_interface) | |
| 529 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) | |
| 530 | MACHINE_CONFIG_END | |
| 531 | ||
| 532 | static MACHINE_CONFIG_DERIVED( dendy, nes ) | |
| 533 | ||
| 534 | /* basic machine hardware */ | |
| 535 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 536 | MCFG_CPU_CLOCK( 26601712/15 ) /* 26.601712MHz / 15 == 1.77344746666... MHz */ | |
| 537 | ||
| 538 | MCFG_DEVICE_REMOVE( "ppu" ) | |
| 539 | MCFG_PPU2C07_ADD( "ppu", nes_ppu_interface ) | |
| 540 | ||
| 541 | /* video hardware */ | |
| 542 | MCFG_SCREEN_MODIFY("screen") | |
| 543 | MCFG_SCREEN_REFRESH_RATE(50.00697796827) | |
| 544 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2))) | |
| 545 | MCFG_VIDEO_START(nes) | |
| 546 | ||
| 547 | /* sound hardware */ | |
| 548 | MCFG_SOUND_REPLACE("nessound", NES, 26601712/15) /* 26.601712MHz / 15 == 1.77344746666... MHz */ | |
| 549 | MCFG_SOUND_CONFIG(nes_apu_interface) | |
| 550 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) | |
| 551 | MACHINE_CONFIG_END | |
| 552 | ||
| 553 | static MACHINE_CONFIG_DERIVED( famicom, nes ) | |
| 554 | ||
| 555 | MCFG_CARTSLOT_MODIFY("cart") | |
| 556 | MCFG_CARTSLOT_EXTENSION_LIST("nes,unf") | |
| 557 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 558 | MCFG_CARTSLOT_LOAD(nes_cart) | |
| 559 | MCFG_CARTSLOT_PARTIALHASH(nes_partialhash) | |
| 560 | ||
| 561 | MCFG_FLOPPY_DRIVE_ADD(FLOPPY_0, nes_floppy_config) | |
| 562 | MACHINE_CONFIG_END | |
| 563 | ||
| 564 | ||
| 565 | /* rom regions are just place-holders: they get removed and re-allocated when a cart is loaded */ | |
| 566 | ROM_START( nes ) | |
| 567 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM + program banks */ | |
| 568 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 569 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 570 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 571 | ROM_END | |
| 572 | ||
| 573 | ROM_START( nespal ) | |
| 574 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM + program banks */ | |
| 575 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 576 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 577 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 578 | ROM_END | |
| 579 | ||
| 580 | ROM_START( famicom ) | |
| 581 | ROM_REGION( 0x10000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 582 | ROM_LOAD_OPTIONAL( "disksys.rom", 0xe000, 0x2000, CRC(5e607dcf) SHA1(57fe1bdee955bb48d357e463ccbf129496930b62) ) | |
| 583 | ||
| 584 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 585 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 586 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 587 | ROM_END | |
| 588 | ||
| 589 | #define rom_fami_key rom_famicom | |
| 590 | ||
| 591 | ROM_START( famitwin ) | |
| 592 | ROM_REGION( 0x10000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 593 | ROM_LOAD_OPTIONAL( "disksyst.rom", 0xe000, 0x2000, CRC(4df24a6c) SHA1(e4e41472c454f928e53eb10e0509bf7d1146ecc1) ) | |
| 594 | ||
| 595 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 596 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 597 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 598 | ROM_END | |
| 599 | ||
| 600 | ROM_START( m82 ) | |
| 601 | ROM_REGION( 0x14000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 602 | /* Banks to be mapped at 0xe000? More investigations needed... */ | |
| 603 | ROM_LOAD( "m82_v1_0.bin", 0x10000, 0x4000, CRC(7d56840a) SHA1(cbd2d14fa073273ba58367758f40d67fd8a9106d) ) | |
| 604 | ||
| 605 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 606 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 607 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 608 | ROM_END | |
| 609 | ||
| 610 | // see http://www.disgruntleddesigner.com/chrisc/drpcjr/index.html | |
| 611 | // and http://www.disgruntleddesigner.com/chrisc/drpcjr/DrPCJrMemMap.txt | |
| 612 | ROM_START( drpcjr ) | |
| 613 | ROM_REGION( 0x18000, "maincpu", 0 ) /* Main RAM + program banks */ | |
| 614 | /* 4 banks to be mapped in 0xe000-0xffff (or 8 banks to be mapped in 0xe000-0xefff & 0xf000-0xffff). | |
| 615 | Banks selected by writing at 0x4180 */ | |
| 616 | ROM_LOAD("drpcjr_bios.bin", 0x10000, 0x8000, CRC(c8fbef89) SHA1(2cb0a817b31400cdf27817d09bae7e69f41b062b) ) // bios vers. 1.0a | |
| 617 | // Not sure if we should support this: hacked version 1.5a by Chris Covell with bugfixes and GameGenie support | |
| 618 | // ROM_LOAD("drpcjr_v1_5_gg.bin", 0x10000, 0x8000, CRC(98f2033b) SHA1(93c114da787a19279d1a46667c2f69b49e25d4f1) ) | |
| 619 | ||
| 620 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 621 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 622 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 623 | ROM_END | |
| 624 | ||
| 625 | ROM_START( dendy ) | |
| 626 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM + program banks */ | |
| 627 | ROM_REGION( 0x2000, "gfx1", ROMREGION_ERASE00 ) /* VROM */ | |
| 628 | ROM_REGION( 0x4000, "gfx2", ROMREGION_ERASE00 ) /* VRAM */ | |
| 629 | ROM_REGION( 0x800, "gfx3", ROMREGION_ERASE00 ) /* CI RAM */ | |
| 630 | ROM_END | |
| 631 | ||
| 632 | /*************************************************************************** | |
| 633 | ||
| 634 | Game driver(s) | |
| 635 | ||
| 636 | ***************************************************************************/ | |
| 637 | ||
| 638 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 639 | CONS( 1985, nes, 0, 0, nes, nes, 0, "Nintendo", "Nintendo Entertainment System / Famicom (NTSC)", GAME_IMPERFECT_GRAPHICS ) | |
| 640 | CONS( 1987, nespal, nes, 0, nespal, nes, 0, "Nintendo", "Nintendo Entertainment System (PAL)", GAME_IMPERFECT_GRAPHICS ) | |
| 641 | CONS( 1983, famicom, nes, 0, famicom, famicom, famicom, "Nintendo", "Famicom (w/ Disk System add-on)", GAME_IMPERFECT_GRAPHICS ) | |
| 642 | CONS( 1983, fami_key, nes, 0, famicom, famikey, famicom, "Nintendo", "Famicom (w/ Disk System add-on + Keyboard add-on)", GAME_IMPERFECT_GRAPHICS ) | |
| 643 | CONS( 1986, famitwin, nes, 0, famicom, famicom, famicom, "Sharp", "Famicom Twin", GAME_IMPERFECT_GRAPHICS ) | |
| 644 | CONS( 198?, m82, nes, 0, nes, nes, 0, "Nintendo", "M82 Display Unit", GAME_IMPERFECT_GRAPHICS ) | |
| 645 | CONS( 1996, drpcjr, nes, 0, famicom, famicom, famicom, "Bung", "Doctor PC Jr", GAME_IMPERFECT_GRAPHICS ) | |
| 646 | CONS( 1992, dendy, nes, 0, dendy, nes, 0, "Steepler", "Dendy Classic", GAME_IMPERFECT_GRAPHICS ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /* | |
| 2 | Nintendo 64 | |
| 3 | ||
| 4 | Driver by Ville Linde | |
| 5 | Reformatted to share hardware by R. Belmont | |
| 6 | Additional work by Ryan Holtz | |
| 7 | Porting from Mupen64 by Harmony | |
| 8 | */ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "cpu/rsp/rsp.h" | |
| 12 | #include "cpu/mips/mips3.h" | |
| 13 | #include "sound/dmadac.h" | |
| 14 | #include "imagedev/cartslot.h" | |
| 15 | #include "includes/n64.h" | |
| 16 | ||
| 17 | ||
| 18 | static ADDRESS_MAP_START( n64_map, AS_PROGRAM, 32 ) | |
| 19 | AM_RANGE(0x00000000, 0x007fffff) AM_RAM AM_BASE(&rdram) // RDRAM | |
| 20 | AM_RANGE(0x03f00000, 0x03f00027) AM_READWRITE(n64_rdram_reg_r, n64_rdram_reg_w) | |
| 21 | AM_RANGE(0x04000000, 0x04000fff) AM_RAM AM_SHARE("dmem") // RSP DMEM | |
| 22 | AM_RANGE(0x04001000, 0x04001fff) AM_RAM AM_SHARE("imem") // RSP IMEM | |
| 23 | AM_RANGE(0x04040000, 0x040fffff) AM_DEVREADWRITE("rsp", n64_sp_reg_r, n64_sp_reg_w) // RSP | |
| 24 | AM_RANGE(0x04100000, 0x041fffff) AM_DEVREADWRITE("rsp", n64_dp_reg_r, n64_dp_reg_w) // RDP | |
| 25 | AM_RANGE(0x04300000, 0x043fffff) AM_READWRITE(n64_mi_reg_r, n64_mi_reg_w) // MIPS Interface | |
| 26 | AM_RANGE(0x04400000, 0x044fffff) AM_READWRITE(n64_vi_reg_r, n64_vi_reg_w) // Video Interface | |
| 27 | AM_RANGE(0x04500000, 0x045fffff) AM_READWRITE(n64_ai_reg_r, n64_ai_reg_w) // Audio Interface | |
| 28 | AM_RANGE(0x04600000, 0x046fffff) AM_READWRITE(n64_pi_reg_r, n64_pi_reg_w) // Peripheral Interface | |
| 29 | AM_RANGE(0x04700000, 0x047fffff) AM_READWRITE(n64_ri_reg_r, n64_ri_reg_w) // RDRAM Interface | |
| 30 | AM_RANGE(0x04800000, 0x048fffff) AM_READWRITE(n64_si_reg_r, n64_si_reg_w) // Serial Interface | |
| 31 | //AM_RANGE(0x08000000, 0x08007fff) AM_RAM // Cartridge SRAM | |
| 32 | AM_RANGE(0x10000000, 0x13ffffff) AM_ROM AM_REGION("user2", 0) // Cartridge | |
| 33 | AM_RANGE(0x1fc00000, 0x1fc007bf) AM_ROM AM_REGION("user1", 0) // PIF ROM | |
| 34 | AM_RANGE(0x1fc007c0, 0x1fc007ff) AM_READWRITE(n64_pif_ram_r, n64_pif_ram_w) | |
| 35 | ADDRESS_MAP_END | |
| 36 | ||
| 37 | static ADDRESS_MAP_START( rsp_map, AS_PROGRAM, 32 ) | |
| 38 | AM_RANGE(0x00000000, 0x00000fff) AM_RAM AM_SHARE("dmem") | |
| 39 | AM_RANGE(0x00001000, 0x00001fff) AM_RAM AM_SHARE("imem") | |
| 40 | AM_RANGE(0x04000000, 0x04000fff) AM_RAM AM_BASE(&rsp_dmem) AM_SHARE("dmem") | |
| 41 | AM_RANGE(0x04001000, 0x04001fff) AM_RAM AM_BASE(&rsp_imem) AM_SHARE("imem") | |
| 42 | ADDRESS_MAP_END | |
| 43 | ||
| 44 | static INPUT_PORTS_START( n64 ) | |
| 45 | PORT_START("P1") | |
| 46 | PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 Button A") | |
| 47 | PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 Button B") | |
| 48 | PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 Button Z") | |
| 49 | PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(1) PORT_NAME("P1 Start") | |
| 50 | PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x91") /* Up */ | |
| 51 | PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x93") /* Down */ | |
| 52 | PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x90") /* Left */ | |
| 53 | PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("P1 Joypad \xE2\x86\x92") /* Right */ | |
| 54 | PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 55 | PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("P1 Button L") | |
| 56 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("P1 Button R") | |
| 57 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x91") /* Up */ | |
| 58 | PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x93") /* Down */ | |
| 59 | PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x90") /* Left */ | |
| 60 | PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_PLAYER(1) PORT_NAME("P1 Button C \xE2\x86\x92") /* Right */ | |
| 61 | ||
| 62 | PORT_START("P1_ANALOG_X") | |
| 63 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(1) | |
| 64 | ||
| 65 | PORT_START("P1_ANALOG_Y") | |
| 66 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(1) PORT_REVERSE | |
| 67 | ||
| 68 | PORT_START("P2") | |
| 69 | PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 Button A") | |
| 70 | PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("P2 Button B") | |
| 71 | PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 Button Z") | |
| 72 | PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(2) PORT_NAME("P2 Start") | |
| 73 | PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x91") /* Up */ | |
| 74 | PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x93") /* Down */ | |
| 75 | PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x90") /* Left */ | |
| 76 | PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_NAME("P2 Joypad \xE2\x86\x92") /* Right */ | |
| 77 | PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 78 | PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("P2 Button L") | |
| 79 | PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("P2 Button R") | |
| 80 | PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x91") /* Up */ | |
| 81 | PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x93") /* Down */ | |
| 82 | PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x90") /* Left */ | |
| 83 | PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_PLAYER(2) PORT_NAME("P2 Button C \xE2\x86\x92") /* Right */ | |
| 84 | ||
| 85 | PORT_START("P2_ANALOG_X") | |
| 86 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(2) | |
| 87 | ||
| 88 | PORT_START("P2_ANALOG_Y") | |
| 89 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_PLAYER(2) PORT_REVERSE | |
| 90 | ||
| 91 | INPUT_PORTS_END | |
| 92 | ||
| 93 | /* ?? */ | |
| 94 | static const mips3_config config = | |
| 95 | { | |
| 96 | 16384, /* code cache size */ | |
| 97 | 8192, /* data cache size */ | |
| 98 | 62500000 /* system clock */ | |
| 99 | }; | |
| 100 | ||
| 101 | static INTERRUPT_GEN( n64_vblank ) | |
| 102 | { | |
| 103 | signal_rcp_interrupt(device->machine(), VI_INTERRUPT); | |
| 104 | } | |
| 105 | ||
| 106 | static DEVICE_IMAGE_LOAD(n64_cart) | |
| 107 | { | |
| 108 | int i, length; | |
| 109 | UINT8 *cart = image.device().machine().region("user2")->base(); | |
| 110 | ||
| 111 | if (image.software_entry() == NULL) | |
| 112 | { | |
| 113 | length = image.fread( cart, 0x4000000); | |
| 114 | } | |
| 115 | else | |
| 116 | { | |
| 117 | length = image.get_software_region_length("rom"); | |
| 118 | memcpy(cart, image.get_software_region("rom"), length); | |
| 119 | } | |
| 120 | ||
| 121 | if (cart[0] == 0x37 && cart[1] == 0x80) | |
| 122 | { | |
| 123 | for (i = 0; i < length; i += 4) | |
| 124 | { | |
| 125 | UINT8 b1 = cart[i + 0]; | |
| 126 | UINT8 b2 = cart[i + 1]; | |
| 127 | UINT8 b3 = cart[i + 2]; | |
| 128 | UINT8 b4 = cart[i + 3]; | |
| 129 | cart[i + 0] = b3; | |
| 130 | cart[i + 1] = b4; | |
| 131 | cart[i + 2] = b1; | |
| 132 | cart[i + 3] = b2; | |
| 133 | } | |
| 134 | } | |
| 135 | else | |
| 136 | { | |
| 137 | for (i = 0; i < length; i += 4) | |
| 138 | { | |
| 139 | UINT8 b1 = cart[i + 0]; | |
| 140 | UINT8 b2 = cart[i + 1]; | |
| 141 | UINT8 b3 = cart[i + 2]; | |
| 142 | UINT8 b4 = cart[i + 3]; | |
| 143 | cart[i + 0] = b4; | |
| 144 | cart[i + 1] = b3; | |
| 145 | cart[i + 2] = b2; | |
| 146 | cart[i + 3] = b1; | |
| 147 | } | |
| 148 | } | |
| 149 | ||
| 150 | logerror("cart length = %d\n", length); | |
| 151 | return IMAGE_INIT_PASS; | |
| 152 | } | |
| 153 | ||
| 154 | static MACHINE_CONFIG_START( n64, _n64_state ) | |
| 155 | ||
| 156 | /* basic machine hardware */ | |
| 157 | MCFG_CPU_ADD("maincpu", VR4300BE, 93750000) | |
| 158 | MCFG_CPU_CONFIG(config) | |
| 159 | MCFG_CPU_PROGRAM_MAP(n64_map) | |
| 160 | MCFG_CPU_VBLANK_INT("screen", n64_vblank) | |
| 161 | ||
| 162 | MCFG_CPU_ADD("rsp", RSP, 62500000) | |
| 163 | MCFG_CPU_CONFIG(n64_rsp_config) | |
| 164 | MCFG_CPU_PROGRAM_MAP(rsp_map) | |
| 165 | ||
| 166 | MCFG_MACHINE_START( n64 ) | |
| 167 | MCFG_MACHINE_RESET( n64 ) | |
| 168 | MCFG_QUANTUM_TIME(attotime::from_hz(600)) | |
| 169 | ||
| 170 | /* video hardware */ | |
| 171 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 172 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 173 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) | |
| 174 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 175 | MCFG_SCREEN_SIZE(640, 525) | |
| 176 | MCFG_SCREEN_VISIBLE_AREA(0, 639, 0, 239) | |
| 177 | MCFG_SCREEN_UPDATE(n64) | |
| 178 | ||
| 179 | MCFG_PALETTE_LENGTH(0x1000) | |
| 180 | ||
| 181 | MCFG_VIDEO_START(n64) | |
| 182 | ||
| 183 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 184 | ||
| 185 | MCFG_SOUND_ADD("dac2", DMADAC, 0) | |
| 186 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) | |
| 187 | MCFG_SOUND_ADD("dac1", DMADAC, 0) | |
| 188 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) | |
| 189 | ||
| 190 | /* cartridge */ | |
| 191 | MCFG_CARTSLOT_ADD("cart") | |
| 192 | MCFG_CARTSLOT_EXTENSION_LIST("v64,z64,rom,n64,bin") | |
| 193 | MCFG_CARTSLOT_MANDATORY | |
| 194 | MCFG_CARTSLOT_INTERFACE("n64_cart") | |
| 195 | MCFG_CARTSLOT_LOAD(n64_cart) | |
| 196 | ||
| 197 | /* software lists */ | |
| 198 | MCFG_SOFTWARE_LIST_ADD("cart_list","n64") | |
| 199 | MACHINE_CONFIG_END | |
| 200 | ||
| 201 | ROM_START( n64 ) | |
| 202 | ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF ) /* dummy region for R4300 */ | |
| 203 | ||
| 204 | ROM_REGION32_BE( 0x800, "user1", 0 ) | |
| 205 | ROM_LOAD( "pifdata.bin", 0x0000, 0x0800, CRC(5ec82be9) SHA1(9174eadc0f0ea2654c95fd941406ab46b9dc9bdd) ) | |
| 206 | ||
| 207 | ROM_REGION32_BE( 0x4000000, "user2", ROMREGION_ERASEFF) | |
| 208 | ||
| 209 | ROM_REGION16_BE( 0x80, "normpoint", 0 ) | |
| 210 | ROM_LOAD( "normpnt.rom", 0x00, 0x80, CRC(e7f2a005) SHA1(c27b4a364a24daeee6e99fd286753fd6216362b4) ) | |
| 211 | ||
| 212 | ROM_REGION16_BE( 0x80, "normslope", 0 ) | |
| 213 | ROM_LOAD( "normslp.rom", 0x00, 0x80, CRC(4f2ae525) SHA1(eab43f8cc52c8551d9cff6fced18ef80eaba6f05) ) | |
| 214 | ROM_END | |
| 215 | ||
| 216 | CONS(1996, n64, 0, 0, n64, n64, 0, "Nintendo", "Nintendo 64", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | snes.c | |
| 4 | ||
| 5 | Driver file to handle emulation of the Nintendo Super NES. | |
| 6 | ||
| 7 | R. Belmont | |
| 8 | Anthony Kruize | |
| 9 | Angelo Salese | |
| 10 | Fabio Priuli | |
| 11 | byuu | |
| 12 | Based on the original MESS driver by Lee Hammerton (aka Savoury Snax) | |
| 13 | ||
| 14 | Driver is preliminary right now. | |
| 15 | ||
| 16 | The memory map included below is setup in a way to make it easier to handle | |
| 17 | Mode 20 and Mode 21 ROMs. | |
| 18 | ||
| 19 | Todo (in no particular order): | |
| 20 | - Fix additional sound bugs | |
| 21 | - Emulate extra chips - superfx, dsp2, sa-1 etc. | |
| 22 | - Add horizontal mosaic, hi-res. interlaced etc to video emulation. | |
| 23 | - Fix support for Mode 7. (In Progress) | |
| 24 | - Handle interleaved roms (maybe even multi-part roms, but how?) | |
| 25 | - Add support for running at 3.58 MHz at the appropriate time. | |
| 26 | - I'm sure there's lots more ... | |
| 27 | ||
| 28 | ***************************************************************************/ | |
| 29 | ||
| 30 | #include "emu.h" | |
| 31 | #include "audio/snes_snd.h" | |
| 32 | #include "cpu/spc700/spc700.h" | |
| 33 | #include "cpu/superfx/superfx.h" | |
| 34 | #include "cpu/g65816/g65816.h" | |
| 35 | #include "cpu/upd7725/upd7725.h" | |
| 36 | #include "includes/snes.h" | |
| 37 | #include "machine/snescart.h" | |
| 38 | #include "crsshair.h" | |
| 39 | ||
| 40 | #define MAX_SNES_CART_SIZE 0x600000 | |
| 41 | ||
| 42 | /************************************* | |
| 43 | * | |
| 44 | * Memory handlers | |
| 45 | * | |
| 46 | *************************************/ | |
| 47 | ||
| 48 | static READ8_DEVICE_HANDLER( spc_ram_100_r ) | |
| 49 | { | |
| 50 | return spc_ram_r(device, offset + 0x100); | |
| 51 | } | |
| 52 | ||
| 53 | static WRITE8_DEVICE_HANDLER( spc_ram_100_w ) | |
| 54 | { | |
| 55 | spc_ram_w(device, offset + 0x100, data); | |
| 56 | } | |
| 57 | ||
| 58 | /************************************* | |
| 59 | * | |
| 60 | * Address maps | |
| 61 | * | |
| 62 | *************************************/ | |
| 63 | ||
| 64 | static ADDRESS_MAP_START( snes_map, AS_PROGRAM, 8) | |
| 65 | AM_RANGE(0x000000, 0x2fffff) AM_READWRITE(snes_r_bank1, snes_w_bank1) /* I/O and ROM (repeats for each bank) */ | |
| 66 | AM_RANGE(0x300000, 0x3fffff) AM_READWRITE(snes_r_bank2, snes_w_bank2) /* I/O and ROM (repeats for each bank) */ | |
| 67 | AM_RANGE(0x400000, 0x5fffff) AM_READ(snes_r_bank3) /* ROM (and reserved in Mode 20) */ | |
| 68 | AM_RANGE(0x600000, 0x6fffff) AM_READWRITE(snes_r_bank4, snes_w_bank4) /* used by Mode 20 DSP-1 */ | |
| 69 | AM_RANGE(0x700000, 0x7dffff) AM_READWRITE(snes_r_bank5, snes_w_bank5) | |
| 70 | AM_RANGE(0x7e0000, 0x7fffff) AM_RAM /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ | |
| 71 | AM_RANGE(0x800000, 0xbfffff) AM_READWRITE(snes_r_bank6, snes_w_bank6) /* Mirror and ROM */ | |
| 72 | AM_RANGE(0xc00000, 0xffffff) AM_READWRITE(snes_r_bank7, snes_w_bank7) /* Mirror and ROM */ | |
| 73 | ADDRESS_MAP_END | |
| 74 | ||
| 75 | static ADDRESS_MAP_START( superfx_map, AS_PROGRAM, 8) | |
| 76 | AM_RANGE(0x000000, 0x3fffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1) | |
| 77 | AM_RANGE(0x400000, 0x5fffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2) | |
| 78 | AM_RANGE(0x600000, 0x7dffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3) | |
| 79 | AM_RANGE(0x800000, 0xbfffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1) | |
| 80 | AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2) | |
| 81 | AM_RANGE(0xe00000, 0xffffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3) | |
| 82 | ADDRESS_MAP_END | |
| 83 | ||
| 84 | static ADDRESS_MAP_START( spc_map, AS_PROGRAM, 8) | |
| 85 | AM_RANGE(0x0000, 0x00ef) AM_DEVREADWRITE("spc700", spc_ram_r, spc_ram_w) /* lower 32k ram */ | |
| 86 | AM_RANGE(0x00f0, 0x00ff) AM_DEVREADWRITE("spc700", spc_io_r, spc_io_w) /* spc io */ | |
| 87 | AM_RANGE(0x0100, 0xffff) AM_DEVWRITE("spc700", spc_ram_100_w) | |
| 88 | AM_RANGE(0x0100, 0xffbf) AM_DEVREAD("spc700", spc_ram_100_r) | |
| 89 | AM_RANGE(0xffc0, 0xffff) AM_DEVREAD("spc700", spc_ipl_r) | |
| 90 | ADDRESS_MAP_END | |
| 91 | ||
| 92 | static ADDRESS_MAP_START( dsp_prg_map, AS_PROGRAM, 32 ) | |
| 93 | AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION("dspprg", 0) | |
| 94 | ADDRESS_MAP_END | |
| 95 | ||
| 96 | static ADDRESS_MAP_START( dsp_data_map, AS_DATA, 16 ) | |
| 97 | AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION("dspdata", 0) | |
| 98 | ADDRESS_MAP_END | |
| 99 | ||
| 100 | static ADDRESS_MAP_START( setadsp_prg_map, AS_PROGRAM, 32 ) | |
| 101 | AM_RANGE(0x0000, 0x3fff) AM_ROM AM_REGION("dspprg", 0) | |
| 102 | ADDRESS_MAP_END | |
| 103 | ||
| 104 | static ADDRESS_MAP_START( setadsp_data_map, AS_DATA, 16 ) | |
| 105 | AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION("dspdata", 0) | |
| 106 | ADDRESS_MAP_END | |
| 107 | ||
| 108 | /************************************* | |
| 109 | * | |
| 110 | * Input ports | |
| 111 | * | |
| 112 | *************************************/ | |
| 113 | ||
| 114 | static CUSTOM_INPUT( snes_mouse_speed_input ) | |
| 115 | { | |
| 116 | snes_state *state = field.machine().driver_data<snes_state>(); | |
| 117 | int port = (FPTR)param; | |
| 118 | ||
| 119 | if (snes_ram[OLDJOY1] & 0x1) | |
| 120 | { | |
| 121 | state->m_mouse[port].speed++; | |
| 122 | if ((state->m_mouse[port].speed & 0x03) == 0x03) | |
| 123 | state->m_mouse[port].speed = 0; | |
| 124 | } | |
| 125 | ||
| 126 | return state->m_mouse[port].speed; | |
| 127 | } | |
| 128 | ||
| 129 | static CUSTOM_INPUT( snes_superscope_offscreen_input ) | |
| 130 | { | |
| 131 | snes_state *state = field.machine().driver_data<snes_state>(); | |
| 132 | int port = (FPTR)param; | |
| 133 | static const char *const portnames[2][3] = | |
| 134 | { | |
| 135 | { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, | |
| 136 | { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" }, | |
| 137 | }; | |
| 138 | ||
| 139 | INT16 x = input_port_read(field.machine(), portnames[port][1]); | |
| 140 | INT16 y = input_port_read(field.machine(), portnames[port][2]); | |
| 141 | ||
| 142 | /* these are the theoretical boundaries, but we currently are always onscreen... */ | |
| 143 | if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= snes_ppu.beam.last_visible_line) | |
| 144 | state->m_scope[port].offscreen = 1; | |
| 145 | else | |
| 146 | state->m_scope[port].offscreen = 0; | |
| 147 | ||
| 148 | return state->m_scope[port].offscreen; | |
| 149 | } | |
| 150 | ||
| 151 | static TIMER_CALLBACK( lightgun_tick ) | |
| 152 | { | |
| 153 | if ((input_port_read(machine, "CTRLSEL") & 0x0f) == 0x03 || (input_port_read(machine, "CTRLSEL") & 0x0f) == 0x04) | |
| 154 | { | |
| 155 | /* enable lightpen crosshair */ | |
| 156 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL); | |
| 157 | } | |
| 158 | else | |
| 159 | { | |
| 160 | /* disable lightpen crosshair */ | |
| 161 | crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE); | |
| 162 | } | |
| 163 | ||
| 164 | if ((input_port_read(machine, "CTRLSEL") & 0xf0) == 0x30 || (input_port_read(machine, "CTRLSEL") & 0xf0) == 0x40) | |
| 165 | { | |
| 166 | /* enable lightpen crosshair */ | |
| 167 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL); | |
| 168 | } | |
| 169 | else | |
| 170 | { | |
| 171 | /* disable lightpen crosshair */ | |
| 172 | crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE); | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | ||
| 177 | static INPUT_PORTS_START( snes_joypads ) | |
| 178 | PORT_START("SERIAL1_DATA1_L") | |
| 179 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 180 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 181 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P1 Button L") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 182 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P1 Button R") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 183 | PORT_START("SERIAL1_DATA1_H") | |
| 184 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 185 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 186 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 187 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START1 ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 188 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 189 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 190 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 191 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 192 | ||
| 193 | PORT_START("SERIAL2_DATA1_L") | |
| 194 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 195 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 196 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 197 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 198 | PORT_START("SERIAL2_DATA1_H") | |
| 199 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 200 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 201 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 202 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START2 ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 203 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 204 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 205 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 206 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 207 | ||
| 208 | PORT_START("SERIAL1_DATA2_L") | |
| 209 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 210 | PORT_START("SERIAL1_DATA2_H") | |
| 211 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 212 | ||
| 213 | PORT_START("SERIAL2_DATA2_L") | |
| 214 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 215 | PORT_START("SERIAL2_DATA2_H") | |
| 216 | PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 217 | INPUT_PORTS_END | |
| 218 | ||
| 219 | static INPUT_PORTS_START( snes_mouse ) | |
| 220 | PORT_START("MOUSE1") | |
| 221 | /* bits 0,3 = mouse signature (must be 1) */ | |
| 222 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 223 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 224 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 225 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 226 | /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */ | |
| 227 | PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_mouse_speed_input, (void *)0) | |
| 228 | /* bits 6,7 = mouse buttons */ | |
| 229 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Mouse Button Left") PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 230 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Mouse Button Right") PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 231 | ||
| 232 | PORT_START("MOUSE1_X") | |
| 233 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 234 | ||
| 235 | PORT_START("MOUSE1_Y") | |
| 236 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CATEGORY(12) | |
| 237 | ||
| 238 | PORT_START("MOUSE2") | |
| 239 | /* bits 0,3 = mouse signature (must be 1) */ | |
| 240 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 241 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 242 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 243 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 244 | /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */ | |
| 245 | PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_mouse_speed_input, (void *)1) | |
| 246 | /* bits 6,7 = mouse buttons */ | |
| 247 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Mouse Button Left") PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 248 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Mouse Button Right") PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 249 | ||
| 250 | PORT_START("MOUSE2_X") | |
| 251 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 252 | ||
| 253 | PORT_START("MOUSE2_Y") | |
| 254 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(2) PORT_CATEGORY(22) | |
| 255 | INPUT_PORTS_END | |
| 256 | ||
| 257 | static INPUT_PORTS_START( snes_superscope ) | |
| 258 | PORT_START("SUPERSCOPE1") | |
| 259 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise | |
| 260 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_superscope_offscreen_input, (void *)0) | |
| 261 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 262 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 263 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port1 Superscope Pause") PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 264 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port1 Superscope Turbo") PORT_TOGGLE PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 265 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port1 Superscope Cursor") PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 266 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port1 Superscope Fire") PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 267 | ||
| 268 | PORT_START("SUPERSCOPE1_X") | |
| 269 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port1 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 270 | ||
| 271 | PORT_START("SUPERSCOPE1_Y") | |
| 272 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port1 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CATEGORY(13) | |
| 273 | ||
| 274 | PORT_START("SUPERSCOPE2") | |
| 275 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise | |
| 276 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_superscope_offscreen_input, (void *)1) | |
| 277 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 278 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) | |
| 279 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port2 Superscope Pause") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 280 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port2 Superscope Turbo") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 281 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port2 Superscope Cursor") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 282 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port2 Superscope Fire") PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 283 | ||
| 284 | PORT_START("SUPERSCOPE2_X") | |
| 285 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port2 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 286 | ||
| 287 | PORT_START("SUPERSCOPE2_Y") | |
| 288 | PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port2 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CATEGORY(23) | |
| 289 | INPUT_PORTS_END | |
| 290 | ||
| 291 | static INPUT_PORTS_START( snes ) | |
| 292 | PORT_START("CTRLSEL") /* Select Controller Type */ | |
| 293 | PORT_CATEGORY_CLASS( 0x0f, 0x01, "P1 Controller") | |
| 294 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 10 ) | |
| 295 | PORT_CATEGORY_ITEM( 0x01, "Gamepad", 11 ) | |
| 296 | PORT_CATEGORY_ITEM( 0x02, "Mouse", 12 ) | |
| 297 | PORT_CATEGORY_ITEM( 0x03, "Superscope", 13 ) | |
| 298 | // PORT_CATEGORY_ITEM( 0x04, "Justfier", 14 ) | |
| 299 | // PORT_CATEGORY_ITEM( 0x05, "Multitap", 15 ) | |
| 300 | PORT_CATEGORY_CLASS( 0xf0, 0x10, "P2 Controller") | |
| 301 | PORT_CATEGORY_ITEM( 0x00, "Unconnected", 20 ) | |
| 302 | PORT_CATEGORY_ITEM( 0x10, "Gamepad", 21 ) | |
| 303 | PORT_CATEGORY_ITEM( 0x20, "Mouse", 22 ) | |
| 304 | PORT_CATEGORY_ITEM( 0x30, "Superscope", 23 ) | |
| 305 | // PORT_CATEGORY_ITEM( 0x40, "Justfier", 24 ) | |
| 306 | // PORT_CATEGORY_ITEM( 0x50, "Multitap", 25 ) | |
| 307 | ||
| 308 | PORT_INCLUDE(snes_joypads) | |
| 309 | PORT_INCLUDE(snes_mouse) | |
| 310 | PORT_INCLUDE(snes_superscope) | |
| 311 | ||
| 312 | PORT_START("OPTIONS") | |
| 313 | PORT_CONFNAME( 0x01, 0x00, "Hi-Res pixels blurring (TV effect)") | |
| 314 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 315 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) | |
| 316 | ||
| 317 | #if SNES_LAYER_DEBUG | |
| 318 | PORT_START("DEBUG1") | |
| 319 | PORT_CONFNAME( 0x03, 0x00, "Select BG1 priority" ) | |
| 320 | PORT_CONFSETTING( 0x00, "All" ) | |
| 321 | PORT_CONFSETTING( 0x01, "BG1B (lower) only" ) | |
| 322 | PORT_CONFSETTING( 0x02, "BG1A (higher) only" ) | |
| 323 | PORT_CONFNAME( 0x0c, 0x00, "Select BG2 priority" ) | |
| 324 | PORT_CONFSETTING( 0x00, "All" ) | |
| 325 | PORT_CONFSETTING( 0x04, "BG2B (lower) only" ) | |
| 326 | PORT_CONFSETTING( 0x08, "BG2A (higher) only" ) | |
| 327 | PORT_CONFNAME( 0x30, 0x00, "Select BG3 priority" ) | |
| 328 | PORT_CONFSETTING( 0x00, "All" ) | |
| 329 | PORT_CONFSETTING( 0x10, "BG3B (lower) only" ) | |
| 330 | PORT_CONFSETTING( 0x20, "BG3A (higher) only" ) | |
| 331 | PORT_CONFNAME( 0xc0, 0x00, "Select BG4 priority" ) | |
| 332 | PORT_CONFSETTING( 0x00, "All" ) | |
| 333 | PORT_CONFSETTING( 0x40, "BG4B (lower) only" ) | |
| 334 | PORT_CONFSETTING( 0x80, "BG4A (higher) only" ) | |
| 335 | ||
| 336 | PORT_START("DEBUG2") | |
| 337 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 1") PORT_CODE(KEYCODE_1_PAD) PORT_TOGGLE | |
| 338 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 2") PORT_CODE(KEYCODE_2_PAD) PORT_TOGGLE | |
| 339 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 3") PORT_CODE(KEYCODE_3_PAD) PORT_TOGGLE | |
| 340 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 4") PORT_CODE(KEYCODE_4_PAD) PORT_TOGGLE | |
| 341 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Objects") PORT_CODE(KEYCODE_5_PAD) PORT_TOGGLE | |
| 342 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Main/Sub") PORT_CODE(KEYCODE_6_PAD) PORT_TOGGLE | |
| 343 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Color Math") PORT_CODE(KEYCODE_7_PAD) PORT_TOGGLE | |
| 344 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Windows") PORT_CODE(KEYCODE_8_PAD) PORT_TOGGLE | |
| 345 | ||
| 346 | PORT_START("DEBUG3") | |
| 347 | PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mosaic") PORT_CODE(KEYCODE_9_PAD) PORT_TOGGLE | |
| 348 | PORT_CONFNAME( 0x70, 0x00, "Select OAM priority" ) | |
| 349 | PORT_CONFSETTING( 0x00, "All" ) | |
| 350 | PORT_CONFSETTING( 0x10, "OAM0 only" ) | |
| 351 | PORT_CONFSETTING( 0x20, "OAM1 only" ) | |
| 352 | PORT_CONFSETTING( 0x30, "OAM2 only" ) | |
| 353 | PORT_CONFSETTING( 0x40, "OAM3 only" ) | |
| 354 | PORT_CONFNAME( 0x80, 0x00, "Draw sprite in reverse order" ) | |
| 355 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 356 | PORT_CONFSETTING( 0x80, DEF_STR( On ) ) | |
| 357 | ||
| 358 | PORT_START("DEBUG4") | |
| 359 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 0 draw") PORT_TOGGLE | |
| 360 | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 1 draw") PORT_TOGGLE | |
| 361 | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 2 draw") PORT_TOGGLE | |
| 362 | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 3 draw") PORT_TOGGLE | |
| 363 | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 4 draw") PORT_TOGGLE | |
| 364 | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 5 draw") PORT_TOGGLE | |
| 365 | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 6 draw") PORT_TOGGLE | |
| 366 | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 7 draw") PORT_TOGGLE | |
| 367 | #endif | |
| 368 | INPUT_PORTS_END | |
| 369 | ||
| 370 | ||
| 371 | /************************************* | |
| 372 | * | |
| 373 | * Input callbacks | |
| 374 | * | |
| 375 | *************************************/ | |
| 376 | ||
| 377 | static void snes_gun_latch( running_machine &machine, INT16 x, INT16 y ) | |
| 378 | { | |
| 379 | /* these are the theoretical boundaries */ | |
| 380 | if (x < 0) | |
| 381 | x = 0; | |
| 382 | if (x > (SNES_SCR_WIDTH - 1)) | |
| 383 | x = SNES_SCR_WIDTH - 1; | |
| 384 | ||
| 385 | if (y < 0) | |
| 386 | y = 0; | |
| 387 | if (y > (snes_ppu.beam.last_visible_line - 1)) | |
| 388 | y = snes_ppu.beam.last_visible_line - 1; | |
| 389 | ||
| 390 | snes_ppu.beam.latch_horz = x; | |
| 391 | snes_ppu.beam.latch_vert = y; | |
| 392 | snes_ram[STAT78] |= 0x40; | |
| 393 | } | |
| 394 | ||
| 395 | static void snes_input_read_joy( running_machine &machine, int port ) | |
| 396 | { | |
| 397 | snes_state *state = machine.driver_data<snes_state>(); | |
| 398 | static const char *const portnames[2][4] = | |
| 399 | { | |
| 400 | { "SERIAL1_DATA1_L", "SERIAL1_DATA1_H", "SERIAL1_DATA2_L", "SERIAL1_DATA2_H" }, | |
| 401 | { "SERIAL2_DATA1_L", "SERIAL2_DATA1_H", "SERIAL2_DATA2_L", "SERIAL2_DATA2_H" }, | |
| 402 | }; | |
| 403 | ||
| 404 | state->m_data1[port] = input_port_read(machine, portnames[port][0]) | (input_port_read(machine, portnames[port][1]) << 8); | |
| 405 | state->m_data2[port] = input_port_read(machine, portnames[port][2]) | (input_port_read(machine, portnames[port][3]) << 8); | |
| 406 | ||
| 407 | // avoid sending signals that could crash games | |
| 408 | // if left, no right | |
| 409 | if (state->m_data1[port] & 0x200) | |
| 410 | state->m_data1[port] &= ~0x100; | |
| 411 | // if up, no down | |
| 412 | if (state->m_data1[port] & 0x800) | |
| 413 | state->m_data1[port] &= ~0x400; | |
| 414 | ||
| 415 | state->m_joypad[port].buttons = state->m_data1[port]; | |
| 416 | } | |
| 417 | ||
| 418 | static void snes_input_read_mouse( running_machine &machine, int port ) | |
| 419 | { | |
| 420 | snes_state *state = machine.driver_data<snes_state>(); | |
| 421 | INT16 var; | |
| 422 | static const char *const portnames[2][3] = | |
| 423 | { | |
| 424 | { "MOUSE1", "MOUSE1_X", "MOUSE1_Y" }, | |
| 425 | { "MOUSE2", "MOUSE2_X", "MOUSE2_Y" }, | |
| 426 | }; | |
| 427 | ||
| 428 | state->m_mouse[port].buttons = input_port_read(machine, portnames[port][0]); | |
| 429 | state->m_mouse[port].x = input_port_read(machine, portnames[port][1]); | |
| 430 | state->m_mouse[port].y = input_port_read(machine, portnames[port][2]); | |
| 431 | var = state->m_mouse[port].x - state->m_mouse[port].oldx; | |
| 432 | ||
| 433 | if (var < -127) | |
| 434 | { | |
| 435 | state->m_mouse[port].deltax = 0xff; | |
| 436 | state->m_mouse[port].oldx -= 127; | |
| 437 | } | |
| 438 | else if (var < 0) | |
| 439 | { | |
| 440 | state->m_mouse[port].deltax = 0x80 | (-var); | |
| 441 | state->m_mouse[port].oldx = state->m_mouse[port].x; | |
| 442 | } | |
| 443 | else if (var > 127) | |
| 444 | { | |
| 445 | state->m_mouse[port].deltax = 0x7f; | |
| 446 | state->m_mouse[port].oldx += 127; | |
| 447 | } | |
| 448 | else | |
| 449 | { | |
| 450 | state->m_mouse[port].deltax = var & 0xff; | |
| 451 | state->m_mouse[port].oldx = state->m_mouse[port].x; | |
| 452 | } | |
| 453 | ||
| 454 | var = state->m_mouse[port].y - state->m_mouse[port].oldy; | |
| 455 | ||
| 456 | if (var < -127) | |
| 457 | { | |
| 458 | state->m_mouse[port].deltay = 0xff; | |
| 459 | state->m_mouse[port].oldy -= 127; | |
| 460 | } | |
| 461 | else if (var < 0) | |
| 462 | { | |
| 463 | state->m_mouse[port].deltay = 0x80 | (-var); | |
| 464 | state->m_mouse[port].oldy = state->m_mouse[port].y; | |
| 465 | } | |
| 466 | else if (var > 127) | |
| 467 | { | |
| 468 | state->m_mouse[port].deltay = 0x7f; | |
| 469 | state->m_mouse[port].oldy += 127; | |
| 470 | } | |
| 471 | else | |
| 472 | { | |
| 473 | state->m_mouse[port].deltay = var & 0xff; | |
| 474 | state->m_mouse[port].oldy = state->m_mouse[port].y; | |
| 475 | } | |
| 476 | ||
| 477 | state->m_data1[port] = state->m_mouse[port].buttons | (0x00 << 8); | |
| 478 | state->m_data2[port] = 0; | |
| 479 | } | |
| 480 | ||
| 481 | static void snes_input_read_superscope( running_machine &machine, int port ) | |
| 482 | { | |
| 483 | snes_state *state = machine.driver_data<snes_state>(); | |
| 484 | static const char *const portnames[2][3] = | |
| 485 | { | |
| 486 | { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, | |
| 487 | { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" }, | |
| 488 | }; | |
| 489 | UINT8 input; | |
| 490 | ||
| 491 | /* first read input bits */ | |
| 492 | state->m_scope[port].x = input_port_read(machine, portnames[port][1]); | |
| 493 | state->m_scope[port].y = input_port_read(machine, portnames[port][2]); | |
| 494 | input = input_port_read(machine, portnames[port][0]); | |
| 495 | ||
| 496 | /* then start elaborating input bits: only keep old turbo value */ | |
| 497 | state->m_scope[port].buttons &= 0x20; | |
| 498 | ||
| 499 | /* set onscreen/offscreen */ | |
| 500 | state->m_scope[port].buttons |= BIT(input, 1); | |
| 501 | ||
| 502 | /* turbo is a switch; toggle is edge sensitive */ | |
| 503 | if (BIT(input, 5) && !state->m_scope[port].turbo_lock) | |
| 504 | { | |
| 505 | state->m_scope[port].buttons ^= 0x20; | |
| 506 | state->m_scope[port].turbo_lock = 1; | |
| 507 | } | |
| 508 | else if (!BIT(input, 5)) | |
| 509 | state->m_scope[port].turbo_lock = 0; | |
| 510 | ||
| 511 | /* fire is a button; if turbo is active, trigger is level sensitive; otherwise it is edge sensitive */ | |
| 512 | if (BIT(input, 7) && (BIT(state->m_scope[port].buttons, 5) || !state->m_scope[port].fire_lock)) | |
| 513 | { | |
| 514 | state->m_scope[port].buttons |= 0x80; | |
| 515 | state->m_scope[port].fire_lock = 1; | |
| 516 | } | |
| 517 | else if (!BIT(input, 7)) | |
| 518 | state->m_scope[port].fire_lock = 0; | |
| 519 | ||
| 520 | /* cursor is a button; it is always level sensitive */ | |
| 521 | state->m_scope[port].buttons |= BIT(input, 6); | |
| 522 | ||
| 523 | /* pause is a button; it is always edge sensitive */ | |
| 524 | if (BIT(input, 4) && !state->m_scope[port].pause_lock) | |
| 525 | { | |
| 526 | state->m_scope[port].buttons |= 0x10; | |
| 527 | state->m_scope[port].pause_lock = 1; | |
| 528 | } | |
| 529 | else if (!BIT(input, 4)) | |
| 530 | state->m_scope[port].pause_lock = 0; | |
| 531 | ||
| 532 | /* If we have pressed fire or cursor and we are on-screen and SuperScope is in Port2, then latch video signal. | |
| 533 | Notice that we only latch Port2 because its IOBit pin is connected to bit7 of the IO Port, while Port1 has | |
| 534 | IOBit pin connected to bit6 of the IO Port, and the latter is not detected by the H/V Counters. In other | |
| 535 | words, you can connect SuperScope to Port1, but there is no way SNES could detect its on-screen position */ | |
| 536 | if ((state->m_scope[port].buttons & 0xc0) && !(state->m_scope[port].buttons & 0x02) && port == 1) | |
| 537 | snes_gun_latch(machine, state->m_scope[port].x, state->m_scope[port].y); | |
| 538 | ||
| 539 | state->m_data1[port] = 0xff | (state->m_scope[port].buttons << 8); | |
| 540 | state->m_data2[port] = 0; | |
| 541 | } | |
| 542 | ||
| 543 | static void snes_input_read( running_machine &machine ) | |
| 544 | { | |
| 545 | snes_state *state = machine.driver_data<snes_state>(); | |
| 546 | UINT8 ctrl1 = input_port_read(machine, "CTRLSEL") & 0x0f; | |
| 547 | UINT8 ctrl2 = (input_port_read(machine, "CTRLSEL") & 0xf0) >> 4; | |
| 548 | ||
| 549 | /* Check if lightgun has been chosen as input: if so, enable crosshair */ | |
| 550 | machine.scheduler().timer_set(attotime::zero, FUNC(lightgun_tick)); | |
| 551 | ||
| 552 | switch (ctrl1) | |
| 553 | { | |
| 554 | case 1: /* SNES joypad */ | |
| 555 | snes_input_read_joy(machine, 0); | |
| 556 | break; | |
| 557 | case 2: /* SNES Mouse */ | |
| 558 | snes_input_read_mouse(machine, 0); | |
| 559 | break; | |
| 560 | case 3: /* SNES Superscope */ | |
| 561 | snes_input_read_superscope(machine, 0); | |
| 562 | break; | |
| 563 | case 0: /* no controller in port1 */ | |
| 564 | default: | |
| 565 | state->m_data1[0] = 0; | |
| 566 | state->m_data2[0] = 0; | |
| 567 | break; | |
| 568 | } | |
| 569 | ||
| 570 | switch (ctrl2) | |
| 571 | { | |
| 572 | case 1: /* SNES joypad */ | |
| 573 | snes_input_read_joy(machine, 1); | |
| 574 | break; | |
| 575 | case 2: /* SNES Mouse */ | |
| 576 | snes_input_read_mouse(machine, 1); | |
| 577 | break; | |
| 578 | case 3: /* SNES Superscope */ | |
| 579 | snes_input_read_superscope(machine, 1); | |
| 580 | break; | |
| 581 | case 0: /* no controller in port2 */ | |
| 582 | default: | |
| 583 | state->m_data1[1] = 0; | |
| 584 | state->m_data2[1] = 0; | |
| 585 | break; | |
| 586 | } | |
| 587 | ||
| 588 | // is automatic reading on? if so, copy port data1/data2 to joy1l->joy4h | |
| 589 | // this actually works like reading the first 16bits from oldjoy1/2 in reverse order | |
| 590 | if (snes_ram[NMITIMEN] & 1) | |
| 591 | { | |
| 592 | state->m_joy1l = (state->m_data1[0] & 0x00ff) >> 0; | |
| 593 | state->m_joy1h = (state->m_data1[0] & 0xff00) >> 8; | |
| 594 | state->m_joy2l = (state->m_data1[1] & 0x00ff) >> 0; | |
| 595 | state->m_joy2h = (state->m_data1[1] & 0xff00) >> 8; | |
| 596 | state->m_joy3l = (state->m_data2[0] & 0x00ff) >> 0; | |
| 597 | state->m_joy3h = (state->m_data2[0] & 0xff00) >> 8; | |
| 598 | state->m_joy4l = (state->m_data2[1] & 0x00ff) >> 0; | |
| 599 | state->m_joy4h = (state->m_data2[1] & 0xff00) >> 8; | |
| 600 | ||
| 601 | // make sure read_idx starts returning all 1s because the auto-read reads it :-) | |
| 602 | state->m_read_idx[0] = 16; | |
| 603 | state->m_read_idx[1] = 16; | |
| 604 | } | |
| 605 | ||
| 606 | } | |
| 607 | ||
| 608 | static UINT8 snes_oldjoy1_read( running_machine &machine ) | |
| 609 | { | |
| 610 | snes_state *state = machine.driver_data<snes_state>(); | |
| 611 | UINT8 ctrl1 = input_port_read(machine, "CTRLSEL") & 0x0f; | |
| 612 | UINT8 res = 0; | |
| 613 | ||
| 614 | switch (ctrl1) | |
| 615 | { | |
| 616 | case 1: /* SNES joypad */ | |
| 617 | if (state->m_read_idx[0] >= 16) | |
| 618 | res = 0x01; | |
| 619 | else | |
| 620 | res = (state->m_joypad[0].buttons >> (15 - state->m_read_idx[0]++)) & 0x01; | |
| 621 | break; | |
| 622 | case 2: /* SNES Mouse */ | |
| 623 | if (state->m_read_idx[0] >= 32) | |
| 624 | res = 0x01; | |
| 625 | else if (state->m_read_idx[0] >= 24) | |
| 626 | res = (state->m_mouse[0].deltax >> (31 - state->m_read_idx[0]++)) & 0x01; | |
| 627 | else if (state->m_read_idx[0] >= 16) | |
| 628 | res = (state->m_mouse[0].deltay >> (23 - state->m_read_idx[0]++)) & 0x01; | |
| 629 | else if (state->m_read_idx[0] >= 8) | |
| 630 | res = (state->m_mouse[0].buttons >> (15 - state->m_read_idx[0]++)) & 0x01; | |
| 631 | else | |
| 632 | res = 0; | |
| 633 | break; | |
| 634 | case 3: /* SNES Superscope */ | |
| 635 | if (state->m_read_idx[0] >= 8) | |
| 636 | res = 0x01; | |
| 637 | else | |
| 638 | res = (state->m_scope[0].buttons >> (7 - state->m_read_idx[0]++)) & 0x01; | |
| 639 | break; | |
| 640 | case 0: /* no controller in port2 */ | |
| 641 | default: | |
| 642 | break; | |
| 643 | } | |
| 644 | ||
| 645 | return res; | |
| 646 | } | |
| 647 | ||
| 648 | static UINT8 snes_oldjoy2_read( running_machine &machine ) | |
| 649 | { | |
| 650 | snes_state *state = machine.driver_data<snes_state>(); | |
| 651 | UINT8 ctrl2 = (input_port_read(machine, "CTRLSEL") & 0xf0) >> 4; | |
| 652 | UINT8 res = 0; | |
| 653 | ||
| 654 | switch (ctrl2) | |
| 655 | { | |
| 656 | case 1: /* SNES joypad */ | |
| 657 | if (state->m_read_idx[1] >= 16) | |
| 658 | res = 0x01; | |
| 659 | else | |
| 660 | res = (state->m_joypad[1].buttons >> (15 - state->m_read_idx[1]++)) & 0x01; | |
| 661 | break; | |
| 662 | case 2: /* SNES Mouse */ | |
| 663 | if (state->m_read_idx[1] >= 32) | |
| 664 | res = 0x01; | |
| 665 | else if (state->m_read_idx[1] >= 24) | |
| 666 | res = (state->m_mouse[1].deltax >> (31 - state->m_read_idx[1]++)) & 0x01; | |
| 667 | else if (state->m_read_idx[1] >= 16) | |
| 668 | res = (state->m_mouse[1].deltay >> (23 - state->m_read_idx[1]++)) & 0x01; | |
| 669 | else if (state->m_read_idx[1] >= 8) | |
| 670 | res = (state->m_mouse[1].buttons >> (15 - state->m_read_idx[1]++)) & 0x01; | |
| 671 | else | |
| 672 | res = 0; | |
| 673 | break; | |
| 674 | case 3: /* SNES Superscope */ | |
| 675 | if (state->m_read_idx[1] >= 8) | |
| 676 | res = 0x01; | |
| 677 | else | |
| 678 | res = (state->m_scope[1].buttons >> (7 - state->m_read_idx[1]++)) & 0x01; | |
| 679 | break; | |
| 680 | case 0: /* no controller in port2 */ | |
| 681 | default: | |
| 682 | break; | |
| 683 | } | |
| 684 | ||
| 685 | return res; | |
| 686 | } | |
| 687 | ||
| 688 | /************************************* | |
| 689 | * | |
| 690 | * Machine driver | |
| 691 | * | |
| 692 | *************************************/ | |
| 693 | ||
| 694 | static MACHINE_RESET( snes_mess ) | |
| 695 | { | |
| 696 | snes_state *state = machine.driver_data<snes_state>(); | |
| 697 | ||
| 698 | MACHINE_RESET_CALL(snes); | |
| 699 | ||
| 700 | state->m_io_read = snes_input_read; | |
| 701 | state->m_oldjoy1_read = snes_oldjoy1_read; | |
| 702 | state->m_oldjoy2_read = snes_oldjoy2_read; | |
| 703 | } | |
| 704 | ||
| 705 | static MACHINE_CONFIG_START( snes_base, snes_state ) | |
| 706 | ||
| 707 | /* basic machine hardware */ | |
| 708 | MCFG_CPU_ADD("maincpu", _5A22, MCLK_NTSC) /* 2.68 MHz, also 3.58 MHz */ | |
| 709 | MCFG_CPU_PROGRAM_MAP(snes_map) | |
| 710 | ||
| 711 | MCFG_CPU_ADD("soundcpu", SPC700, 1024000) /* 1.024 MHz */ | |
| 712 | MCFG_CPU_PROGRAM_MAP(spc_map) | |
| 713 | ||
| 714 | //MCFG_QUANTUM_TIME(attotime::from_hz(48000)) | |
| 715 | MCFG_QUANTUM_PERFECT_CPU("maincpu") | |
| 716 | ||
| 717 | MCFG_MACHINE_START(snes_mess) | |
| 718 | MCFG_MACHINE_RESET(snes_mess) | |
| 719 | ||
| 720 | /* video hardware */ | |
| 721 | MCFG_VIDEO_START(snes) | |
| 722 | ||
| 723 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 724 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 725 | MCFG_SCREEN_RAW_PARAMS(DOTCLK_NTSC, SNES_HTOTAL, 0, SNES_SCR_WIDTH, SNES_VTOTAL_NTSC, 0, SNES_SCR_HEIGHT_NTSC) | |
| 726 | MCFG_SCREEN_UPDATE(snes) | |
| 727 | ||
| 728 | /* sound hardware */ | |
| 729 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 730 | MCFG_SOUND_ADD("spc700", SNES, 0) | |
| 731 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) | |
| 732 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) | |
| 733 | MACHINE_CONFIG_END | |
| 734 | ||
| 735 | static MACHINE_CONFIG_DERIVED( snes, snes_base ) | |
| 736 | ||
| 737 | MCFG_FRAGMENT_ADD(snes_cartslot) | |
| 738 | MACHINE_CONFIG_END | |
| 739 | ||
| 740 | static SUPERFX_CONFIG( snes_superfx_config ) | |
| 741 | { | |
| 742 | DEVCB_LINE(snes_extern_irq_w) /* IRQ line from cart */ | |
| 743 | }; | |
| 744 | ||
| 745 | static MACHINE_CONFIG_DERIVED( snessfx, snes ) | |
| 746 | ||
| 747 | MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */ | |
| 748 | MCFG_CPU_PROGRAM_MAP(superfx_map) | |
| 749 | MCFG_CPU_CONFIG(snes_superfx_config) | |
| 750 | MACHINE_CONFIG_END | |
| 751 | ||
| 752 | static MACHINE_CONFIG_DERIVED( snesdsp, snes ) | |
| 753 | ||
| 754 | MCFG_CPU_ADD("dsp", UPD7725, 8000000) | |
| 755 | MCFG_CPU_PROGRAM_MAP(dsp_prg_map) | |
| 756 | MCFG_CPU_DATA_MAP(dsp_data_map) | |
| 757 | MACHINE_CONFIG_END | |
| 758 | ||
| 759 | static MACHINE_CONFIG_DERIVED( snesst10, snes ) | |
| 760 | ||
| 761 | MCFG_CPU_ADD("setadsp", UPD96050, 10000000) | |
| 762 | MCFG_CPU_PROGRAM_MAP(setadsp_prg_map) | |
| 763 | MCFG_CPU_DATA_MAP(setadsp_data_map) | |
| 764 | MACHINE_CONFIG_END | |
| 765 | ||
| 766 | static MACHINE_CONFIG_DERIVED( snesst11, snes ) | |
| 767 | ||
| 768 | MCFG_CPU_ADD("setadsp", UPD96050, 15000000) | |
| 769 | MCFG_CPU_PROGRAM_MAP(setadsp_prg_map) | |
| 770 | MCFG_CPU_DATA_MAP(setadsp_data_map) | |
| 771 | MACHINE_CONFIG_END | |
| 772 | ||
| 773 | static MACHINE_CONFIG_DERIVED( snespal, snes ) | |
| 774 | MCFG_CPU_MODIFY( "maincpu" ) | |
| 775 | MCFG_CPU_CLOCK( MCLK_PAL ) | |
| 776 | ||
| 777 | MCFG_SCREEN_MODIFY("screen") | |
| 778 | MCFG_SCREEN_RAW_PARAMS(DOTCLK_PAL, SNES_HTOTAL, 0, SNES_SCR_WIDTH, SNES_VTOTAL_PAL, 0, SNES_SCR_HEIGHT_PAL) | |
| 779 | MACHINE_CONFIG_END | |
| 780 | ||
| 781 | static MACHINE_CONFIG_DERIVED( snespsfx, snespal ) | |
| 782 | ||
| 783 | MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */ | |
| 784 | MCFG_CPU_PROGRAM_MAP(superfx_map) | |
| 785 | MCFG_CPU_CONFIG(snes_superfx_config) | |
| 786 | MACHINE_CONFIG_END | |
| 787 | ||
| 788 | static MACHINE_CONFIG_DERIVED( snespdsp, snespal ) | |
| 789 | ||
| 790 | MCFG_CPU_ADD("dsp", UPD7725, 8000000) | |
| 791 | MCFG_CPU_PROGRAM_MAP(dsp_prg_map) | |
| 792 | MCFG_CPU_DATA_MAP(dsp_data_map) | |
| 793 | MACHINE_CONFIG_END | |
| 794 | ||
| 795 | static MACHINE_CONFIG_DERIVED( snesst, snes_base ) | |
| 796 | ||
| 797 | MCFG_MACHINE_START(snesst) | |
| 798 | ||
| 799 | MCFG_FRAGMENT_ADD(sufami_cartslot) | |
| 800 | MACHINE_CONFIG_END | |
| 801 | ||
| 802 | static MACHINE_CONFIG_DERIVED( snesbsx, snes_base ) | |
| 803 | ||
| 804 | MCFG_FRAGMENT_ADD(bsx_cartslot) | |
| 805 | MACHINE_CONFIG_END | |
| 806 | ||
| 807 | ||
| 808 | /************************************* | |
| 809 | * | |
| 810 | * ROM definition(s) | |
| 811 | * | |
| 812 | *************************************/ | |
| 813 | ||
| 814 | ROM_START( snes ) | |
| 815 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 816 | ||
| 817 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 818 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 819 | ||
| 820 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 821 | ||
| 822 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 823 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 824 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 825 | ROM_END | |
| 826 | ||
| 827 | ROM_START( snesdsp ) | |
| 828 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 829 | ||
| 830 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 831 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 832 | ||
| 833 | ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 834 | ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) | |
| 835 | ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) | |
| 836 | ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) | |
| 837 | ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) | |
| 838 | ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) | |
| 839 | ||
| 840 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 841 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 842 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 843 | ROM_END | |
| 844 | ||
| 845 | ROM_START( snesst10 ) | |
| 846 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 847 | ||
| 848 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 849 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 850 | ||
| 851 | ROM_REGION( 0x11000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 852 | ROM_LOAD( "st010.bin", 0x000000, 0x011000, CRC(aa11ee2d) SHA1(cc1984e989cb94e3dcbb5f99e085b5414e18a017) ) | |
| 853 | ||
| 854 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 855 | ROM_REGION( 0x10000, "dspprg", ROMREGION_ERASEFF) | |
| 856 | ROM_REGION( 0x1000, "dspdata", ROMREGION_ERASEFF) | |
| 857 | ROM_END | |
| 858 | ||
| 859 | ROM_START( snesst11 ) | |
| 860 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 861 | ||
| 862 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 863 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 864 | ||
| 865 | ROM_REGION( 0x11000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 866 | ROM_LOAD( "st011.bin", 0x000000, 0x011000, CRC(34d2952c) SHA1(1375b8c1efc8cae4962b57dfe22f6b78e1ddacc8) ) | |
| 867 | ||
| 868 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 869 | ROM_REGION( 0x10000, "dspprg", ROMREGION_ERASEFF) | |
| 870 | ROM_REGION( 0x1000, "dspdata", ROMREGION_ERASEFF) | |
| 871 | ROM_END | |
| 872 | ||
| 873 | ROM_START( snessfx ) | |
| 874 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 875 | ||
| 876 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 877 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 878 | ||
| 879 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 880 | ||
| 881 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 882 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 883 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 884 | ROM_END | |
| 885 | ||
| 886 | ROM_START( snespal ) | |
| 887 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 888 | ||
| 889 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 890 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 891 | ||
| 892 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 893 | ||
| 894 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 895 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 896 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 897 | ROM_END | |
| 898 | ||
| 899 | ROM_START( snespdsp ) | |
| 900 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 901 | ||
| 902 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 903 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 904 | ||
| 905 | ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 906 | ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) | |
| 907 | ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) | |
| 908 | ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) | |
| 909 | ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) | |
| 910 | ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) | |
| 911 | ||
| 912 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 913 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 914 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 915 | ROM_END | |
| 916 | ||
| 917 | ROM_START( snespsfx ) | |
| 918 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 919 | ||
| 920 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 921 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 922 | ||
| 923 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 924 | ||
| 925 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 926 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 927 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 928 | ROM_END | |
| 929 | ||
| 930 | ROM_START( snesst ) | |
| 931 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 932 | ||
| 933 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 934 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 935 | ||
| 936 | ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 937 | ||
| 938 | ROM_REGION( 0x40000, "sufami", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 939 | ROM_LOAD( "shvc-qh-0.bin", 0, 0x40000, CRC(9b4ca911) SHA1(ef86ea192eed03d5c413fdbbfd46043be1d7a127) ) | |
| 940 | ||
| 941 | ROM_REGION( MAX_SNES_CART_SIZE, "slot_a", ROMREGION_ERASE00 ) | |
| 942 | ROM_REGION( MAX_SNES_CART_SIZE, "slot_b", ROMREGION_ERASE00 ) | |
| 943 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 944 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 945 | ROM_END | |
| 946 | ||
| 947 | ROM_START( snesbsx ) | |
| 948 | ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) | |
| 949 | ||
| 950 | ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */ | |
| 951 | ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ | |
| 952 | ||
| 953 | ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */ | |
| 954 | ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) | |
| 955 | ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) | |
| 956 | ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) | |
| 957 | ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) | |
| 958 | ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) | |
| 959 | ||
| 960 | ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 ) | |
| 961 | ROM_REGION( MAX_SNES_CART_SIZE, "flash", ROMREGION_ERASE00 ) | |
| 962 | ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) | |
| 963 | ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF) | |
| 964 | ROM_END | |
| 965 | ||
| 966 | ||
| 967 | ||
| 968 | /************************************* | |
| 969 | * | |
| 970 | * Game driver(s) | |
| 971 | * | |
| 972 | *************************************/ | |
| 973 | ||
| 974 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 975 | CONS( 1989, snes, 0, 0, snes, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 976 | CONS( 1991, snespal, snes, 0, snespal, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 977 | ||
| 978 | // FIXME: the "hacked" drivers below, currently needed due to limitations in the core device design, should eventually be removed | |
| 979 | ||
| 980 | // These would require CPU to be added/removed depending on the cart which is loaded | |
| 981 | CONS( 1989, snesdsp, snes, 0, snesdsp, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/DSP-x)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 982 | CONS( 1991, snespdsp, snes, 0, snespdsp, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/DSP-x)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 983 | CONS( 1989, snessfx, snes, 0, snessfx, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/SuperFX)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 984 | CONS( 1991, snespsfx, snes, 0, snespsfx, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/SuperFX)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 985 | CONS( 1989, snesst10, snes, 0, snesst10, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/ST-010)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 986 | CONS( 1989, snesst11, snes, 0, snesst11, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/ST-011)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 987 | //CONS( 1989, snessa1, snes, 0, snessa1, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/SA-1)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 988 | //CONS( 1991, snespsa1, snes, 0, snespsa1, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/SA-1)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) | |
| 989 | ||
| 990 | // These would require cartslot to be added/removed depending on the cart which is loaded | |
| 991 | CONS( 1989, snesst, snes, 0, snesst, snes, snesst, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/Sufami Turbo)", GAME_NOT_WORKING ) | |
| 992 | CONS( 1989, snesbsx, snes, 0, snesbsx, snes, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/BS-X Satellaview slotted cart)", GAME_NOT_WORKING ) |
| r0 | r11532 | |
|---|---|---|
| 1 | /****************************************************************************** | |
| 2 | * | |
| 3 | * Acorn Archimedes 310 | |
| 4 | * | |
| 5 | * Skeleton: Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000 | |
| 6 | * Enhanced: R. Belmont, June 2007 | |
| 7 | * Angelo Salese, August 2010 | |
| 8 | * | |
| 9 | * TODO: | |
| 10 | * - try to understand why bios 2 was working at some point and now isn't | |
| 11 | * - fix RISC OS / Arthur booting, possible causes: | |
| 12 | * \- missing reset page size hook-up | |
| 13 | * \- some subtle memory paging fault | |
| 14 | * \- missing RAM max size | |
| 15 | * \- ARM bug? | |
| 16 | * | |
| 17 | * | |
| 18 | ======================================================================================= | |
| 19 | * | |
| 20 | * Memory map (from http://b-em.bbcmicro.com/arculator/archdocs.txt) | |
| 21 | * | |
| 22 | * 0000000 - 1FFFFFF - logical RAM (32 meg) | |
| 23 | * 2000000 - 2FFFFFF - physical RAM (supervisor only - max 16MB - requires quad MEMCs) | |
| 24 | * 3000000 - 33FFFFF - IOC (IO controllers - supervisor only) | |
| 25 | * 3310000 - FDC - WD1772 | |
| 26 | * 33A0000 - Econet - 6854 | |
| 27 | * 33B0000 - Serial - 6551 | |
| 28 | * 3240000 - 33FFFFF - internal expansion cards | |
| 29 | * 32D0000 - hard disc controller (not IDE) - HD63463 | |
| 30 | * 3350010 - printer | |
| 31 | * 3350018 - latch A | |
| 32 | * 3350040 - latch B | |
| 33 | * 3270000 - external expansion cards | |
| 34 | * | |
| 35 | * 3400000 - 3FFFFFF - ROM (read - 12 meg - Arthur and RiscOS 2 512k, RiscOS 3 2MB) | |
| 36 | * 3400000 - 37FFFFF - Low ROM (4 meg, I think this is expansion ROMs) | |
| 37 | * 3800000 - 3FFFFFF - High ROM (main OS ROM) | |
| 38 | * | |
| 39 | * 3400000 - 35FFFFF - VICD10 (write - supervisor only) | |
| 40 | * 3600000 - 3FFFFFF - MEMC (write - supervisor only) | |
| 41 | * | |
| 42 | *****************************************************************************/ | |
| 43 | /* | |
| 44 | DASM of code (bios 2 / RISC OS 2) | |
| 45 | 0x380d4e0: MEMC: control to 0x10c (page size 32 kbytes, DRAM ram refresh only during flyback) | |
| 46 | 0x380d4f0: VIDC: params (screen + sound frequency) | |
| 47 | 0x380d51c: IOC: sets control to 0xff, clear IRQA and FIQ masks, sets IRQB mask to 0x80 (keyboard receive full irq) | |
| 48 | 0x380d530: IOC: sets timer 0 to 0x4e20, go command | |
| 49 | 0x380e0a8: work RAM physical check, max size etc. | |
| 50 | 0x380e1f8: IOC: Disables DRAM ram refresh, sets timer 1 to 0x7ffe, go command, then it tests the latch of this timer, enables DRAM refresh | |
| 51 | 0x380d00c: Set up default logical space | |
| 52 | 0x380d16c: Set up case by case logical space | |
| 53 | ||
| 54 | ||
| 55 | */ | |
| 56 | ||
| 57 | ||
| 58 | #include "emu.h" | |
| 59 | #include "machine/wd17xx.h" | |
| 60 | #include "imagedev/flopdrv.h" | |
| 61 | #include "cpu/arm/arm.h" | |
| 62 | #include "sound/dac.h" | |
| 63 | #include "includes/archimds.h" | |
| 64 | #include "machine/i2cmem.h" | |
| 65 | #include "machine/ram.h" | |
| 66 | ||
| 67 | ||
| 68 | class a310_state : public driver_device | |
| 69 | { | |
| 70 | public: | |
| 71 | a310_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 72 | : driver_device(mconfig, type, tag) { } | |
| 73 | ||
| 74 | }; | |
| 75 | ||
| 76 | ||
| 77 | static WRITE_LINE_DEVICE_HANDLER( a310_wd177x_intrq_w ) | |
| 78 | { | |
| 79 | if (state) | |
| 80 | archimedes_request_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY); | |
| 81 | else | |
| 82 | archimedes_clear_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY); | |
| 83 | } | |
| 84 | ||
| 85 | static WRITE_LINE_DEVICE_HANDLER( a310_wd177x_drq_w ) | |
| 86 | { | |
| 87 | if (state) | |
| 88 | archimedes_request_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY_DRQ); | |
| 89 | else | |
| 90 | archimedes_clear_fiq(device->machine(), ARCHIMEDES_FIQ_FLOPPY_DRQ); | |
| 91 | } | |
| 92 | ||
| 93 | static READ32_HANDLER( a310_psy_wram_r ) | |
| 94 | { | |
| 95 | return archimedes_memc_physmem[offset]; | |
| 96 | } | |
| 97 | ||
| 98 | static WRITE32_HANDLER( a310_psy_wram_w ) | |
| 99 | { | |
| 100 | COMBINE_DATA(&archimedes_memc_physmem[offset]); | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | static DRIVER_INIT(a310) | |
| 105 | { | |
| 106 | UINT32 ram_size = ram_get_size(machine.device(RAM_TAG)); | |
| 107 | ||
| 108 | archimedes_memc_physmem = auto_alloc_array(machine, UINT32, 0x01000000); | |
| 109 | ||
| 110 | machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler( 0x02000000, 0x02000000+(ram_size-1), FUNC(a310_psy_wram_r), FUNC(a310_psy_wram_w) ); | |
| 111 | ||
| 112 | archimedes_driver_init(machine); | |
| 113 | } | |
| 114 | ||
| 115 | static MACHINE_START( a310 ) | |
| 116 | { | |
| 117 | archimedes_init(machine); | |
| 118 | ||
| 119 | // reset the DAC to centerline | |
| 120 | //dac_signed_data_w(machine.device("dac"), 0x80); | |
| 121 | } | |
| 122 | ||
| 123 | static MACHINE_RESET( a310 ) | |
| 124 | { | |
| 125 | archimedes_reset(machine); | |
| 126 | } | |
| 127 | ||
| 128 | static ADDRESS_MAP_START( a310_mem, AS_PROGRAM, 32 ) | |
| 129 | AM_RANGE(0x00000000, 0x01ffffff) AM_READWRITE(archimedes_memc_logical_r, archimedes_memc_logical_w) | |
| 130 | // AM_RANGE(0x02000000, 0x02ffffff) AM_RAM AM_BASE(&archimedes_memc_physmem) /* physical RAM - 16 MB for now, should be 512k for the A310 */ | |
| 131 | AM_RANGE(0x03000000, 0x033fffff) AM_READWRITE(archimedes_ioc_r, archimedes_ioc_w) | |
| 132 | AM_RANGE(0x03400000, 0x035fffff) AM_READWRITE(archimedes_vidc_r, archimedes_vidc_w) | |
| 133 | AM_RANGE(0x03600000, 0x037fffff) AM_READWRITE(archimedes_memc_r, archimedes_memc_w) | |
| 134 | AM_RANGE(0x03800000, 0x03ffffff) AM_ROM AM_REGION("maincpu", 0) AM_WRITE(archimedes_memc_page_w) | |
| 135 | ADDRESS_MAP_END | |
| 136 | ||
| 137 | ||
| 138 | static INPUT_PORTS_START( a310 ) | |
| 139 | PORT_START("dip") /* DIP switches */ | |
| 140 | PORT_BIT(0xfd, 0xfd, IPT_UNUSED) | |
| 141 | ||
| 142 | PORT_START("key0") /* KEY ROW 0 */ | |
| 143 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) | |
| 144 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) | |
| 145 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) | |
| 146 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) | |
| 147 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) | |
| 148 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) | |
| 149 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) | |
| 150 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("7 '") PORT_CODE(KEYCODE_7) | |
| 151 | ||
| 152 | PORT_START("key1") /* KEY ROW 1 */ | |
| 153 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) | |
| 154 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) | |
| 155 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) | |
| 156 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) | |
| 157 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) | |
| 158 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("` ~") PORT_CODE(KEYCODE_TILDE) | |
| 159 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("BACK SPACE") PORT_CODE(KEYCODE_BACKSPACE) | |
| 160 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) | |
| 161 | ||
| 162 | PORT_START("key2") /* KEY ROW 2 */ | |
| 163 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("q Q") PORT_CODE(KEYCODE_Q) | |
| 164 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("w W") PORT_CODE(KEYCODE_W) | |
| 165 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("e E") PORT_CODE(KEYCODE_E) | |
| 166 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("r R") PORT_CODE(KEYCODE_R) | |
| 167 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("t T") PORT_CODE(KEYCODE_T) | |
| 168 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("y Y") PORT_CODE(KEYCODE_Y) | |
| 169 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("u U") PORT_CODE(KEYCODE_U) | |
| 170 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("i I") PORT_CODE(KEYCODE_I) | |
| 171 | ||
| 172 | PORT_START("key3") /* KEY ROW 3 */ | |
| 173 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("o O") PORT_CODE(KEYCODE_O) | |
| 174 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("p P") PORT_CODE(KEYCODE_P) | |
| 175 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) | |
| 176 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) | |
| 177 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) | |
| 178 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) | |
| 179 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) | |
| 180 | PORT_BIT(0x80, 0x80, IPT_KEYBOARD) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE | |
| 181 | ||
| 182 | PORT_START("key4") /* KEY ROW 4 */ | |
| 183 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("a A") PORT_CODE(KEYCODE_A) | |
| 184 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("s S") PORT_CODE(KEYCODE_S) | |
| 185 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("d D") PORT_CODE(KEYCODE_D) | |
| 186 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("f F") PORT_CODE(KEYCODE_F) | |
| 187 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("g G") PORT_CODE(KEYCODE_G) | |
| 188 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("h H") PORT_CODE(KEYCODE_H) | |
| 189 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("j J") PORT_CODE(KEYCODE_J) | |
| 190 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("k K") PORT_CODE(KEYCODE_K) | |
| 191 | ||
| 192 | PORT_START("key5") /* KEY ROW 5 */ | |
| 193 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("l L") PORT_CODE(KEYCODE_L) | |
| 194 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) | |
| 195 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) | |
| 196 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_ASTERISK) | |
| 197 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("SHIFT (L)") PORT_CODE(KEYCODE_LSHIFT) | |
| 198 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("z Z") PORT_CODE(KEYCODE_Z) | |
| 199 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("x X") PORT_CODE(KEYCODE_X) | |
| 200 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("c C") PORT_CODE(KEYCODE_C) | |
| 201 | ||
| 202 | PORT_START("key6") /* KEY ROW 6 */ | |
| 203 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("v V") PORT_CODE(KEYCODE_V) | |
| 204 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("b B") PORT_CODE(KEYCODE_B) | |
| 205 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("n N") PORT_CODE(KEYCODE_N) | |
| 206 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("m M") PORT_CODE(KEYCODE_M) | |
| 207 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) | |
| 208 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) | |
| 209 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) | |
| 210 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("SHIFT (R)") PORT_CODE(KEYCODE_RSHIFT) | |
| 211 | ||
| 212 | PORT_START("key7") /* KEY ROW 7 */ | |
| 213 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("LINE FEED") | |
| 214 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) | |
| 215 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("- (KP)") PORT_CODE(KEYCODE_MINUS_PAD) | |
| 216 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME(", (KP)") PORT_CODE(KEYCODE_PLUS_PAD) | |
| 217 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("ENTER (KP)") PORT_CODE(KEYCODE_ENTER_PAD) | |
| 218 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME(". (KP)") PORT_CODE(KEYCODE_DEL_PAD) | |
| 219 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("0 (KP)") PORT_CODE(KEYCODE_0_PAD) | |
| 220 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("1 (KP)") PORT_CODE(KEYCODE_1_PAD) | |
| 221 | ||
| 222 | PORT_START("key8") /* KEY ROW 8 */ | |
| 223 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("2 (KP)") PORT_CODE(KEYCODE_2_PAD) | |
| 224 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("3 (KP)") PORT_CODE(KEYCODE_3_PAD) | |
| 225 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("4 (KP)") PORT_CODE(KEYCODE_4_PAD) | |
| 226 | PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("5 (KP)") PORT_CODE(KEYCODE_5_PAD) | |
| 227 | PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("6 (KP)") PORT_CODE(KEYCODE_6_PAD) | |
| 228 | PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("7 (KP)") PORT_CODE(KEYCODE_7_PAD) | |
| 229 | PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("8 (KP)") PORT_CODE(KEYCODE_8_PAD) | |
| 230 | PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_NAME("9 (KP)") PORT_CODE(KEYCODE_9_PAD) | |
| 231 | ||
| 232 | PORT_START("via1a") /* VIA #1 PORT A */ | |
| 233 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START) PORT_PLAYER(1) | |
| 234 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START) PORT_PLAYER(2) | |
| 235 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) | |
| 236 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) | |
| 237 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_4WAY | |
| 238 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_4WAY | |
| 239 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_4WAY | |
| 240 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_4WAY | |
| 241 | ||
| 242 | PORT_START("tape")/* tape control */ | |
| 243 | PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("TAPE STOP") PORT_CODE(KEYCODE_F5) | |
| 244 | PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("TAPE PLAY") PORT_CODE(KEYCODE_F6) | |
| 245 | PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("TAPE REW") PORT_CODE(KEYCODE_F7) | |
| 246 | PORT_BIT (0xf8, 0x80, IPT_UNUSED) | |
| 247 | INPUT_PORTS_END | |
| 248 | ||
| 249 | static const wd17xx_interface a310_wd17xx_interface = | |
| 250 | { | |
| 251 | DEVCB_NULL, | |
| 252 | DEVCB_LINE(a310_wd177x_intrq_w), | |
| 253 | DEVCB_LINE(a310_wd177x_drq_w), | |
| 254 | {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3} | |
| 255 | }; | |
| 256 | ||
| 257 | static const i2cmem_interface i2cmem_interface = | |
| 258 | { | |
| 259 | I2CMEM_SLAVE_ADDRESS, 0, 0x100 | |
| 260 | }; | |
| 261 | ||
| 262 | static MACHINE_CONFIG_START( a310, a310_state ) | |
| 263 | /* basic machine hardware */ | |
| 264 | MCFG_CPU_ADD("maincpu", ARM, 8000000) /* 8 MHz */ | |
| 265 | MCFG_CPU_PROGRAM_MAP(a310_mem) | |
| 266 | ||
| 267 | MCFG_MACHINE_START( a310 ) | |
| 268 | MCFG_MACHINE_RESET( a310 ) | |
| 269 | ||
| 270 | MCFG_I2CMEM_ADD("i2cmem",i2cmem_interface) | |
| 271 | ||
| 272 | /* video hardware */ | |
| 273 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 274 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 275 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 276 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) | |
| 277 | MCFG_SCREEN_SIZE(1280, 1024) //TODO: default screen size | |
| 278 | MCFG_SCREEN_VISIBLE_AREA(0*8, 1280 - 1, 0*16, 1024 - 1) | |
| 279 | MCFG_SCREEN_UPDATE(archimds_vidc) | |
| 280 | ||
| 281 | MCFG_PALETTE_LENGTH(32768) | |
| 282 | ||
| 283 | MCFG_VIDEO_START(archimds_vidc) | |
| 284 | ||
| 285 | MCFG_RAM_ADD(RAM_TAG) | |
| 286 | MCFG_RAM_DEFAULT_SIZE("2M") | |
| 287 | MCFG_RAM_EXTRA_OPTIONS("512K, 1M, 4M, 8M, 16M") | |
| 288 | ||
| 289 | MCFG_WD1772_ADD("wd1772", a310_wd17xx_interface ) | |
| 290 | ||
| 291 | //MCFG_FLOPPY_4_DRIVES_ADD(a310_floppy_config) | |
| 292 | ||
| 293 | MCFG_SPEAKER_STANDARD_MONO("mono") | |
| 294 | MCFG_SOUND_ADD("dac0", DAC, 0) | |
| 295 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 296 | ||
| 297 | MCFG_SOUND_ADD("dac1", DAC, 0) | |
| 298 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 299 | ||
| 300 | MCFG_SOUND_ADD("dac2", DAC, 0) | |
| 301 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 302 | ||
| 303 | MCFG_SOUND_ADD("dac3", DAC, 0) | |
| 304 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 305 | ||
| 306 | MCFG_SOUND_ADD("dac4", DAC, 0) | |
| 307 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 308 | ||
| 309 | MCFG_SOUND_ADD("dac5", DAC, 0) | |
| 310 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 311 | ||
| 312 | MCFG_SOUND_ADD("dac6", DAC, 0) | |
| 313 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 314 | ||
| 315 | MCFG_SOUND_ADD("dac7", DAC, 0) | |
| 316 | MCFG_SOUND_ROUTE(0, "mono", 0.10) | |
| 317 | MACHINE_CONFIG_END | |
| 318 | ||
| 319 | ROM_START(a310) | |
| 320 | ROM_REGION( 0x800000, "maincpu", 0 ) | |
| 321 | ROM_SYSTEM_BIOS( 0, "311", "RiscOS 3.11 (29 Sep 1992)" ) | |
| 322 | ROMX_LOAD( "ic24.rom", 0x000000, 0x80000, CRC(c1adde84) SHA1(12d060e0401dd0523d44453f947bdc55dd2c3240), ROM_BIOS(1) ) | |
| 323 | ROMX_LOAD( "ic25.rom", 0x080000, 0x80000, CRC(15d89664) SHA1(78f5d0e6f1e8ee603317807f53ff8fe65a3b3518), ROM_BIOS(1) ) | |
| 324 | ROMX_LOAD( "ic26.rom", 0x100000, 0x80000, CRC(a81ceb7c) SHA1(46b870876bc1f68f242726415f0c49fef7be0c72), ROM_BIOS(1) ) | |
| 325 | ROMX_LOAD( "ic27.rom", 0x180000, 0x80000, CRC(707b0c6c) SHA1(345199a33fed23996374b9db8170a52ab63f0380), ROM_BIOS(1) ) | |
| 326 | ROM_SYSTEM_BIOS( 1, "120", "Arthur/RiscOS 1.20 (25 Sep 1987)" ) | |
| 327 | ROMX_LOAD( "arthur.bin", 0x000000, 0x080000, CRC(eb3fda57) SHA1(1181ff9c2c2f3d6d414054ec33b2260404bafc81), ROM_BIOS(2) ) | |
| 328 | ROM_SYSTEM_BIOS( 2, "200", "RiscOS 2.0 (05 Oct 1988)" ) | |
| 329 | ROMX_LOAD( "riscos2.bin", 0x000000, 0x080000, CRC(89c4ad36) SHA1(b82a78830dac386f9b649b6d32a34f9c6910546d), ROM_BIOS(3) ) | |
| 330 | ||
| 331 | ROM_REGION( 0x200000, "vram", ROMREGION_ERASE00 ) | |
| 332 | ||
| 333 | ROM_REGION( 0x100, "i2cmem", ROMREGION_ERASE00 ) | |
| 334 | ROM_END | |
| 335 | ||
| 336 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 337 | COMP( 1988, a310, 0, 0, a310, a310, a310, "Acorn", "Archimedes 310", GAME_NOT_WORKING) |
| r0 | r11532 | |
|---|---|---|
| 1 | /**************************************************************************** | |
| 2 | ||
| 3 | PC-Engine / Turbo Grafx 16 driver | |
| 4 | by Charles Mac Donald | |
| 5 | E-Mail: cgfm2@hooked.net | |
| 6 | ||
| 7 | Thanks to David Shadoff and Brian McPhail for help with the driver. | |
| 8 | ||
| 9 | ****************************************************************************/ | |
| 10 | ||
| 11 | /********************************************************************** | |
| 12 | To-Do List: | |
| 13 | - convert h6280-based drivers to internal memory map for the I/O region | |
| 14 | - test sprite collision and overflow interrupts | |
| 15 | - sprite precaching | |
| 16 | - rewrite the base renderer loop | |
| 17 | - Add CD support | |
| 18 | - Add 6 button joystick support | |
| 19 | - Add 263 line mode | |
| 20 | - Sprite DMA should use vdc VRAM functions | |
| 21 | - properly implement the pixel clocks instead of the simple scaling we do now | |
| 22 | ||
| 23 | Banking | |
| 24 | ======= | |
| 25 | ||
| 26 | Normally address spacebanks 00-F6 are assigned to regular HuCard ROM space. There | |
| 27 | are a couple of special situations: | |
| 28 | ||
| 29 | Street Fighter II: | |
| 30 | - address space banks 40-7F switchable by writing to 1FF0-1FF3 | |
| 31 | 1FF0 - select rom banks 40-7F | |
| 32 | 1FF1 - select rom banks 80-BF | |
| 33 | 1FF2 - select rom banks C0-FF | |
| 34 | 1FF3 - select rom banks 100-13F | |
| 35 | ||
| 36 | Populous: | |
| 37 | - address space banks 40-43 contains 32KB RAM | |
| 38 | ||
| 39 | CDRom units: | |
| 40 | - address space banks 80-87 contains 64KB RAM | |
| 41 | ||
| 42 | Super System Card: | |
| 43 | - address space banks 68-7F contains 192KB RAM | |
| 44 | ||
| 45 | **********************************************************************/ | |
| 46 | ||
| 47 | /********************************************************************** | |
| 48 | Known Bugs | |
| 49 | *********************************************************************** | |
| 50 | - Benkei Gaiden: hangs after a few Sunsoft logo spins. | |
| 51 | - Busou Keiji Cyber Cross: hangs on attract mode | |
| 52 | - Cadash: After choosing character and name, the game starts and the display 'jiggles' like tracking if off a VCR | |
| 53 | - Fighting Run: has color and sprite issues during gameplay; | |
| 54 | - Hisou Kihei - Xserd: black screen; | |
| 55 | **********************************************************************/ | |
| 56 | ||
| 57 | #include "emu.h" | |
| 58 | #include "deprecat.h" | |
| 59 | #include "video/vdc.h" | |
| 60 | #include "cpu/h6280/h6280.h" | |
| 61 | #include "includes/pce.h" | |
| 62 | #include "imagedev/cartslot.h" | |
| 63 | #include "imagedev/chd_cd.h" | |
| 64 | #include "sound/c6280.h" | |
| 65 | #include "sound/cdda.h" | |
| 66 | #include "sound/msm5205.h" | |
| 67 | #include "hash.h" | |
| 68 | ||
| 69 | ||
| 70 | static ADDRESS_MAP_START( pce_mem , AS_PROGRAM, 8) | |
| 71 | AM_RANGE( 0x000000, 0x07FFFF) AM_ROMBANK("bank1") | |
| 72 | AM_RANGE( 0x080000, 0x087FFF) AM_ROMBANK("bank2") | |
| 73 | AM_RANGE( 0x088000, 0x0CFFFF) AM_ROMBANK("bank3") | |
| 74 | AM_RANGE( 0x0D0000, 0x0FFFFF) AM_ROMBANK("bank4") | |
| 75 | AM_RANGE( 0x100000, 0x10FFFF) AM_RAM AM_BASE_MEMBER( pce_state, m_cd_ram ) | |
| 76 | AM_RANGE( 0x110000, 0x1EDFFF) AM_NOP | |
| 77 | AM_RANGE( 0x1EE000, 0x1EE7FF) AM_ROMBANK("bank10") AM_WRITE( pce_cd_bram_w ) | |
| 78 | AM_RANGE( 0x1EE800, 0x1EFFFF) AM_NOP | |
| 79 | AM_RANGE( 0x1F0000, 0x1F1FFF) AM_RAM AM_MIRROR(0x6000) AM_BASE_MEMBER( pce_state, m_user_ram ) | |
| 80 | AM_RANGE( 0x1FE000, 0x1FE3FF) AM_READWRITE( vdc_0_r, vdc_0_w ) | |
| 81 | AM_RANGE( 0x1FE400, 0x1FE7FF) AM_READWRITE( vce_r, vce_w ) | |
| 82 | AM_RANGE( 0x1FE800, 0x1FEBFF) AM_DEVREADWRITE(C6280_TAG, c6280_r, c6280_w ) | |
| 83 | AM_RANGE( 0x1FEC00, 0x1FEFFF) AM_READWRITE( h6280_timer_r, h6280_timer_w ) | |
| 84 | AM_RANGE( 0x1FF000, 0x1FF3FF) AM_READWRITE( pce_joystick_r, pce_joystick_w ) | |
| 85 | AM_RANGE( 0x1FF400, 0x1FF7FF) AM_READWRITE( h6280_irq_status_r, h6280_irq_status_w ) | |
| 86 | AM_RANGE( 0x1FF800, 0x1FFBFF) AM_READWRITE( pce_cd_intf_r, pce_cd_intf_w ) | |
| 87 | ADDRESS_MAP_END | |
| 88 | ||
| 89 | static ADDRESS_MAP_START( pce_io , AS_IO, 8) | |
| 90 | AM_RANGE( 0x00, 0x03) AM_READWRITE( vdc_0_r, vdc_0_w ) | |
| 91 | ADDRESS_MAP_END | |
| 92 | ||
| 93 | static ADDRESS_MAP_START( sgx_mem , AS_PROGRAM, 8) | |
| 94 | AM_RANGE( 0x000000, 0x07FFFF) AM_ROMBANK("bank1") | |
| 95 | AM_RANGE( 0x080000, 0x087FFF) AM_ROMBANK("bank2") | |
| 96 | AM_RANGE( 0x088000, 0x0CFFFF) AM_ROMBANK("bank3") | |
| 97 | AM_RANGE( 0x0D0000, 0x0FFFFF) AM_ROMBANK("bank4") | |
| 98 | AM_RANGE( 0x100000, 0x10FFFF) AM_RAM AM_BASE_MEMBER( pce_state, m_cd_ram ) | |
| 99 | AM_RANGE( 0x110000, 0x1EDFFF) AM_NOP | |
| 100 | AM_RANGE( 0x1EE000, 0x1EE7FF) AM_ROMBANK("bank10") AM_WRITE( pce_cd_bram_w ) | |
| 101 | AM_RANGE( 0x1EE800, 0x1EFFFF) AM_NOP | |
| 102 | AM_RANGE( 0x1F0000, 0x1F7FFF) AM_RAM AM_BASE_MEMBER( pce_state, m_user_ram ) | |
| 103 | AM_RANGE( 0x1FE000, 0x1FE007) AM_READWRITE( vdc_0_r, vdc_0_w ) AM_MIRROR(0x03E0) | |
| 104 | AM_RANGE( 0x1FE008, 0x1FE00F) AM_READWRITE( vpc_r, vpc_w ) AM_MIRROR(0x03E0) | |
| 105 | AM_RANGE( 0x1FE010, 0x1FE017) AM_READWRITE( vdc_1_r, vdc_1_w ) AM_MIRROR(0x03E0) | |
| 106 | AM_RANGE( 0x1FE400, 0x1FE7FF) AM_READWRITE( vce_r, vce_w ) | |
| 107 | AM_RANGE( 0x1FE800, 0x1FEBFF) AM_DEVREADWRITE(C6280_TAG, c6280_r, c6280_w ) | |
| 108 | AM_RANGE( 0x1FEC00, 0x1FEFFF) AM_READWRITE( h6280_timer_r, h6280_timer_w ) | |
| 109 | AM_RANGE( 0x1FF000, 0x1FF3FF) AM_READWRITE( pce_joystick_r, pce_joystick_w ) | |
| 110 | AM_RANGE( 0x1FF400, 0x1FF7FF) AM_READWRITE( h6280_irq_status_r, h6280_irq_status_w ) | |
| 111 | AM_RANGE( 0x1FF800, 0x1FFBFF) AM_READWRITE( pce_cd_intf_r, pce_cd_intf_w ) | |
| 112 | ADDRESS_MAP_END | |
| 113 | ||
| 114 | static ADDRESS_MAP_START( sgx_io , AS_IO, 8) | |
| 115 | AM_RANGE( 0x00, 0x03) AM_READWRITE( sgx_vdc_r, sgx_vdc_w ) | |
| 116 | ADDRESS_MAP_END | |
| 117 | ||
| 118 | /* todo: alternate forms of input (multitap, mouse, etc.) */ | |
| 119 | static INPUT_PORTS_START( pce ) | |
| 120 | ||
| 121 | PORT_START("JOY_P1") | |
| 122 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 123 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button I") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 124 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button II") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 125 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 126 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P1 Run") PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 127 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 128 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 129 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 130 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY(10) | |
| 131 | ||
| 132 | PORT_START("JOY_P2") | |
| 133 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 134 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Button I") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 135 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Button II") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 136 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 137 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P2 Run") PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 138 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 139 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 140 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 141 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY(20) | |
| 142 | ||
| 143 | PORT_START("JOY_P3") | |
| 144 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 145 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P3 Button I") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 146 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P3 Button II") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 147 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P3 Select") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 148 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P3 Run") PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 149 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 150 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 151 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 152 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CATEGORY(30) | |
| 153 | ||
| 154 | PORT_START("JOY_P4") | |
| 155 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 156 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P4 Button I") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 157 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P4 Button II") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 158 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P4 Select") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 159 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P4 Run") PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 160 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 161 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 162 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 163 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) PORT_CATEGORY(40) | |
| 164 | ||
| 165 | PORT_START("JOY_P5") | |
| 166 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 167 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P5 Button I") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 168 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P5 Button II") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 169 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P5 Select") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 170 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P5 Run") PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 171 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 172 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 173 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 174 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(5) PORT_CATEGORY(50) | |
| 175 | ||
| 176 | PORT_START("JOY6B_P1") | |
| 177 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 178 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button I") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 179 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button II") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 180 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 181 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P1 Run") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 182 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 183 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 184 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 185 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 186 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button III") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 187 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button IV") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 188 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Button V") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 189 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Button VI") PORT_PLAYER(1) PORT_CATEGORY(11) | |
| 190 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 191 | ||
| 192 | PORT_START("JOY6B_P2") /* Player 2 controls */ | |
| 193 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 194 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Button I") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 195 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Button II") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 196 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 197 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P2 Run") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 198 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 199 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 200 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 201 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 202 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P2 Button III") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 203 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P2 Button IV") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 204 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button V") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 205 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button VI") PORT_PLAYER(2) PORT_CATEGORY(21) | |
| 206 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 207 | ||
| 208 | PORT_START("JOY6B_P3") /* Player 3 controls */ | |
| 209 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 210 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P3 Button I") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 211 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P3 Button II") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 212 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P3 Select") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 213 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P3 Run") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 214 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 215 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 216 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 217 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 218 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P3 Button III") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 219 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P3 Button IV") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 220 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P3 Button V") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 221 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P3 Button VI") PORT_PLAYER(3) PORT_CATEGORY(31) | |
| 222 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 223 | ||
| 224 | PORT_START("JOY6B_P4") /* Player 4 controls */ | |
| 225 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 226 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P4 Button I") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 227 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P4 Button II") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 228 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P4 Select") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 229 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P4 Run") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 230 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 231 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 232 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 233 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 234 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P3 Button III") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 235 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P3 Button IV") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 236 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P3 Button V") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 237 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P3 Button VI") PORT_PLAYER(4) PORT_CATEGORY(41) | |
| 238 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 239 | ||
| 240 | PORT_START("JOY6B_P5") /* Player 5 controls */ | |
| 241 | /* II is left of I on the original pad so we map them in reverse order */ | |
| 242 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P5 Button I") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 243 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P5 Button II") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 244 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P5 Select") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 245 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("P5 Run") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 246 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 247 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 248 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 249 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 250 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P5 Button III") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 251 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P5 Button IV") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 252 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P5 Button V") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 253 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P5 Button VI") PORT_PLAYER(5) PORT_CATEGORY(51) | |
| 254 | PORT_BIT( 0xf000, IP_ACTIVE_HIGH,IPT_UNUSED ) //6-button pad header | |
| 255 | ||
| 256 | PORT_START("JOY_TYPE") | |
| 257 | PORT_CATEGORY_CLASS(0x0003,0x0000,"Joystick Type Player 1") | |
| 258 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 10) | |
| 259 | // PORT_CATEGORY_ITEM( 0x0001,"3-buttons", xx) | |
| 260 | PORT_CATEGORY_ITEM( 0x0002,"6-buttons", 11) | |
| 261 | // PORT_CATEGORY_ITEM( 0x0003,"Mouse", xx) | |
| 262 | PORT_CATEGORY_CLASS(0x000c,0x0000,"Joystick Type Player 2") | |
| 263 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 20) | |
| 264 | // PORT_CATEGORY_ITEM( 0x0004,"3-buttons", xx) | |
| 265 | PORT_CATEGORY_ITEM( 0x0008,"6-buttons", 21) | |
| 266 | // PORT_CATEGORY_ITEM( 0x000c,"Mouse", xx) | |
| 267 | PORT_CATEGORY_CLASS(0x0030,0x0000,"Joystick Type Player 3") | |
| 268 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 30) | |
| 269 | // PORT_CATEGORY_ITEM( 0x0010,"3-buttons", xx) | |
| 270 | PORT_CATEGORY_ITEM( 0x0020,"6-buttons", 31) | |
| 271 | // PORT_CATEGORY_ITEM( 0x0030,"Mouse", xx) | |
| 272 | PORT_CATEGORY_CLASS(0x00c0,0x0000,"Joystick Type Player 4") | |
| 273 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 40) | |
| 274 | // PORT_CATEGORY_ITEM( 0x0040,"3-buttons", xx) | |
| 275 | PORT_CATEGORY_ITEM( 0x0080,"6-buttons", 41) | |
| 276 | // PORT_CATEGORY_ITEM( 0x00c0,"Mouse", xx) | |
| 277 | PORT_CATEGORY_CLASS(0x0300,0x0000,"Joystick Type Player 5") | |
| 278 | PORT_CATEGORY_ITEM( 0x0000,"2-buttons", 50) | |
| 279 | // PORT_CATEGORY_ITEM( 0x0100,"3-buttons", xx) | |
| 280 | PORT_CATEGORY_ITEM( 0x0200,"6-buttons", 51) | |
| 281 | // PORT_CATEGORY_ITEM( 0x0300,"Mouse", xx) | |
| 282 | ||
| 283 | PORT_START("A_CARD") | |
| 284 | PORT_CONFNAME( 0x01, 0x01, "Arcade Card" ) | |
| 285 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 286 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) | |
| 287 | INPUT_PORTS_END | |
| 288 | ||
| 289 | ||
| 290 | static void pce_partialhash(hash_collection &dest, const unsigned char *data, | |
| 291 | unsigned long length, const char *functions) | |
| 292 | { | |
| 293 | if ( ( length <= PCE_HEADER_SIZE ) || ( length & PCE_HEADER_SIZE ) ) { | |
| 294 | dest.compute(&data[PCE_HEADER_SIZE], length - PCE_HEADER_SIZE, functions); | |
| 295 | } else { | |
| 296 | dest.compute(data, length, functions); | |
| 297 | } | |
| 298 | } | |
| 299 | ||
| 300 | static const c6280_interface c6280_config = | |
| 301 | { | |
| 302 | "maincpu" | |
| 303 | }; | |
| 304 | static MACHINE_CONFIG_FRAGMENT( pce_cdslot ) | |
| 305 | MCFG_CDROM_ADD( "cdrom" ) | |
| 306 | MCFG_CDROM_INTERFACE("pce_cdrom") | |
| 307 | ||
| 308 | MCFG_SOFTWARE_LIST_ADD("cd_list","pcecd") | |
| 309 | MACHINE_CONFIG_END | |
| 310 | ||
| 311 | static MACHINE_CONFIG_FRAGMENT( pce_cartslot ) | |
| 312 | MCFG_CARTSLOT_ADD("cart") | |
| 313 | MCFG_CARTSLOT_EXTENSION_LIST("pce,bin") | |
| 314 | MCFG_CARTSLOT_MANDATORY | |
| 315 | MCFG_CARTSLOT_INTERFACE("pce_cart") | |
| 316 | MCFG_CARTSLOT_LOAD(pce_cart) | |
| 317 | MCFG_CARTSLOT_PARTIALHASH(pce_partialhash) | |
| 318 | MCFG_SOFTWARE_LIST_ADD("cart_list","pce") | |
| 319 | MACHINE_CONFIG_END | |
| 320 | ||
| 321 | static MACHINE_CONFIG_FRAGMENT( tg16_cartslot ) | |
| 322 | MCFG_CARTSLOT_ADD("cart") | |
| 323 | MCFG_CARTSLOT_EXTENSION_LIST("pce,bin") | |
| 324 | MCFG_CARTSLOT_MANDATORY | |
| 325 | MCFG_CARTSLOT_INTERFACE("tg16_cart") | |
| 326 | MCFG_CARTSLOT_LOAD(pce_cart) | |
| 327 | MCFG_CARTSLOT_PARTIALHASH(pce_partialhash) | |
| 328 | MCFG_SOFTWARE_LIST_ADD("cart_list","tg16") | |
| 329 | MACHINE_CONFIG_END | |
| 330 | ||
| 331 | static MACHINE_CONFIG_FRAGMENT( sgx_cartslot ) | |
| 332 | MCFG_CARTSLOT_ADD("cart") | |
| 333 | MCFG_CARTSLOT_EXTENSION_LIST("pce,bin") | |
| 334 | MCFG_CARTSLOT_MANDATORY | |
| 335 | MCFG_CARTSLOT_INTERFACE("pce_cart") | |
| 336 | MCFG_CARTSLOT_LOAD(pce_cart) | |
| 337 | MCFG_CARTSLOT_PARTIALHASH(pce_partialhash) | |
| 338 | MCFG_SOFTWARE_LIST_ADD("cart_list","sgx") | |
| 339 | MACHINE_CONFIG_END | |
| 340 | ||
| 341 | static MACHINE_CONFIG_START( pce_common, pce_state ) | |
| 342 | /* basic machine hardware */ | |
| 343 | MCFG_CPU_ADD("maincpu", H6280, MAIN_CLOCK/3) | |
| 344 | MCFG_CPU_PROGRAM_MAP(pce_mem) | |
| 345 | MCFG_CPU_IO_MAP(pce_io) | |
| 346 | MCFG_CPU_VBLANK_INT_HACK(pce_interrupt, VDC_LPF) | |
| 347 | MCFG_QUANTUM_TIME(attotime::from_hz(60)) | |
| 348 | ||
| 349 | MCFG_MACHINE_START( pce ) | |
| 350 | MCFG_MACHINE_RESET( pce ) | |
| 351 | ||
| 352 | /* video hardware */ | |
| 353 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 354 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 355 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 356 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 357 | MCFG_SCREEN_RAW_PARAMS(MAIN_CLOCK/2, VDC_WPF, 70, 70 + 512 + 32, VDC_LPF, 14, 14+242) | |
| 358 | MCFG_SCREEN_UPDATE( pce ) | |
| 359 | ||
| 360 | /* MCFG_GFXDECODE( pce ) */ | |
| 361 | MCFG_PALETTE_LENGTH(1024) | |
| 362 | MCFG_PALETTE_INIT( vce ) | |
| 363 | ||
| 364 | MCFG_VIDEO_START( pce ) | |
| 365 | ||
| 366 | MCFG_NVRAM_HANDLER( pce ) | |
| 367 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 368 | MCFG_SOUND_ADD(C6280_TAG, C6280, MAIN_CLOCK/6) | |
| 369 | MCFG_SOUND_CONFIG(c6280_config) | |
| 370 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) | |
| 371 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) | |
| 372 | ||
| 373 | MCFG_SOUND_ADD( "msm5205", MSM5205, PCE_CD_CLOCK / 6 ) | |
| 374 | MCFG_SOUND_CONFIG( pce_cd_msm5205_interface ) | |
| 375 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "lspeaker", 0.50 ) | |
| 376 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "rspeaker", 0.50 ) | |
| 377 | ||
| 378 | MCFG_SOUND_ADD( "cdda", CDDA, 0 ) | |
| 379 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) | |
| 380 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) | |
| 381 | MACHINE_CONFIG_END | |
| 382 | ||
| 383 | static MACHINE_CONFIG_DERIVED( pce, pce_common ) | |
| 384 | MCFG_FRAGMENT_ADD( pce_cartslot ) | |
| 385 | MCFG_FRAGMENT_ADD( pce_cdslot ) | |
| 386 | MACHINE_CONFIG_END | |
| 387 | ||
| 388 | static MACHINE_CONFIG_DERIVED( tg16, pce_common ) | |
| 389 | MCFG_FRAGMENT_ADD( tg16_cartslot ) | |
| 390 | MCFG_FRAGMENT_ADD( pce_cdslot ) | |
| 391 | MACHINE_CONFIG_END | |
| 392 | ||
| 393 | static MACHINE_CONFIG_START( sgx, pce_state ) | |
| 394 | /* basic machine hardware */ | |
| 395 | MCFG_CPU_ADD("maincpu", H6280, MAIN_CLOCK/3) | |
| 396 | MCFG_CPU_PROGRAM_MAP(sgx_mem) | |
| 397 | MCFG_CPU_IO_MAP(sgx_io) | |
| 398 | MCFG_CPU_VBLANK_INT_HACK(sgx_interrupt, VDC_LPF) | |
| 399 | MCFG_QUANTUM_TIME(attotime::from_hz(60)) | |
| 400 | ||
| 401 | MCFG_MACHINE_START( pce ) | |
| 402 | MCFG_MACHINE_RESET( pce ) | |
| 403 | ||
| 404 | /* video hardware */ | |
| 405 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 406 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 407 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ | |
| 408 | MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) | |
| 409 | MCFG_SCREEN_RAW_PARAMS(MAIN_CLOCK/2, VDC_WPF, 70, 70 + 512 + 32, VDC_LPF, 14, 14+242) | |
| 410 | MCFG_SCREEN_UPDATE( pce ) | |
| 411 | ||
| 412 | MCFG_PALETTE_LENGTH(1024) | |
| 413 | MCFG_PALETTE_INIT( vce ) | |
| 414 | ||
| 415 | MCFG_VIDEO_START( pce ) | |
| 416 | ||
| 417 | MCFG_NVRAM_HANDLER( pce ) | |
| 418 | MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") | |
| 419 | MCFG_SOUND_ADD(C6280_TAG, C6280, MAIN_CLOCK/6) | |
| 420 | MCFG_SOUND_CONFIG(c6280_config) | |
| 421 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) | |
| 422 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) | |
| 423 | ||
| 424 | MCFG_SOUND_ADD( "msm5205", MSM5205, PCE_CD_CLOCK / 6 ) | |
| 425 | MCFG_SOUND_CONFIG( pce_cd_msm5205_interface ) | |
| 426 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "lspeaker", 0.00 ) | |
| 427 | MCFG_SOUND_ROUTE( ALL_OUTPUTS, "rspeaker", 0.00 ) | |
| 428 | ||
| 429 | MCFG_SOUND_ADD( "cdda", CDDA, 0 ) | |
| 430 | MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) | |
| 431 | MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) | |
| 432 | ||
| 433 | MCFG_FRAGMENT_ADD( sgx_cartslot ) | |
| 434 | MCFG_FRAGMENT_ADD( pce_cdslot ) | |
| 435 | MACHINE_CONFIG_END | |
| 436 | ||
| 437 | /*************************************************************************** | |
| 438 | ||
| 439 | Game driver(s) | |
| 440 | ||
| 441 | ***************************************************************************/ | |
| 442 | ||
| 443 | ROM_START( pce ) | |
| 444 | ROM_REGION( PCE_ROM_MAXSIZE, "user1", 0 ) /* Cartridge ROM area */ | |
| 445 | ROM_FILL( 0, PCE_ROM_MAXSIZE, 0xFF ) | |
| 446 | ROM_END | |
| 447 | ||
| 448 | #define rom_tg16 rom_pce | |
| 449 | #define rom_sgx rom_pce | |
| 450 | ||
| 451 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ | |
| 452 | CONS( 1987, pce, 0, 0, pce, pce, pce, "Nippon Electronic Company", "PC Engine", GAME_IMPERFECT_SOUND) | |
| 453 | CONS( 1989, tg16, pce, 0, tg16, pce, tg16, "Nippon Electronic Company", "TurboGrafx 16", GAME_IMPERFECT_SOUND) | |
| 454 | CONS( 1989, sgx, pce, 0, sgx, pce, sgx, "Nippon Electronic Company", "SuperGrafx", GAME_IMPERFECT_SOUND) |
| r11531 | r11532 | |
|---|---|---|
| 498 | 498 | $(MAME_DRIVERS)/segasms.o \ |
| 499 | 499 | $(MAME_DRIVERS)/sg1000.o \ |
| 500 | 500 | $(MAME_MACHINE)/gdrom.o \ |
| 501 | $(MAME_DRIVERS)/a310.o \ | |
| 502 | $(MAME_DRIVERS)/a7000.o \ | |
| 503 | $(MAME_MACHINE)/amigafdc.o \ | |
| 504 | $(MAME_MACHINE)/amigacrt.o \ | |
| 505 | $(MAME_MACHINE)/amigacd.o \ | |
| 506 | $(MAME_MACHINE)/amigakbd.o \ | |
| 507 | $(MAME_DRIVERS)/amiga.o \ | |
| 508 | $(MAME_DRIVERS)/a3000.o \ | |
| 509 | $(MAME_DRIVERS)/ami1200.o \ | |
| 510 | $(MAME_MACHINE)/ataricrt.o \ | |
| 511 | $(MAME_MACHINE)/atarifdc.o \ | |
| 512 | $(MAME_DRIVERS)/atari400.o \ | |
| 513 | $(MAME_MACHINE)/pce.o \ | |
| 514 | $(MAME_DRIVERS)/pce.o \ | |
| 515 | $(MAME_MACHINE)/nes_mmc.o \ | |
| 516 | $(MAME_VIDEO)/nes.o \ | |
| 517 | $(MAME_MACHINE)/nes.o \ | |
| 518 | $(MAME_DRIVERS)/nes.o \ | |
| 519 | $(MAME_MACHINE)/snescart.o \ | |
| 520 | $(MAME_DRIVERS)/snes.o \ | |
| 521 | $(MAME_DRIVERS)/n64.o \ | |
| 522 | $(MAME_MACHINE)/aescart.o \ | |
| 523 | $(MAME_DRIVERS)/ng_aes.o \ | |
| 501 | $(MESS_DRIVERS)/a310.o \ | |
| 502 | $(MESS_DRIVERS)/a7000.o \ | |
| 503 | $(MESS_MACHINE)/amigafdc.o \ | |
| 504 | $(MESS_MACHINE)/amigacrt.o \ | |
| 505 | $(MESS_MACHINE)/amigacd.o \ | |
| 506 | $(MESS_MACHINE)/amigakbd.o \ | |
| 507 | $(MESS_DRIVERS)/amiga.o \ | |
| 508 | $(MESS_DRIVERS)/a3000.o \ | |
| 509 | $(MESS_DRIVERS)/ami1200.o \ | |
| 510 | $(MESS_MACHINE)/ataricrt.o \ | |
| 511 | $(MESS_MACHINE)/atarifdc.o \ | |
| 512 | $(MESS_DRIVERS)/atari400.o \ | |
| 513 | $(MESS_MACHINE)/pce.o \ | |
| 514 | $(MESS_DRIVERS)/pce.o \ | |
| 515 | $(MESS_MACHINE)/nes_mmc.o \ | |
| 516 | $(MESS_VIDEO)/nes.o \ | |
| 517 | $(MESS_MACHINE)/nes.o \ | |
| 518 | $(MESS_DRIVERS)/nes.o \ | |
| 519 | $(MESS_MACHINE)/snescart.o \ | |
| 520 | $(MESS_DRIVERS)/snes.o \ | |
| 521 | $(MESS_DRIVERS)/n64.o \ | |
| 522 | $(MESS_DRIVERS)/ng_aes.o \ | |
| 524 | 523 | $(MESS_DRIVERS)/psx.o \ |
| 525 | 524 | $(MESS_MACHINE)/psxcd.o \ |
| 526 | 525 | $(MESS_MACHINE)/psxcddrv.o \ |
| 527 | 526 | $(MESS_MACHINE)/psxcard.o \ |
| 527 | $(MESS_DEVICES)/aescart.o \ | |
| 528 | 528 | $(MAME_DRIVERS)/saturn.o \ |
| 529 | 529 | $(MAME_DRIVERS)/cps1.o \ |
| 530 | 530 | $(MAME_VIDEO)/cps1.o \ |
| r11531 | r11532 | |
| 1802 | 1802 | $(MESS_DRIVERS)/mmd1.o: $(MESS_LAYOUT)/mmd1.lh \ |
| 1803 | 1803 | $(MESS_LAYOUT)/mmd2.lh |
| 1804 | 1804 | $(MESS_VIDEO)/newbrain.o: $(MESS_LAYOUT)/newbrain.lh |
| 1805 | $(M | |
| 1805 | $(M | |
| 1806 | 1806 | $(MESS_DRIVERS)/poly880.o: $(MESS_LAYOUT)/poly880.lh |
| 1807 | 1807 | $(MESS_DRIVERS)/pc1500.o: $(MESS_LAYOUT)/pc1500.lh |
| 1808 | 1808 | $(MESS_VIDEO)/pc8401a.o: $(MESS_LAYOUT)/pc8500.lh |
| Previous | 15994 Revisions | Next |