src/mess/machine/ti99/gromport.c
| r9488 | r9489 | |
| 1 | | /********************************************************************** |
| 2 | | |
| 3 | | gromport.c |
| 4 | | |
| 5 | | *********************************************************************/ |
| 6 | | |
| 7 | | #include "emu.h" |
| 8 | | #include "gromport.h" |
| 9 | | #include "devices/cartslot.h" |
| 10 | | #include "devices/multcart.h" |
| 11 | | #include "grom.h" |
| 12 | | |
| 13 | | typedef UINT8 (*read8z_device_func) (ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT8 *value); |
| 14 | | |
| 15 | | /* We set the number of slots to 8, although we may have up to 16. From a |
| 16 | | logical point of view we could have 256, but the operating system only checks |
| 17 | | the first 16 banks. */ |
| 18 | | #define NUMBER_OF_CARTRIDGE_SLOTS 8 |
| 19 | | |
| 20 | | typedef int assmfct(running_device *); |
| 21 | | |
| 22 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_NONE, ti99_cartridge_pcb_none); |
| 23 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_STD, ti99_cartridge_pcb_std); |
| 24 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED, ti99_cartridge_pcb_paged); |
| 25 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MINIMEM, ti99_cartridge_pcb_minimem); |
| 26 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_SUPER, ti99_cartridge_pcb_super); |
| 27 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MBX, ti99_cartridge_pcb_mbx); |
| 28 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED379I, ti99_cartridge_pcb_paged379i); |
| 29 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGEDCRU, ti99_cartridge_pcb_pagedcru); |
| 30 | | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_GRAMKRACKER, ti99_cartridge_pcb_gramkracker); |
| 31 | | |
| 32 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_NONE, ti99_cartridge_pcb_none); |
| 33 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_STD, ti99_cartridge_pcb_std); |
| 34 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED, ti99_cartridge_pcb_paged); |
| 35 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MINIMEM, ti99_cartridge_pcb_minimem); |
| 36 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_SUPER, ti99_cartridge_pcb_super); |
| 37 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MBX, ti99_cartridge_pcb_mbx); |
| 38 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED379I, ti99_cartridge_pcb_paged379i); |
| 39 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGEDCRU, ti99_cartridge_pcb_pagedcru); |
| 40 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_GRAMKRACKER, ti99_cartridge_pcb_gramkracker); |
| 41 | | |
| 42 | | /* Generic TI99 cartridge structure. */ |
| 43 | | struct _cartridge_t |
| 44 | | { |
| 45 | | // PCB device associated to this cartridge. If NULL, the slot is empty. |
| 46 | | running_device *pcb; |
| 47 | | |
| 48 | | // ROM page. |
| 49 | | int rom_page; |
| 50 | | |
| 51 | | // RAM page. |
| 52 | | int ram_page; |
| 53 | | |
| 54 | | // GROM buffer size. |
| 55 | | int grom_size; |
| 56 | | |
| 57 | | // ROM buffer size. All banks have equal sizes. |
| 58 | | int rom_size; |
| 59 | | |
| 60 | | // RAM buffer size. All banks have equal sizes. |
| 61 | | int ram_size; |
| 62 | | |
| 63 | | // GROM buffer. |
| 64 | | UINT8 *grom_ptr; |
| 65 | | |
| 66 | | // ROM buffer. |
| 67 | | UINT8 *rom_ptr; |
| 68 | | |
| 69 | | // ROM buffer for the second bank of paged cartridges. |
| 70 | | UINT8 *rom2_ptr; |
| 71 | | |
| 72 | | // RAM buffer. The persistence service is done by the cartridge system. |
| 73 | | // The RAM space is a consecutive space; all banks are in one buffer. |
| 74 | | UINT8 *ram_ptr; |
| 75 | | |
| 76 | | /* GK support. */ |
| 77 | | UINT16 grom_address; |
| 78 | | int waddr_LSB; |
| 79 | | }; |
| 80 | | typedef struct _cartridge_t cartridge_t; |
| 81 | | |
| 82 | | enum |
| 83 | | { |
| 84 | | TI99CARTINFO_FCT_6000_R = DEVINFO_FCT_DEVICE_SPECIFIC, |
| 85 | | TI99CARTINFO_FCT_6000_W, |
| 86 | | TI99CARTINFO_FCT_CRU_R, |
| 87 | | TI99CARTINFO_FCT_CRU_W, |
| 88 | | TI99CART_FCT_ASSM, |
| 89 | | TI99CART_FCT_DISASSM |
| 90 | | }; |
| 91 | | |
| 92 | | typedef struct _ti99_multicart_state |
| 93 | | { |
| 94 | | // Reserves space for all cartridges. This is also used in the legacy |
| 95 | | // cartridge system, but only for slot 0. |
| 96 | | cartridge_t cartridge[NUMBER_OF_CARTRIDGE_SLOTS]; |
| 97 | | |
| 98 | | // Determines which slot is currently active. This value is changed when |
| 99 | | // there are accesses to other GROM base addresses. |
| 100 | | int active_slot; |
| 101 | | |
| 102 | | // Used in order to enforce a special slot. This value is retrieved |
| 103 | | // from the dipswitch setting. A value of -1 means automatic, that is, |
| 104 | | // the grom base switch is used. Values 0 .. max refer to the |
| 105 | | // respective slot. |
| 106 | | int fixed_slot; |
| 107 | | |
| 108 | | // Holds the highest index of a cartridge being plugged in plus one. |
| 109 | | // If we only have one cartridge inserted, we don't want to get a |
| 110 | | // selection option, so we just mirror the memory contents. |
| 111 | | int next_free_slot; |
| 112 | | |
| 113 | | /* GK support. */ |
| 114 | | int gk_slot; |
| 115 | | int gk_guest_slot; |
| 116 | | |
| 117 | | /* Legacy support. */ |
| 118 | | // Counts the number of slots which currently contain legacy format |
| 119 | | // cartridge images. |
| 120 | | int legacy_slots; |
| 121 | | |
| 122 | | // Counts the number of slots which currently contain new format |
| 123 | | // cartridge images. |
| 124 | | int multi_slots; |
| 125 | | |
| 126 | | /* Used to cache the switch settings. */ |
| 127 | | UINT8 gk_switch[8]; |
| 128 | | |
| 129 | | /* Ready line */ |
| 130 | | devcb_resolved_write_line ready; |
| 131 | | |
| 132 | | } ti99_multicart_state; |
| 133 | | |
| 134 | | #define AUTO -1 |
| 135 | | |
| 136 | | /* Access to the pcb. Contained in the token of the pcb instance. */ |
| 137 | | struct _ti99_pcb_t |
| 138 | | { |
| 139 | | /* Read function for this cartridge. */ |
| 140 | | read8z_device_func read; |
| 141 | | |
| 142 | | /* Write function for this cartridge. */ |
| 143 | | write8_device_func write; |
| 144 | | |
| 145 | | /* Read function for this cartridge, CRU. */ |
| 146 | | read8z_device_func cruread; |
| 147 | | |
| 148 | | /* Write function for this cartridge, CRU. */ |
| 149 | | write8_device_func cruwrite; |
| 150 | | |
| 151 | | /* Link up to the cartridge structure which contains this pcb. */ |
| 152 | | cartridge_t *cartridge; |
| 153 | | |
| 154 | | /* Function to assemble this cartridge. */ |
| 155 | | assmfct *assemble; |
| 156 | | |
| 157 | | /* Function to disassemble this cartridge. */ |
| 158 | | assmfct *disassemble; |
| 159 | | |
| 160 | | /* Points to the (max 5) GROM devices. */ |
| 161 | | running_device *grom[5]; |
| 162 | | }; |
| 163 | | typedef struct _ti99_pcb_t ti99_pcb_t; |
| 164 | | |
| 165 | | INLINE ti99_multicart_state *get_safe_token(running_device *device) |
| 166 | | { |
| 167 | | assert(device != NULL); |
| 168 | | return (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 169 | | } |
| 170 | | |
| 171 | | INLINE const ti99_multicart_config *get_config(running_device *device) |
| 172 | | { |
| 173 | | assert(device != NULL); |
| 174 | | assert(device->type() == TI99_MULTICART); |
| 175 | | return (const ti99_multicart_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config(); |
| 176 | | } |
| 177 | | |
| 178 | | INLINE ti99_pcb_t *get_safe_pcb_token(running_device *device) |
| 179 | | { |
| 180 | | assert(device != NULL); |
| 181 | | return (ti99_pcb_t *)downcast<legacy_device_base *>(device)->token(); |
| 182 | | } |
| 183 | | |
| 184 | | static WRITE_LINE_DEVICE_HANDLER( cart_grom_ready ) |
| 185 | | { |
| 186 | | running_device *cartdev = device->owner()->owner(); |
| 187 | | ti99_multicart_state *cartslots = get_safe_token(cartdev); |
| 188 | | devcb_call_write_line( &cartslots->ready, state ); |
| 189 | | } |
| 190 | | |
| 191 | | /* |
| 192 | | The console writes the values in this array to cache them. |
| 193 | | */ |
| 194 | | void set_gk_switches(running_device *cartsys, int number, int value) |
| 195 | | { |
| 196 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 197 | | cartslots->gk_switch[number] = value; |
| 198 | | } |
| 199 | | |
| 200 | | static int get_gk_switch(running_device *cartsys, int number) |
| 201 | | { |
| 202 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 203 | | return cartslots->gk_switch[number]; |
| 204 | | } |
| 205 | | |
| 206 | | static int in_legacy_mode(running_device *device) |
| 207 | | { |
| 208 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 209 | | return ((cartslots->legacy_slots>0) && (cartslots->multi_slots==0)); |
| 210 | | } |
| 211 | | |
| 212 | | /* |
| 213 | | Activates a slot in the multi-cartridge extender. |
| 214 | | */ |
| 215 | | static void cartridge_slot_set(running_device *cartsys, UINT8 slotnumber) |
| 216 | | { |
| 217 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 218 | | // if (cartslots->active_slot != slotnumber) printf("Setting cartslot to %d\n", slotnumber); |
| 219 | | if (cartslots->fixed_slot==AUTO) |
| 220 | | cartslots->active_slot = slotnumber; |
| 221 | | else |
| 222 | | cartslots->active_slot = cartslots->fixed_slot; |
| 223 | | } |
| 224 | | |
| 225 | | static int slot_is_empty(running_device *cartsys, int slotnumber) |
| 226 | | { |
| 227 | | cartridge_t *cart; |
| 228 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 229 | | |
| 230 | | cart = &cartslots->cartridge[slotnumber]; |
| 231 | | |
| 232 | | if ((cart->rom_size==0) && (cart->ram_size==0) && (cart->grom_size==0)) |
| 233 | | return TRUE; |
| 234 | | return FALSE; |
| 235 | | } |
| 236 | | |
| 237 | | static void clear_slot(running_device *cartsys, int slotnumber) |
| 238 | | { |
| 239 | | cartridge_t *cart; |
| 240 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 241 | | |
| 242 | | cart = &cartslots->cartridge[slotnumber]; |
| 243 | | |
| 244 | | cart->rom_size = cart->ram_size = cart->grom_size = 0; |
| 245 | | cart->rom_ptr = NULL; |
| 246 | | cart->rom2_ptr = NULL; |
| 247 | | cart->ram_ptr = NULL; |
| 248 | | } |
| 249 | | |
| 250 | | /* |
| 251 | | Find the index of the cartridge name. We assume the format |
| 252 | | <name><number>, i.e. the number is the longest string from the right |
| 253 | | which can be interpreted as a number. |
| 254 | | */ |
| 255 | | static int get_index_from_tagname(running_device *image) |
| 256 | | { |
| 257 | | const char *tag = image->tag(); |
| 258 | | int maxlen = strlen(tag); |
| 259 | | int i; |
| 260 | | for (i=maxlen-1; i >=0; i--) |
| 261 | | if (tag[i] < 48 || tag[i] > 57) break; |
| 262 | | |
| 263 | | return atoi(tag+i+1); |
| 264 | | } |
| 265 | | |
| 266 | | /* |
| 267 | | Common routine to assemble cartridges from resources. |
| 268 | | */ |
| 269 | | static cartridge_t *assemble_common(running_device *cartslot) |
| 270 | | { |
| 271 | | /* Pointer to the cartridge structure. */ |
| 272 | | cartridge_t *cartridge; |
| 273 | | running_device *cartsys = cartslot->owner(); |
| 274 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 275 | | running_device *pcb = cartslot->subdevice("pcb"); |
| 276 | | ti99_pcb_t *pcb_def; |
| 277 | | |
| 278 | | void *socketcont; |
| 279 | | int reslength; |
| 280 | | // int i; |
| 281 | | |
| 282 | | int slotnumber = get_index_from_tagname(cartslot)-1; |
| 283 | | assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS); |
| 284 | | |
| 285 | | /* There is a cartridge in this slot, check the maximum slot number. */ |
| 286 | | if (cartslots->next_free_slot <= slotnumber) |
| 287 | | { |
| 288 | | cartslots->next_free_slot = slotnumber+1; |
| 289 | | } |
| 290 | | cartridge = &cartslots->cartridge[slotnumber]; |
| 291 | | |
| 292 | | // Get the socket which is retrieved by the multicart instance in |
| 293 | | // the state of the cartslot instance. |
| 294 | | socketcont = cartslot_get_socket(cartslot, "grom_socket"); |
| 295 | | reslength = cartslot_get_resource_length(cartslot, "grom_socket"); |
| 296 | | if (socketcont != NULL) |
| 297 | | { |
| 298 | | cartridge->grom_ptr = (UINT8 *)socketcont; |
| 299 | | // printf("grom_socket = %lx\n", cartridge->grom_ptr); |
| 300 | | cartridge->grom_size = reslength; |
| 301 | | } |
| 302 | | |
| 303 | | socketcont = cartslot_get_socket(cartslot, "rom_socket"); |
| 304 | | reslength = cartslot_get_resource_length(cartslot, "rom_socket"); |
| 305 | | if (socketcont != NULL) |
| 306 | | { |
| 307 | | cartridge->rom_ptr = (UINT8 *)socketcont; |
| 308 | | cartridge->rom_size = reslength; |
| 309 | | // printf("set rom ptr = %lx, romlength = %04x, data = %02x %02x\n", cartridge->rom_ptr, cartridge->rom_size, cartridge->rom_ptr[0], cartridge->rom_ptr[1]); |
| 310 | | } |
| 311 | | |
| 312 | | socketcont = cartslot_get_socket(cartslot, "rom2_socket"); |
| 313 | | // reslength = cartslot_get_resource_length(cartslot, "rom2_socket"); /* cannot differ from rom_socket */ |
| 314 | | if (socketcont != NULL) |
| 315 | | { |
| 316 | | cartridge->rom2_ptr = (UINT8 *)socketcont; |
| 317 | | } |
| 318 | | |
| 319 | | socketcont = cartslot_get_socket(cartslot, "ram_socket"); |
| 320 | | reslength = cartslot_get_resource_length(cartslot, "ram_socket"); |
| 321 | | if (socketcont != NULL) |
| 322 | | { |
| 323 | | cartridge->ram_ptr = (UINT8 *)socketcont; |
| 324 | | cartridge->ram_size = reslength; |
| 325 | | } |
| 326 | | |
| 327 | | // Register the GROMs |
| 328 | | pcb_def = (ti99_pcb_t *)downcast<legacy_device_base *>(pcb)->token(); |
| 329 | | for (int i=0; i < 5; i++) pcb_def->grom[i]= NULL; |
| 330 | | if (cartridge->grom_size > 0) pcb_def->grom[0] = pcb->subdevice("grom_3"); |
| 331 | | if (cartridge->grom_size > 0x2000) pcb_def->grom[1] = pcb->subdevice("grom_4"); |
| 332 | | if (cartridge->grom_size > 0x4000) pcb_def->grom[2] = pcb->subdevice("grom_5"); |
| 333 | | if (cartridge->grom_size > 0x6000) pcb_def->grom[3] = pcb->subdevice("grom_6"); |
| 334 | | if (cartridge->grom_size > 0x8000) pcb_def->grom[4] = pcb->subdevice("grom_7"); |
| 335 | | |
| 336 | | return cartridge; |
| 337 | | } |
| 338 | | |
| 339 | | static void set_pointers(running_device *pcb, int index) |
| 340 | | { |
| 341 | | running_device *cartsys = pcb->owner()->owner(); |
| 342 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 343 | | ti99_pcb_t *pcb_def = (ti99_pcb_t *)downcast<legacy_device_base *>(pcb)->token(); |
| 344 | | |
| 345 | | pcb_def->read = (read8z_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_6000_R); |
| 346 | | pcb_def->write = (write8_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_6000_W); |
| 347 | | pcb_def->cruread = (read8z_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_CRU_R); |
| 348 | | pcb_def->cruwrite = (write8_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_CRU_W); |
| 349 | | |
| 350 | | pcb_def->assemble = (assmfct *)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CART_FCT_ASSM); |
| 351 | | pcb_def->disassemble = (assmfct *)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CART_FCT_DISASSM); |
| 352 | | |
| 353 | | pcb_def->cartridge = &cartslots->cartridge[index]; |
| 354 | | pcb_def->cartridge->pcb = pcb; |
| 355 | | } |
| 356 | | |
| 357 | | /***************************************************************************** |
| 358 | | Cartridge type: None |
| 359 | | This PCB device is just a pseudo device; the legacy mode is handled |
| 360 | | by dedicated functions. |
| 361 | | ******************************************************************************/ |
| 362 | | static DEVICE_START(ti99_pcb_none) |
| 363 | | { |
| 364 | | /* device is ti99_cartslot:cartridge:pcb */ |
| 365 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 366 | | } |
| 367 | | |
| 368 | | /***************************************************************************** |
| 369 | | Cartridge type: Standard |
| 370 | | Most cartridges are built in this type. Every cartridge may contain |
| 371 | | GROM between 0 and 40 KiB, and ROM with 8 KiB length, no banking. |
| 372 | | ******************************************************************************/ |
| 373 | | |
| 374 | | static DEVICE_START(ti99_pcb_std) |
| 375 | | { |
| 376 | | /* device is ti99_cartslot:cartridge:pcb */ |
| 377 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 378 | | } |
| 379 | | |
| 380 | | /* |
| 381 | | Read handler for the CPU address space of the cartridge |
| 382 | | Images for this area are found in the rom_sockets. |
| 383 | | */ |
| 384 | | static READ8Z_DEVICE_HANDLER( read_cart_std ) |
| 385 | | { |
| 386 | | /* device is pcb, owner is cartslot (cartridge is only a part of the state of cartslot) */ |
| 387 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 388 | | cartridge_t *cartridge = pcb->cartridge; |
| 389 | | if (cartridge->rom_ptr!=NULL) |
| 390 | | { |
| 391 | | // For TI-99/8 we should plan for 16K cartridges. However, none was produced. Well, just ignore this thought, |
| 392 | | *value = (cartridge->rom_ptr)[offset & 0x1fff]; |
| 393 | | // printf("read cartridge rom space (length %04x) %04x = %02x\n", cartridge->rom_size, offset, *value); |
| 394 | | } |
| 395 | | } |
| 396 | | |
| 397 | | static WRITE8_DEVICE_HANDLER( write_cart_std ) |
| 398 | | { |
| 399 | | logerror("Write access to cartridge ROM at address %04x ignored\n", offset); |
| 400 | | } |
| 401 | | |
| 402 | | /* |
| 403 | | The standard cartridge assemble routine. We just call the common |
| 404 | | function here. |
| 405 | | */ |
| 406 | | static int assemble_std(running_device *image) |
| 407 | | { |
| 408 | | assemble_common(image); |
| 409 | | return IMAGE_INIT_PASS; |
| 410 | | } |
| 411 | | |
| 412 | | /* |
| 413 | | Removes pointers and restores the state before plugging in the |
| 414 | | cartridge. |
| 415 | | The pointer to the location after the last cartridge is adjusted. |
| 416 | | As it seems, we can use the same function for the disassembling of all |
| 417 | | cartridge types. |
| 418 | | */ |
| 419 | | static int disassemble_std(running_device *image) |
| 420 | | { |
| 421 | | int slotnumber; |
| 422 | | int i; |
| 423 | | // cartridge_t *cart; |
| 424 | | running_device *cartsys = image->owner(); |
| 425 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 426 | | |
| 427 | | slotnumber = get_index_from_tagname(image)-1; |
| 428 | | |
| 429 | | /* Search the highest remaining cartridge. */ |
| 430 | | cartslots->next_free_slot = 0; |
| 431 | | for (i=NUMBER_OF_CARTRIDGE_SLOTS-1; i >= 0; i--) |
| 432 | | { |
| 433 | | if (i != slotnumber) |
| 434 | | { |
| 435 | | if (!slot_is_empty(cartsys, i)) |
| 436 | | { |
| 437 | | cartslots->next_free_slot = i+1; |
| 438 | | break; |
| 439 | | } |
| 440 | | } |
| 441 | | } |
| 442 | | |
| 443 | | clear_slot(cartsys, slotnumber); |
| 444 | | |
| 445 | | return IMAGE_INIT_PASS; |
| 446 | | } |
| 447 | | |
| 448 | | /***************************************************************************** |
| 449 | | Cartridge type: Paged (Extended Basic) |
| 450 | | This cartridge consists of GROM memory and 2 pages of standard ROM. |
| 451 | | The page is set by writing any value to a location in |
| 452 | | the address area, where an even word offset sets the page to 0 and an |
| 453 | | odd word offset sets the page to 1 (e.g. 6000 = bank 0, and |
| 454 | | 6002 = bank 1). |
| 455 | | ******************************************************************************/ |
| 456 | | |
| 457 | | static DEVICE_START(ti99_pcb_paged) |
| 458 | | { |
| 459 | | /* device is ti99_cartslot:cartridge:pcb */ |
| 460 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 461 | | } |
| 462 | | |
| 463 | | /* |
| 464 | | Read handler for the CPU address space of the cartridge |
| 465 | | Images for this area are found in the rom_sockets. |
| 466 | | */ |
| 467 | | static READ8Z_DEVICE_HANDLER( read_cart_paged ) |
| 468 | | { |
| 469 | | /* device is pcb, owner is cartslot */ |
| 470 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 471 | | cartridge_t *cartridge = pcb->cartridge; |
| 472 | | UINT8 *rombank; |
| 473 | | |
| 474 | | if (cartridge->rom_page==0) |
| 475 | | rombank = (UINT8*)cartridge->rom_ptr; |
| 476 | | else |
| 477 | | rombank = (UINT8*)cartridge->rom2_ptr; |
| 478 | | |
| 479 | | if (rombank==NULL) |
| 480 | | { |
| 481 | | /* TODO: Check for consistency with the GROM memory handling. */ |
| 482 | | *value = 0; |
| 483 | | } |
| 484 | | else |
| 485 | | { |
| 486 | | *value = rombank[offset & 0x1fff]; |
| 487 | | } |
| 488 | | } |
| 489 | | |
| 490 | | /* |
| 491 | | Handle paging. Extended Basic switches between ROM banks by |
| 492 | | using the value of the LSB of the address where any value |
| 493 | | is written to. |
| 494 | | */ |
| 495 | | static WRITE8_DEVICE_HANDLER( write_cart_paged ) |
| 496 | | { |
| 497 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 498 | | cartridge_t *cartridge = pcb->cartridge; |
| 499 | | cartridge->rom_page = (offset >> 1) & 1; |
| 500 | | } |
| 501 | | |
| 502 | | /* |
| 503 | | We require paged modules to have at least those two rom banks. |
| 504 | | */ |
| 505 | | static int assemble_paged(running_device *image) |
| 506 | | { |
| 507 | | cartridge_t *cart; |
| 508 | | |
| 509 | | cart = assemble_common(image); |
| 510 | | if (cart->rom_ptr==NULL) |
| 511 | | { |
| 512 | | logerror("Missing ROM for paged cartridge"); |
| 513 | | return IMAGE_INIT_FAIL; |
| 514 | | } |
| 515 | | if (cart->rom2_ptr==NULL) |
| 516 | | { |
| 517 | | logerror("Missing second ROM for paged cartridge"); |
| 518 | | return IMAGE_INIT_FAIL; |
| 519 | | } |
| 520 | | |
| 521 | | return IMAGE_INIT_PASS; |
| 522 | | } |
| 523 | | |
| 524 | | /***************************************************************************** |
| 525 | | Cartridge type: Mini Memory |
| 526 | | GROM: 6 KiB (occupies G>6000 to G>7800) |
| 527 | | ROM: 4 KiB (romfile is actually 8 K long, second half with zeros, 0x6000-0x6fff) |
| 528 | | persistent RAM: 4 KiB (0x7000-0x7fff) |
| 529 | | ******************************************************************************/ |
| 530 | | |
| 531 | | static DEVICE_START(ti99_pcb_minimem) |
| 532 | | { |
| 533 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 534 | | } |
| 535 | | |
| 536 | | static READ8Z_DEVICE_HANDLER( read_cart_minimem ) |
| 537 | | { |
| 538 | | /* device is pcb, owner is cartslot */ |
| 539 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 540 | | cartridge_t *cartridge = pcb->cartridge; |
| 541 | | |
| 542 | | if ((offset & 0xf000)==0x6000) |
| 543 | | { |
| 544 | | *value = (cartridge->rom_ptr==NULL)? 0 : (cartridge->rom_ptr)[offset & 0x0fff]; |
| 545 | | } |
| 546 | | else |
| 547 | | { |
| 548 | | *value = (cartridge->ram_ptr==NULL)? 0 : (cartridge->ram_ptr)[offset & 0x0fff]; |
| 549 | | } |
| 550 | | } |
| 551 | | |
| 552 | | /* |
| 553 | | Mini Memory cartridge write operation. RAM is located at 0x7000. |
| 554 | | */ |
| 555 | | static WRITE8_DEVICE_HANDLER( write_cart_minimem ) |
| 556 | | { |
| 557 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 558 | | cartridge_t *cartridge = pcb->cartridge; |
| 559 | | |
| 560 | | if (offset < 0x7000) |
| 561 | | { |
| 562 | | logerror("Write access to cartridge ROM at address %04x ignored", offset); |
| 563 | | } |
| 564 | | else |
| 565 | | { |
| 566 | | if (cartridge->ram_ptr==NULL) |
| 567 | | { |
| 568 | | logerror("No cartridge RAM at address %04x", offset); |
| 569 | | /* TODO: Check for consistency with the GROM memory handling. */ |
| 570 | | } |
| 571 | | else |
| 572 | | { |
| 573 | | (cartridge->ram_ptr)[offset-0x7000] = data; |
| 574 | | } |
| 575 | | } |
| 576 | | } |
| 577 | | |
| 578 | | static int assemble_minimem(running_device *image) |
| 579 | | { |
| 580 | | cartridge_t *cart; |
| 581 | | |
| 582 | | cart = assemble_common(image); |
| 583 | | if (cart->grom_size==0) |
| 584 | | { |
| 585 | | logerror("Missing GROM for Mini Memory"); |
| 586 | | // should not fail here because there may be variations of |
| 587 | | // cartridges which do not use all parts |
| 588 | | // return IMAGE_INIT_FAIL; |
| 589 | | } |
| 590 | | if (cart->rom_size==0) |
| 591 | | { |
| 592 | | logerror("Missing ROM for Mini Memory"); |
| 593 | | // return IMAGE_INIT_FAIL; |
| 594 | | } |
| 595 | | if (cart->ram_size==0) |
| 596 | | { |
| 597 | | logerror("Missing RAM for Mini Memory"); |
| 598 | | // return IMAGE_INIT_FAIL; |
| 599 | | } |
| 600 | | |
| 601 | | return IMAGE_INIT_PASS; |
| 602 | | } |
| 603 | | |
| 604 | | /***************************************************************************** |
| 605 | | Cartridge type: SuperSpace II |
| 606 | | SuperSpace cartridge type. SuperSpace is intended as a user-definable |
| 607 | | blank cartridge containing buffered RAM |
| 608 | | It has an Editor/Assembler GROM which helps the user to load |
| 609 | | the user program into the cartridge. If the user program has a suitable |
| 610 | | header, the console recognizes the cartridge as runnable, and |
| 611 | | assigns a number in the selection screen. |
| 612 | | Switching the RAM banks in this cartridge is achieved by setting |
| 613 | | CRU bits (the system serial interface). |
| 614 | | |
| 615 | | GROM: Editor/Assembler GROM |
| 616 | | ROM: none |
| 617 | | persistent RAM: 32 KiB (0x6000-0x7fff, 4 banks) |
| 618 | | Switching the bank is done via CRU write |
| 619 | | ******************************************************************************/ |
| 620 | | |
| 621 | | static DEVICE_START(ti99_pcb_super) |
| 622 | | { |
| 623 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 624 | | } |
| 625 | | |
| 626 | | /* |
| 627 | | The CRU read handler. The CRU is a serial interface in the console. |
| 628 | | Using the CRU we can switch the banks in the SuperSpace cartridge. |
| 629 | | */ |
| 630 | | static READ8Z_DEVICE_HANDLER( read_cart_cru ) |
| 631 | | { |
| 632 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 633 | | cartridge_t *cartridge = pcb->cartridge; |
| 634 | | // offset is the bit number. The CRU base address is already divided by 2. |
| 635 | | |
| 636 | | // ram_page contains the bank number. We have a maximum of |
| 637 | | // 4 banks; the Super Space II manual says: |
| 638 | | // |
| 639 | | // Banks are selected by writing a bit pattern to CRU address >0800: |
| 640 | | // |
| 641 | | // Bank # Value |
| 642 | | // 0 >02 = 0000 0010 |
| 643 | | // 1 >08 = 0000 1000 |
| 644 | | // 2 >20 = 0010 0000 |
| 645 | | // 3 >80 = 1000 0000 |
| 646 | | // |
| 647 | | // With the bank number (0, 1, 2, or 3) in R0: |
| 648 | | // |
| 649 | | // BNKSW LI R12,>0800 Set CRU address |
| 650 | | // LI R1,2 Load Shift Bit |
| 651 | | // SLA R0,1 Align Bank Number |
| 652 | | // JEQ BNKS1 Skip shift if Bank 0 |
| 653 | | // SLA R1,0 Align Shift Bit |
| 654 | | // BNKS1 LDCR R1,0 Switch Banks |
| 655 | | // SRL R0,1 Restore Bank Number (optional) |
| 656 | | // RT |
| 657 | | printf("Superspace: CRU accessed at %04x\n", offset); |
| 658 | | if ((offset & 1) == 0 || offset > 7) |
| 659 | | *value = 0; |
| 660 | | |
| 661 | | // CRU addresses are only 1 bit wide. Bytes are transferred from LSB |
| 662 | | // to MSB. That is, 8 bit are eight consecutive addresses. */ |
| 663 | | *value = (cartridge->ram_page == (offset-1)/2); |
| 664 | | } |
| 665 | | |
| 666 | | static WRITE8_DEVICE_HANDLER( write_cart_cru ) |
| 667 | | { |
| 668 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 669 | | cartridge_t *cartridge = pcb->cartridge; |
| 670 | | // data is bit |
| 671 | | // offset is address |
| 672 | | printf("Superspace: CRU accessed at %04x\n", offset); |
| 673 | | if (offset < 8) |
| 674 | | { |
| 675 | | if (data != 0) |
| 676 | | cartridge->ram_page = (offset-1)/2; |
| 677 | | } |
| 678 | | } |
| 679 | | |
| 680 | | /* |
| 681 | | SuperSpace RAM read operation. RAM is located at 0x6000 to 0x7fff |
| 682 | | as 4 banks of 8 KiB each |
| 683 | | */ |
| 684 | | static READ8Z_DEVICE_HANDLER( read_cart_super ) |
| 685 | | { |
| 686 | | /* device is pcb, owner is cartslot */ |
| 687 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 688 | | cartridge_t *cartridge = pcb->cartridge; |
| 689 | | offs_t boffset; |
| 690 | | |
| 691 | | if (cartridge->ram_ptr==NULL) |
| 692 | | { |
| 693 | | *value = 0; |
| 694 | | } |
| 695 | | else |
| 696 | | { |
| 697 | | boffset = cartridge->ram_page * 0x2000 + (offset & 0x1fff); |
| 698 | | *value = (cartridge->ram_ptr)[boffset]; |
| 699 | | } |
| 700 | | } |
| 701 | | |
| 702 | | /* |
| 703 | | SuperSpace RAM write operation. RAM is located at 0x6000 to 0x7fff |
| 704 | | as 4 banks of 8 KiB each |
| 705 | | */ |
| 706 | | static WRITE8_DEVICE_HANDLER( write_cart_super ) |
| 707 | | { |
| 708 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 709 | | cartridge_t *cartridge = pcb->cartridge; |
| 710 | | offs_t boffset; |
| 711 | | |
| 712 | | if (cartridge->ram_ptr==NULL) |
| 713 | | { |
| 714 | | logerror("No cartridge RAM at address %04x", offset); |
| 715 | | } |
| 716 | | else |
| 717 | | { |
| 718 | | boffset = cartridge->ram_page * 0x2000 + (offset & 0x1fff); |
| 719 | | (cartridge->ram_ptr)[boffset] = data; |
| 720 | | } |
| 721 | | } |
| 722 | | |
| 723 | | static int assemble_super(running_device *image) |
| 724 | | { |
| 725 | | cartridge_t *cart; |
| 726 | | |
| 727 | | cart = assemble_common(image); |
| 728 | | if (cart->ram_size==0) |
| 729 | | { |
| 730 | | logerror("Missing RAM for SuperSpace"); |
| 731 | | return IMAGE_INIT_FAIL; |
| 732 | | } |
| 733 | | return IMAGE_INIT_PASS; |
| 734 | | } |
| 735 | | |
| 736 | | /***************************************************************************** |
| 737 | | Cartridge type: MBX |
| 738 | | GROM: up to 40 KiB |
| 739 | | ROM: up to 16 KiB (in up to 2 banks of 8KiB each) |
| 740 | | RAM: 1022 B (0x6c00-0x6ffd, overrides ROM in that area) |
| 741 | | ROM mapper: 6ffe |
| 742 | | |
| 743 | | Note that some MBX cartridges assume the presence of the MBX system |
| 744 | | (additional console) and will not run without it. The MBX hardware is |
| 745 | | not emulated yet. |
| 746 | | ******************************************************************************/ |
| 747 | | |
| 748 | | static DEVICE_START(ti99_pcb_mbx) |
| 749 | | { |
| 750 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 751 | | } |
| 752 | | |
| 753 | | static READ8Z_DEVICE_HANDLER( read_cart_mbx ) |
| 754 | | { |
| 755 | | /* device is pcb, owner is cartslot */ |
| 756 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 757 | | cartridge_t *cartridge = pcb->cartridge; |
| 758 | | |
| 759 | | if ((offset & 0x1c00)==0x0c00) |
| 760 | | { |
| 761 | | // This is the RAM area which overrides any ROM. There is no |
| 762 | | // known banking behavior for the RAM, so we must assume that |
| 763 | | // there is only one bank. |
| 764 | | if (cartridge->ram_ptr != NULL) |
| 765 | | *value = (cartridge->ram_ptr)[offset & 0x03ff]; |
| 766 | | } |
| 767 | | else |
| 768 | | { |
| 769 | | if (cartridge->rom_ptr != NULL) |
| 770 | | *value = (cartridge->rom_ptr)[(offset & 0x1fff)+ cartridge->rom_page*0x2000]; |
| 771 | | } |
| 772 | | } |
| 773 | | |
| 774 | | /* |
| 775 | | MBX write operation. |
| 776 | | */ |
| 777 | | static WRITE8_DEVICE_HANDLER( write_cart_mbx ) |
| 778 | | { |
| 779 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 780 | | cartridge_t *cartridge = pcb->cartridge; |
| 781 | | |
| 782 | | if (offset == 0x6ffe) |
| 783 | | { |
| 784 | | cartridge->rom_page = data & 1; |
| 785 | | return; |
| 786 | | } |
| 787 | | |
| 788 | | if ((offset & 0x1c00)==0x0c00) |
| 789 | | { |
| 790 | | if (cartridge->ram_ptr == NULL) return; |
| 791 | | cartridge->ram_ptr[offset - 0x6c00] = data; |
| 792 | | } |
| 793 | | } |
| 794 | | |
| 795 | | |
| 796 | | static int assemble_mbx(running_device *image) |
| 797 | | { |
| 798 | | assemble_common(image); |
| 799 | | return IMAGE_INIT_PASS; |
| 800 | | } |
| 801 | | |
| 802 | | /***************************************************************************** |
| 803 | | Cartridge type: paged379i |
| 804 | | This cartridge consists of one 16 KiB, 32 KiB, 64 KiB, or 128 KiB EEPROM |
| 805 | | which is organised in 2, 4, 8, or 16 pages of 8 KiB each. The complete |
| 806 | | memory contents must be stored in one dump file. |
| 807 | | The pages are selected by writing a value to some memory locations. Due to |
| 808 | | using the inverted outputs of the LS379 latch, setting the inputs of the |
| 809 | | latch to all 0 selects the highest bank, while setting to all 1 selects the |
| 810 | | lowest. There are some cartridges (16 KiB) which are using this scheme, and |
| 811 | | there are new hardware developments mainly relying on this scheme. |
| 812 | | |
| 813 | | Writing to selects page (16K/32K/64K/128K) |
| 814 | | >6000 1 / 3 / 7 / 15 |
| 815 | | >6002 0 / 2 / 6 / 14 |
| 816 | | >6004 1 / 1 / 5 / 13 |
| 817 | | >6006 0 / 0 / 4 / 12 |
| 818 | | >6008 1 / 3 / 3 / 11 |
| 819 | | >600A 0 / 2 / 2 / 10 |
| 820 | | >600C 1 / 1 / 1 / 9 |
| 821 | | >600E 0 / 0 / 0 / 8 |
| 822 | | >6010 1 / 3 / 7 / 7 |
| 823 | | >6012 0 / 2 / 6 / 6 |
| 824 | | >6014 1 / 1 / 5 / 5 |
| 825 | | >6016 0 / 0 / 4 / 4 |
| 826 | | >6018 1 / 3 / 3 / 3 |
| 827 | | >601A 0 / 2 / 2 / 2 |
| 828 | | >601C 1 / 1 / 1 / 1 |
| 829 | | >601E 0 / 0 / 0 / 0 |
| 830 | | |
| 831 | | ******************************************************************************/ |
| 832 | | |
| 833 | | static DEVICE_START(ti99_pcb_paged379i) |
| 834 | | { |
| 835 | | /* device is ti99_cartslot:cartridge:pcb */ |
| 836 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 837 | | } |
| 838 | | |
| 839 | | /* |
| 840 | | Read handler for the CPU address space of the cartridge |
| 841 | | Images for this area are found in the rom_sockets. |
| 842 | | */ |
| 843 | | static READ8Z_DEVICE_HANDLER( read_cart_paged379i ) |
| 844 | | { |
| 845 | | /* device is pcb, owner is cartslot */ |
| 846 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 847 | | cartridge_t *cartridge = pcb->cartridge; |
| 848 | | |
| 849 | | if (cartridge->rom_ptr!=NULL) |
| 850 | | { |
| 851 | | *value = (cartridge->rom_ptr)[cartridge->rom_page*0x2000 + (offset & 0x1fff)]; |
| 852 | | } |
| 853 | | } |
| 854 | | |
| 855 | | /* |
| 856 | | Determines which bank to set, depending on the size of the ROM. This is |
| 857 | | some magic code that actually represents different PCB versions. |
| 858 | | */ |
| 859 | | static void set_paged379i_bank(cartridge_t *cartridge, int rompage) |
| 860 | | { |
| 861 | | int mask = 0; |
| 862 | | if (cartridge->rom_size > 16384) |
| 863 | | { |
| 864 | | if (cartridge->rom_size > 32768) |
| 865 | | { |
| 866 | | if (cartridge->rom_size > 65536) |
| 867 | | mask = 15; |
| 868 | | else |
| 869 | | mask = 7; |
| 870 | | } |
| 871 | | else |
| 872 | | mask = 3; |
| 873 | | } |
| 874 | | else |
| 875 | | mask = 1; |
| 876 | | |
| 877 | | cartridge->rom_page = rompage & mask; |
| 878 | | } |
| 879 | | |
| 880 | | /* |
| 881 | | Handle paging. We use a LS379 latch for storing the page number. On this |
| 882 | | PCB, the inverted output of the latch is used, so the order of pages |
| 883 | | is reversed. (No problem as long as the memory dump is kept exactly |
| 884 | | in the way it is stored in the EPROM.) |
| 885 | | The latch can store a value of 4 bits. We adjust the number of |
| 886 | | significant bits by the size of the memory dump (16K, 32K, 64K). |
| 887 | | */ |
| 888 | | static WRITE8_DEVICE_HANDLER( write_cart_paged379i ) |
| 889 | | { |
| 890 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 891 | | cartridge_t *cartridge = pcb->cartridge; |
| 892 | | |
| 893 | | // Bits: 011x xxxx xxxb bbbx |
| 894 | | // x = don't care, bbbb = bank |
| 895 | | set_paged379i_bank(cartridge, 15 - ((offset>>1) & 15)); |
| 896 | | } |
| 897 | | |
| 898 | | /* |
| 899 | | Paged379i modules have one EPROM dump. |
| 900 | | */ |
| 901 | | static int assemble_paged379i(running_device *image) |
| 902 | | { |
| 903 | | cartridge_t *cart; |
| 904 | | |
| 905 | | cart = assemble_common(image); |
| 906 | | if (cart->rom_ptr==NULL) |
| 907 | | { |
| 908 | | logerror("Missing ROM for paged cartridge"); |
| 909 | | return IMAGE_INIT_FAIL; |
| 910 | | } |
| 911 | | set_paged379i_bank(cart, 15); |
| 912 | | return IMAGE_INIT_PASS; |
| 913 | | } |
| 914 | | |
| 915 | | /***************************************************************************** |
| 916 | | Cartridge type: pagedcru |
| 917 | | This cartridge consists of one 16 KiB, 32 KiB, or 64 KiB EEPROM which is |
| 918 | | organised in 2, 4, or 8 pages of 8 KiB each. We assume there is only one |
| 919 | | dump file of the respective size. |
| 920 | | The pages are selected by writing a value to the CRU. This scheme is |
| 921 | | similar to the one used for the SuperSpace cartridge, with the exception |
| 922 | | that we are using ROM only, and we can have up to 8 pages. |
| 923 | | |
| 924 | | Bank Value written to CRU>0800 |
| 925 | | 0 >0002 = 0000 0000 0000 0010 |
| 926 | | 1 >0008 = 0000 0000 0000 1000 |
| 927 | | 2 >0020 = 0000 0000 0010 0000 |
| 928 | | 3 >0080 = 0000 0000 1000 0000 |
| 929 | | 4 >0200 = 0000 0010 0000 0000 |
| 930 | | 5 >0800 = 0000 1000 0000 0000 |
| 931 | | 6 >2000 = 0010 0000 0000 0000 |
| 932 | | 7 >8000 = 1000 0000 0000 0000 |
| 933 | | |
| 934 | | ******************************************************************************/ |
| 935 | | |
| 936 | | static DEVICE_START(ti99_pcb_pagedcru) |
| 937 | | { |
| 938 | | /* device is ti99_cartslot:cartridge:pcb */ |
| 939 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 940 | | } |
| 941 | | |
| 942 | | /* |
| 943 | | Read handler for the CPU address space of the cartridge |
| 944 | | Images for this area are found in the rom_sockets. |
| 945 | | */ |
| 946 | | static READ8Z_DEVICE_HANDLER( read_cart_pagedcru ) |
| 947 | | { |
| 948 | | /* device is pcb, owner is cartslot */ |
| 949 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 950 | | cartridge_t *cartridge = pcb->cartridge; |
| 951 | | |
| 952 | | if (cartridge->rom_ptr!=NULL) |
| 953 | | { |
| 954 | | *value = (cartridge->rom_ptr)[cartridge->rom_page*0x2000 + (offset & 0x1fff)]; |
| 955 | | } |
| 956 | | } |
| 957 | | |
| 958 | | /* |
| 959 | | This type of cartridge does not support writing to the EPROM address |
| 960 | | space. |
| 961 | | */ |
| 962 | | static WRITE8_DEVICE_HANDLER( write_cart_pagedcru ) |
| 963 | | { |
| 964 | | return; |
| 965 | | } |
| 966 | | |
| 967 | | /* |
| 968 | | The CRU read handler. The CRU is a serial interface in the console. |
| 969 | | Using the CRU we can switch the banks in the SuperSpace cartridge. |
| 970 | | For documentation see the corresponding cru function above. Note we are |
| 971 | | using rom_page here. |
| 972 | | */ |
| 973 | | static READ8Z_DEVICE_HANDLER( read_cart_cru_paged ) |
| 974 | | { |
| 975 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 976 | | cartridge_t *cartridge = pcb->cartridge; |
| 977 | | |
| 978 | | int page = cartridge->rom_page; |
| 979 | | if ((offset & 0xf800)==0x0800) |
| 980 | | { |
| 981 | | int bit = (offset & 0x001e)/2; |
| 982 | | if (bit != 0) |
| 983 | | { |
| 984 | | page = page-(bit/2); // 4 page flags per 8 bits |
| 985 | | } |
| 986 | | *value = 1 << (page*2+1); |
| 987 | | } |
| 988 | | } |
| 989 | | |
| 990 | | static WRITE8_DEVICE_HANDLER( write_cart_cru_paged ) |
| 991 | | { |
| 992 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 993 | | cartridge_t *cartridge = pcb->cartridge; |
| 994 | | |
| 995 | | if ((offset & 0xf800)==0x0800) |
| 996 | | { |
| 997 | | int bit = (offset & 0x001e)/2; |
| 998 | | if (data != 0 && bit > 0) |
| 999 | | { |
| 1000 | | cartridge->rom_page = (bit-1)/2; |
| 1001 | | } |
| 1002 | | } |
| 1003 | | } |
| 1004 | | |
| 1005 | | /* |
| 1006 | | Pagedcru modules have one EPROM dump. |
| 1007 | | */ |
| 1008 | | static int assemble_pagedcru(running_device *image) |
| 1009 | | { |
| 1010 | | cartridge_t *cart; |
| 1011 | | |
| 1012 | | cart = assemble_common(image); |
| 1013 | | if (cart->rom_ptr==NULL) |
| 1014 | | { |
| 1015 | | logerror("Missing ROM for pagedcru cartridge"); |
| 1016 | | return IMAGE_INIT_FAIL; |
| 1017 | | } |
| 1018 | | cart->rom_page = 0; |
| 1019 | | return IMAGE_INIT_PASS; |
| 1020 | | } |
| 1021 | | |
| 1022 | | /***************************************************************************** |
| 1023 | | Cartridge type: gramkracker |
| 1024 | | ******************************************************************************/ |
| 1025 | | |
| 1026 | | static DEVICE_START(ti99_pcb_gramkracker) |
| 1027 | | { |
| 1028 | | /* device is ti99_cartslot:cartridge:pcb */ |
| 1029 | | // printf("DEVICE_START(ti99_pcb_pagedcru), tag of device=%s\n", device->tag()); |
| 1030 | | set_pointers(device, get_index_from_tagname(device->owner())-1); |
| 1031 | | } |
| 1032 | | |
| 1033 | | /* |
| 1034 | | The GRAM Kracker contains one GROM and several buffered RAM chips |
| 1035 | | */ |
| 1036 | | static int assemble_gramkracker(running_device *image) |
| 1037 | | { |
| 1038 | | cartridge_t *cart; |
| 1039 | | int id,i; |
| 1040 | | |
| 1041 | | running_device *cartsys = image->owner(); |
| 1042 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 1043 | | |
| 1044 | | cart = assemble_common(image); |
| 1045 | | |
| 1046 | | if (cart->grom_ptr==NULL) |
| 1047 | | { |
| 1048 | | logerror("Missing loader GROM for GRAM Kracker system"); |
| 1049 | | return IMAGE_INIT_FAIL; |
| 1050 | | } |
| 1051 | | |
| 1052 | | if (cart->ram_size < 81920) |
| 1053 | | { |
| 1054 | | logerror("Missing or insufficient RAM for GRAM Kracker system"); |
| 1055 | | return IMAGE_INIT_FAIL; |
| 1056 | | } |
| 1057 | | |
| 1058 | | // Get slot number |
| 1059 | | id = get_index_from_tagname(image); |
| 1060 | | cartslots->gk_slot = id-1; |
| 1061 | | cartslots->gk_guest_slot = -1; |
| 1062 | | // The first cartridge that is still plugged in is the "guest" of the |
| 1063 | | // GRAM Kracker |
| 1064 | | for (i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++) |
| 1065 | | { |
| 1066 | | if (!slot_is_empty(cartsys, i) && (i != cartslots->gk_slot)) |
| 1067 | | { |
| 1068 | | cartslots->gk_guest_slot = i; |
| 1069 | | break; |
| 1070 | | } |
| 1071 | | } |
| 1072 | | return IMAGE_INIT_PASS; |
| 1073 | | } |
| 1074 | | |
| 1075 | | /* |
| 1076 | | Unplugs the GRAM Kracker. The "guest" is still plugged in, but will be |
| 1077 | | treated as normal. |
| 1078 | | */ |
| 1079 | | static int disassemble_gramkracker(running_device *cartslot) |
| 1080 | | { |
| 1081 | | running_device *cartsys = cartslot->owner(); |
| 1082 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 1083 | | |
| 1084 | | int slotnumber = get_index_from_tagname(cartslot)-1; |
| 1085 | | assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS); |
| 1086 | | |
| 1087 | | cartslots->gk_slot = -1; |
| 1088 | | cartslots->gk_guest_slot = -1; |
| 1089 | | |
| 1090 | | return disassemble_std(cartslot); |
| 1091 | | } |
| 1092 | | |
| 1093 | | |
| 1094 | | /***************************************************************************** |
| 1095 | | Device metadata |
| 1096 | | ******************************************************************************/ |
| 1097 | | |
| 1098 | | /* |
| 1099 | | Get the pointer to the GROM data from the cartridge. Called by the GROM. |
| 1100 | | */ |
| 1101 | | static UINT8 *get_grom_ptr(running_device *device) |
| 1102 | | { |
| 1103 | | ti99_pcb_t *pcb = get_safe_pcb_token(device); |
| 1104 | | return pcb->cartridge->grom_ptr; |
| 1105 | | } |
| 1106 | | |
| 1107 | | static MACHINE_CONFIG_FRAGMENT(ti99_cart_common) |
| 1108 | | MDRV_GROM_ADD_P( "grom_3", 3, get_grom_ptr, 0x0000, 0x1800, cart_grom_ready ) |
| 1109 | | MDRV_GROM_ADD_P( "grom_4", 4, get_grom_ptr, 0x2000, 0x1800, cart_grom_ready ) |
| 1110 | | MDRV_GROM_ADD_P( "grom_5", 5, get_grom_ptr, 0x4000, 0x1800, cart_grom_ready ) |
| 1111 | | MDRV_GROM_ADD_P( "grom_6", 6, get_grom_ptr, 0x6000, 0x1800, cart_grom_ready ) |
| 1112 | | MDRV_GROM_ADD_P( "grom_7", 7, get_grom_ptr, 0x8000, 0x1800, cart_grom_ready ) |
| 1113 | | MACHINE_CONFIG_END |
| 1114 | | |
| 1115 | | static DEVICE_GET_INFO(ti99_cart_common) |
| 1116 | | { |
| 1117 | | switch(state) |
| 1118 | | { |
| 1119 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1120 | | case DEVINFO_INT_TOKEN_BYTES: |
| 1121 | | info->i = sizeof(ti99_pcb_t); |
| 1122 | | break; |
| 1123 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: |
| 1124 | | info->i = 0; |
| 1125 | | break; |
| 1126 | | |
| 1127 | | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1128 | | info->machine_config = MACHINE_CONFIG_NAME(ti99_cart_common); |
| 1129 | | break; |
| 1130 | | |
| 1131 | | /* --- the following bits of info are returned as pointers to functions --- */ |
| 1132 | | case DEVINFO_FCT_START: |
| 1133 | | info->start = DEVICE_START_NAME(ti99_pcb_std); |
| 1134 | | break; |
| 1135 | | case DEVINFO_FCT_STOP: |
| 1136 | | /* Nothing */ |
| 1137 | | break; |
| 1138 | | case DEVINFO_FCT_RESET: |
| 1139 | | /* Nothing */ |
| 1140 | | break; |
| 1141 | | case TI99CARTINFO_FCT_6000_R: |
| 1142 | | info->f = (genf *) read_cart_std; break; |
| 1143 | | |
| 1144 | | case TI99CARTINFO_FCT_6000_W: |
| 1145 | | info->f = (genf *) write_cart_std; break; |
| 1146 | | |
| 1147 | | case TI99CARTINFO_FCT_CRU_R: |
| 1148 | | /* Nothing */ |
| 1149 | | break; |
| 1150 | | |
| 1151 | | case TI99CARTINFO_FCT_CRU_W: |
| 1152 | | /* Nothing */ |
| 1153 | | break; |
| 1154 | | |
| 1155 | | case TI99CART_FCT_ASSM: |
| 1156 | | info->f = (genf *) assemble_std; |
| 1157 | | break; |
| 1158 | | |
| 1159 | | case TI99CART_FCT_DISASSM: |
| 1160 | | info->f = (genf *) disassemble_std; |
| 1161 | | break; |
| 1162 | | |
| 1163 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1164 | | case DEVINFO_STR_NAME: |
| 1165 | | strcpy(info->s, "TI99 standard cartridge pcb"); |
| 1166 | | break; |
| 1167 | | case DEVINFO_STR_FAMILY: |
| 1168 | | strcpy(info->s, "TI99 cartridge pcb"); |
| 1169 | | break; |
| 1170 | | case DEVINFO_STR_VERSION: |
| 1171 | | strcpy(info->s, "1.0"); |
| 1172 | | break; |
| 1173 | | case DEVINFO_STR_SOURCE_FILE: |
| 1174 | | strcpy(info->s, __FILE__); |
| 1175 | | break; |
| 1176 | | case DEVINFO_STR_CREDITS: |
| 1177 | | /* Nothing */ |
| 1178 | | break; |
| 1179 | | } |
| 1180 | | } |
| 1181 | | |
| 1182 | | DEVICE_GET_INFO(ti99_cartridge_pcb_none) |
| 1183 | | { |
| 1184 | | switch(state) |
| 1185 | | { |
| 1186 | | case DEVINFO_FCT_START: |
| 1187 | | info->start = DEVICE_START_NAME(ti99_pcb_none); |
| 1188 | | break; |
| 1189 | | |
| 1190 | | case DEVINFO_STR_NAME: |
| 1191 | | strcpy(info->s, "TI99 empty cartridge"); |
| 1192 | | break; |
| 1193 | | |
| 1194 | | // Don't create GROMs |
| 1195 | | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1196 | | break; |
| 1197 | | |
| 1198 | | default: |
| 1199 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1200 | | break; |
| 1201 | | } |
| 1202 | | } |
| 1203 | | |
| 1204 | | DEVICE_GET_INFO(ti99_cartridge_pcb_std) |
| 1205 | | { |
| 1206 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1207 | | } |
| 1208 | | |
| 1209 | | DEVICE_GET_INFO(ti99_cartridge_pcb_paged) |
| 1210 | | { |
| 1211 | | switch(state) |
| 1212 | | { |
| 1213 | | case DEVINFO_FCT_START: |
| 1214 | | info->start = DEVICE_START_NAME(ti99_pcb_paged); |
| 1215 | | break; |
| 1216 | | |
| 1217 | | case TI99CART_FCT_ASSM: |
| 1218 | | info->f = (genf *) assemble_paged; |
| 1219 | | break; |
| 1220 | | |
| 1221 | | case TI99CARTINFO_FCT_6000_R: |
| 1222 | | info->f = (genf *) read_cart_paged; |
| 1223 | | break; |
| 1224 | | |
| 1225 | | case TI99CARTINFO_FCT_6000_W: |
| 1226 | | info->f = (genf *) write_cart_paged; |
| 1227 | | break; |
| 1228 | | |
| 1229 | | case DEVINFO_STR_NAME: |
| 1230 | | strcpy(info->s, "TI99 paged cartridge pcb"); |
| 1231 | | break; |
| 1232 | | |
| 1233 | | default: |
| 1234 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1235 | | break; |
| 1236 | | } |
| 1237 | | } |
| 1238 | | |
| 1239 | | DEVICE_GET_INFO(ti99_cartridge_pcb_minimem) |
| 1240 | | { |
| 1241 | | switch(state) |
| 1242 | | { |
| 1243 | | case DEVINFO_FCT_START: |
| 1244 | | info->start = DEVICE_START_NAME(ti99_pcb_minimem); |
| 1245 | | break; |
| 1246 | | |
| 1247 | | case TI99CART_FCT_ASSM: |
| 1248 | | info->f = (genf *) assemble_minimem; |
| 1249 | | break; |
| 1250 | | case TI99CARTINFO_FCT_6000_R: |
| 1251 | | info->f = (genf *) read_cart_minimem; |
| 1252 | | break; |
| 1253 | | case TI99CARTINFO_FCT_6000_W: |
| 1254 | | info->f = (genf *) write_cart_minimem; |
| 1255 | | break; |
| 1256 | | |
| 1257 | | case DEVINFO_STR_NAME: |
| 1258 | | strcpy(info->s, "TI99 MiniMemory cartridge pcb"); |
| 1259 | | break; |
| 1260 | | |
| 1261 | | default: |
| 1262 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1263 | | break; |
| 1264 | | } |
| 1265 | | } |
| 1266 | | |
| 1267 | | DEVICE_GET_INFO(ti99_cartridge_pcb_super) |
| 1268 | | { |
| 1269 | | switch(state) |
| 1270 | | { |
| 1271 | | case DEVINFO_FCT_START: |
| 1272 | | info->start = DEVICE_START_NAME(ti99_pcb_super); |
| 1273 | | break; |
| 1274 | | |
| 1275 | | case TI99CART_FCT_ASSM: |
| 1276 | | info->f = (genf *) assemble_super; |
| 1277 | | break; |
| 1278 | | case TI99CARTINFO_FCT_6000_R: |
| 1279 | | info->f = (genf *) read_cart_super; |
| 1280 | | break; |
| 1281 | | case TI99CARTINFO_FCT_6000_W: |
| 1282 | | info->f = (genf *) write_cart_super; |
| 1283 | | break; |
| 1284 | | case TI99CARTINFO_FCT_CRU_R: |
| 1285 | | info->f = (genf *) read_cart_cru; |
| 1286 | | break; |
| 1287 | | case TI99CARTINFO_FCT_CRU_W: |
| 1288 | | info->f = (genf *) write_cart_cru; |
| 1289 | | break; |
| 1290 | | |
| 1291 | | // Don't create GROMs |
| 1292 | | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1293 | | break; |
| 1294 | | |
| 1295 | | case DEVINFO_STR_NAME: |
| 1296 | | strcpy(info->s, "TI99 SuperSpace cartridge pcb"); |
| 1297 | | break; |
| 1298 | | |
| 1299 | | default: |
| 1300 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1301 | | break; |
| 1302 | | } |
| 1303 | | } |
| 1304 | | |
| 1305 | | DEVICE_GET_INFO(ti99_cartridge_pcb_mbx) |
| 1306 | | { |
| 1307 | | switch(state) |
| 1308 | | { |
| 1309 | | case DEVINFO_FCT_START: |
| 1310 | | info->start = DEVICE_START_NAME(ti99_pcb_mbx); |
| 1311 | | break; |
| 1312 | | |
| 1313 | | case TI99CART_FCT_ASSM: |
| 1314 | | info->f = (genf *) assemble_mbx; |
| 1315 | | break; |
| 1316 | | case TI99CARTINFO_FCT_6000_R: |
| 1317 | | info->f = (genf *) read_cart_mbx; |
| 1318 | | break; |
| 1319 | | case TI99CARTINFO_FCT_6000_W: |
| 1320 | | info->f = (genf *) write_cart_mbx; |
| 1321 | | break; |
| 1322 | | |
| 1323 | | case DEVINFO_STR_NAME: |
| 1324 | | strcpy(info->s, "TI99 MBX cartridge pcb"); |
| 1325 | | break; |
| 1326 | | |
| 1327 | | default: |
| 1328 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1329 | | break; |
| 1330 | | } |
| 1331 | | } |
| 1332 | | |
| 1333 | | DEVICE_GET_INFO(ti99_cartridge_pcb_paged379i) |
| 1334 | | { |
| 1335 | | switch(state) |
| 1336 | | { |
| 1337 | | case DEVINFO_FCT_START: |
| 1338 | | info->start = DEVICE_START_NAME(ti99_pcb_paged379i); |
| 1339 | | break; |
| 1340 | | |
| 1341 | | case TI99CART_FCT_ASSM: |
| 1342 | | info->f = (genf *) assemble_paged379i; break; |
| 1343 | | |
| 1344 | | case TI99CARTINFO_FCT_6000_R: |
| 1345 | | info->f = (genf *) read_cart_paged379i; |
| 1346 | | break; |
| 1347 | | |
| 1348 | | case TI99CARTINFO_FCT_6000_W: |
| 1349 | | info->f = (genf *) write_cart_paged379i; |
| 1350 | | break; |
| 1351 | | |
| 1352 | | case DEVINFO_STR_NAME: |
| 1353 | | strcpy(info->s, "TI99 paged379i cartridge pcb"); |
| 1354 | | break; |
| 1355 | | |
| 1356 | | default: |
| 1357 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1358 | | break; |
| 1359 | | } |
| 1360 | | } |
| 1361 | | |
| 1362 | | DEVICE_GET_INFO(ti99_cartridge_pcb_pagedcru) |
| 1363 | | { |
| 1364 | | switch(state) |
| 1365 | | { |
| 1366 | | case DEVINFO_FCT_START: |
| 1367 | | info->start = DEVICE_START_NAME(ti99_pcb_pagedcru); |
| 1368 | | break; |
| 1369 | | |
| 1370 | | case TI99CART_FCT_ASSM: |
| 1371 | | info->f = (genf *) assemble_pagedcru; |
| 1372 | | break; |
| 1373 | | |
| 1374 | | case TI99CARTINFO_FCT_6000_R: |
| 1375 | | info->f = (genf *) read_cart_pagedcru; |
| 1376 | | break; |
| 1377 | | |
| 1378 | | case TI99CARTINFO_FCT_6000_W: |
| 1379 | | info->f = (genf *) write_cart_pagedcru; |
| 1380 | | break; |
| 1381 | | |
| 1382 | | case TI99CARTINFO_FCT_CRU_R: |
| 1383 | | info->f = (genf *) read_cart_cru_paged; |
| 1384 | | break; |
| 1385 | | case TI99CARTINFO_FCT_CRU_W: |
| 1386 | | info->f = (genf *) write_cart_cru_paged; |
| 1387 | | break; |
| 1388 | | |
| 1389 | | case DEVINFO_STR_NAME: |
| 1390 | | strcpy(info->s, "TI99 pagedcru cartridge pcb"); |
| 1391 | | break; |
| 1392 | | |
| 1393 | | default: |
| 1394 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1395 | | break; |
| 1396 | | } |
| 1397 | | } |
| 1398 | | |
| 1399 | | DEVICE_GET_INFO(ti99_cartridge_pcb_gramkracker) |
| 1400 | | { |
| 1401 | | switch(state) |
| 1402 | | { |
| 1403 | | case DEVINFO_FCT_START: |
| 1404 | | info->start = DEVICE_START_NAME(ti99_pcb_gramkracker); |
| 1405 | | break; |
| 1406 | | |
| 1407 | | case TI99CART_FCT_ASSM: |
| 1408 | | info->f = (genf *) assemble_gramkracker; |
| 1409 | | break; |
| 1410 | | |
| 1411 | | case TI99CART_FCT_DISASSM: |
| 1412 | | info->f = (genf *) disassemble_gramkracker; |
| 1413 | | break; |
| 1414 | | |
| 1415 | | case DEVINFO_STR_NAME: |
| 1416 | | strcpy(info->s, "TI99 GRAM Kracker system"); |
| 1417 | | break; |
| 1418 | | |
| 1419 | | default: |
| 1420 | | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1421 | | break; |
| 1422 | | } |
| 1423 | | } |
| 1424 | | |
| 1425 | | /***************************************************************************** |
| 1426 | | The cartridge handling of the multi-cartridge system. |
| 1427 | | Every cartridge contains a PCB device. The memory handlers delegate the calls |
| 1428 | | to the respective handlers of the cartridges. |
| 1429 | | ******************************************************************************/ |
| 1430 | | /* |
| 1431 | | Initialize a cartridge. Each cartridge contains a PCB device. |
| 1432 | | */ |
| 1433 | | static DEVICE_START( ti99_cartridge ) |
| 1434 | | { |
| 1435 | | cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(device)->token(); |
| 1436 | | |
| 1437 | | /* find the PCB device */ |
| 1438 | | cart->pcb_device = device->subdevice(TAG_PCB); |
| 1439 | | } |
| 1440 | | |
| 1441 | | /* |
| 1442 | | Load the cartridge image files. Apart from reading, we set pointers |
| 1443 | | to the image files so that during runtime we do not need search |
| 1444 | | operations. |
| 1445 | | */ |
| 1446 | | static DEVICE_IMAGE_LOAD( ti99_cartridge ) |
| 1447 | | { |
| 1448 | | running_device *pcbdev = cartslot_get_pcb(&image.device()); |
| 1449 | | // running_device *cartsys = image.device().owner(); |
| 1450 | | // ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 1451 | | |
| 1452 | | int result; |
| 1453 | | |
| 1454 | | if (pcbdev != NULL) |
| 1455 | | { |
| 1456 | | /* If we are here, we have a multicart. */ |
| 1457 | | ti99_pcb_t *pcb = (ti99_pcb_t *)downcast<legacy_device_base *>(pcbdev)->token(); |
| 1458 | | cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(&image.device())->token(); |
| 1459 | | |
| 1460 | | /* try opening this as a multicart */ |
| 1461 | | // This line requires that cartslot_t be included in cartslot.h, |
| 1462 | | // otherwise one cannot make use of multicart handling within such a |
| 1463 | | // custom LOAD function. |
| 1464 | | multicart_open_error me = multicart_open(image.filename(), image.device().machine->gamedrv->name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc); |
| 1465 | | |
| 1466 | | // Now that we have loaded the image files, let the PCB put them all |
| 1467 | | // together. This means we put the images in a structure which allows |
| 1468 | | // for a quick access by the memory handlers. Every PCB defines an |
| 1469 | | // own assembly method. |
| 1470 | | if (me == MCERR_NONE) |
| 1471 | | result = pcb->assemble(image); |
| 1472 | | else |
| 1473 | | fatalerror("Error loading multicart: %s", multicart_error_text(me)); |
| 1474 | | } |
| 1475 | | else |
| 1476 | | { |
| 1477 | | fatalerror("Error loading multicart: no pcb found."); |
| 1478 | | } |
| 1479 | | return result; |
| 1480 | | } |
| 1481 | | |
| 1482 | | /* |
| 1483 | | This is called when the cartridge is unplugged (or the emulator is |
| 1484 | | stopped). |
| 1485 | | */ |
| 1486 | | static DEVICE_IMAGE_UNLOAD( ti99_cartridge ) |
| 1487 | | { |
| 1488 | | running_device *pcbdev; |
| 1489 | | // ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(image.device().owner())->token(); |
| 1490 | | |
| 1491 | | if (downcast<legacy_device_base *>(&image.device())->token() == NULL) |
| 1492 | | { |
| 1493 | | // This means something went wrong during the pcb |
| 1494 | | // identification (e.g. one of the cartridge files was not |
| 1495 | | // found). We do not need to (and cannot) unload the cartridge. |
| 1496 | | return; |
| 1497 | | } |
| 1498 | | pcbdev = cartslot_get_pcb(image); |
| 1499 | | |
| 1500 | | if (pcbdev != NULL) |
| 1501 | | { |
| 1502 | | ti99_pcb_t *pcb = (ti99_pcb_t *)downcast<legacy_device_base *>(pcbdev)->token(); |
| 1503 | | cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(&image.device())->token(); |
| 1504 | | |
| 1505 | | if (cart->mc != NULL) |
| 1506 | | { |
| 1507 | | /* Remove pointers and de-big-endianize RAM contents. */ |
| 1508 | | pcb->disassemble(image); |
| 1509 | | |
| 1510 | | // Close the multicart; all RAM resources will be |
| 1511 | | // written to disk |
| 1512 | | multicart_close(cart->mc); |
| 1513 | | cart->mc = NULL; |
| 1514 | | |
| 1515 | | } |
| 1516 | | } |
| 1517 | | } |
| 1518 | | |
| 1519 | | /***************************************************************************** |
| 1520 | | The overall multi-cartridge slot system. It contains instances of |
| 1521 | | cartridges which contain PCB devices. The memory handlers delegate the calls |
| 1522 | | to the respective handlers of the cartridges. |
| 1523 | | |
| 1524 | | Note that the term "multi-cartridge system" and "multicart" are not the same: |
| 1525 | | A "multicart" may contain multiple resources, organized on a PCB. The multi- |
| 1526 | | cart system may thus host multiple multicarts. |
| 1527 | | |
| 1528 | | Actually, the name of the device should be changed (however, the device name |
| 1529 | | length is limited) |
| 1530 | | ******************************************************************************/ |
| 1531 | | |
| 1532 | | static READ8Z_DEVICE_HANDLER( ti99_cart_gk_rz ); |
| 1533 | | static WRITE8_DEVICE_HANDLER( ti99_cart_gk_w ); |
| 1534 | | static void cartridge_gram_kracker_writeg(running_device *cartsys, int offset, UINT8 data); |
| 1535 | | static void cartridge_gram_kracker_readg(running_device *device, UINT8 *value); |
| 1536 | | static READ8Z_DEVICE_HANDLER( ti99_cart_cru_gk_rz ); |
| 1537 | | static WRITE8_DEVICE_HANDLER( ti99_cart_cru_gk_w ); |
| 1538 | | |
| 1539 | | /* |
| 1540 | | Instantiation of a multicart system for the TI family. |
| 1541 | | */ |
| 1542 | | static DEVICE_START(ti99_multicart) |
| 1543 | | { |
| 1544 | | int i; |
| 1545 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 1546 | | const ti99_multicart_config* cartconf = (const ti99_multicart_config*)get_config(device); |
| 1547 | | |
| 1548 | | cartslots->active_slot = 0; |
| 1549 | | cartslots->next_free_slot = 0; |
| 1550 | | |
| 1551 | | for (i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++) |
| 1552 | | { |
| 1553 | | cartslots->cartridge[i].pcb = NULL; |
| 1554 | | clear_slot(device, i); |
| 1555 | | } |
| 1556 | | |
| 1557 | | devcb_write_line ready = DEVCB_LINE(cartconf->ready); |
| 1558 | | |
| 1559 | | devcb_resolve_write_line(&cartslots->ready, &ready, device); |
| 1560 | | |
| 1561 | | // The cartslot system is initialized now. The cartridges themselves |
| 1562 | | // need to check whether their parts are available. |
| 1563 | | } |
| 1564 | | |
| 1565 | | static DEVICE_STOP(ti99_multicart) |
| 1566 | | { |
| 1567 | | // printf("DEVICE_STOP(ti99_multicart)\n"); |
| 1568 | | } |
| 1569 | | |
| 1570 | | static DEVICE_RESET(ti99_multicart) |
| 1571 | | { |
| 1572 | | // Consider to propagate RESET to cartridges. |
| 1573 | | // However, schematics do not reveal any pin for resetting a cartridge; |
| 1574 | | // the reset line is an input used when plugging in a cartridge. |
| 1575 | | |
| 1576 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 1577 | | int slotnumber = input_port_read(device->machine, "CARTSLOT"); |
| 1578 | | cartslots->fixed_slot = slotnumber-1; /* auto = -1 */ |
| 1579 | | } |
| 1580 | | |
| 1581 | | /* |
| 1582 | | Accesses the ROM regions of the cartridge for reading. |
| 1583 | | */ |
| 1584 | | READ8Z_DEVICE_HANDLER( gromportr_rz ) |
| 1585 | | { |
| 1586 | | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token(); |
| 1587 | | int slot = cartslots->active_slot; |
| 1588 | | cartridge_t *cart; |
| 1589 | | |
| 1590 | | // Handle GRAM Kracker |
| 1591 | | // We could also consider to use a flag, but input_port_read uses |
| 1592 | | // a hashtable, so this should not be too slow |
| 1593 | | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| 1594 | | { |
| 1595 | | ti99_cart_gk_rz(device, offset, value); |
| 1596 | | return; |
| 1597 | | } |
| 1598 | | |
| 1599 | | /* Sanity check. Higher slots are always empty. */ |
| 1600 | | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1601 | | return; |
| 1602 | | |
| 1603 | | // Same as above (GROM read) |
| 1604 | | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1605 | | slot=0; |
| 1606 | | |
| 1607 | | cart = &cartslots->cartridge[slot]; |
| 1608 | | |
| 1609 | | if (!slot_is_empty(device, slot)) |
| 1610 | | { |
| 1611 | | // printf("try it on slot %d\n", slot); |
| 1612 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token(); |
| 1613 | | (*pcbdef->read)(cart->pcb, offset, value); |
| 1614 | | } |
| 1615 | | } |
| 1616 | | |
| 1617 | | /* |
| 1618 | | Accesses the ROM regions of the cartridge for writing. |
| 1619 | | */ |
| 1620 | | WRITE8_DEVICE_HANDLER( gromportr_w ) |
| 1621 | | { |
| 1622 | | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token(); |
| 1623 | | int slot = cartslots->active_slot; |
| 1624 | | cartridge_t *cart; |
| 1625 | | |
| 1626 | | // Handle GRAM Kracker |
| 1627 | | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| 1628 | | ti99_cart_gk_w(device, offset, data); |
| 1629 | | |
| 1630 | | /* Sanity check. Higher slots are always empty. */ |
| 1631 | | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1632 | | return; |
| 1633 | | |
| 1634 | | /* Same as above (READ16). */ |
| 1635 | | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1636 | | slot=0; |
| 1637 | | |
| 1638 | | cart = &cartslots->cartridge[slot]; |
| 1639 | | |
| 1640 | | if (!slot_is_empty(device, slot)) |
| 1641 | | { |
| 1642 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token(); |
| 1643 | | (*pcbdef->write)(cart->pcb, offset, data); |
| 1644 | | } |
| 1645 | | } |
| 1646 | | |
| 1647 | | /* |
| 1648 | | Set the address pointer value or write to GRAM (if available). |
| 1649 | | */ |
| 1650 | | WRITE8_DEVICE_HANDLER(gromportg_w) |
| 1651 | | { |
| 1652 | | int slot; |
| 1653 | | cartridge_t *cartridge; |
| 1654 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 1655 | | |
| 1656 | | // Set the cart slot. |
| 1657 | | // 1001 1wbb bbbb bbr0 |
| 1658 | | |
| 1659 | | cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff)); |
| 1660 | | slot = cartslots->active_slot; |
| 1661 | | |
| 1662 | | // The selection mechanism of the console checks the different GROM address |
| 1663 | | // bases, and when it finds different data, it concludes that there is |
| 1664 | | // indeed a multi-cartridge facility. Empty slots return 0 at all |
| 1665 | | // addresses. |
| 1666 | | // Unfortunately, TI's cartridge selection mechanism has an undesirable |
| 1667 | | // side-effect which we work around in this implementation. |
| 1668 | | // When we have only one cartridge we would like to get only the option to |
| 1669 | | // select this cartridge and not an option to switch to the next one (which |
| 1670 | | // would immediately cycle back to cartridge 1). However, the console |
| 1671 | | // routines always show the switch option when any two slots have different |
| 1672 | | // content, and this is the case with only one cartridge (slot 2 will then |
| 1673 | | // be filled with zeros). |
| 1674 | | // So if next_free_slot==1, we have one cartridge in slot 0. |
| 1675 | | // In that case we trick the OS to believe that the addressed |
| 1676 | | // cartridge appears at all locations which causes it to assume a |
| 1677 | | // standard single cartslot. |
| 1678 | | |
| 1679 | | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1680 | | slot=0; |
| 1681 | | |
| 1682 | | // Handle the GRAM Kracker |
| 1683 | | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| 1684 | | { |
| 1685 | | cartridge_gram_kracker_writeg(device, offset, data); |
| 1686 | | return; |
| 1687 | | } |
| 1688 | | |
| 1689 | | if (slot < NUMBER_OF_CARTRIDGE_SLOTS) |
| 1690 | | { |
| 1691 | | cartridge = &cartslots->cartridge[slot]; |
| 1692 | | // Send the request to all mounted GROMs |
| 1693 | | if (cartridge->pcb!=NULL) |
| 1694 | | { |
| 1695 | | for (int i=0; i < 5; i++) |
| 1696 | | { |
| 1697 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cartridge->pcb)->token(); |
| 1698 | | if (pcbdef->grom[i]!=NULL) |
| 1699 | | ti99grom_w(pcbdef->grom[i], offset, data); |
| 1700 | | } |
| 1701 | | } |
| 1702 | | } |
| 1703 | | } |
| 1704 | | |
| 1705 | | /* |
| 1706 | | GROM access. Nota bene: We only react to the request if there is a GROM |
| 1707 | | at the selected bank with the currently selected ID. If not, just do |
| 1708 | | nothing; do not return a value. |
| 1709 | | (We must not return a value since all GROMs are connected in parallel, so |
| 1710 | | returning a 0, for instance, will spoil the processing of other GROMs.) |
| 1711 | | */ |
| 1712 | | READ8Z_DEVICE_HANDLER(gromportg_rz) |
| 1713 | | { |
| 1714 | | int slot; |
| 1715 | | cartridge_t *cartridge; |
| 1716 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 1717 | | |
| 1718 | | // Set the cart slot. Note that the port must be adjusted for 16-bit |
| 1719 | | // systems, i.e. it should be shifted left by 1. |
| 1720 | | // 1001 1wbb bbbb bbr0 |
| 1721 | | |
| 1722 | | cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff)); |
| 1723 | | |
| 1724 | | // Handle the GRAM Kracker |
| 1725 | | // BTW, the GK does not have a readable address counter, but the console |
| 1726 | | // GROMs will keep our addess counter up to date. That is |
| 1727 | | // exactly what happens in the real machine. |
| 1728 | | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| 1729 | | { |
| 1730 | | if ((offset & 0x0002)==0) cartridge_gram_kracker_readg(device, value); |
| 1731 | | return; |
| 1732 | | } |
| 1733 | | |
| 1734 | | slot = cartslots->active_slot; |
| 1735 | | |
| 1736 | | // This fixes a minor issue: The selection mechanism of the console |
| 1737 | | // concludes that there are multiple cartridges plugged in when it |
| 1738 | | // checks the different GROM bases and finds different data. Empty |
| 1739 | | // slots should return 0 at all addresses, but when we have only |
| 1740 | | // one cartridge, this entails that the second cartridge is |
| 1741 | | // different (all zeros), and so we get a meaningless selection |
| 1742 | | // option between cartridge 1 and 1 and 1 ... |
| 1743 | | // |
| 1744 | | // So if next_free_slot==1, we have one cartridge in slot 0. |
| 1745 | | // In that case we trick the OS to believe that the addressed |
| 1746 | | // cartridge appears at all locations which causes it to assume a |
| 1747 | | // standard single cartslot. |
| 1748 | | |
| 1749 | | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1750 | | slot=0; |
| 1751 | | |
| 1752 | | if (slot < NUMBER_OF_CARTRIDGE_SLOTS) |
| 1753 | | { |
| 1754 | | // Select the cartridge which the multicart system is currently pointing at |
| 1755 | | cartridge = &cartslots->cartridge[slot]; |
| 1756 | | // Send the request to all mounted GROMs on this PCB |
| 1757 | | if (cartridge->pcb!=NULL) |
| 1758 | | { |
| 1759 | | for (int i=0; i < 5; i++) |
| 1760 | | { |
| 1761 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cartridge->pcb)->token(); |
| 1762 | | if (pcbdef->grom[i]!=NULL) |
| 1763 | | ti99grom_rz(pcbdef->grom[i], offset, value); |
| 1764 | | } |
| 1765 | | } |
| 1766 | | } |
| 1767 | | } |
| 1768 | | |
| 1769 | | /* |
| 1770 | | CRU interface to cartridges, used only by SuperSpace and Pagedcru |
| 1771 | | style cartridges. |
| 1772 | | The SuperSpace has a CRU-based memory mapper. It is accessed via the |
| 1773 | | cartridge slot on CRU base >0800. |
| 1774 | | */ |
| 1775 | | READ8Z_DEVICE_HANDLER( gromportc_rz ) |
| 1776 | | { |
| 1777 | | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token(); |
| 1778 | | cartridge_t *cart; |
| 1779 | | |
| 1780 | | int slot = cartslots->active_slot; |
| 1781 | | |
| 1782 | | // Handle GRAM Kracker |
| 1783 | | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| 1784 | | { |
| 1785 | | ti99_cart_cru_gk_rz(device, offset, value); |
| 1786 | | return; |
| 1787 | | } |
| 1788 | | |
| 1789 | | /* Sanity check. Higher slots are always empty. */ |
| 1790 | | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1791 | | return; |
| 1792 | | |
| 1793 | | /* Same as above (READ16). */ |
| 1794 | | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1795 | | slot=0; |
| 1796 | | |
| 1797 | | cart = &cartslots->cartridge[slot]; |
| 1798 | | |
| 1799 | | if (!slot_is_empty(device, slot)) |
| 1800 | | { |
| 1801 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();; |
| 1802 | | if (pcbdef->cruread != NULL) |
| 1803 | | (*pcbdef->cruread)(cart->pcb, offset, value); |
| 1804 | | } |
| 1805 | | } |
| 1806 | | |
| 1807 | | /* |
| 1808 | | Write cartridge mapper CRU interface (SuperSpace, Pagedcru) |
| 1809 | | */ |
| 1810 | | WRITE8_DEVICE_HANDLER( gromportc_w ) |
| 1811 | | { |
| 1812 | | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token(); |
| 1813 | | cartridge_t *cart; |
| 1814 | | |
| 1815 | | int slot = cartslots->active_slot; |
| 1816 | | |
| 1817 | | // Handle GRAM Kracker |
| 1818 | | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| 1819 | | { |
| 1820 | | ti99_cart_cru_gk_w(device, offset, data); |
| 1821 | | return; |
| 1822 | | } |
| 1823 | | |
| 1824 | | /* Sanity check. Higher slots are always empty. */ |
| 1825 | | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1826 | | return; |
| 1827 | | |
| 1828 | | /* Same as above (READ16). */ |
| 1829 | | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1830 | | slot=0; |
| 1831 | | |
| 1832 | | cart = &cartslots->cartridge[slot]; |
| 1833 | | |
| 1834 | | if (!slot_is_empty(device, slot)) |
| 1835 | | { |
| 1836 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();; |
| 1837 | | if (pcbdef->cruwrite != NULL) |
| 1838 | | (*pcbdef->cruwrite)(cart->pcb, offset, data); |
| 1839 | | } |
| 1840 | | } |
| 1841 | | |
| 1842 | | /***************************************************************************** |
| 1843 | | GramKracker support |
| 1844 | | The 80 KiB of the GK are allocated as follows |
| 1845 | | 00000 - 01fff: GRAM 0 |
| 1846 | | 02000 - 03fff: GRAM 1 (alternatively, the loader GROM appears here) |
| 1847 | | 04000 - 05fff: GRAM 2 |
| 1848 | | 06000 - 0ffff: GRAM 3-7 (alternatively, the guest GROMs appear here) |
| 1849 | | 10000 - 11fff: RAM 1 |
| 1850 | | 12000 - 13fff: RAM 2 |
| 1851 | | |
| 1852 | | The GK emulates GROMs, but without a readable address counter. Thus it |
| 1853 | | relies on the console GROMs being still in place (compare with the HSGPL). |
| 1854 | | Also, the GK does not implement a GROM buffer. |
| 1855 | | ******************************************************************************/ |
| 1856 | | |
| 1857 | | /* |
| 1858 | | Reads from the GRAM space of the GRAM Kracker. |
| 1859 | | */ |
| 1860 | | static void cartridge_gram_kracker_readg(running_device *cartsys, UINT8 *value) |
| 1861 | | { |
| 1862 | | // gk_slot is the slot where the GK module is plugged in |
| 1863 | | // gk_guest_slot is the slot where the cartridge is plugged in |
| 1864 | | |
| 1865 | | cartridge_t *gromkrackerbox, *gkguestcart; |
| 1866 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 1867 | | |
| 1868 | | // Not null, since this is only called when there is really a GK module |
| 1869 | | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot]; |
| 1870 | | |
| 1871 | | if ((gromkrackerbox->grom_address & 0xe000) == 0x0000) |
| 1872 | | { |
| 1873 | | // GRAM 0. Only return a value if switch 2 is in GRAM0 position. |
| 1874 | | if (get_gk_switch(cartsys, 2)==GK_GRAM0) |
| 1875 | | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1876 | | } |
| 1877 | | |
| 1878 | | if ((gromkrackerbox->grom_address & 0xe000) == 0x2000) |
| 1879 | | { |
| 1880 | | // If the loader is turned on, return loader contents. |
| 1881 | | if (get_gk_switch(cartsys, 5)==GK_LDON) |
| 1882 | | { |
| 1883 | | // The only ROM contained in the GK box is the loader |
| 1884 | | *value = gromkrackerbox->grom_ptr[gromkrackerbox->grom_address & 0x1fff]; |
| 1885 | | } |
| 1886 | | else |
| 1887 | | { |
| 1888 | | // Loader off |
| 1889 | | // GRAM 1. Only return a value if switch 3 is in GRAM12 position. |
| 1890 | | if (get_gk_switch(cartsys, 3)==GK_GRAM12) |
| 1891 | | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1892 | | } |
| 1893 | | } |
| 1894 | | |
| 1895 | | if ((gromkrackerbox->grom_address & 0xe000) == 0x4000) |
| 1896 | | { |
| 1897 | | // GRAM 2. Only return a value if switch 3 is in GRAM12 position. |
| 1898 | | if (get_gk_switch(cartsys, 3)==GK_GRAM12) |
| 1899 | | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1900 | | } |
| 1901 | | |
| 1902 | | if (((gromkrackerbox->grom_address & 0xe000) == 0x6000) || |
| 1903 | | ((gromkrackerbox->grom_address & 0x8000) == 0x8000)) |
| 1904 | | { |
| 1905 | | // Cartridge space |
| 1906 | | // When a cartridge is installed, it overrides the GK contents |
| 1907 | | // but only if it has GROMs |
| 1908 | | int cartwithgrom = FALSE; |
| 1909 | | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot]; |
| 1910 | | |
| 1911 | | // Send the request to all mounted GROMs |
| 1912 | | if (gkguestcart->pcb!=NULL) |
| 1913 | | { |
| 1914 | | for (int i=0; i < 5; i++) |
| 1915 | | { |
| 1916 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token(); |
| 1917 | | if (pcbdef->grom[i]!=NULL) |
| 1918 | | { |
| 1919 | | ti99grom_rz(pcbdef->grom[i], 0x9800, value); |
| 1920 | | cartwithgrom = TRUE; |
| 1921 | | } |
| 1922 | | } |
| 1923 | | } |
| 1924 | | if (!cartwithgrom && get_gk_switch(cartsys, 1)==GK_NORMAL) |
| 1925 | | { |
| 1926 | | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1927 | | } |
| 1928 | | } |
| 1929 | | |
| 1930 | | // The GK GROM emulation does not wrap at 8K boundaries. |
| 1931 | | gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff; |
| 1932 | | |
| 1933 | | /* Reset the write address flipflop. */ |
| 1934 | | gromkrackerbox->waddr_LSB = FALSE; |
| 1935 | | } |
| 1936 | | |
| 1937 | | /* |
| 1938 | | Writes to the GRAM space of the GRAM Kracker. |
| 1939 | | */ |
| 1940 | | static void cartridge_gram_kracker_writeg(running_device *cartsys, int offset, UINT8 data) |
| 1941 | | { |
| 1942 | | // gk_slot is the slot where the GK module is plugged in |
| 1943 | | // gk_guest_slot is the slot where the cartridge is plugged in |
| 1944 | | cartridge_t *gromkrackerbox; |
| 1945 | | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 1946 | | |
| 1947 | | // This is only called when there is really a GK module |
| 1948 | | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot]; |
| 1949 | | |
| 1950 | | if ((offset & 0x0002)==0x0002) |
| 1951 | | { |
| 1952 | | // Set address |
| 1953 | | if (gromkrackerbox->waddr_LSB) |
| 1954 | | { |
| 1955 | | /* Accept low byte (2nd write) */ |
| 1956 | | gromkrackerbox->grom_address = (gromkrackerbox->grom_address & 0xff00) | data; |
| 1957 | | gromkrackerbox->waddr_LSB = FALSE; |
| 1958 | | } |
| 1959 | | else |
| 1960 | | { |
| 1961 | | /* Accept high byte (1st write) */ |
| 1962 | | gromkrackerbox->grom_address = ((data<<8) & 0xff00) | (gromkrackerbox->grom_address & 0x00ff); |
| 1963 | | gromkrackerbox->waddr_LSB = TRUE; |
| 1964 | | } |
| 1965 | | } |
| 1966 | | else |
| 1967 | | { |
| 1968 | | if (get_gk_switch(cartsys, 4) != GK_WP) |
| 1969 | | { |
| 1970 | | // Write protection off |
| 1971 | | if ( (((gromkrackerbox->grom_address & 0xe000)==0x0000) && get_gk_switch(cartsys, 2)==GK_GRAM0) |
| 1972 | | || (((gromkrackerbox->grom_address & 0xe000)==0x2000) && get_gk_switch(cartsys, 3)==GK_GRAM12 && (get_gk_switch(cartsys, 5)==GK_LDOFF)) |
| 1973 | | || (((gromkrackerbox->grom_address & 0xe000)==0x4000) && get_gk_switch(cartsys, 3)==GK_GRAM12) |
| 1974 | | || (((gromkrackerbox->grom_address & 0xe000)==0x6000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1)) |
| 1975 | | || (((gromkrackerbox->grom_address & 0x8000)==0x8000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1))) |
| 1976 | | { |
| 1977 | | (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address] = data; |
| 1978 | | } |
| 1979 | | } |
| 1980 | | // The GK GROM emulation does not wrap at 8K boundaries. |
| 1981 | | gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff; |
| 1982 | | |
| 1983 | | /* Reset the write address flipflop. */ |
| 1984 | | gromkrackerbox->waddr_LSB = FALSE; |
| 1985 | | } |
| 1986 | | } |
| 1987 | | |
| 1988 | | /* |
| 1989 | | Reads from the RAM space of the GRAM Kracker. |
| 1990 | | */ |
| 1991 | | static READ8Z_DEVICE_HANDLER( ti99_cart_gk_rz ) |
| 1992 | | { |
| 1993 | | // gk_slot is the slot where the GK module is plugged in |
| 1994 | | // gk_guest_slot is the slot where the cartridge is plugged in |
| 1995 | | cartridge_t *gromkrackerbox, *gkguestcart; |
| 1996 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 1997 | | |
| 1998 | | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot]; |
| 1999 | | |
| 2000 | | if (cartslots->gk_guest_slot != -1) |
| 2001 | | { |
| 2002 | | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot]; |
| 2003 | | // Legacy mode is not supported with the GK |
| 2004 | | if (in_legacy_mode(device)) |
| 2005 | | { |
| 2006 | | return; |
| 2007 | | } |
| 2008 | | // printf("accessing cartridge in slot %d\n", slot); |
| 2009 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token(); |
| 2010 | | // printf("address=%lx, offset=%lx\n", pcbdef, offset); |
| 2011 | | (*pcbdef->read)(gkguestcart->pcb, offset, value); |
| 2012 | | return; |
| 2013 | | } |
| 2014 | | else |
| 2015 | | { |
| 2016 | | if (get_gk_switch(device, 1)==GK_OFF) return; |
| 2017 | | if (get_gk_switch(device, 4)==GK_BANK1) |
| 2018 | | { |
| 2019 | | *value = (gromkrackerbox->ram_ptr)[offset+0x10000]; |
| 2020 | | } |
| 2021 | | else |
| 2022 | | { |
| 2023 | | if (get_gk_switch(device, 4)==GK_BANK2) |
| 2024 | | { |
| 2025 | | *value = (gromkrackerbox->ram_ptr)[offset+0x12000]; |
| 2026 | | } |
| 2027 | | else |
| 2028 | | { |
| 2029 | | // Write protection on; auto-bank |
| 2030 | | if (gromkrackerbox->ram_page==0) |
| 2031 | | { |
| 2032 | | *value = (gromkrackerbox->ram_ptr)[offset+0x10000]; |
| 2033 | | } |
| 2034 | | else |
| 2035 | | { |
| 2036 | | *value = (gromkrackerbox->ram_ptr)[offset+0x12000]; |
| 2037 | | } |
| 2038 | | } |
| 2039 | | } |
| 2040 | | } |
| 2041 | | } |
| 2042 | | |
| 2043 | | /* |
| 2044 | | Writes to the RAM space of the GRAM Kracker. |
| 2045 | | */ |
| 2046 | | static WRITE8_DEVICE_HANDLER( ti99_cart_gk_w ) |
| 2047 | | { |
| 2048 | | // gk_slot is the slot where the GK module is plugged in |
| 2049 | | // gk_guest_slot is the slot where the cartridge is plugged in |
| 2050 | | cartridge_t *gromkrackerbox, *gkguestcart; |
| 2051 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 2052 | | |
| 2053 | | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot]; |
| 2054 | | |
| 2055 | | if (cartslots->gk_guest_slot != -1) |
| 2056 | | { |
| 2057 | | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot]; |
| 2058 | | // Legacy mode is not supported with the GK |
| 2059 | | if (in_legacy_mode(device)) |
| 2060 | | { |
| 2061 | | return; |
| 2062 | | } |
| 2063 | | |
| 2064 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token(); |
| 2065 | | (*pcbdef->write)(gkguestcart->pcb, offset, data); |
| 2066 | | } |
| 2067 | | else |
| 2068 | | { |
| 2069 | | if (get_gk_switch(device, 1)==GK_OFF) |
| 2070 | | return; |
| 2071 | | |
| 2072 | | if (get_gk_switch(device, 4)==GK_BANK1) |
| 2073 | | { |
| 2074 | | (gromkrackerbox->ram_ptr)[offset + 0x10000] = data; |
| 2075 | | } |
| 2076 | | else |
| 2077 | | { |
| 2078 | | if (get_gk_switch(device, 4)==GK_BANK2) |
| 2079 | | { |
| 2080 | | (gromkrackerbox->ram_ptr)[offset + 0x12000] = data; |
| 2081 | | } |
| 2082 | | else |
| 2083 | | { |
| 2084 | | // Write protection on |
| 2085 | | // This is handled like in Extended Basic |
| 2086 | | gromkrackerbox->ram_page = (offset & 2)>>1; |
| 2087 | | } |
| 2088 | | } |
| 2089 | | } |
| 2090 | | } |
| 2091 | | |
| 2092 | | /* |
| 2093 | | Read cartridge mapper CRU interface (Guest in GRAM Kracker) |
| 2094 | | */ |
| 2095 | | static READ8Z_DEVICE_HANDLER( ti99_cart_cru_gk_rz ) |
| 2096 | | { |
| 2097 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 2098 | | cartridge_t *gkguestcart; |
| 2099 | | |
| 2100 | | if (cartslots->gk_guest_slot != -1) |
| 2101 | | { |
| 2102 | | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot]; |
| 2103 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token(); |
| 2104 | | if (pcbdef->cruread != NULL) |
| 2105 | | (*pcbdef->cruread)(gkguestcart->pcb, offset, value); |
| 2106 | | } |
| 2107 | | } |
| 2108 | | |
| 2109 | | /* |
| 2110 | | Write cartridge mapper CRU interface (Guest in GRAM Kracker) |
| 2111 | | */ |
| 2112 | | static WRITE8_DEVICE_HANDLER( ti99_cart_cru_gk_w ) |
| 2113 | | { |
| 2114 | | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token(); |
| 2115 | | cartridge_t *gkguestcart; |
| 2116 | | |
| 2117 | | if (cartslots->gk_guest_slot != -1) |
| 2118 | | { |
| 2119 | | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot]; |
| 2120 | | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token(); |
| 2121 | | if (pcbdef->cruwrite != NULL) |
| 2122 | | (*pcbdef->cruwrite)(gkguestcart->pcb, offset, data); |
| 2123 | | } |
| 2124 | | } |
| 2125 | | |
| 2126 | | /*****************************************************************************/ |
| 2127 | | #define TI99_CARTRIDGE_SLOT(p) MDRV_CARTSLOT_ADD(p) \ |
| 2128 | | MDRV_CARTSLOT_EXTENSION_LIST("rpk,bin") \ |
| 2129 | | MDRV_CARTSLOT_PCBTYPE(0, "none", TI99_CARTRIDGE_PCB_NONE) \ |
| 2130 | | MDRV_CARTSLOT_PCBTYPE(1, "standard", TI99_CARTRIDGE_PCB_STD) \ |
| 2131 | | MDRV_CARTSLOT_PCBTYPE(2, "paged", TI99_CARTRIDGE_PCB_PAGED) \ |
| 2132 | | MDRV_CARTSLOT_PCBTYPE(3, "minimem", TI99_CARTRIDGE_PCB_MINIMEM) \ |
| 2133 | | MDRV_CARTSLOT_PCBTYPE(4, "super", TI99_CARTRIDGE_PCB_SUPER) \ |
| 2134 | | MDRV_CARTSLOT_PCBTYPE(5, "mbx", TI99_CARTRIDGE_PCB_MBX) \ |
| 2135 | | MDRV_CARTSLOT_PCBTYPE(6, "paged379i", TI99_CARTRIDGE_PCB_PAGED379I) \ |
| 2136 | | MDRV_CARTSLOT_PCBTYPE(7, "pagedcru", TI99_CARTRIDGE_PCB_PAGEDCRU) \ |
| 2137 | | MDRV_CARTSLOT_PCBTYPE(8, "gramkracker", TI99_CARTRIDGE_PCB_GRAMKRACKER) \ |
| 2138 | | MDRV_CARTSLOT_START(ti99_cartridge) \ |
| 2139 | | MDRV_CARTSLOT_LOAD(ti99_cartridge) \ |
| 2140 | | MDRV_CARTSLOT_UNLOAD(ti99_cartridge) |
| 2141 | | |
| 2142 | | static MACHINE_CONFIG_FRAGMENT(ti99_multicart) |
| 2143 | | TI99_CARTRIDGE_SLOT("cartridge1") |
| 2144 | | TI99_CARTRIDGE_SLOT("cartridge2") |
| 2145 | | TI99_CARTRIDGE_SLOT("cartridge3") |
| 2146 | | TI99_CARTRIDGE_SLOT("cartridge4") |
| 2147 | | MACHINE_CONFIG_END |
| 2148 | | |
| 2149 | | static const char DEVTEMPLATE_SOURCE[] = __FILE__; |
| 2150 | | |
| 2151 | | #define DEVTEMPLATE_ID(p,s) p##ti99_multicart##s |
| 2152 | | #define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG |
| 2153 | | #define DEVTEMPLATE_NAME "TI99 Multi-Cartridge Extender" |
| 2154 | | #define DEVTEMPLATE_FAMILY "Multi-cartridge system" |
| 2155 | | #include "devtempl.h" |
| 2156 | | |
| 2157 | | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_MULTICART, ti99_multicart); |
| 1 | /**********************************************************************
|
| 2 | |
| 3 | gromport.c
|
| 4 | |
| 5 | *********************************************************************/
|
| 6 | |
| 7 | #include "emu.h"
|
| 8 | #include "gromport.h"
|
| 9 | #include "devices/cartslot.h"
|
| 10 | #include "devices/multcart.h"
|
| 11 | #include "grom.h"
|
| 12 | |
| 13 | typedef UINT8 (*read8z_device_func) (ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT8 *value);
|
| 14 | |
| 15 | /* We set the number of slots to 8, although we may have up to 16. From a
|
| 16 | logical point of view we could have 256, but the operating system only checks
|
| 17 | the first 16 banks. */
|
| 18 | #define NUMBER_OF_CARTRIDGE_SLOTS 8
|
| 19 | |
| 20 | typedef int assmfct(running_device *);
|
| 21 | |
| 22 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_NONE, ti99_cartridge_pcb_none);
|
| 23 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_STD, ti99_cartridge_pcb_std);
|
| 24 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED, ti99_cartridge_pcb_paged);
|
| 25 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MINIMEM, ti99_cartridge_pcb_minimem);
|
| 26 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_SUPER, ti99_cartridge_pcb_super);
|
| 27 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MBX, ti99_cartridge_pcb_mbx);
|
| 28 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED379I, ti99_cartridge_pcb_paged379i);
|
| 29 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGEDCRU, ti99_cartridge_pcb_pagedcru);
|
| 30 | DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_GRAMKRACKER, ti99_cartridge_pcb_gramkracker);
|
| 31 | |
| 32 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_NONE, ti99_cartridge_pcb_none);
|
| 33 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_STD, ti99_cartridge_pcb_std);
|
| 34 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED, ti99_cartridge_pcb_paged);
|
| 35 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MINIMEM, ti99_cartridge_pcb_minimem);
|
| 36 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_SUPER, ti99_cartridge_pcb_super);
|
| 37 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MBX, ti99_cartridge_pcb_mbx);
|
| 38 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED379I, ti99_cartridge_pcb_paged379i);
|
| 39 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGEDCRU, ti99_cartridge_pcb_pagedcru);
|
| 40 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_GRAMKRACKER, ti99_cartridge_pcb_gramkracker);
|
| 41 | |
| 42 | /* Generic TI99 cartridge structure. */
|
| 43 | struct _cartridge_t
|
| 44 | {
|
| 45 | // PCB device associated to this cartridge. If NULL, the slot is empty.
|
| 46 | running_device *pcb;
|
| 47 | |
| 48 | // ROM page.
|
| 49 | int rom_page;
|
| 50 | |
| 51 | // RAM page.
|
| 52 | int ram_page;
|
| 53 | |
| 54 | // GROM buffer size.
|
| 55 | int grom_size;
|
| 56 |
|
| 57 | // ROM buffer size. All banks have equal sizes.
|
| 58 | int rom_size;
|
| 59 |
|
| 60 | // RAM buffer size. All banks have equal sizes.
|
| 61 | int ram_size;
|
| 62 | |
| 63 | // GROM buffer. |
| 64 | UINT8 *grom_ptr;
|
| 65 | |
| 66 | // ROM buffer. |
| 67 | UINT8 *rom_ptr;
|
| 68 | |
| 69 | // ROM buffer for the second bank of paged cartridges.
|
| 70 | UINT8 *rom2_ptr;
|
| 71 | |
| 72 | // RAM buffer. The persistence service is done by the cartridge system.
|
| 73 | // The RAM space is a consecutive space; all banks are in one buffer.
|
| 74 | UINT8 *ram_ptr;
|
| 75 |
|
| 76 | /* GK support. */
|
| 77 | UINT16 grom_address;
|
| 78 | int waddr_LSB;
|
| 79 | };
|
| 80 | typedef struct _cartridge_t cartridge_t;
|
| 81 | |
| 82 | enum
|
| 83 | {
|
| 84 | TI99CARTINFO_FCT_6000_R = DEVINFO_FCT_DEVICE_SPECIFIC,
|
| 85 | TI99CARTINFO_FCT_6000_W,
|
| 86 | TI99CARTINFO_FCT_CRU_R,
|
| 87 | TI99CARTINFO_FCT_CRU_W,
|
| 88 | TI99CART_FCT_ASSM,
|
| 89 | TI99CART_FCT_DISASSM
|
| 90 | };
|
| 91 | |
| 92 | typedef struct _ti99_multicart_state
|
| 93 | {
|
| 94 | // Reserves space for all cartridges. This is also used in the legacy
|
| 95 | // cartridge system, but only for slot 0.
|
| 96 | cartridge_t cartridge[NUMBER_OF_CARTRIDGE_SLOTS];
|
| 97 | |
| 98 | // Determines which slot is currently active. This value is changed when
|
| 99 | // there are accesses to other GROM base addresses.
|
| 100 | int active_slot;
|
| 101 | |
| 102 | // Used in order to enforce a special slot. This value is retrieved
|
| 103 | // from the dipswitch setting. A value of -1 means automatic, that is,
|
| 104 | // the grom base switch is used. Values 0 .. max refer to the
|
| 105 | // respective slot.
|
| 106 | int fixed_slot;
|
| 107 | |
| 108 | // Holds the highest index of a cartridge being plugged in plus one.
|
| 109 | // If we only have one cartridge inserted, we don't want to get a
|
| 110 | // selection option, so we just mirror the memory contents.
|
| 111 | int next_free_slot;
|
| 112 |
|
| 113 | /* GK support. */
|
| 114 | int gk_slot;
|
| 115 | int gk_guest_slot;
|
| 116 |
|
| 117 | /* Legacy support. */
|
| 118 | // Counts the number of slots which currently contain legacy format
|
| 119 | // cartridge images.
|
| 120 | int legacy_slots;
|
| 121 | |
| 122 | // Counts the number of slots which currently contain new format
|
| 123 | // cartridge images.
|
| 124 | int multi_slots;
|
| 125 |
|
| 126 | /* Used to cache the switch settings. */
|
| 127 | UINT8 gk_switch[8];
|
| 128 | |
| 129 | /* Ready line */
|
| 130 | devcb_resolved_write_line ready;
|
| 131 |
|
| 132 | } ti99_multicart_state;
|
| 133 | |
| 134 | #define AUTO -1
|
| 135 | |
| 136 | /* Access to the pcb. Contained in the token of the pcb instance. */
|
| 137 | struct _ti99_pcb_t
|
| 138 | {
|
| 139 | /* Read function for this cartridge. */
|
| 140 | read8z_device_func read;
|
| 141 | |
| 142 | /* Write function for this cartridge. */
|
| 143 | write8_device_func write;
|
| 144 | |
| 145 | /* Read function for this cartridge, CRU. */
|
| 146 | read8z_device_func cruread;
|
| 147 | |
| 148 | /* Write function for this cartridge, CRU. */
|
| 149 | write8_device_func cruwrite;
|
| 150 | |
| 151 | /* Link up to the cartridge structure which contains this pcb. */
|
| 152 | cartridge_t *cartridge;
|
| 153 | |
| 154 | /* Function to assemble this cartridge. */
|
| 155 | assmfct *assemble;
|
| 156 | |
| 157 | /* Function to disassemble this cartridge. */
|
| 158 | assmfct *disassemble;
|
| 159 |
|
| 160 | /* Points to the (max 5) GROM devices. */
|
| 161 | running_device *grom[5];
|
| 162 | };
|
| 163 | typedef struct _ti99_pcb_t ti99_pcb_t;
|
| 164 | |
| 165 | INLINE ti99_multicart_state *get_safe_token(running_device *device)
|
| 166 | {
|
| 167 | assert(device != NULL);
|
| 168 | return (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 169 | }
|
| 170 | |
| 171 | INLINE const ti99_multicart_config *get_config(running_device *device)
|
| 172 | {
|
| 173 | assert(device != NULL);
|
| 174 | assert(device->type() == TI99_MULTICART);
|
| 175 | return (const ti99_multicart_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
|
| 176 | }
|
| 177 | |
| 178 | INLINE ti99_pcb_t *get_safe_pcb_token(running_device *device)
|
| 179 | {
|
| 180 | assert(device != NULL);
|
| 181 | return (ti99_pcb_t *)downcast<legacy_device_base *>(device)->token();
|
| 182 | }
|
| 183 | |
| 184 | static WRITE_LINE_DEVICE_HANDLER( cart_grom_ready )
|
| 185 | {
|
| 186 | running_device *cartdev = device->owner()->owner();
|
| 187 | ti99_multicart_state *cartslots = get_safe_token(cartdev);
|
| 188 | devcb_call_write_line( &cartslots->ready, state );
|
| 189 | }
|
| 190 | |
| 191 | /*
|
| 192 | The console writes the values in this array to cache them.
|
| 193 | */
|
| 194 | void set_gk_switches(running_device *cartsys, int number, int value)
|
| 195 | {
|
| 196 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 197 | cartslots->gk_switch[number] = value;
|
| 198 | }
|
| 199 | |
| 200 | static int get_gk_switch(running_device *cartsys, int number)
|
| 201 | {
|
| 202 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 203 | return cartslots->gk_switch[number];
|
| 204 | }
|
| 205 | |
| 206 | static int in_legacy_mode(running_device *device)
|
| 207 | {
|
| 208 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 209 | return ((cartslots->legacy_slots>0) && (cartslots->multi_slots==0));
|
| 210 | }
|
| 211 | |
| 212 | /*
|
| 213 | Activates a slot in the multi-cartridge extender.
|
| 214 | */
|
| 215 | static void cartridge_slot_set(running_device *cartsys, UINT8 slotnumber)
|
| 216 | {
|
| 217 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 218 | // if (cartslots->active_slot != slotnumber) printf("Setting cartslot to %d\n", slotnumber);
|
| 219 | if (cartslots->fixed_slot==AUTO)
|
| 220 | cartslots->active_slot = slotnumber;
|
| 221 | else
|
| 222 | cartslots->active_slot = cartslots->fixed_slot;
|
| 223 | }
|
| 224 | |
| 225 | static int slot_is_empty(running_device *cartsys, int slotnumber)
|
| 226 | {
|
| 227 | cartridge_t *cart;
|
| 228 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 229 | |
| 230 | cart = &cartslots->cartridge[slotnumber];
|
| 231 | |
| 232 | if ((cart->rom_size==0) && (cart->ram_size==0) && (cart->grom_size==0))
|
| 233 | return TRUE;
|
| 234 | return FALSE;
|
| 235 | }
|
| 236 | |
| 237 | static void clear_slot(running_device *cartsys, int slotnumber)
|
| 238 | {
|
| 239 | cartridge_t *cart;
|
| 240 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 241 | |
| 242 | cart = &cartslots->cartridge[slotnumber];
|
| 243 | |
| 244 | cart->rom_size = cart->ram_size = cart->grom_size = 0;
|
| 245 | cart->rom_ptr = NULL;
|
| 246 | cart->rom2_ptr = NULL;
|
| 247 | cart->ram_ptr = NULL;
|
| 248 | }
|
| 249 | |
| 250 | /*
|
| 251 | Find the index of the cartridge name. We assume the format
|
| 252 | <name><number>, i.e. the number is the longest string from the right
|
| 253 | which can be interpreted as a number.
|
| 254 | */
|
| 255 | static int get_index_from_tagname(running_device *image)
|
| 256 | {
|
| 257 | const char *tag = image->tag();
|
| 258 | int maxlen = strlen(tag);
|
| 259 | int i;
|
| 260 | for (i=maxlen-1; i >=0; i--)
|
| 261 | if (tag[i] < 48 || tag[i] > 57) break;
|
| 262 | |
| 263 | return atoi(tag+i+1);
|
| 264 | }
|
| 265 | |
| 266 | /*
|
| 267 | Common routine to assemble cartridges from resources.
|
| 268 | */
|
| 269 | static cartridge_t *assemble_common(running_device *cartslot)
|
| 270 | {
|
| 271 | /* Pointer to the cartridge structure. */
|
| 272 | cartridge_t *cartridge;
|
| 273 | running_device *cartsys = cartslot->owner();
|
| 274 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 275 | running_device *pcb = cartslot->subdevice("pcb");
|
| 276 | ti99_pcb_t *pcb_def;
|
| 277 |
|
| 278 | void *socketcont;
|
| 279 | int reslength;
|
| 280 | // int i;
|
| 281 | |
| 282 | int slotnumber = get_index_from_tagname(cartslot)-1;
|
| 283 | assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS);
|
| 284 | |
| 285 | /* There is a cartridge in this slot, check the maximum slot number. */
|
| 286 | if (cartslots->next_free_slot <= slotnumber)
|
| 287 | {
|
| 288 | cartslots->next_free_slot = slotnumber+1;
|
| 289 | }
|
| 290 | cartridge = &cartslots->cartridge[slotnumber];
|
| 291 | |
| 292 | // Get the socket which is retrieved by the multicart instance in
|
| 293 | // the state of the cartslot instance.
|
| 294 | socketcont = cartslot_get_socket(cartslot, "grom_socket");
|
| 295 | reslength = cartslot_get_resource_length(cartslot, "grom_socket");
|
| 296 | if (socketcont != NULL)
|
| 297 | {
|
| 298 | cartridge->grom_ptr = (UINT8 *)socketcont;
|
| 299 | // printf("grom_socket = %lx\n", cartridge->grom_ptr);
|
| 300 | cartridge->grom_size = reslength;
|
| 301 | }
|
| 302 | |
| 303 | socketcont = cartslot_get_socket(cartslot, "rom_socket");
|
| 304 | reslength = cartslot_get_resource_length(cartslot, "rom_socket");
|
| 305 | if (socketcont != NULL)
|
| 306 | {
|
| 307 | cartridge->rom_ptr = (UINT8 *)socketcont;
|
| 308 | cartridge->rom_size = reslength;
|
| 309 | // printf("set rom ptr = %lx, romlength = %04x, data = %02x %02x\n", cartridge->rom_ptr, cartridge->rom_size, cartridge->rom_ptr[0], cartridge->rom_ptr[1]);
|
| 310 | }
|
| 311 | |
| 312 | socketcont = cartslot_get_socket(cartslot, "rom2_socket");
|
| 313 | // reslength = cartslot_get_resource_length(cartslot, "rom2_socket"); /* cannot differ from rom_socket */
|
| 314 | if (socketcont != NULL)
|
| 315 | {
|
| 316 | cartridge->rom2_ptr = (UINT8 *)socketcont;
|
| 317 | }
|
| 318 | |
| 319 | socketcont = cartslot_get_socket(cartslot, "ram_socket");
|
| 320 | reslength = cartslot_get_resource_length(cartslot, "ram_socket");
|
| 321 | if (socketcont != NULL)
|
| 322 | {
|
| 323 | cartridge->ram_ptr = (UINT8 *)socketcont;
|
| 324 | cartridge->ram_size = reslength;
|
| 325 | }
|
| 326 | |
| 327 | // Register the GROMs
|
| 328 | pcb_def = (ti99_pcb_t *)downcast<legacy_device_base *>(pcb)->token();
|
| 329 | for (int i=0; i < 5; i++) pcb_def->grom[i]= NULL;
|
| 330 | if (cartridge->grom_size > 0) pcb_def->grom[0] = pcb->subdevice("grom_3");
|
| 331 | if (cartridge->grom_size > 0x2000) pcb_def->grom[1] = pcb->subdevice("grom_4");
|
| 332 | if (cartridge->grom_size > 0x4000) pcb_def->grom[2] = pcb->subdevice("grom_5");
|
| 333 | if (cartridge->grom_size > 0x6000) pcb_def->grom[3] = pcb->subdevice("grom_6");
|
| 334 | if (cartridge->grom_size > 0x8000) pcb_def->grom[4] = pcb->subdevice("grom_7");
|
| 335 |
|
| 336 | return cartridge;
|
| 337 | }
|
| 338 | |
| 339 | static void set_pointers(running_device *pcb, int index)
|
| 340 | {
|
| 341 | running_device *cartsys = pcb->owner()->owner();
|
| 342 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 343 | ti99_pcb_t *pcb_def = (ti99_pcb_t *)downcast<legacy_device_base *>(pcb)->token();
|
| 344 | |
| 345 | pcb_def->read = (read8z_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_6000_R);
|
| 346 | pcb_def->write = (write8_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_6000_W);
|
| 347 | pcb_def->cruread = (read8z_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_CRU_R);
|
| 348 | pcb_def->cruwrite = (write8_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_CRU_W);
|
| 349 | |
| 350 | pcb_def->assemble = (assmfct *)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CART_FCT_ASSM);
|
| 351 | pcb_def->disassemble = (assmfct *)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CART_FCT_DISASSM);
|
| 352 | |
| 353 | pcb_def->cartridge = &cartslots->cartridge[index];
|
| 354 | pcb_def->cartridge->pcb = pcb;
|
| 355 | }
|
| 356 | |
| 357 | /*****************************************************************************
|
| 358 | Cartridge type: None
|
| 359 | This PCB device is just a pseudo device; the legacy mode is handled
|
| 360 | by dedicated functions.
|
| 361 | ******************************************************************************/
|
| 362 | static DEVICE_START(ti99_pcb_none)
|
| 363 | {
|
| 364 | /* device is ti99_cartslot:cartridge:pcb */
|
| 365 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 366 | }
|
| 367 | |
| 368 | /*****************************************************************************
|
| 369 | Cartridge type: Standard
|
| 370 | Most cartridges are built in this type. Every cartridge may contain
|
| 371 | GROM between 0 and 40 KiB, and ROM with 8 KiB length, no banking.
|
| 372 | ******************************************************************************/
|
| 373 | |
| 374 | static DEVICE_START(ti99_pcb_std)
|
| 375 | {
|
| 376 | /* device is ti99_cartslot:cartridge:pcb */
|
| 377 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 378 | }
|
| 379 | |
| 380 | /*
|
| 381 | Read handler for the CPU address space of the cartridge
|
| 382 | Images for this area are found in the rom_sockets.
|
| 383 | */
|
| 384 | static READ8Z_DEVICE_HANDLER( read_cart_std )
|
| 385 | {
|
| 386 | /* device is pcb, owner is cartslot (cartridge is only a part of the state of cartslot) */
|
| 387 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 388 | cartridge_t *cartridge = pcb->cartridge;
|
| 389 | if (cartridge->rom_ptr!=NULL)
|
| 390 | {
|
| 391 | // For TI-99/8 we should plan for 16K cartridges. However, none was produced. Well, just ignore this thought,
|
| 392 | *value = (cartridge->rom_ptr)[offset & 0x1fff]; |
| 393 | // printf("read cartridge rom space (length %04x) %04x = %02x\n", cartridge->rom_size, offset, *value);
|
| 394 | }
|
| 395 | }
|
| 396 | |
| 397 | static WRITE8_DEVICE_HANDLER( write_cart_std )
|
| 398 | {
|
| 399 | logerror("Write access to cartridge ROM at address %04x ignored\n", offset);
|
| 400 | }
|
| 401 | |
| 402 | /*
|
| 403 | The standard cartridge assemble routine. We just call the common
|
| 404 | function here.
|
| 405 | */
|
| 406 | static int assemble_std(running_device *image)
|
| 407 | {
|
| 408 | assemble_common(image);
|
| 409 | return IMAGE_INIT_PASS;
|
| 410 | }
|
| 411 | |
| 412 | /*
|
| 413 | Removes pointers and restores the state before plugging in the
|
| 414 | cartridge.
|
| 415 | The pointer to the location after the last cartridge is adjusted.
|
| 416 | As it seems, we can use the same function for the disassembling of all
|
| 417 | cartridge types.
|
| 418 | */
|
| 419 | static int disassemble_std(running_device *image)
|
| 420 | {
|
| 421 | int slotnumber;
|
| 422 | int i;
|
| 423 | // cartridge_t *cart;
|
| 424 | running_device *cartsys = image->owner();
|
| 425 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 426 | |
| 427 | slotnumber = get_index_from_tagname(image)-1;
|
| 428 | |
| 429 | /* Search the highest remaining cartridge. */
|
| 430 | cartslots->next_free_slot = 0;
|
| 431 | for (i=NUMBER_OF_CARTRIDGE_SLOTS-1; i >= 0; i--)
|
| 432 | {
|
| 433 | if (i != slotnumber)
|
| 434 | {
|
| 435 | if (!slot_is_empty(cartsys, i))
|
| 436 | {
|
| 437 | cartslots->next_free_slot = i+1;
|
| 438 | break;
|
| 439 | }
|
| 440 | }
|
| 441 | }
|
| 442 | |
| 443 | clear_slot(cartsys, slotnumber);
|
| 444 | |
| 445 | return IMAGE_INIT_PASS;
|
| 446 | }
|
| 447 | |
| 448 | /*****************************************************************************
|
| 449 | Cartridge type: Paged (Extended Basic)
|
| 450 | This cartridge consists of GROM memory and 2 pages of standard ROM.
|
| 451 | The page is set by writing any value to a location in
|
| 452 | the address area, where an even word offset sets the page to 0 and an
|
| 453 | odd word offset sets the page to 1 (e.g. 6000 = bank 0, and
|
| 454 | 6002 = bank 1).
|
| 455 | ******************************************************************************/
|
| 456 | |
| 457 | static DEVICE_START(ti99_pcb_paged)
|
| 458 | {
|
| 459 | /* device is ti99_cartslot:cartridge:pcb */
|
| 460 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 461 | }
|
| 462 | |
| 463 | /*
|
| 464 | Read handler for the CPU address space of the cartridge
|
| 465 | Images for this area are found in the rom_sockets.
|
| 466 | */
|
| 467 | static READ8Z_DEVICE_HANDLER( read_cart_paged )
|
| 468 | {
|
| 469 | /* device is pcb, owner is cartslot */
|
| 470 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 471 | cartridge_t *cartridge = pcb->cartridge;
|
| 472 | UINT8 *rombank;
|
| 473 | |
| 474 | if (cartridge->rom_page==0)
|
| 475 | rombank = (UINT8*)cartridge->rom_ptr;
|
| 476 | else
|
| 477 | rombank = (UINT8*)cartridge->rom2_ptr;
|
| 478 | |
| 479 | if (rombank==NULL)
|
| 480 | {
|
| 481 | /* TODO: Check for consistency with the GROM memory handling. */
|
| 482 | *value = 0;
|
| 483 | }
|
| 484 | else
|
| 485 | {
|
| 486 | *value = rombank[offset & 0x1fff];
|
| 487 | }
|
| 488 | }
|
| 489 | |
| 490 | /*
|
| 491 | Handle paging. Extended Basic switches between ROM banks by
|
| 492 | using the value of the LSB of the address where any value
|
| 493 | is written to.
|
| 494 | */
|
| 495 | static WRITE8_DEVICE_HANDLER( write_cart_paged )
|
| 496 | {
|
| 497 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 498 | cartridge_t *cartridge = pcb->cartridge;
|
| 499 | cartridge->rom_page = (offset >> 1) & 1;
|
| 500 | }
|
| 501 | |
| 502 | /*
|
| 503 | We require paged modules to have at least those two rom banks.
|
| 504 | */
|
| 505 | static int assemble_paged(running_device *image)
|
| 506 | {
|
| 507 | cartridge_t *cart;
|
| 508 | |
| 509 | cart = assemble_common(image);
|
| 510 | if (cart->rom_ptr==NULL)
|
| 511 | {
|
| 512 | logerror("Missing ROM for paged cartridge");
|
| 513 | return IMAGE_INIT_FAIL;
|
| 514 | }
|
| 515 | if (cart->rom2_ptr==NULL)
|
| 516 | {
|
| 517 | logerror("Missing second ROM for paged cartridge");
|
| 518 | return IMAGE_INIT_FAIL;
|
| 519 | }
|
| 520 | |
| 521 | return IMAGE_INIT_PASS;
|
| 522 | }
|
| 523 | |
| 524 | /*****************************************************************************
|
| 525 | Cartridge type: Mini Memory
|
| 526 | GROM: 6 KiB (occupies G>6000 to G>7800)
|
| 527 | ROM: 4 KiB (romfile is actually 8 K long, second half with zeros, 0x6000-0x6fff)
|
| 528 | persistent RAM: 4 KiB (0x7000-0x7fff)
|
| 529 | ******************************************************************************/
|
| 530 | |
| 531 | static DEVICE_START(ti99_pcb_minimem)
|
| 532 | {
|
| 533 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 534 | }
|
| 535 | |
| 536 | static READ8Z_DEVICE_HANDLER( read_cart_minimem )
|
| 537 | {
|
| 538 | /* device is pcb, owner is cartslot */
|
| 539 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 540 | cartridge_t *cartridge = pcb->cartridge;
|
| 541 | |
| 542 | if ((offset & 0xf000)==0x6000)
|
| 543 | {
|
| 544 | *value = (cartridge->rom_ptr==NULL)? 0 : (cartridge->rom_ptr)[offset & 0x0fff];
|
| 545 | }
|
| 546 | else
|
| 547 | {
|
| 548 | *value = (cartridge->ram_ptr==NULL)? 0 : (cartridge->ram_ptr)[offset & 0x0fff];
|
| 549 | }
|
| 550 | }
|
| 551 | |
| 552 | /*
|
| 553 | Mini Memory cartridge write operation. RAM is located at 0x7000.
|
| 554 | */
|
| 555 | static WRITE8_DEVICE_HANDLER( write_cart_minimem )
|
| 556 | {
|
| 557 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 558 | cartridge_t *cartridge = pcb->cartridge;
|
| 559 | |
| 560 | if (offset < 0x7000)
|
| 561 | {
|
| 562 | logerror("Write access to cartridge ROM at address %04x ignored", offset);
|
| 563 | }
|
| 564 | else
|
| 565 | {
|
| 566 | if (cartridge->ram_ptr==NULL)
|
| 567 | {
|
| 568 | logerror("No cartridge RAM at address %04x", offset);
|
| 569 | /* TODO: Check for consistency with the GROM memory handling. */
|
| 570 | }
|
| 571 | else
|
| 572 | {
|
| 573 | (cartridge->ram_ptr)[offset-0x7000] = data;
|
| 574 | }
|
| 575 | }
|
| 576 | }
|
| 577 | |
| 578 | static int assemble_minimem(running_device *image)
|
| 579 | {
|
| 580 | cartridge_t *cart;
|
| 581 | |
| 582 | cart = assemble_common(image);
|
| 583 | if (cart->grom_size==0)
|
| 584 | {
|
| 585 | logerror("Missing GROM for Mini Memory");
|
| 586 | // should not fail here because there may be variations of
|
| 587 | // cartridges which do not use all parts
|
| 588 | // return IMAGE_INIT_FAIL;
|
| 589 | }
|
| 590 | if (cart->rom_size==0)
|
| 591 | {
|
| 592 | logerror("Missing ROM for Mini Memory");
|
| 593 | // return IMAGE_INIT_FAIL;
|
| 594 | }
|
| 595 | if (cart->ram_size==0)
|
| 596 | {
|
| 597 | logerror("Missing RAM for Mini Memory");
|
| 598 | // return IMAGE_INIT_FAIL;
|
| 599 | }
|
| 600 | |
| 601 | return IMAGE_INIT_PASS;
|
| 602 | }
|
| 603 | |
| 604 | /*****************************************************************************
|
| 605 | Cartridge type: SuperSpace II
|
| 606 | SuperSpace cartridge type. SuperSpace is intended as a user-definable
|
| 607 | blank cartridge containing buffered RAM
|
| 608 | It has an Editor/Assembler GROM which helps the user to load
|
| 609 | the user program into the cartridge. If the user program has a suitable
|
| 610 | header, the console recognizes the cartridge as runnable, and
|
| 611 | assigns a number in the selection screen.
|
| 612 | Switching the RAM banks in this cartridge is achieved by setting
|
| 613 | CRU bits (the system serial interface).
|
| 614 | |
| 615 | GROM: Editor/Assembler GROM
|
| 616 | ROM: none
|
| 617 | persistent RAM: 32 KiB (0x6000-0x7fff, 4 banks)
|
| 618 | Switching the bank is done via CRU write
|
| 619 | ******************************************************************************/
|
| 620 | |
| 621 | static DEVICE_START(ti99_pcb_super)
|
| 622 | {
|
| 623 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 624 | }
|
| 625 | |
| 626 | /*
|
| 627 | The CRU read handler. The CRU is a serial interface in the console.
|
| 628 | Using the CRU we can switch the banks in the SuperSpace cartridge.
|
| 629 | */
|
| 630 | static READ8Z_DEVICE_HANDLER( read_cart_cru )
|
| 631 | {
|
| 632 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 633 | cartridge_t *cartridge = pcb->cartridge;
|
| 634 | // offset is the bit number. The CRU base address is already divided by 2.
|
| 635 | |
| 636 | // ram_page contains the bank number. We have a maximum of
|
| 637 | // 4 banks; the Super Space II manual says:
|
| 638 | //
|
| 639 | // Banks are selected by writing a bit pattern to CRU address >0800:
|
| 640 | //
|
| 641 | // Bank # Value
|
| 642 | // 0 >02 = 0000 0010
|
| 643 | // 1 >08 = 0000 1000
|
| 644 | // 2 >20 = 0010 0000
|
| 645 | // 3 >80 = 1000 0000
|
| 646 | //
|
| 647 | // With the bank number (0, 1, 2, or 3) in R0:
|
| 648 | //
|
| 649 | // BNKSW LI R12,>0800 Set CRU address
|
| 650 | // LI R1,2 Load Shift Bit
|
| 651 | // SLA R0,1 Align Bank Number
|
| 652 | // JEQ BNKS1 Skip shift if Bank 0
|
| 653 | // SLA R1,0 Align Shift Bit
|
| 654 | // BNKS1 LDCR R1,0 Switch Banks
|
| 655 | // SRL R0,1 Restore Bank Number (optional)
|
| 656 | // RT
|
| 657 | printf("Superspace: CRU accessed at %04x\n", offset);
|
| 658 | if ((offset & 1) == 0 || offset > 7)
|
| 659 | *value = 0;
|
| 660 | |
| 661 | // CRU addresses are only 1 bit wide. Bytes are transferred from LSB
|
| 662 | // to MSB. That is, 8 bit are eight consecutive addresses. */
|
| 663 | *value = (cartridge->ram_page == (offset-1)/2);
|
| 664 | }
|
| 665 | |
| 666 | static WRITE8_DEVICE_HANDLER( write_cart_cru )
|
| 667 | {
|
| 668 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 669 | cartridge_t *cartridge = pcb->cartridge;
|
| 670 | // data is bit
|
| 671 | // offset is address
|
| 672 | printf("Superspace: CRU accessed at %04x\n", offset);
|
| 673 | if (offset < 8)
|
| 674 | {
|
| 675 | if (data != 0)
|
| 676 | cartridge->ram_page = (offset-1)/2;
|
| 677 | }
|
| 678 | }
|
| 679 | |
| 680 | /*
|
| 681 | SuperSpace RAM read operation. RAM is located at 0x6000 to 0x7fff
|
| 682 | as 4 banks of 8 KiB each
|
| 683 | */
|
| 684 | static READ8Z_DEVICE_HANDLER( read_cart_super )
|
| 685 | {
|
| 686 | /* device is pcb, owner is cartslot */
|
| 687 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 688 | cartridge_t *cartridge = pcb->cartridge;
|
| 689 | offs_t boffset;
|
| 690 | |
| 691 | if (cartridge->ram_ptr==NULL)
|
| 692 | {
|
| 693 | *value = 0;
|
| 694 | }
|
| 695 | else
|
| 696 | {
|
| 697 | boffset = cartridge->ram_page * 0x2000 + (offset & 0x1fff);
|
| 698 | *value = (cartridge->ram_ptr)[boffset];
|
| 699 | }
|
| 700 | }
|
| 701 | |
| 702 | /*
|
| 703 | SuperSpace RAM write operation. RAM is located at 0x6000 to 0x7fff
|
| 704 | as 4 banks of 8 KiB each
|
| 705 | */
|
| 706 | static WRITE8_DEVICE_HANDLER( write_cart_super )
|
| 707 | {
|
| 708 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 709 | cartridge_t *cartridge = pcb->cartridge;
|
| 710 | offs_t boffset;
|
| 711 | |
| 712 | if (cartridge->ram_ptr==NULL)
|
| 713 | {
|
| 714 | logerror("No cartridge RAM at address %04x", offset);
|
| 715 | }
|
| 716 | else
|
| 717 | {
|
| 718 | boffset = cartridge->ram_page * 0x2000 + (offset & 0x1fff);
|
| 719 | (cartridge->ram_ptr)[boffset] = data;
|
| 720 | }
|
| 721 | }
|
| 722 | |
| 723 | static int assemble_super(running_device *image)
|
| 724 | {
|
| 725 | cartridge_t *cart;
|
| 726 | |
| 727 | cart = assemble_common(image);
|
| 728 | if (cart->ram_size==0)
|
| 729 | {
|
| 730 | logerror("Missing RAM for SuperSpace");
|
| 731 | return IMAGE_INIT_FAIL;
|
| 732 | }
|
| 733 | return IMAGE_INIT_PASS;
|
| 734 | }
|
| 735 | |
| 736 | /*****************************************************************************
|
| 737 | Cartridge type: MBX
|
| 738 | GROM: up to 40 KiB
|
| 739 | ROM: up to 16 KiB (in up to 2 banks of 8KiB each)
|
| 740 | RAM: 1022 B (0x6c00-0x6ffd, overrides ROM in that area)
|
| 741 | ROM mapper: 6ffe
|
| 742 | |
| 743 | Note that some MBX cartridges assume the presence of the MBX system
|
| 744 | (additional console) and will not run without it. The MBX hardware is
|
| 745 | not emulated yet.
|
| 746 | ******************************************************************************/
|
| 747 | |
| 748 | static DEVICE_START(ti99_pcb_mbx)
|
| 749 | {
|
| 750 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 751 | }
|
| 752 | |
| 753 | static READ8Z_DEVICE_HANDLER( read_cart_mbx )
|
| 754 | {
|
| 755 | /* device is pcb, owner is cartslot */
|
| 756 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 757 | cartridge_t *cartridge = pcb->cartridge;
|
| 758 | |
| 759 | if ((offset & 0x1c00)==0x0c00)
|
| 760 | {
|
| 761 | // This is the RAM area which overrides any ROM. There is no
|
| 762 | // known banking behavior for the RAM, so we must assume that
|
| 763 | // there is only one bank.
|
| 764 | if (cartridge->ram_ptr != NULL)
|
| 765 | *value = (cartridge->ram_ptr)[offset & 0x03ff];
|
| 766 | }
|
| 767 | else
|
| 768 | {
|
| 769 | if (cartridge->rom_ptr != NULL)
|
| 770 | *value = (cartridge->rom_ptr)[(offset & 0x1fff)+ cartridge->rom_page*0x2000];
|
| 771 | }
|
| 772 | }
|
| 773 | |
| 774 | /*
|
| 775 | MBX write operation.
|
| 776 | */
|
| 777 | static WRITE8_DEVICE_HANDLER( write_cart_mbx )
|
| 778 | {
|
| 779 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 780 | cartridge_t *cartridge = pcb->cartridge;
|
| 781 | |
| 782 | if (offset == 0x6ffe)
|
| 783 | {
|
| 784 | cartridge->rom_page = data & 1;
|
| 785 | return;
|
| 786 | }
|
| 787 | |
| 788 | if ((offset & 0x1c00)==0x0c00)
|
| 789 | {
|
| 790 | if (cartridge->ram_ptr == NULL) return;
|
| 791 | cartridge->ram_ptr[offset - 0x6c00] = data;
|
| 792 | }
|
| 793 | }
|
| 794 | |
| 795 | |
| 796 | static int assemble_mbx(running_device *image)
|
| 797 | {
|
| 798 | assemble_common(image);
|
| 799 | return IMAGE_INIT_PASS;
|
| 800 | }
|
| 801 | |
| 802 | /*****************************************************************************
|
| 803 | Cartridge type: paged379i
|
| 804 | This cartridge consists of one 16 KiB, 32 KiB, 64 KiB, or 128 KiB EEPROM
|
| 805 | which is organised in 2, 4, 8, or 16 pages of 8 KiB each. The complete
|
| 806 | memory contents must be stored in one dump file.
|
| 807 | The pages are selected by writing a value to some memory locations. Due to
|
| 808 | using the inverted outputs of the LS379 latch, setting the inputs of the
|
| 809 | latch to all 0 selects the highest bank, while setting to all 1 selects the
|
| 810 | lowest. There are some cartridges (16 KiB) which are using this scheme, and
|
| 811 | there are new hardware developments mainly relying on this scheme.
|
| 812 | |
| 813 | Writing to selects page (16K/32K/64K/128K)
|
| 814 | >6000 1 / 3 / 7 / 15
|
| 815 | >6002 0 / 2 / 6 / 14
|
| 816 | >6004 1 / 1 / 5 / 13
|
| 817 | >6006 0 / 0 / 4 / 12
|
| 818 | >6008 1 / 3 / 3 / 11
|
| 819 | >600A 0 / 2 / 2 / 10
|
| 820 | >600C 1 / 1 / 1 / 9
|
| 821 | >600E 0 / 0 / 0 / 8
|
| 822 | >6010 1 / 3 / 7 / 7
|
| 823 | >6012 0 / 2 / 6 / 6
|
| 824 | >6014 1 / 1 / 5 / 5
|
| 825 | >6016 0 / 0 / 4 / 4
|
| 826 | >6018 1 / 3 / 3 / 3
|
| 827 | >601A 0 / 2 / 2 / 2
|
| 828 | >601C 1 / 1 / 1 / 1
|
| 829 | >601E 0 / 0 / 0 / 0
|
| 830 | |
| 831 | ******************************************************************************/
|
| 832 | |
| 833 | static DEVICE_START(ti99_pcb_paged379i)
|
| 834 | {
|
| 835 | /* device is ti99_cartslot:cartridge:pcb */
|
| 836 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 837 | }
|
| 838 | |
| 839 | /*
|
| 840 | Read handler for the CPU address space of the cartridge
|
| 841 | Images for this area are found in the rom_sockets.
|
| 842 | */
|
| 843 | static READ8Z_DEVICE_HANDLER( read_cart_paged379i )
|
| 844 | {
|
| 845 | /* device is pcb, owner is cartslot */
|
| 846 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 847 | cartridge_t *cartridge = pcb->cartridge;
|
| 848 | |
| 849 | if (cartridge->rom_ptr!=NULL)
|
| 850 | {
|
| 851 | *value = (cartridge->rom_ptr)[cartridge->rom_page*0x2000 + (offset & 0x1fff)];
|
| 852 | }
|
| 853 | }
|
| 854 | |
| 855 | /*
|
| 856 | Determines which bank to set, depending on the size of the ROM. This is
|
| 857 | some magic code that actually represents different PCB versions.
|
| 858 | */
|
| 859 | static void set_paged379i_bank(cartridge_t *cartridge, int rompage)
|
| 860 | {
|
| 861 | int mask = 0;
|
| 862 | if (cartridge->rom_size > 16384)
|
| 863 | {
|
| 864 | if (cartridge->rom_size > 32768)
|
| 865 | {
|
| 866 | if (cartridge->rom_size > 65536)
|
| 867 | mask = 15;
|
| 868 | else
|
| 869 | mask = 7;
|
| 870 | }
|
| 871 | else
|
| 872 | mask = 3;
|
| 873 | }
|
| 874 | else
|
| 875 | mask = 1;
|
| 876 | |
| 877 | cartridge->rom_page = rompage & mask;
|
| 878 | }
|
| 879 | |
| 880 | /*
|
| 881 | Handle paging. We use a LS379 latch for storing the page number. On this
|
| 882 | PCB, the inverted output of the latch is used, so the order of pages
|
| 883 | is reversed. (No problem as long as the memory dump is kept exactly
|
| 884 | in the way it is stored in the EPROM.)
|
| 885 | The latch can store a value of 4 bits. We adjust the number of
|
| 886 | significant bits by the size of the memory dump (16K, 32K, 64K).
|
| 887 | */
|
| 888 | static WRITE8_DEVICE_HANDLER( write_cart_paged379i )
|
| 889 | {
|
| 890 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 891 | cartridge_t *cartridge = pcb->cartridge;
|
| 892 | |
| 893 | // Bits: 011x xxxx xxxb bbbx
|
| 894 | // x = don't care, bbbb = bank
|
| 895 | set_paged379i_bank(cartridge, 15 - ((offset>>1) & 15));
|
| 896 | }
|
| 897 | |
| 898 | /*
|
| 899 | Paged379i modules have one EPROM dump.
|
| 900 | */
|
| 901 | static int assemble_paged379i(running_device *image)
|
| 902 | {
|
| 903 | cartridge_t *cart;
|
| 904 | |
| 905 | cart = assemble_common(image);
|
| 906 | if (cart->rom_ptr==NULL)
|
| 907 | {
|
| 908 | logerror("Missing ROM for paged cartridge");
|
| 909 | return IMAGE_INIT_FAIL;
|
| 910 | }
|
| 911 | set_paged379i_bank(cart, 15);
|
| 912 | return IMAGE_INIT_PASS;
|
| 913 | }
|
| 914 | |
| 915 | /*****************************************************************************
|
| 916 | Cartridge type: pagedcru
|
| 917 | This cartridge consists of one 16 KiB, 32 KiB, or 64 KiB EEPROM which is
|
| 918 | organised in 2, 4, or 8 pages of 8 KiB each. We assume there is only one
|
| 919 | dump file of the respective size.
|
| 920 | The pages are selected by writing a value to the CRU. This scheme is
|
| 921 | similar to the one used for the SuperSpace cartridge, with the exception
|
| 922 | that we are using ROM only, and we can have up to 8 pages.
|
| 923 | |
| 924 | Bank Value written to CRU>0800
|
| 925 | 0 >0002 = 0000 0000 0000 0010
|
| 926 | 1 >0008 = 0000 0000 0000 1000
|
| 927 | 2 >0020 = 0000 0000 0010 0000
|
| 928 | 3 >0080 = 0000 0000 1000 0000
|
| 929 | 4 >0200 = 0000 0010 0000 0000
|
| 930 | 5 >0800 = 0000 1000 0000 0000
|
| 931 | 6 >2000 = 0010 0000 0000 0000
|
| 932 | 7 >8000 = 1000 0000 0000 0000
|
| 933 | |
| 934 | ******************************************************************************/
|
| 935 | |
| 936 | static DEVICE_START(ti99_pcb_pagedcru)
|
| 937 | {
|
| 938 | /* device is ti99_cartslot:cartridge:pcb */
|
| 939 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 940 | }
|
| 941 | |
| 942 | /*
|
| 943 | Read handler for the CPU address space of the cartridge
|
| 944 | Images for this area are found in the rom_sockets.
|
| 945 | */
|
| 946 | static READ8Z_DEVICE_HANDLER( read_cart_pagedcru )
|
| 947 | {
|
| 948 | /* device is pcb, owner is cartslot */
|
| 949 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 950 | cartridge_t *cartridge = pcb->cartridge;
|
| 951 | |
| 952 | if (cartridge->rom_ptr!=NULL)
|
| 953 | {
|
| 954 | *value = (cartridge->rom_ptr)[cartridge->rom_page*0x2000 + (offset & 0x1fff)];
|
| 955 | }
|
| 956 | }
|
| 957 | |
| 958 | /*
|
| 959 | This type of cartridge does not support writing to the EPROM address
|
| 960 | space.
|
| 961 | */
|
| 962 | static WRITE8_DEVICE_HANDLER( write_cart_pagedcru )
|
| 963 | {
|
| 964 | return;
|
| 965 | }
|
| 966 | |
| 967 | /*
|
| 968 | The CRU read handler. The CRU is a serial interface in the console.
|
| 969 | Using the CRU we can switch the banks in the SuperSpace cartridge.
|
| 970 | For documentation see the corresponding cru function above. Note we are
|
| 971 | using rom_page here.
|
| 972 | */
|
| 973 | static READ8Z_DEVICE_HANDLER( read_cart_cru_paged )
|
| 974 | {
|
| 975 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 976 | cartridge_t *cartridge = pcb->cartridge;
|
| 977 | |
| 978 | int page = cartridge->rom_page;
|
| 979 | if ((offset & 0xf800)==0x0800)
|
| 980 | {
|
| 981 | int bit = (offset & 0x001e)/2;
|
| 982 | if (bit != 0)
|
| 983 | {
|
| 984 | page = page-(bit/2); // 4 page flags per 8 bits
|
| 985 | } |
| 986 | *value = 1 << (page*2+1);
|
| 987 | }
|
| 988 | }
|
| 989 | |
| 990 | static WRITE8_DEVICE_HANDLER( write_cart_cru_paged )
|
| 991 | {
|
| 992 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 993 | cartridge_t *cartridge = pcb->cartridge;
|
| 994 | |
| 995 | if ((offset & 0xf800)==0x0800)
|
| 996 | {
|
| 997 | int bit = (offset & 0x001e)/2;
|
| 998 | if (data != 0 && bit > 0)
|
| 999 | {
|
| 1000 | cartridge->rom_page = (bit-1)/2;
|
| 1001 | }
|
| 1002 | }
|
| 1003 | }
|
| 1004 | |
| 1005 | /*
|
| 1006 | Pagedcru modules have one EPROM dump.
|
| 1007 | */
|
| 1008 | static int assemble_pagedcru(running_device *image)
|
| 1009 | {
|
| 1010 | cartridge_t *cart;
|
| 1011 | |
| 1012 | cart = assemble_common(image);
|
| 1013 | if (cart->rom_ptr==NULL)
|
| 1014 | {
|
| 1015 | logerror("Missing ROM for pagedcru cartridge");
|
| 1016 | return IMAGE_INIT_FAIL;
|
| 1017 | }
|
| 1018 | cart->rom_page = 0;
|
| 1019 | return IMAGE_INIT_PASS;
|
| 1020 | }
|
| 1021 | |
| 1022 | /*****************************************************************************
|
| 1023 | Cartridge type: gramkracker
|
| 1024 | ******************************************************************************/
|
| 1025 | |
| 1026 | static DEVICE_START(ti99_pcb_gramkracker)
|
| 1027 | {
|
| 1028 | /* device is ti99_cartslot:cartridge:pcb */
|
| 1029 | // printf("DEVICE_START(ti99_pcb_pagedcru), tag of device=%s\n", device->tag());
|
| 1030 | set_pointers(device, get_index_from_tagname(device->owner())-1);
|
| 1031 | }
|
| 1032 | |
| 1033 | /*
|
| 1034 | The GRAM Kracker contains one GROM and several buffered RAM chips
|
| 1035 | */
|
| 1036 | static int assemble_gramkracker(running_device *image)
|
| 1037 | {
|
| 1038 | cartridge_t *cart;
|
| 1039 | int id,i;
|
| 1040 | |
| 1041 | running_device *cartsys = image->owner();
|
| 1042 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 1043 | |
| 1044 | cart = assemble_common(image);
|
| 1045 | |
| 1046 | if (cart->grom_ptr==NULL)
|
| 1047 | {
|
| 1048 | logerror("Missing loader GROM for GRAM Kracker system");
|
| 1049 | return IMAGE_INIT_FAIL;
|
| 1050 | }
|
| 1051 | |
| 1052 | if (cart->ram_size < 81920)
|
| 1053 | {
|
| 1054 | logerror("Missing or insufficient RAM for GRAM Kracker system");
|
| 1055 | return IMAGE_INIT_FAIL;
|
| 1056 | }
|
| 1057 | |
| 1058 | // Get slot number
|
| 1059 | id = get_index_from_tagname(image);
|
| 1060 | cartslots->gk_slot = id-1;
|
| 1061 | cartslots->gk_guest_slot = -1;
|
| 1062 | // The first cartridge that is still plugged in is the "guest" of the
|
| 1063 | // GRAM Kracker
|
| 1064 | for (i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
| 1065 | {
|
| 1066 | if (!slot_is_empty(cartsys, i) && (i != cartslots->gk_slot))
|
| 1067 | {
|
| 1068 | cartslots->gk_guest_slot = i;
|
| 1069 | break;
|
| 1070 | }
|
| 1071 | }
|
| 1072 | return IMAGE_INIT_PASS;
|
| 1073 | }
|
| 1074 | |
| 1075 | /*
|
| 1076 | Unplugs the GRAM Kracker. The "guest" is still plugged in, but will be
|
| 1077 | treated as normal.
|
| 1078 | */
|
| 1079 | static int disassemble_gramkracker(running_device *cartslot)
|
| 1080 | {
|
| 1081 | running_device *cartsys = cartslot->owner();
|
| 1082 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 1083 | |
| 1084 | //int slotnumber = get_index_from_tagname(cartslot)-1;
|
| 1085 | //assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS);
|
| 1086 | |
| 1087 | cartslots->gk_slot = -1;
|
| 1088 | cartslots->gk_guest_slot = -1;
|
| 1089 | |
| 1090 | return disassemble_std(cartslot);
|
| 1091 | }
|
| 1092 | |
| 1093 | |
| 1094 | /*****************************************************************************
|
| 1095 | Device metadata
|
| 1096 | ******************************************************************************/
|
| 1097 | |
| 1098 | /*
|
| 1099 | Get the pointer to the GROM data from the cartridge. Called by the GROM.
|
| 1100 | */
|
| 1101 | static UINT8 *get_grom_ptr(running_device *device)
|
| 1102 | {
|
| 1103 | ti99_pcb_t *pcb = get_safe_pcb_token(device);
|
| 1104 | return pcb->cartridge->grom_ptr;
|
| 1105 | }
|
| 1106 | |
| 1107 | static MACHINE_CONFIG_FRAGMENT(ti99_cart_common)
|
| 1108 | MDRV_GROM_ADD_P( "grom_3", 3, get_grom_ptr, 0x0000, 0x1800, cart_grom_ready )
|
| 1109 | MDRV_GROM_ADD_P( "grom_4", 4, get_grom_ptr, 0x2000, 0x1800, cart_grom_ready )
|
| 1110 | MDRV_GROM_ADD_P( "grom_5", 5, get_grom_ptr, 0x4000, 0x1800, cart_grom_ready )
|
| 1111 | MDRV_GROM_ADD_P( "grom_6", 6, get_grom_ptr, 0x6000, 0x1800, cart_grom_ready )
|
| 1112 | MDRV_GROM_ADD_P( "grom_7", 7, get_grom_ptr, 0x8000, 0x1800, cart_grom_ready )
|
| 1113 | MACHINE_CONFIG_END
|
| 1114 | |
| 1115 | static DEVICE_GET_INFO(ti99_cart_common)
|
| 1116 | {
|
| 1117 | switch(state)
|
| 1118 | {
|
| 1119 | /* --- the following bits of info are returned as 64-bit signed integers --- */
|
| 1120 | case DEVINFO_INT_TOKEN_BYTES:
|
| 1121 | info->i = sizeof(ti99_pcb_t);
|
| 1122 | break;
|
| 1123 | case DEVINFO_INT_INLINE_CONFIG_BYTES:
|
| 1124 | info->i = 0;
|
| 1125 | break;
|
| 1126 |
|
| 1127 | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1128 | info->machine_config = MACHINE_CONFIG_NAME(ti99_cart_common);
|
| 1129 | break;
|
| 1130 | |
| 1131 | /* --- the following bits of info are returned as pointers to functions --- */
|
| 1132 | case DEVINFO_FCT_START:
|
| 1133 | info->start = DEVICE_START_NAME(ti99_pcb_std);
|
| 1134 | break;
|
| 1135 | case DEVINFO_FCT_STOP:
|
| 1136 | /* Nothing */
|
| 1137 | break;
|
| 1138 | case DEVINFO_FCT_RESET:
|
| 1139 | /* Nothing */
|
| 1140 | break;
|
| 1141 | case TI99CARTINFO_FCT_6000_R:
|
| 1142 | info->f = (genf *) read_cart_std; break;
|
| 1143 | |
| 1144 | case TI99CARTINFO_FCT_6000_W:
|
| 1145 | info->f = (genf *) write_cart_std; break;
|
| 1146 | |
| 1147 | case TI99CARTINFO_FCT_CRU_R:
|
| 1148 | /* Nothing */
|
| 1149 | break;
|
| 1150 | |
| 1151 | case TI99CARTINFO_FCT_CRU_W:
|
| 1152 | /* Nothing */
|
| 1153 | break;
|
| 1154 | |
| 1155 | case TI99CART_FCT_ASSM:
|
| 1156 | info->f = (genf *) assemble_std;
|
| 1157 | break;
|
| 1158 | |
| 1159 | case TI99CART_FCT_DISASSM:
|
| 1160 | info->f = (genf *) disassemble_std;
|
| 1161 | break;
|
| 1162 | |
| 1163 | /* --- the following bits of info are returned as NULL-terminated strings --- */
|
| 1164 | case DEVINFO_STR_NAME:
|
| 1165 | strcpy(info->s, "TI99 standard cartridge pcb");
|
| 1166 | break;
|
| 1167 | case DEVINFO_STR_FAMILY:
|
| 1168 | strcpy(info->s, "TI99 cartridge pcb");
|
| 1169 | break;
|
| 1170 | case DEVINFO_STR_VERSION:
|
| 1171 | strcpy(info->s, "1.0");
|
| 1172 | break;
|
| 1173 | case DEVINFO_STR_SOURCE_FILE:
|
| 1174 | strcpy(info->s, __FILE__);
|
| 1175 | break;
|
| 1176 | case DEVINFO_STR_CREDITS:
|
| 1177 | /* Nothing */
|
| 1178 | break;
|
| 1179 | }
|
| 1180 | }
|
| 1181 | |
| 1182 | DEVICE_GET_INFO(ti99_cartridge_pcb_none)
|
| 1183 | {
|
| 1184 | switch(state)
|
| 1185 | {
|
| 1186 | case DEVINFO_FCT_START:
|
| 1187 | info->start = DEVICE_START_NAME(ti99_pcb_none);
|
| 1188 | break;
|
| 1189 | |
| 1190 | case DEVINFO_STR_NAME:
|
| 1191 | strcpy(info->s, "TI99 empty cartridge");
|
| 1192 | break;
|
| 1193 | |
| 1194 | // Don't create GROMs |
| 1195 | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1196 | break;
|
| 1197 |
|
| 1198 | default:
|
| 1199 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1200 | break;
|
| 1201 | }
|
| 1202 | }
|
| 1203 | |
| 1204 | DEVICE_GET_INFO(ti99_cartridge_pcb_std)
|
| 1205 | {
|
| 1206 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1207 | }
|
| 1208 | |
| 1209 | DEVICE_GET_INFO(ti99_cartridge_pcb_paged)
|
| 1210 | {
|
| 1211 | switch(state)
|
| 1212 | {
|
| 1213 | case DEVINFO_FCT_START:
|
| 1214 | info->start = DEVICE_START_NAME(ti99_pcb_paged);
|
| 1215 | break;
|
| 1216 | |
| 1217 | case TI99CART_FCT_ASSM:
|
| 1218 | info->f = (genf *) assemble_paged; |
| 1219 | break;
|
| 1220 | |
| 1221 | case TI99CARTINFO_FCT_6000_R:
|
| 1222 | info->f = (genf *) read_cart_paged;
|
| 1223 | break;
|
| 1224 | |
| 1225 | case TI99CARTINFO_FCT_6000_W:
|
| 1226 | info->f = (genf *) write_cart_paged;
|
| 1227 | break;
|
| 1228 | |
| 1229 | case DEVINFO_STR_NAME:
|
| 1230 | strcpy(info->s, "TI99 paged cartridge pcb");
|
| 1231 | break;
|
| 1232 | |
| 1233 | default:
|
| 1234 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1235 | break;
|
| 1236 | }
|
| 1237 | }
|
| 1238 | |
| 1239 | DEVICE_GET_INFO(ti99_cartridge_pcb_minimem)
|
| 1240 | {
|
| 1241 | switch(state)
|
| 1242 | {
|
| 1243 | case DEVINFO_FCT_START:
|
| 1244 | info->start = DEVICE_START_NAME(ti99_pcb_minimem);
|
| 1245 | break;
|
| 1246 | |
| 1247 | case TI99CART_FCT_ASSM:
|
| 1248 | info->f = (genf *) assemble_minimem;
|
| 1249 | break;
|
| 1250 | case TI99CARTINFO_FCT_6000_R:
|
| 1251 | info->f = (genf *) read_cart_minimem;
|
| 1252 | break;
|
| 1253 | case TI99CARTINFO_FCT_6000_W:
|
| 1254 | info->f = (genf *) write_cart_minimem;
|
| 1255 | break;
|
| 1256 |
|
| 1257 | case DEVINFO_STR_NAME:
|
| 1258 | strcpy(info->s, "TI99 MiniMemory cartridge pcb");
|
| 1259 | break;
|
| 1260 | |
| 1261 | default:
|
| 1262 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1263 | break;
|
| 1264 | }
|
| 1265 | }
|
| 1266 | |
| 1267 | DEVICE_GET_INFO(ti99_cartridge_pcb_super)
|
| 1268 | {
|
| 1269 | switch(state)
|
| 1270 | {
|
| 1271 | case DEVINFO_FCT_START:
|
| 1272 | info->start = DEVICE_START_NAME(ti99_pcb_super);
|
| 1273 | break;
|
| 1274 | |
| 1275 | case TI99CART_FCT_ASSM:
|
| 1276 | info->f = (genf *) assemble_super;
|
| 1277 | break;
|
| 1278 | case TI99CARTINFO_FCT_6000_R:
|
| 1279 | info->f = (genf *) read_cart_super;
|
| 1280 | break;
|
| 1281 | case TI99CARTINFO_FCT_6000_W:
|
| 1282 | info->f = (genf *) write_cart_super;
|
| 1283 | break;
|
| 1284 | case TI99CARTINFO_FCT_CRU_R:
|
| 1285 | info->f = (genf *) read_cart_cru;
|
| 1286 | break;
|
| 1287 | case TI99CARTINFO_FCT_CRU_W:
|
| 1288 | info->f = (genf *) write_cart_cru;
|
| 1289 | break;
|
| 1290 | |
| 1291 | // Don't create GROMs |
| 1292 | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1293 | break;
|
| 1294 | |
| 1295 | case DEVINFO_STR_NAME:
|
| 1296 | strcpy(info->s, "TI99 SuperSpace cartridge pcb");
|
| 1297 | break;
|
| 1298 | |
| 1299 | default:
|
| 1300 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1301 | break;
|
| 1302 | }
|
| 1303 | }
|
| 1304 | |
| 1305 | DEVICE_GET_INFO(ti99_cartridge_pcb_mbx)
|
| 1306 | {
|
| 1307 | switch(state)
|
| 1308 | {
|
| 1309 | case DEVINFO_FCT_START:
|
| 1310 | info->start = DEVICE_START_NAME(ti99_pcb_mbx);
|
| 1311 | break;
|
| 1312 | |
| 1313 | case TI99CART_FCT_ASSM:
|
| 1314 | info->f = (genf *) assemble_mbx;
|
| 1315 | break;
|
| 1316 | case TI99CARTINFO_FCT_6000_R:
|
| 1317 | info->f = (genf *) read_cart_mbx;
|
| 1318 | break;
|
| 1319 | case TI99CARTINFO_FCT_6000_W:
|
| 1320 | info->f = (genf *) write_cart_mbx;
|
| 1321 | break;
|
| 1322 | |
| 1323 | case DEVINFO_STR_NAME:
|
| 1324 | strcpy(info->s, "TI99 MBX cartridge pcb");
|
| 1325 | break;
|
| 1326 | |
| 1327 | default:
|
| 1328 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1329 | break;
|
| 1330 | }
|
| 1331 | }
|
| 1332 | |
| 1333 | DEVICE_GET_INFO(ti99_cartridge_pcb_paged379i)
|
| 1334 | {
|
| 1335 | switch(state)
|
| 1336 | {
|
| 1337 | case DEVINFO_FCT_START:
|
| 1338 | info->start = DEVICE_START_NAME(ti99_pcb_paged379i);
|
| 1339 | break;
|
| 1340 | |
| 1341 | case TI99CART_FCT_ASSM:
|
| 1342 | info->f = (genf *) assemble_paged379i; break;
|
| 1343 | |
| 1344 | case TI99CARTINFO_FCT_6000_R:
|
| 1345 | info->f = (genf *) read_cart_paged379i;
|
| 1346 | break;
|
| 1347 | |
| 1348 | case TI99CARTINFO_FCT_6000_W:
|
| 1349 | info->f = (genf *) write_cart_paged379i;
|
| 1350 | break;
|
| 1351 | |
| 1352 | case DEVINFO_STR_NAME:
|
| 1353 | strcpy(info->s, "TI99 paged379i cartridge pcb");
|
| 1354 | break;
|
| 1355 | |
| 1356 | default:
|
| 1357 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1358 | break;
|
| 1359 | }
|
| 1360 | }
|
| 1361 | |
| 1362 | DEVICE_GET_INFO(ti99_cartridge_pcb_pagedcru)
|
| 1363 | {
|
| 1364 | switch(state)
|
| 1365 | {
|
| 1366 | case DEVINFO_FCT_START:
|
| 1367 | info->start = DEVICE_START_NAME(ti99_pcb_pagedcru);
|
| 1368 | break;
|
| 1369 | |
| 1370 | case TI99CART_FCT_ASSM:
|
| 1371 | info->f = (genf *) assemble_pagedcru;
|
| 1372 | break;
|
| 1373 | |
| 1374 | case TI99CARTINFO_FCT_6000_R:
|
| 1375 | info->f = (genf *) read_cart_pagedcru;
|
| 1376 | break;
|
| 1377 | |
| 1378 | case TI99CARTINFO_FCT_6000_W:
|
| 1379 | info->f = (genf *) write_cart_pagedcru;
|
| 1380 | break;
|
| 1381 | |
| 1382 | case TI99CARTINFO_FCT_CRU_R:
|
| 1383 | info->f = (genf *) read_cart_cru_paged;
|
| 1384 | break;
|
| 1385 | case TI99CARTINFO_FCT_CRU_W:
|
| 1386 | info->f = (genf *) write_cart_cru_paged;
|
| 1387 | break;
|
| 1388 | |
| 1389 | case DEVINFO_STR_NAME:
|
| 1390 | strcpy(info->s, "TI99 pagedcru cartridge pcb");
|
| 1391 | break;
|
| 1392 | |
| 1393 | default:
|
| 1394 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1395 | break;
|
| 1396 | }
|
| 1397 | }
|
| 1398 | |
| 1399 | DEVICE_GET_INFO(ti99_cartridge_pcb_gramkracker)
|
| 1400 | {
|
| 1401 | switch(state)
|
| 1402 | {
|
| 1403 | case DEVINFO_FCT_START:
|
| 1404 | info->start = DEVICE_START_NAME(ti99_pcb_gramkracker);
|
| 1405 | break;
|
| 1406 | |
| 1407 | case TI99CART_FCT_ASSM:
|
| 1408 | info->f = (genf *) assemble_gramkracker;
|
| 1409 | break;
|
| 1410 | |
| 1411 | case TI99CART_FCT_DISASSM:
|
| 1412 | info->f = (genf *) disassemble_gramkracker;
|
| 1413 | break;
|
| 1414 | |
| 1415 | case DEVINFO_STR_NAME:
|
| 1416 | strcpy(info->s, "TI99 GRAM Kracker system");
|
| 1417 | break;
|
| 1418 | |
| 1419 | default:
|
| 1420 | DEVICE_GET_INFO_CALL(ti99_cart_common);
|
| 1421 | break;
|
| 1422 | }
|
| 1423 | }
|
| 1424 | |
| 1425 | /*****************************************************************************
|
| 1426 | The cartridge handling of the multi-cartridge system.
|
| 1427 | Every cartridge contains a PCB device. The memory handlers delegate the calls
|
| 1428 | to the respective handlers of the cartridges.
|
| 1429 | ******************************************************************************/
|
| 1430 | /*
|
| 1431 | Initialize a cartridge. Each cartridge contains a PCB device.
|
| 1432 | */
|
| 1433 | static DEVICE_START( ti99_cartridge )
|
| 1434 | {
|
| 1435 | cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(device)->token();
|
| 1436 | |
| 1437 | /* find the PCB device */
|
| 1438 | cart->pcb_device = device->subdevice(TAG_PCB);
|
| 1439 | }
|
| 1440 | |
| 1441 | /*
|
| 1442 | Load the cartridge image files. Apart from reading, we set pointers
|
| 1443 | to the image files so that during runtime we do not need search
|
| 1444 | operations.
|
| 1445 | */
|
| 1446 | static DEVICE_IMAGE_LOAD( ti99_cartridge )
|
| 1447 | {
|
| 1448 | running_device *pcbdev = cartslot_get_pcb(&image.device());
|
| 1449 | // running_device *cartsys = image.device().owner();
|
| 1450 | // ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 1451 | |
| 1452 | int result;
|
| 1453 | |
| 1454 | if (pcbdev != NULL)
|
| 1455 | {
|
| 1456 | /* If we are here, we have a multicart. */
|
| 1457 | ti99_pcb_t *pcb = (ti99_pcb_t *)downcast<legacy_device_base *>(pcbdev)->token();
|
| 1458 | cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(&image.device())->token();
|
| 1459 | |
| 1460 | /* try opening this as a multicart */
|
| 1461 | // This line requires that cartslot_t be included in cartslot.h,
|
| 1462 | // otherwise one cannot make use of multicart handling within such a
|
| 1463 | // custom LOAD function.
|
| 1464 | multicart_open_error me = multicart_open(image.filename(), image.device().machine->gamedrv->name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc);
|
| 1465 | |
| 1466 | // Now that we have loaded the image files, let the PCB put them all
|
| 1467 | // together. This means we put the images in a structure which allows
|
| 1468 | // for a quick access by the memory handlers. Every PCB defines an
|
| 1469 | // own assembly method.
|
| 1470 | if (me == MCERR_NONE)
|
| 1471 | result = pcb->assemble(image);
|
| 1472 | else
|
| 1473 | fatalerror("Error loading multicart: %s", multicart_error_text(me));
|
| 1474 | }
|
| 1475 | else
|
| 1476 | {
|
| 1477 | fatalerror("Error loading multicart: no pcb found.");
|
| 1478 | }
|
| 1479 | return result;
|
| 1480 | }
|
| 1481 | |
| 1482 | /*
|
| 1483 | This is called when the cartridge is unplugged (or the emulator is
|
| 1484 | stopped).
|
| 1485 | */
|
| 1486 | static DEVICE_IMAGE_UNLOAD( ti99_cartridge )
|
| 1487 | {
|
| 1488 | running_device *pcbdev;
|
| 1489 | // ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(image.device().owner())->token();
|
| 1490 | |
| 1491 | if (downcast<legacy_device_base *>(&image.device())->token() == NULL)
|
| 1492 | {
|
| 1493 | // This means something went wrong during the pcb
|
| 1494 | // identification (e.g. one of the cartridge files was not
|
| 1495 | // found). We do not need to (and cannot) unload the cartridge.
|
| 1496 | return;
|
| 1497 | }
|
| 1498 | pcbdev = cartslot_get_pcb(image);
|
| 1499 | |
| 1500 | if (pcbdev != NULL)
|
| 1501 | {
|
| 1502 | ti99_pcb_t *pcb = (ti99_pcb_t *)downcast<legacy_device_base *>(pcbdev)->token();
|
| 1503 | cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(&image.device())->token();
|
| 1504 | |
| 1505 | if (cart->mc != NULL)
|
| 1506 | {
|
| 1507 | /* Remove pointers and de-big-endianize RAM contents. */
|
| 1508 | pcb->disassemble(image);
|
| 1509 | |
| 1510 | // Close the multicart; all RAM resources will be
|
| 1511 | // written to disk
|
| 1512 | multicart_close(cart->mc);
|
| 1513 | cart->mc = NULL;
|
| 1514 | |
| 1515 | }
|
| 1516 | }
|
| 1517 | }
|
| 1518 | |
| 1519 | /*****************************************************************************
|
| 1520 | The overall multi-cartridge slot system. It contains instances of
|
| 1521 | cartridges which contain PCB devices. The memory handlers delegate the calls
|
| 1522 | to the respective handlers of the cartridges.
|
| 1523 | |
| 1524 | Note that the term "multi-cartridge system" and "multicart" are not the same:
|
| 1525 | A "multicart" may contain multiple resources, organized on a PCB. The multi-
|
| 1526 | cart system may thus host multiple multicarts.
|
| 1527 | |
| 1528 | Actually, the name of the device should be changed (however, the device name
|
| 1529 | length is limited)
|
| 1530 | ******************************************************************************/
|
| 1531 | |
| 1532 | static READ8Z_DEVICE_HANDLER( ti99_cart_gk_rz );
|
| 1533 | static WRITE8_DEVICE_HANDLER( ti99_cart_gk_w );
|
| 1534 | static void cartridge_gram_kracker_writeg(running_device *cartsys, int offset, UINT8 data);
|
| 1535 | static void cartridge_gram_kracker_readg(running_device *device, UINT8 *value);
|
| 1536 | static READ8Z_DEVICE_HANDLER( ti99_cart_cru_gk_rz );
|
| 1537 | static WRITE8_DEVICE_HANDLER( ti99_cart_cru_gk_w );
|
| 1538 | |
| 1539 | /*
|
| 1540 | Instantiation of a multicart system for the TI family.
|
| 1541 | */
|
| 1542 | static DEVICE_START(ti99_multicart)
|
| 1543 | {
|
| 1544 | int i;
|
| 1545 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 1546 | const ti99_multicart_config* cartconf = (const ti99_multicart_config*)get_config(device);
|
| 1547 | |
| 1548 | cartslots->active_slot = 0;
|
| 1549 | cartslots->next_free_slot = 0;
|
| 1550 | |
| 1551 | for (i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
| 1552 | {
|
| 1553 | cartslots->cartridge[i].pcb = NULL;
|
| 1554 | clear_slot(device, i);
|
| 1555 | }
|
| 1556 |
|
| 1557 | devcb_write_line ready = DEVCB_LINE(cartconf->ready);
|
| 1558 | |
| 1559 | devcb_resolve_write_line(&cartslots->ready, &ready, device);
|
| 1560 |
|
| 1561 | // The cartslot system is initialized now. The cartridges themselves
|
| 1562 | // need to check whether their parts are available.
|
| 1563 | }
|
| 1564 | |
| 1565 | static DEVICE_STOP(ti99_multicart)
|
| 1566 | {
|
| 1567 | // printf("DEVICE_STOP(ti99_multicart)\n");
|
| 1568 | }
|
| 1569 | |
| 1570 | static DEVICE_RESET(ti99_multicart)
|
| 1571 | {
|
| 1572 | // Consider to propagate RESET to cartridges.
|
| 1573 | // However, schematics do not reveal any pin for resetting a cartridge;
|
| 1574 | // the reset line is an input used when plugging in a cartridge.
|
| 1575 | |
| 1576 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 1577 | int slotnumber = input_port_read(device->machine, "CARTSLOT");
|
| 1578 | cartslots->fixed_slot = slotnumber-1; /* auto = -1 */
|
| 1579 | }
|
| 1580 | |
| 1581 | /*
|
| 1582 | Accesses the ROM regions of the cartridge for reading.
|
| 1583 | */
|
| 1584 | READ8Z_DEVICE_HANDLER( gromportr_rz )
|
| 1585 | {
|
| 1586 | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
|
| 1587 | int slot = cartslots->active_slot;
|
| 1588 | cartridge_t *cart;
|
| 1589 | |
| 1590 | // Handle GRAM Kracker
|
| 1591 | // We could also consider to use a flag, but input_port_read uses
|
| 1592 | // a hashtable, so this should not be too slow
|
| 1593 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
|
| 1594 | {
|
| 1595 | ti99_cart_gk_rz(device, offset, value);
|
| 1596 | return;
|
| 1597 | }
|
| 1598 |
|
| 1599 | /* Sanity check. Higher slots are always empty. */
|
| 1600 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
| 1601 | return;
|
| 1602 | |
| 1603 | // Same as above (GROM read)
|
| 1604 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
|
| 1605 | slot=0;
|
| 1606 | |
| 1607 | cart = &cartslots->cartridge[slot];
|
| 1608 | |
| 1609 | if (!slot_is_empty(device, slot))
|
| 1610 | {
|
| 1611 | // printf("try it on slot %d\n", slot);
|
| 1612 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();
|
| 1613 | (*pcbdef->read)(cart->pcb, offset, value);
|
| 1614 | }
|
| 1615 | }
|
| 1616 | |
| 1617 | /*
|
| 1618 | Accesses the ROM regions of the cartridge for writing.
|
| 1619 | */
|
| 1620 | WRITE8_DEVICE_HANDLER( gromportr_w )
|
| 1621 | {
|
| 1622 | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
|
| 1623 | int slot = cartslots->active_slot;
|
| 1624 | cartridge_t *cart;
|
| 1625 | |
| 1626 | // Handle GRAM Kracker
|
| 1627 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
|
| 1628 | ti99_cart_gk_w(device, offset, data);
|
| 1629 | |
| 1630 | /* Sanity check. Higher slots are always empty. */
|
| 1631 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
| 1632 | return;
|
| 1633 | |
| 1634 | /* Same as above (READ16). */
|
| 1635 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
|
| 1636 | slot=0;
|
| 1637 | |
| 1638 | cart = &cartslots->cartridge[slot];
|
| 1639 | |
| 1640 | if (!slot_is_empty(device, slot))
|
| 1641 | {
|
| 1642 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();
|
| 1643 | (*pcbdef->write)(cart->pcb, offset, data);
|
| 1644 | }
|
| 1645 | }
|
| 1646 | |
| 1647 | /*
|
| 1648 | Set the address pointer value or write to GRAM (if available).
|
| 1649 | */
|
| 1650 | WRITE8_DEVICE_HANDLER(gromportg_w)
|
| 1651 | {
|
| 1652 | int slot;
|
| 1653 | cartridge_t *cartridge;
|
| 1654 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 1655 | |
| 1656 | // Set the cart slot.
|
| 1657 | // 1001 1wbb bbbb bbr0
|
| 1658 | |
| 1659 | cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff));
|
| 1660 | slot = cartslots->active_slot;
|
| 1661 | |
| 1662 | // The selection mechanism of the console checks the different GROM address
|
| 1663 | // bases, and when it finds different data, it concludes that there is |
| 1664 | // indeed a multi-cartridge facility. Empty slots return 0 at all |
| 1665 | // addresses.
|
| 1666 | // Unfortunately, TI's cartridge selection mechanism has an undesirable |
| 1667 | // side-effect which we work around in this implementation.
|
| 1668 | // When we have only one cartridge we would like to get only the option to
|
| 1669 | // select this cartridge and not an option to switch to the next one (which
|
| 1670 | // would immediately cycle back to cartridge 1). However, the console |
| 1671 | // routines always show the switch option when any two slots have different
|
| 1672 | // content, and this is the case with only one cartridge (slot 2 will then
|
| 1673 | // be filled with zeros).
|
| 1674 | // So if next_free_slot==1, we have one cartridge in slot 0.
|
| 1675 | // In that case we trick the OS to believe that the addressed
|
| 1676 | // cartridge appears at all locations which causes it to assume a
|
| 1677 | // standard single cartslot.
|
| 1678 | |
| 1679 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
|
| 1680 | slot=0;
|
| 1681 | |
| 1682 | // Handle the GRAM Kracker
|
| 1683 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
|
| 1684 | {
|
| 1685 | cartridge_gram_kracker_writeg(device, offset, data);
|
| 1686 | return;
|
| 1687 | }
|
| 1688 | |
| 1689 | if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
|
| 1690 | {
|
| 1691 | cartridge = &cartslots->cartridge[slot];
|
| 1692 | // Send the request to all mounted GROMs
|
| 1693 | if (cartridge->pcb!=NULL)
|
| 1694 | {
|
| 1695 | for (int i=0; i < 5; i++)
|
| 1696 | {
|
| 1697 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cartridge->pcb)->token();
|
| 1698 | if (pcbdef->grom[i]!=NULL)
|
| 1699 | ti99grom_w(pcbdef->grom[i], offset, data);
|
| 1700 | }
|
| 1701 | }
|
| 1702 | }
|
| 1703 | }
|
| 1704 | |
| 1705 | /*
|
| 1706 | GROM access. Nota bene: We only react to the request if there is a GROM
|
| 1707 | at the selected bank with the currently selected ID. If not, just do
|
| 1708 | nothing; do not return a value.
|
| 1709 | (We must not return a value since all GROMs are connected in parallel, so
|
| 1710 | returning a 0, for instance, will spoil the processing of other GROMs.)
|
| 1711 | */
|
| 1712 | READ8Z_DEVICE_HANDLER(gromportg_rz)
|
| 1713 | {
|
| 1714 | int slot;
|
| 1715 | cartridge_t *cartridge;
|
| 1716 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 1717 | |
| 1718 | // Set the cart slot. Note that the port must be adjusted for 16-bit
|
| 1719 | // systems, i.e. it should be shifted left by 1.
|
| 1720 | // 1001 1wbb bbbb bbr0
|
| 1721 | |
| 1722 | cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff));
|
| 1723 |
|
| 1724 | // Handle the GRAM Kracker
|
| 1725 | // BTW, the GK does not have a readable address counter, but the console |
| 1726 | // GROMs will keep our addess counter up to date. That is
|
| 1727 | // exactly what happens in the real machine.
|
| 1728 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
|
| 1729 | {
|
| 1730 | if ((offset & 0x0002)==0) cartridge_gram_kracker_readg(device, value);
|
| 1731 | return;
|
| 1732 | }
|
| 1733 | |
| 1734 | slot = cartslots->active_slot;
|
| 1735 |
|
| 1736 | // This fixes a minor issue: The selection mechanism of the console
|
| 1737 | // concludes that there are multiple cartridges plugged in when it
|
| 1738 | // checks the different GROM bases and finds different data. Empty
|
| 1739 | // slots should return 0 at all addresses, but when we have only
|
| 1740 | // one cartridge, this entails that the second cartridge is
|
| 1741 | // different (all zeros), and so we get a meaningless selection
|
| 1742 | // option between cartridge 1 and 1 and 1 ...
|
| 1743 | //
|
| 1744 | // So if next_free_slot==1, we have one cartridge in slot 0.
|
| 1745 | // In that case we trick the OS to believe that the addressed
|
| 1746 | // cartridge appears at all locations which causes it to assume a
|
| 1747 | // standard single cartslot.
|
| 1748 |
|
| 1749 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
|
| 1750 | slot=0;
|
| 1751 |
|
| 1752 | if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
|
| 1753 | {
|
| 1754 | // Select the cartridge which the multicart system is currently pointing at
|
| 1755 | cartridge = &cartslots->cartridge[slot];
|
| 1756 | // Send the request to all mounted GROMs on this PCB
|
| 1757 | if (cartridge->pcb!=NULL)
|
| 1758 | {
|
| 1759 | for (int i=0; i < 5; i++)
|
| 1760 | {
|
| 1761 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cartridge->pcb)->token();
|
| 1762 | if (pcbdef->grom[i]!=NULL)
|
| 1763 | ti99grom_rz(pcbdef->grom[i], offset, value);
|
| 1764 | }
|
| 1765 | }
|
| 1766 | }
|
| 1767 | }
|
| 1768 | |
| 1769 | /*
|
| 1770 | CRU interface to cartridges, used only by SuperSpace and Pagedcru
|
| 1771 | style cartridges.
|
| 1772 | The SuperSpace has a CRU-based memory mapper. It is accessed via the
|
| 1773 | cartridge slot on CRU base >0800.
|
| 1774 | */
|
| 1775 | READ8Z_DEVICE_HANDLER( gromportc_rz )
|
| 1776 | {
|
| 1777 | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
|
| 1778 | cartridge_t *cart;
|
| 1779 | |
| 1780 | int slot = cartslots->active_slot;
|
| 1781 | |
| 1782 | // Handle GRAM Kracker
|
| 1783 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
|
| 1784 | {
|
| 1785 | ti99_cart_cru_gk_rz(device, offset, value);
|
| 1786 | return;
|
| 1787 | }
|
| 1788 |
|
| 1789 | /* Sanity check. Higher slots are always empty. */
|
| 1790 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
| 1791 | return;
|
| 1792 | |
| 1793 | /* Same as above (READ16). */
|
| 1794 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
|
| 1795 | slot=0;
|
| 1796 | |
| 1797 | cart = &cartslots->cartridge[slot];
|
| 1798 | |
| 1799 | if (!slot_is_empty(device, slot))
|
| 1800 | {
|
| 1801 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();;
|
| 1802 | if (pcbdef->cruread != NULL)
|
| 1803 | (*pcbdef->cruread)(cart->pcb, offset, value);
|
| 1804 | }
|
| 1805 | }
|
| 1806 | |
| 1807 | /*
|
| 1808 | Write cartridge mapper CRU interface (SuperSpace, Pagedcru)
|
| 1809 | */
|
| 1810 | WRITE8_DEVICE_HANDLER( gromportc_w )
|
| 1811 | {
|
| 1812 | ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
|
| 1813 | cartridge_t *cart;
|
| 1814 | |
| 1815 | int slot = cartslots->active_slot;
|
| 1816 | |
| 1817 | // Handle GRAM Kracker
|
| 1818 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
|
| 1819 | {
|
| 1820 | ti99_cart_cru_gk_w(device, offset, data);
|
| 1821 | return;
|
| 1822 | }
|
| 1823 |
|
| 1824 | /* Sanity check. Higher slots are always empty. */
|
| 1825 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
| 1826 | return;
|
| 1827 | |
| 1828 | /* Same as above (READ16). */
|
| 1829 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
|
| 1830 | slot=0;
|
| 1831 | |
| 1832 | cart = &cartslots->cartridge[slot];
|
| 1833 | |
| 1834 | if (!slot_is_empty(device, slot))
|
| 1835 | {
|
| 1836 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();;
|
| 1837 | if (pcbdef->cruwrite != NULL)
|
| 1838 | (*pcbdef->cruwrite)(cart->pcb, offset, data);
|
| 1839 | }
|
| 1840 | }
|
| 1841 | |
| 1842 | /*****************************************************************************
|
| 1843 | GramKracker support
|
| 1844 | The 80 KiB of the GK are allocated as follows
|
| 1845 | 00000 - 01fff: GRAM 0
|
| 1846 | 02000 - 03fff: GRAM 1 (alternatively, the loader GROM appears here)
|
| 1847 | 04000 - 05fff: GRAM 2
|
| 1848 | 06000 - 0ffff: GRAM 3-7 (alternatively, the guest GROMs appear here)
|
| 1849 | 10000 - 11fff: RAM 1
|
| 1850 | 12000 - 13fff: RAM 2
|
| 1851 |
|
| 1852 | The GK emulates GROMs, but without a readable address counter. Thus it
|
| 1853 | relies on the console GROMs being still in place (compare with the HSGPL).
|
| 1854 | Also, the GK does not implement a GROM buffer.
|
| 1855 | ******************************************************************************/
|
| 1856 | |
| 1857 | /*
|
| 1858 | Reads from the GRAM space of the GRAM Kracker.
|
| 1859 | */
|
| 1860 | static void cartridge_gram_kracker_readg(running_device *cartsys, UINT8 *value)
|
| 1861 | {
|
| 1862 | // gk_slot is the slot where the GK module is plugged in
|
| 1863 | // gk_guest_slot is the slot where the cartridge is plugged in
|
| 1864 | |
| 1865 | cartridge_t *gromkrackerbox, *gkguestcart;
|
| 1866 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 1867 | |
| 1868 | // Not null, since this is only called when there is really a GK module
|
| 1869 | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
|
| 1870 | |
| 1871 | if ((gromkrackerbox->grom_address & 0xe000) == 0x0000)
|
| 1872 | {
|
| 1873 | // GRAM 0. Only return a value if switch 2 is in GRAM0 position.
|
| 1874 | if (get_gk_switch(cartsys, 2)==GK_GRAM0)
|
| 1875 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
|
| 1876 | }
|
| 1877 |
|
| 1878 | if ((gromkrackerbox->grom_address & 0xe000) == 0x2000)
|
| 1879 | {
|
| 1880 | // If the loader is turned on, return loader contents.
|
| 1881 | if (get_gk_switch(cartsys, 5)==GK_LDON)
|
| 1882 | {
|
| 1883 | // The only ROM contained in the GK box is the loader
|
| 1884 | *value = gromkrackerbox->grom_ptr[gromkrackerbox->grom_address & 0x1fff];
|
| 1885 | }
|
| 1886 | else
|
| 1887 | {
|
| 1888 | // Loader off
|
| 1889 | // GRAM 1. Only return a value if switch 3 is in GRAM12 position.
|
| 1890 | if (get_gk_switch(cartsys, 3)==GK_GRAM12)
|
| 1891 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
|
| 1892 | }
|
| 1893 | }
|
| 1894 | |
| 1895 | if ((gromkrackerbox->grom_address & 0xe000) == 0x4000)
|
| 1896 | {
|
| 1897 | // GRAM 2. Only return a value if switch 3 is in GRAM12 position.
|
| 1898 | if (get_gk_switch(cartsys, 3)==GK_GRAM12)
|
| 1899 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
|
| 1900 | }
|
| 1901 | |
| 1902 | if (((gromkrackerbox->grom_address & 0xe000) == 0x6000) || |
| 1903 | ((gromkrackerbox->grom_address & 0x8000) == 0x8000))
|
| 1904 | {
|
| 1905 | // Cartridge space
|
| 1906 | // When a cartridge is installed, it overrides the GK contents
|
| 1907 | // but only if it has GROMs |
| 1908 | int cartwithgrom = FALSE;
|
| 1909 | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
|
| 1910 | |
| 1911 | // Send the request to all mounted GROMs
|
| 1912 | if (gkguestcart->pcb!=NULL)
|
| 1913 | {
|
| 1914 | for (int i=0; i < 5; i++)
|
| 1915 | {
|
| 1916 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
|
| 1917 | if (pcbdef->grom[i]!=NULL)
|
| 1918 | {
|
| 1919 | ti99grom_rz(pcbdef->grom[i], 0x9800, value);
|
| 1920 | cartwithgrom = TRUE;
|
| 1921 | }
|
| 1922 | }
|
| 1923 | }
|
| 1924 | if (!cartwithgrom && get_gk_switch(cartsys, 1)==GK_NORMAL)
|
| 1925 | {
|
| 1926 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
|
| 1927 | }
|
| 1928 | }
|
| 1929 | |
| 1930 | // The GK GROM emulation does not wrap at 8K boundaries.
|
| 1931 | gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff;
|
| 1932 | |
| 1933 | /* Reset the write address flipflop. */
|
| 1934 | gromkrackerbox->waddr_LSB = FALSE;
|
| 1935 | }
|
| 1936 | |
| 1937 | /*
|
| 1938 | Writes to the GRAM space of the GRAM Kracker.
|
| 1939 | */
|
| 1940 | static void cartridge_gram_kracker_writeg(running_device *cartsys, int offset, UINT8 data)
|
| 1941 | {
|
| 1942 | // gk_slot is the slot where the GK module is plugged in
|
| 1943 | // gk_guest_slot is the slot where the cartridge is plugged in
|
| 1944 | cartridge_t *gromkrackerbox;
|
| 1945 | ti99_multicart_state *cartslots = get_safe_token(cartsys);
|
| 1946 | |
| 1947 | // This is only called when there is really a GK module
|
| 1948 | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
|
| 1949 | |
| 1950 | if ((offset & 0x0002)==0x0002)
|
| 1951 | {
|
| 1952 | // Set address |
| 1953 | if (gromkrackerbox->waddr_LSB)
|
| 1954 | {
|
| 1955 | /* Accept low byte (2nd write) */
|
| 1956 | gromkrackerbox->grom_address = (gromkrackerbox->grom_address & 0xff00) | data;
|
| 1957 | gromkrackerbox->waddr_LSB = FALSE;
|
| 1958 | }
|
| 1959 | else
|
| 1960 | {
|
| 1961 | /* Accept high byte (1st write) */
|
| 1962 | gromkrackerbox->grom_address = ((data<<8) & 0xff00) | (gromkrackerbox->grom_address & 0x00ff);
|
| 1963 | gromkrackerbox->waddr_LSB = TRUE;
|
| 1964 | }
|
| 1965 | }
|
| 1966 | else
|
| 1967 | {
|
| 1968 | if (get_gk_switch(cartsys, 4) != GK_WP)
|
| 1969 | {
|
| 1970 | // Write protection off
|
| 1971 | if ( (((gromkrackerbox->grom_address & 0xe000)==0x0000) && get_gk_switch(cartsys, 2)==GK_GRAM0)
|
| 1972 | || (((gromkrackerbox->grom_address & 0xe000)==0x2000) && get_gk_switch(cartsys, 3)==GK_GRAM12 && (get_gk_switch(cartsys, 5)==GK_LDOFF))
|
| 1973 | || (((gromkrackerbox->grom_address & 0xe000)==0x4000) && get_gk_switch(cartsys, 3)==GK_GRAM12)
|
| 1974 | || (((gromkrackerbox->grom_address & 0xe000)==0x6000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1))
|
| 1975 | || (((gromkrackerbox->grom_address & 0x8000)==0x8000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1))) |
| 1976 | {
|
| 1977 | (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address] = data;
|
| 1978 | }
|
| 1979 | }
|
| 1980 | // The GK GROM emulation does not wrap at 8K boundaries.
|
| 1981 | gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff;
|
| 1982 | |
| 1983 | /* Reset the write address flipflop. */
|
| 1984 | gromkrackerbox->waddr_LSB = FALSE;
|
| 1985 | }
|
| 1986 | }
|
| 1987 | |
| 1988 | /*
|
| 1989 | Reads from the RAM space of the GRAM Kracker.
|
| 1990 | */
|
| 1991 | static READ8Z_DEVICE_HANDLER( ti99_cart_gk_rz )
|
| 1992 | {
|
| 1993 | // gk_slot is the slot where the GK module is plugged in
|
| 1994 | // gk_guest_slot is the slot where the cartridge is plugged in
|
| 1995 | cartridge_t *gromkrackerbox, *gkguestcart;
|
| 1996 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 1997 | |
| 1998 | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
|
| 1999 | |
| 2000 | if (cartslots->gk_guest_slot != -1)
|
| 2001 | {
|
| 2002 | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
|
| 2003 | // Legacy mode is not supported with the GK
|
| 2004 | if (in_legacy_mode(device))
|
| 2005 | {
|
| 2006 | return;
|
| 2007 | }
|
| 2008 | // printf("accessing cartridge in slot %d\n", slot);
|
| 2009 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
|
| 2010 | // printf("address=%lx, offset=%lx\n", pcbdef, offset);
|
| 2011 | (*pcbdef->read)(gkguestcart->pcb, offset, value);
|
| 2012 | return;
|
| 2013 | }
|
| 2014 | else
|
| 2015 | {
|
| 2016 | if (get_gk_switch(device, 1)==GK_OFF) return;
|
| 2017 | if (get_gk_switch(device, 4)==GK_BANK1)
|
| 2018 | {
|
| 2019 | *value = (gromkrackerbox->ram_ptr)[offset+0x10000];
|
| 2020 | }
|
| 2021 | else
|
| 2022 | {
|
| 2023 | if (get_gk_switch(device, 4)==GK_BANK2)
|
| 2024 | {
|
| 2025 | *value = (gromkrackerbox->ram_ptr)[offset+0x12000];
|
| 2026 | }
|
| 2027 | else
|
| 2028 | {
|
| 2029 | // Write protection on; auto-bank
|
| 2030 | if (gromkrackerbox->ram_page==0)
|
| 2031 | {
|
| 2032 | *value = (gromkrackerbox->ram_ptr)[offset+0x10000];
|
| 2033 | }
|
| 2034 | else
|
| 2035 | {
|
| 2036 | *value = (gromkrackerbox->ram_ptr)[offset+0x12000];
|
| 2037 | }
|
| 2038 | }
|
| 2039 | }
|
| 2040 | }
|
| 2041 | }
|
| 2042 | |
| 2043 | /*
|
| 2044 | Writes to the RAM space of the GRAM Kracker.
|
| 2045 | */
|
| 2046 | static WRITE8_DEVICE_HANDLER( ti99_cart_gk_w )
|
| 2047 | {
|
| 2048 | // gk_slot is the slot where the GK module is plugged in
|
| 2049 | // gk_guest_slot is the slot where the cartridge is plugged in
|
| 2050 | cartridge_t *gromkrackerbox, *gkguestcart;
|
| 2051 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 2052 | |
| 2053 | gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
|
| 2054 | |
| 2055 | if (cartslots->gk_guest_slot != -1)
|
| 2056 | {
|
| 2057 | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
|
| 2058 | // Legacy mode is not supported with the GK
|
| 2059 | if (in_legacy_mode(device))
|
| 2060 | {
|
| 2061 | return;
|
| 2062 | }
|
| 2063 | |
| 2064 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
|
| 2065 | (*pcbdef->write)(gkguestcart->pcb, offset, data);
|
| 2066 | }
|
| 2067 | else
|
| 2068 | {
|
| 2069 | if (get_gk_switch(device, 1)==GK_OFF)
|
| 2070 | return;
|
| 2071 | |
| 2072 | if (get_gk_switch(device, 4)==GK_BANK1)
|
| 2073 | {
|
| 2074 | (gromkrackerbox->ram_ptr)[offset + 0x10000] = data;
|
| 2075 | }
|
| 2076 | else
|
| 2077 | {
|
| 2078 | if (get_gk_switch(device, 4)==GK_BANK2)
|
| 2079 | {
|
| 2080 | (gromkrackerbox->ram_ptr)[offset + 0x12000] = data;
|
| 2081 | }
|
| 2082 | else
|
| 2083 | {
|
| 2084 | // Write protection on
|
| 2085 | // This is handled like in Extended Basic
|
| 2086 | gromkrackerbox->ram_page = (offset & 2)>>1;
|
| 2087 | }
|
| 2088 | }
|
| 2089 | }
|
| 2090 | }
|
| 2091 | |
| 2092 | /*
|
| 2093 | Read cartridge mapper CRU interface (Guest in GRAM Kracker)
|
| 2094 | */
|
| 2095 | static READ8Z_DEVICE_HANDLER( ti99_cart_cru_gk_rz )
|
| 2096 | {
|
| 2097 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 2098 | cartridge_t *gkguestcart;
|
| 2099 | |
| 2100 | if (cartslots->gk_guest_slot != -1)
|
| 2101 | {
|
| 2102 | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
|
| 2103 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
|
| 2104 | if (pcbdef->cruread != NULL)
|
| 2105 | (*pcbdef->cruread)(gkguestcart->pcb, offset, value);
|
| 2106 | }
|
| 2107 | }
|
| 2108 | |
| 2109 | /*
|
| 2110 | Write cartridge mapper CRU interface (Guest in GRAM Kracker)
|
| 2111 | */
|
| 2112 | static WRITE8_DEVICE_HANDLER( ti99_cart_cru_gk_w )
|
| 2113 | {
|
| 2114 | ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
|
| 2115 | cartridge_t *gkguestcart;
|
| 2116 | |
| 2117 | if (cartslots->gk_guest_slot != -1)
|
| 2118 | {
|
| 2119 | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
|
| 2120 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
|
| 2121 | if (pcbdef->cruwrite != NULL)
|
| 2122 | (*pcbdef->cruwrite)(gkguestcart->pcb, offset, data);
|
| 2123 | }
|
| 2124 | }
|
| 2125 | |
| 2126 | /*****************************************************************************/
|
| 2127 | #define TI99_CARTRIDGE_SLOT(p) MDRV_CARTSLOT_ADD(p) \
|
| 2128 | MDRV_CARTSLOT_EXTENSION_LIST("rpk,bin") \
|
| 2129 | MDRV_CARTSLOT_PCBTYPE(0, "none", TI99_CARTRIDGE_PCB_NONE) \
|
| 2130 | MDRV_CARTSLOT_PCBTYPE(1, "standard", TI99_CARTRIDGE_PCB_STD) \
|
| 2131 | MDRV_CARTSLOT_PCBTYPE(2, "paged", TI99_CARTRIDGE_PCB_PAGED) \
|
| 2132 | MDRV_CARTSLOT_PCBTYPE(3, "minimem", TI99_CARTRIDGE_PCB_MINIMEM) \
|
| 2133 | MDRV_CARTSLOT_PCBTYPE(4, "super", TI99_CARTRIDGE_PCB_SUPER) \
|
| 2134 | MDRV_CARTSLOT_PCBTYPE(5, "mbx", TI99_CARTRIDGE_PCB_MBX) \
|
| 2135 | MDRV_CARTSLOT_PCBTYPE(6, "paged379i", TI99_CARTRIDGE_PCB_PAGED379I) \
|
| 2136 | MDRV_CARTSLOT_PCBTYPE(7, "pagedcru", TI99_CARTRIDGE_PCB_PAGEDCRU) \
|
| 2137 | MDRV_CARTSLOT_PCBTYPE(8, "gramkracker", TI99_CARTRIDGE_PCB_GRAMKRACKER) \
|
| 2138 | MDRV_CARTSLOT_START(ti99_cartridge) \
|
| 2139 | MDRV_CARTSLOT_LOAD(ti99_cartridge) \
|
| 2140 | MDRV_CARTSLOT_UNLOAD(ti99_cartridge)
|
| 2141 | |
| 2142 | static MACHINE_CONFIG_FRAGMENT(ti99_multicart)
|
| 2143 | TI99_CARTRIDGE_SLOT("cartridge1")
|
| 2144 | TI99_CARTRIDGE_SLOT("cartridge2")
|
| 2145 | TI99_CARTRIDGE_SLOT("cartridge3")
|
| 2146 | TI99_CARTRIDGE_SLOT("cartridge4")
|
| 2147 | MACHINE_CONFIG_END
|
| 2148 | |
| 2149 | static const char DEVTEMPLATE_SOURCE[] = __FILE__;
|
| 2150 | |
| 2151 | #define DEVTEMPLATE_ID(p,s) p##ti99_multicart##s
|
| 2152 | #define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
|
| 2153 | #define DEVTEMPLATE_NAME "TI99 Multi-Cartridge Extender"
|
| 2154 | #define DEVTEMPLATE_FAMILY "Multi-cartridge system"
|
| 2155 | #include "devtempl.h"
|
| 2156 | |
| 2157 | DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_MULTICART, ti99_multicart);
|