trunk/src/emu/bus/a7800/a78_slot.c
| r31771 | r31772 | |
| 39 | 39 | //------------------------------------------------- |
| 40 | 40 | |
| 41 | 41 | device_a78_cart_interface::device_a78_cart_interface (const machine_config &mconfig, device_t &device) |
| 42 | | : device_slot_card_interface(mconfig, device) |
| 42 | : device_slot_card_interface(mconfig, device), |
| 43 | m_base_rom(0x8000), |
| 44 | m_bank_mask(0) |
| 43 | 45 | { |
| 44 | 46 | } |
| 45 | 47 | |
| r31771 | r31772 | |
| 60 | 62 | { |
| 61 | 63 | if (m_rom == NULL) |
| 62 | 64 | { |
| 63 | | // allocate rom |
| 64 | 65 | m_rom.resize(size); |
| 65 | | |
| 66 | |
| 66 | 67 | // setup other helpers |
| 67 | 68 | if ((size / 0x4000) & 1) // compensate for SuperGame carts with 9 x 16K banks (to my knowledge no other cart has m_bank_mask != power of 2) |
| 68 | 69 | m_bank_mask = (size / 0x4000) - 2; |
| 69 | 70 | else |
| 70 | 71 | m_bank_mask = (size / 0x4000) - 1; |
| 71 | | |
| 72 | |
| 72 | 73 | // the rom is mapped to the top of the memory area |
| 73 | 74 | // so we store the starting point of data to simplify |
| 74 | 75 | // the access handling |
| r31771 | r31772 | |
| 207 | 208 | |
| 208 | 209 | bool a78_cart_slot_device::call_load() |
| 209 | 210 | { |
| 210 | | UINT8 *ROM; |
| 211 | | UINT32 len; |
| 212 | | |
| 213 | | if (software_entry() != NULL) |
| 211 | if (m_cart) |
| 214 | 212 | { |
| 215 | | const char *pcb_name; |
| 216 | | len = get_software_region_length("rom"); |
| 217 | | |
| 218 | | m_cart->rom_alloc(len); |
| 219 | | ROM = m_cart->get_rom_base(); |
| 220 | | memcpy(ROM, get_software_region("rom"), len); |
| 221 | | |
| 222 | | if ((pcb_name = get_feature("slot")) != NULL) |
| 223 | | m_type = a78_get_pcb_id(pcb_name); |
| 224 | | else |
| 225 | | m_type = A78_TYPE0; |
| 226 | | } |
| 227 | | else |
| 228 | | { |
| 229 | | // Load and check the header |
| 230 | | char head[128]; |
| 231 | | fread(head, 128); |
| 213 | UINT8 *ROM; |
| 214 | UINT32 len; |
| 232 | 215 | |
| 233 | | if (verify_header((char *)head) == IMAGE_VERIFY_FAIL) |
| 234 | | return IMAGE_INIT_FAIL; |
| 235 | | |
| 236 | | len = (head[49] << 24) |(head[50] << 16) |(head[51] << 8) | head[52]; |
| 237 | | if (len + 128 > length()) |
| 216 | if (software_entry() != NULL) |
| 238 | 217 | { |
| 239 | | logerror("Invalid length in the header. The game might be corrupted.\n"); |
| 240 | | len = length() - 128; |
| 218 | const char *pcb_name; |
| 219 | len = get_software_region_length("rom"); |
| 220 | |
| 221 | m_cart->rom_alloc(len); |
| 222 | ROM = m_cart->get_rom_base(); |
| 223 | memcpy(ROM, get_software_region("rom"), len); |
| 224 | |
| 225 | if ((pcb_name = get_feature("slot")) != NULL) |
| 226 | m_type = a78_get_pcb_id(pcb_name); |
| 227 | else |
| 228 | m_type = A78_TYPE0; |
| 241 | 229 | } |
| 242 | | |
| 243 | | switch ((head[53] << 8) | head[54]) |
| 230 | else |
| 244 | 231 | { |
| 245 | | case 0x0000: |
| 246 | | m_type = A78_TYPE0; |
| 247 | | break; |
| 248 | | case 0x0001: |
| 249 | | m_type = A78_TYPE1; |
| 250 | | break; |
| 251 | | case 0x0002: |
| 252 | | m_type = A78_TYPE2; |
| 253 | | break; |
| 254 | | case 0x0003: |
| 255 | | m_type = A78_TYPE3; |
| 256 | | break; |
| 257 | | case 0x0006: |
| 258 | | m_type = A78_TYPE6; |
| 259 | | break; |
| 260 | | case 0x000a: |
| 261 | | m_type = A78_TYPEA; |
| 262 | | break; |
| 263 | | case 0x000b: |
| 264 | | m_type = A78_TYPEB; |
| 265 | | break; |
| 266 | | case 0x0020: |
| 267 | | m_type = A78_BANKRAM; |
| 268 | | break; |
| 269 | | case 0x0100: |
| 270 | | m_type = A78_ABSOLUTE; |
| 271 | | break; |
| 272 | | case 0x0200: |
| 273 | | m_type = A78_ACTIVISION; |
| 274 | | break; |
| 232 | // Load and check the header |
| 233 | char head[128]; |
| 234 | fread(head, 128); |
| 235 | |
| 236 | if (verify_header((char *)head) == IMAGE_VERIFY_FAIL) |
| 237 | return IMAGE_INIT_FAIL; |
| 238 | |
| 239 | len = (head[49] << 24) | (head[50] << 16) | (head[51] << 8) | head[52]; |
| 240 | if (len + 128 > length()) |
| 241 | { |
| 242 | logerror("Invalid length in the header. The game might be corrupted.\n"); |
| 243 | len = length() - 128; |
| 244 | } |
| 245 | |
| 246 | switch ((head[53] << 8) | head[54]) |
| 247 | { |
| 248 | case 0x0000: |
| 249 | m_type = A78_TYPE0; |
| 250 | break; |
| 251 | case 0x0001: |
| 252 | m_type = A78_TYPE1; |
| 253 | break; |
| 254 | case 0x0002: |
| 255 | m_type = A78_TYPE2; |
| 256 | break; |
| 257 | case 0x0003: |
| 258 | m_type = A78_TYPE3; |
| 259 | break; |
| 260 | case 0x0006: |
| 261 | m_type = A78_TYPE6; |
| 262 | break; |
| 263 | case 0x000a: |
| 264 | m_type = A78_TYPEA; |
| 265 | break; |
| 266 | case 0x000b: |
| 267 | m_type = A78_TYPEB; |
| 268 | break; |
| 269 | case 0x0020: |
| 270 | m_type = A78_BANKRAM; |
| 271 | break; |
| 272 | case 0x0100: |
| 273 | m_type = A78_ABSOLUTE; |
| 274 | break; |
| 275 | case 0x0200: |
| 276 | m_type = A78_ACTIVISION; |
| 277 | break; |
| 278 | } |
| 279 | logerror("Cart type: %x\n", m_type); |
| 280 | |
| 281 | internal_header_logging((UINT8 *)head, length()); |
| 282 | |
| 283 | m_cart->rom_alloc(len); |
| 284 | ROM = m_cart->get_rom_base(); |
| 285 | fread(ROM, len); |
| 275 | 286 | } |
| 276 | | logerror("Cart type: %x\n", m_type); |
| 277 | 287 | |
| 278 | | // This field is currently only used for logging |
| 279 | | m_stick_type = head[55]; |
| 288 | //printf("Type: %s\n", a78_get_slot(m_type)); |
| 280 | 289 | |
| 281 | | m_cart->rom_alloc(len); |
| 282 | | ROM = m_cart->get_rom_base(); |
| 283 | | fread(ROM, len); |
| 290 | if (m_type == A78_TYPE6) |
| 291 | m_cart->ram_alloc(0x4000); |
| 292 | if (m_type == A78_BANKRAM) |
| 293 | m_cart->ram_alloc(0x8000); |
| 294 | if (m_type == A78_XB_BOARD || m_type == A78_XM_BOARD) |
| 295 | m_cart->ram_alloc(0x20000); |
| 296 | if (m_type == A78_HSC || m_type == A78_XM_BOARD) |
| 297 | { |
| 298 | m_cart->nvram_alloc(0x800); |
| 299 | battery_load(m_cart->get_nvram_base(), 0x800, 0xff); |
| 300 | } |
| 284 | 301 | } |
| 285 | | |
| 286 | | //printf("Type: %s\n", a78_get_slot(m_type)); |
| 287 | | |
| 288 | | if (m_type == A78_TYPE6) |
| 289 | | m_cart->ram_alloc(0x4000); |
| 290 | | if (m_type == A78_BANKRAM) |
| 291 | | m_cart->ram_alloc(0x8000); |
| 292 | | if (m_type == A78_XB_BOARD || m_type == A78_XM_BOARD) |
| 293 | | m_cart->ram_alloc(0x20000); |
| 294 | | if (m_type == A78_HSC || m_type == A78_XM_BOARD) |
| 295 | | { |
| 296 | | m_cart->nvram_alloc(0x800); |
| 297 | | battery_load(m_cart->get_nvram_base(), 0x800, 0xff); |
| 298 | | } |
| 299 | | |
| 300 | 302 | return IMAGE_INIT_PASS; |
| 301 | 303 | } |
| 302 | 304 | |
| r31771 | r31772 | |
| 380 | 382 | case 0x0003: |
| 381 | 383 | type = A78_TYPE3; |
| 382 | 384 | break; |
| 383 | | case 0x0004: |
| 385 | case 0x0006: |
| 384 | 386 | type = A78_TYPE6; |
| 385 | 387 | break; |
| 386 | 388 | case 0x000a: |
| r31771 | r31772 | |
| 477 | 479 | } |
| 478 | 480 | |
| 479 | 481 | |
| 480 | | /* Header format |
| 481 | | 0 Header version - 1 byte |
| 482 | | 1..16 "ATARI7800 " - 16 bytes |
| 483 | | 17..48 Cart title - 32 bytes |
| 484 | | 49..52 data length - 4 bytes |
| 485 | | 53..54 cart type - 2 bytes |
| 486 | | bit 0 0x01 - pokey cart |
| 487 | | bit 1 0x02 - supercart bank switched |
| 488 | | bit 2 0x04 - supercart RAM at $4000 |
| 489 | | bit 3 0x08 - additional ROM at $4000 |
| 490 | | bit 4 0x10 - bank 6 at $4000 |
| 491 | | bit 5 0x20 - supercart banked RAM |
| 492 | | |
| 493 | | bit 8-15 - Special |
| 494 | | 0 = Normal cart |
| 495 | | 1 = Absolute (F18 Hornet) |
| 496 | | 2 = Activision |
| 497 | | |
| 498 | | 55 controller 1 type - 1 byte |
| 499 | | 56 controller 2 type - 1 byte |
| 500 | | 0 = None |
| 501 | | 1 = Joystick |
| 502 | | 2 = Light Gun |
| 503 | | 57 0 = NTSC/1 = PAL |
| 504 | | |
| 505 | | 100..127 "ACTUAL CART DATA STARTS HERE" - 28 bytes |
| 506 | | |
| 507 | | Versions: |
| 508 | | Version 0: Initial release |
| 509 | | Version 1: Added PAL/NTSC bit. Added Special cart byte. |
| 510 | | Changed 53 bit 2, added bit 3 |
| 511 | | |
| 512 | | */ |
| 482 | /*------------------------------------------------- |
| 483 | A78 header logging |
| 484 | -------------------------------------------------*/ |
| 513 | 485 | |
| 514 | | // TODO: log all properties from the header |
| | No newline at end of file |
| 486 | void a78_cart_slot_device::internal_header_logging(UINT8 *header, UINT32 len) |
| 487 | { |
| 488 | char head_title[35]; |
| 489 | UINT32 head_length = (header[49] << 24) | (header[50] << 16) | (header[51] << 8) | header[52]; |
| 490 | UINT16 head_mapper = (header[53] << 8) | header[54]; |
| 491 | UINT8 head_ctrl1 = header[55]; |
| 492 | UINT8 head_ctrl2 = header[56]; |
| 493 | UINT8 head_ispal = header[57]; |
| 494 | astring cart_mapper, ctrl1, ctrl2; |
| 495 | memcpy(head_title, header + 0x11, 0x20); |
| 496 | |
| 497 | switch (head_mapper) |
| 498 | { |
| 499 | case 0x0000: |
| 500 | cart_mapper.cpy("No Bankswitch"); |
| 501 | break; |
| 502 | case 0x0001: |
| 503 | cart_mapper.cpy("No Bankswitch + POKEY"); |
| 504 | break; |
| 505 | case 0x0002: |
| 506 | cart_mapper.cpy("SuperCart Bankswitch"); |
| 507 | break; |
| 508 | case 0x0003: |
| 509 | cart_mapper.cpy("SuperCart Bankswitch + POKEY"); |
| 510 | break; |
| 511 | case 0x0006: |
| 512 | cart_mapper.cpy("SuperCart Bankswitch + RAM"); |
| 513 | break; |
| 514 | case 0x000a: |
| 515 | cart_mapper.cpy("SuperCart 9Banks"); |
| 516 | break; |
| 517 | case 0x000b: |
| 518 | cart_mapper.cpy("SuperCart XM Compatible"); |
| 519 | break; |
| 520 | case 0x0020: |
| 521 | cart_mapper.cpy("SuperCart Bankswitch + 32K RAM"); |
| 522 | break; |
| 523 | case 0x0100: |
| 524 | cart_mapper.cpy("Absolute Bankswitch"); |
| 525 | break; |
| 526 | case 0x0200: |
| 527 | cart_mapper.cpy("Activision Bankswitch"); |
| 528 | break; |
| 529 | default: |
| 530 | cart_mapper.cpy("Unknown mapper"); |
| 531 | break; |
| 532 | } |
| 533 | |
| 534 | switch (head_ctrl1) |
| 535 | { |
| 536 | case 0x00: |
| 537 | ctrl1.cpy("None"); |
| 538 | break; |
| 539 | case 0x01: |
| 540 | ctrl1.cpy("Joystick"); |
| 541 | break; |
| 542 | case 0x02: |
| 543 | ctrl1.cpy("Light Gun"); |
| 544 | break; |
| 545 | default: |
| 546 | ctrl1.cpy("Unknown controller"); |
| 547 | break; |
| 548 | } |
| 549 | |
| 550 | switch (head_ctrl2) |
| 551 | { |
| 552 | case 0x00: |
| 553 | ctrl2.cpy("None"); |
| 554 | break; |
| 555 | case 0x01: |
| 556 | ctrl2.cpy("Joystick"); |
| 557 | break; |
| 558 | case 0x02: |
| 559 | ctrl2.cpy("Light Gun"); |
| 560 | break; |
| 561 | default: |
| 562 | ctrl2.cpy("Unknown controller"); |
| 563 | break; |
| 564 | } |
| 565 | |
| 566 | logerror( "ROM DETAILS\n" ); |
| 567 | logerror( "===========\n\n" ); |
| 568 | logerror( "\tTotal length (with header): 0x%x (%dK + 128b header)\n\nn", len, len/0x400); |
| 569 | logerror( "HEADER DETAILS\n" ); |
| 570 | logerror( "==============\n\n" ); |
| 571 | logerror( "\tTitle: %.32s\n", head_title); |
| 572 | logerror( "\tLength: 0x%X [real 0x%X]\n", head_length, len); |
| 573 | logerror( "\tMapper: %s\n", cart_mapper.cstr()); |
| 574 | logerror( "\t\tPOKEY: %s\n", BIT(head_mapper, 0) ? "Yes" : "No"); |
| 575 | logerror( "\t\tSC Bankswitch: %s\n", BIT(head_mapper, 1) ? "Yes" : "No"); |
| 576 | logerror( "\t\tRAM at $4000: %s\n", BIT(head_mapper, 2) ? "Yes" : "No"); |
| 577 | logerror( "\t\tbank0 at $4000: %s\n", BIT(head_mapper, 3) ? "Yes" : "No"); |
| 578 | logerror( "\t\tbank6 at $4000: %s\n", BIT(head_mapper, 4) ? "Yes" : "No"); |
| 579 | logerror( "\t\tbanked RAM: %s\n", BIT(head_mapper, 5) ? "Yes" : "No"); |
| 580 | logerror( "\t\tSpecial: %s ", (head_mapper & 0xff00) ? "Yes" : "No"); |
| 581 | if (head_mapper & 0xff00) |
| 582 | { |
| 583 | logerror( "[%s]\n", (head_mapper & 0xff00) == 0x100 ? "Absolute" : |
| 584 | (head_mapper & 0xff00) == 0x200 ? "Activision" : "Unknown" ); |
| 585 | } |
| 586 | else |
| 587 | logerror( "\n"); |
| 588 | logerror( "\tController 1: 0x%.2X [%s]\n", head_ctrl1, ctrl1.cstr()); |
| 589 | logerror( "\tController 2: 0x%.2X [%s]\n", head_ctrl2, ctrl2.cstr()); |
| 590 | logerror( "\tVideo: %s\n", (head_ispal) ? "PAL" : "NTSC"); |
| 591 | } |