src/mess/devices/ti99cart.c
| r7794 | r7795 | |
| 29 | 29 | { |
| 30 | 30 | /* PCB device associated to this cartridge. If NULL, the slot is empty. */ |
| 31 | 31 | running_device *pcb; |
| 32 | | |
| 32 | |
| 33 | 33 | /* GROM buffer size. */ |
| 34 | 34 | int grom_size; |
| 35 | | |
| 35 | |
| 36 | 36 | /* ROM page. */ |
| 37 | 37 | int rom_page; |
| 38 | 38 | /* RAM page. */ |
| 39 | 39 | int ram_page; |
| 40 | | |
| 40 | |
| 41 | 41 | /* ROM buffer size. All banks have equal sizes. */ |
| 42 | 42 | int rom_size; |
| 43 | 43 | /* RAM buffer size. All banks have equal sizes. */ |
| 44 | 44 | int ram_size; |
| 45 | | |
| 45 | |
| 46 | 46 | /* pointer to GROM data. */ |
| 47 | 47 | UINT8 *grom_ptr; |
| 48 | | |
| 48 | |
| 49 | 49 | /* GROM buffered data output. */ |
| 50 | 50 | /* UINT8 grom_buffer; */ /* Now handled by the multicart system. */ |
| 51 | | |
| 51 | |
| 52 | 52 | /* ROM buffer. We are using this for both 16 bit (99/4a) and 8 bit |
| 53 | 53 | (99/8) access. */ |
| 54 | 54 | void *rom_ptr; |
| 55 | | |
| 55 | |
| 56 | 56 | /* ROM buffer for the second bank of paged cartridges. Other cartridges |
| 57 | 57 | usually store their ROM in one large file. */ |
| 58 | 58 | void *rom2_ptr; |
| 59 | | |
| 59 | |
| 60 | 60 | /* RAM buffer. The persistence service is done by the cartridge system. |
| 61 | 61 | The RAM space is a consecutive space; all banks are in one buffer. */ |
| 62 | 62 | void *ram_ptr; |
| r7794 | r7795 | |
| 89 | 89 | /* Reserves space for all cartridges. This is also used in the legacy |
| 90 | 90 | cartridge system, but only for slot 0. */ |
| 91 | 91 | cartridge_t cartridge[NUMBER_OF_CARTRIDGE_SLOTS]; |
| 92 | | |
| 92 | |
| 93 | 93 | /* Determines which slot is currently active. This value is changed when there |
| 94 | 94 | are accesses to other GROM base addresses. */ |
| 95 | 95 | int active_slot; |
| 96 | | |
| 96 | |
| 97 | 97 | /* Used in order to enforce a special slot. This value is retrieved |
| 98 | 98 | from the dipswitch setting. A value of -1 means automatic, that is, |
| 99 | 99 | the grom base switch is used. Values 0 .. max refer to the |
| 100 | 100 | respective slot. */ |
| 101 | 101 | int fixed_slot; |
| 102 | | |
| 102 | |
| 103 | 103 | /* Holds the highest index of a cartridge being plugged in plus one. |
| 104 | 104 | If we only have one cartridge inserted, we don't want to get a |
| 105 | 105 | selection option, so we just mirror the memory contents. */ |
| 106 | 106 | int next_free_slot; |
| 107 | | |
| 107 | |
| 108 | 108 | /* Counts the number of slots which currently contain legacy format |
| 109 | 109 | cartridge images. */ |
| 110 | 110 | int legacy_slots; |
| 111 | | |
| 111 | |
| 112 | 112 | /* Counts the number of slots which currently contain new format |
| 113 | 113 | cartridge images. */ |
| 114 | 114 | int multi_slots; |
| 115 | | |
| 115 | |
| 116 | 116 | /* Legacy mode. Stores the slot number where the cartridge part is mounted. |
| 117 | 117 | Index is from slotc_type_t. */ |
| 118 | 118 | int legacy_slotnumber[5]; |
| 119 | | |
| 119 | |
| 120 | 120 | /* current address pointer for the active GROM in port (16 bits) */ |
| 121 | 121 | UINT16 grom_address; |
| 122 | 122 | /* GROM data buffer */ |
| r7794 | r7795 | |
| 290 | 290 | systems, i.e. it should be shifted left by 1. |
| 291 | 291 | // 1001 1wbb bbbb bbr0 |
| 292 | 292 | */ |
| 293 | | cartridge_slot_set(device, (offset>>2) & 0x00ff); |
| 294 | | |
| 295 | | if (offset & 0x0002) |
| 293 | cartridge_slot_set(device, (offset>>2) & 0x00ff); |
| 294 | |
| 295 | if (offset & 0x0002) |
| 296 | 296 | grom_write_address(cartslots, data); |
| 297 | 297 | else |
| 298 | 298 | cartslots->raddr_LSB = cartslots->waddr_LSB = FALSE; |
| 299 | | /* TODO: write to GRAM */ |
| 299 | /* TODO: write to GRAM */ |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | 302 | /* |
| r7794 | r7795 | |
| 309 | 309 | /* When reading, reset the hi/lo flag byte for writing. |
| 310 | 310 | TODO: Verify this with a real machine. */ |
| 311 | 311 | cartslots->waddr_LSB = FALSE; |
| 312 | | |
| 312 | |
| 313 | 313 | /* Address reading is done in two steps; first, the high byte |
| 314 | 314 | is transferred, then the low byte. */ |
| 315 | 315 | if (cartslots->raddr_LSB) |
| r7794 | r7795 | |
| 352 | 352 | systems, i.e. it should be shifted left by 1. |
| 353 | 353 | 1001 1wbb bbbb bbr0 |
| 354 | 354 | */ |
| 355 | | cartridge_slot_set(device, (offset>>2) & 0x00ff); |
| 356 | | |
| 357 | | if (offset & 0x0002) |
| 355 | cartridge_slot_set(device, (offset>>2) & 0x00ff); |
| 356 | |
| 357 | if (offset & 0x0002) |
| 358 | 358 | return grom_read_address(cartslots); |
| 359 | 359 | |
| 360 | 360 | /* Handle the legacy mode. */ |
| r7794 | r7795 | |
| 370 | 370 | one cartridge, this entails that the second cartridge is |
| 371 | 371 | different (all zeros), and so we get a meaningless selection |
| 372 | 372 | option between cartridge 1 and 1 and 1 ... |
| 373 | | |
| 373 | |
| 374 | 374 | So if next_free_slot==1, we have one cartridge in slot 0. |
| 375 | 375 | In that case we trick the OS to believe that the addressed |
| 376 | 376 | cartridge appears at all locations which causes it to assume a |
| r7794 | r7795 | |
| 391 | 391 | /* TODO: replace this using a bitmap of the available GROMs */ |
| 392 | 392 | if ((cartslots->grom_address < 0x6000) || (cartslots->grom_address > (cartridge->grom_size+0x6000))) |
| 393 | 393 | value = 0; |
| 394 | | else |
| 394 | else |
| 395 | 395 | { |
| 396 | 396 | /* Buffered GROM access. We use a (virtual) common buffer to avoid implementing this for each cartridge. */ |
| 397 | 397 | value = (UINT8)cartslots->grom_buffer; |
| r7794 | r7795 | |
| 409 | 409 | /* The program counter wraps at each GROM chip size (8K), |
| 410 | 410 | so 0x5fff + 1 = 0x4000. */ |
| 411 | 411 | cartslots->grom_address = ((cartslots->grom_address + 1) & 0x1FFF) | (cartslots->grom_address & 0xE000); |
| 412 | | |
| 412 | |
| 413 | 413 | /* Reset the read and write address flipflops. */ |
| 414 | 414 | cartslots->raddr_LSB = cartslots->waddr_LSB = FALSE; |
| 415 | 415 | } |
| r7794 | r7795 | |
| 441 | 441 | cartridge_t *cartridge; |
| 442 | 442 | running_device *cartsys = cartslot->owner; |
| 443 | 443 | ti99_multicart_state *cartslots = (ti99_multicart_state *)cartsys->token; |
| 444 | | |
| 444 | |
| 445 | 445 | void *socketcont; |
| 446 | 446 | int reslength; |
| 447 | 447 | int i; |
| 448 | | |
| 448 | |
| 449 | 449 | int slotnumber = get_index_from_tagname(cartslot)-1; |
| 450 | 450 | assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS); |
| 451 | | |
| 451 | |
| 452 | 452 | /* There is a cartridge in this slot, check the maximum slot number. */ |
| 453 | 453 | if (cartslots->next_free_slot <= slotnumber) |
| 454 | 454 | { |
| 455 | 455 | cartslots->next_free_slot = slotnumber+1; |
| 456 | 456 | } |
| 457 | 457 | cartridge = &cartslots->cartridge[slotnumber]; |
| 458 | | |
| 458 | |
| 459 | 459 | /* Get the socket which is retrieved by the multicart instance in |
| 460 | 460 | the state of the cartslot instance. */ |
| 461 | 461 | socketcont = cartslot_get_socket(cartslot, "grom_socket"); |
| r7794 | r7795 | |
| 465 | 465 | cartridge->grom_ptr = (UINT8 *)socketcont; |
| 466 | 466 | cartridge->grom_size = reslength; |
| 467 | 467 | } |
| 468 | | |
| 468 | |
| 469 | 469 | socketcont = cartslot_get_socket(cartslot, "rom_socket"); |
| 470 | 470 | reslength = cartslot_get_resource_length(cartslot, "rom_socket"); |
| 471 | 471 | if (socketcont != NULL) |
| r7794 | r7795 | |
| 480 | 480 | cont16b[i] = BIG_ENDIANIZE_INT16(cont16b[i]); |
| 481 | 481 | } |
| 482 | 482 | } |
| 483 | | |
| 483 | |
| 484 | 484 | socketcont = cartslot_get_socket(cartslot, "rom2_socket"); |
| 485 | 485 | // reslength = cartslot_get_resource_length(cartslot, "rom2_socket"); /* cannot differ from rom_socket */ |
| 486 | 486 | if (socketcont != NULL) |
| r7794 | r7795 | |
| 2013 | 2013 | /* If we are here, we have a multicart. */ |
| 2014 | 2014 | ti99_pcb_t *pcb = (ti99_pcb_t *)pcbdev->token; |
| 2015 | 2015 | cartslot_t *cart = (cartslot_t *)image->token; |
| 2016 | | |
| 2016 | |
| 2017 | 2017 | /* try opening this as a multicart */ |
| 2018 | 2018 | /* This line requires that cartslot_t be included in cartslot.h, |
| 2019 | 2019 | otherwise one cannot make use of multicart handling within such a |
| 2020 | 2020 | custom LOAD function. */ |
| 2021 | 2021 | multicart_open_error me = multicart_open(image_filename(image), image->machine->gamedrv->name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc); |
| 2022 | | |
| 2022 | |
| 2023 | 2023 | /* Now that we have loaded the image files, let the PCB put them all |
| 2024 | 2024 | together. This means we put the images in a structure which allows |
| 2025 | 2025 | for a quick access by the memory handlers. Every PCB defines an |
| r7794 | r7795 | |
| 2028 | 2028 | result = pcb->assemble(image); |
| 2029 | 2029 | else |
| 2030 | 2030 | fatalerror("Error loading multicart: %s\n", multicart_error_text(me)); |
| 2031 | | |
| 2031 | |
| 2032 | 2032 | /* This is for legacy support. If we have no multicart left |
| 2033 | 2033 | but there are still legacy dumps, we switch to legacy mode. */ |
| 2034 | 2034 | if (result != INIT_FAIL) |
| r7794 | r7795 | |
| 2131 | 2131 | access beyond the image size must be detected. */ |
| 2132 | 2132 | if ((cartslots->grom_address < 0x6000) || (cartslots->grom_address > (cartridge->grom_size+0x6000))) |
| 2133 | 2133 | return 0; |
| 2134 | | |
| 2134 | |
| 2135 | 2135 | value = (UINT8)cartslots->grom_buffer; |
| 2136 | 2136 | /* read ahead */ |
| 2137 | 2137 | cartslots->grom_buffer = cartridge->grom_ptr[cartslots->grom_address-0x6000]; |
| r7794 | r7795 | |
| 2139 | 2139 | /* The program counter wraps at each GROM chip size (8K), |
| 2140 | 2140 | so 0x5fff + 1 = 0x4000. */ |
| 2141 | 2141 | cartslots->grom_address = ((cartslots->grom_address + 1) & 0x1FFF) | (cartslots->grom_address & 0xE000); |
| 2142 | | |
| 2142 | |
| 2143 | 2143 | /* Reset the read and write address flipflops. */ |
| 2144 | 2144 | cartslots->raddr_LSB = cartslots->waddr_LSB = FALSE; |
| 2145 | 2145 | } |
| r7794 | r7795 | |
| 2514 | 2514 | if (ti99_is_99_8()) |
| 2515 | 2515 | { |
| 2516 | 2516 | // printf("** is 99/8\n"); |
| 2517 | | image_battery_load(image, cart8rom+0x1000,0x1000); |
| 2517 | image_battery_load(image, cart8rom+0x1000,0x1000, 0x00); |
| 2518 | 2518 | cartslots->cartridge[id].ram_ptr = cart8rom + 0x1000; |
| 2519 | 2519 | } |
| 2520 | 2520 | else |
| 2521 | 2521 | { |
| 2522 | | image_battery_load(image, cartrom+0x800,0x1000); |
| 2522 | image_battery_load(image, cartrom+0x800,0x1000, 0x00); |
| 2523 | 2523 | for (i = 0x800; i < 0x1000; i++) |
| 2524 | 2524 | cartrom[i] = BIG_ENDIANIZE_INT16(cartrom[i]); |
| 2525 | 2525 | cartslots->cartridge[id].ram_ptr = (UINT16 *)cartrom + 0x800; |
| r7794 | r7795 | |
| 2533 | 2533 | if (ti99_is_99_8()) |
| 2534 | 2534 | { |
| 2535 | 2535 | // printf("** is 99/8\n"); |
| 2536 | | image_battery_load(image, cart8rom+0x0c00, 0x0400); |
| 2536 | image_battery_load(image, cart8rom+0x0c00, 0x0400, 0x00); |
| 2537 | 2537 | cartslots->cartridge[id].ram_ptr = cart8rom + 0xc00; |
| 2538 | 2538 | } |
| 2539 | 2539 | else |
| 2540 | 2540 | { |
| 2541 | | image_battery_load(image, cartrom+0x0600, 0x0400); |
| 2541 | image_battery_load(image, cartrom+0x0600, 0x0400, 0x00); |
| 2542 | 2542 | for (i = 0x0600; i < 0x0800; i++) |
| 2543 | 2543 | cartrom[i] = BIG_ENDIANIZE_INT16(cartrom[i]); |
| 2544 | 2544 | cartslots->cartridge[id].ram_ptr = (UINT16 *)cartrom + 0x600; |
| r7794 | r7795 | |
| 2709 | 2709 | |
| 2710 | 2710 | /* Allows to manually lock the cartslot system to a specific slot. |
| 2711 | 2711 | We take slot numbers from 0 (automatic mode) to the maximum. */ |
| 2712 | | |
| 2712 | |
| 2713 | 2713 | ti99_multicart_state *cartslots = (ti99_multicart_state *)device->token; |
| 2714 | 2714 | int slotnumber = (input_port_read(device->machine, "CFG") >> config_cartslot_bit) & config_cartslot_mask; |
| 2715 | 2715 | assert(slotnumber>=0 && slotnumber<=255); |
| r7794 | r7795 | |
| 2734 | 2734 | ti99_multicart_state *cartslots = (ti99_multicart_state *) device->token; |
| 2735 | 2735 | int slot = cartslots->active_slot; |
| 2736 | 2736 | cartridge_t *cart; |
| 2737 | | |
| 2737 | |
| 2738 | 2738 | /* Sanity check. Higher slots are always empty. */ |
| 2739 | 2739 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 2740 | 2740 | return 0; |
| 2741 | | |
| 2741 | |
| 2742 | 2742 | /* Same as above (GROM read): If there is only one cartridge there |
| 2743 | 2743 | is no use of trying other banks. There is one issue with the |
| 2744 | 2744 | selection mechanism: When the console probes the GROM banks and |
| r7794 | r7795 | |
| 2749 | 2749 | around this with the following line. */ |
| 2750 | 2750 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 2751 | 2751 | slot=0; |
| 2752 | | |
| 2752 | |
| 2753 | 2753 | cart = &cartslots->cartridge[slot]; |
| 2754 | | |
| 2754 | |
| 2755 | 2755 | /* Idle the CPU */ |
| 2756 | 2756 | cpu_adjust_icount(devtag_get_device(device->machine, "maincpu"),-4); |
| 2757 | | |
| 2757 | |
| 2758 | 2758 | // Alternatively: |
| 2759 | 2759 | // cpu_spinuntil_time(device->machine->firstcpu, ATTOTIME_IN_USEC(6)); |
| 2760 | | |
| 2760 | |
| 2761 | 2761 | // printf("rpk = %d, bin = %d\n", cartslots->multi_slots,cartslots->legacy_slots); |
| 2762 | | |
| 2762 | |
| 2763 | 2763 | /* Handle legacy mode. */ |
| 2764 | 2764 | if (in_legacy_mode(device)) |
| 2765 | 2765 | { |
| 2766 | 2766 | return ti99_cart_r_legacy(device, offset, mem_mask); |
| 2767 | 2767 | } |
| 2768 | | |
| 2768 | |
| 2769 | 2769 | if (!slot_is_empty(device, slot)) |
| 2770 | 2770 | { |
| 2771 | 2771 | // printf("accessing cartridge in slot %d\n", slot); |