src/mess/machine/ti99/grom.c
| r9498 | r9499 | |
| 2 | 2 | |
| 3 | 3 | GROM emulation (aka TMC0430) |
| 4 | 4 | |
| 5 | | This is a preliminary implementation since it does not yet contain |
| 6 | | internal timing; instead, it directly accesses the processor to |
| 5 | This is a preliminary implementation since it does not yet contain |
| 6 | internal timing; instead, it directly accesses the processor to |
| 7 | 7 | simulate wait states |
| 8 | 8 | When this will have become available, the file will be moved to the |
| 9 | 9 | general circuit collection (emu/machine) |
| 10 | | |
| 11 | | +----+--+----+ |
| 12 | | AD7 |1 G 16| Vss |
| 10 | |
| 11 | +----+--+----+ |
| 12 | AD7 |1 G 16| Vss |
| 13 | 13 | AD6 |2 R 15| GR |
| 14 | 14 | AD5 |3 O 14| Vdd |
| 15 | | AD4 |4 M 13| GRC |
| 15 | AD4 |4 M 13| GRC |
| 16 | 16 | AD3 |5 12| M |
| 17 | 17 | AD2 |6 11| MO |
| 18 | 18 | AD1 |7 10| GS* |
| 19 | | AD0 |8 9| Vcc |
| 19 | AD0 |8 9| Vcc |
| 20 | 20 | +------------+ |
| 21 | 21 | |
| 22 | 22 | GR = GROM Ready. Should be connected to processor's READY/HOLD*. |
| r9498 | r9499 | |
| 24 | 24 | M = Direction. 1=read, 0=write |
| 25 | 25 | MO = Mode. 1=address counter access, 0=data access |
| 26 | 26 | GS* = GROM select. 0=select, 1=deselect |
| 27 | | |
| 28 | | Every GROM has an internal ID which represents the high-order three |
| 27 | |
| 28 | Every GROM has an internal ID which represents the high-order three |
| 29 | 29 | address bits. The address counter can be set to any value from 0 |
| 30 | 30 | to 0xffff; the GROM will only react if selected and if the current |
| 31 | 31 | address counter's high-order bits match the ID of the chip. |
| 32 | | Example: When the ID is 6, the GROM will react when the address |
| 32 | Example: When the ID is 6, the GROM will react when the address |
| 33 | 33 | counter contains a value from 0xc000 to 0xdfff. |
| 34 | | |
| 34 | |
| 35 | 35 | Writable GROMs are called GRAMs. Although the TI-99 systems reserve a |
| 36 | | port in the memory space, no one has ever seen a GRAM circuit in the wild. |
| 37 | | However, third-party products like HSGPL or GRAM Kracker simulate GRAMs |
| 38 | | using conventional RAM with some addressing circuitry, usually in a custom |
| 36 | port in the memory space, no one has ever seen a GRAM circuit in the wild. |
| 37 | However, third-party products like HSGPL or GRAM Kracker simulate GRAMs |
| 38 | using conventional RAM with some addressing circuitry, usually in a custom |
| 39 | 39 | chip. |
| 40 | | |
| 40 | |
| 41 | 41 | CHECK: Reading the address increases the counter only once. The first access |
| 42 | 42 | returns the MSB, the second (and all following accesses) return the LSB. |
| 43 | | |
| 43 | |
| 44 | 44 | Michael Zapf, August 2010 |
| 45 | | |
| 45 | |
| 46 | 46 | ***************************************************************************/ |
| 47 | 47 | |
| 48 | 48 | #include "emu.h" |
| r9498 | r9499 | |
| 59 | 59 | |
| 60 | 60 | /* GROM data buffer. */ |
| 61 | 61 | UINT8 buffer; |
| 62 | | |
| 62 | |
| 63 | 63 | /* Internal flip-flop. Used when retrieving the address counter. */ |
| 64 | 64 | UINT8 raddr_LSB; |
| 65 | 65 | |
| 66 | 66 | /* Internal flip-flops. Used when writing the address counter.*/ |
| 67 | 67 | UINT8 waddr_LSB; |
| 68 | | |
| 68 | |
| 69 | 69 | /* ID of this GROM. */ |
| 70 | 70 | UINT8 ident; |
| 71 | | |
| 71 | |
| 72 | 72 | /* Pointer to the memory region contained in this GROM. */ |
| 73 | 73 | UINT8 *memptr; |
| 74 | | |
| 74 | |
| 75 | 75 | /* GROM size. May be 0x1800 or 0x2000. */ |
| 76 | | // If the GROM has only 6 KiB, the remaining 2 KiB are filled with a |
| 76 | // If the GROM has only 6 KiB, the remaining 2 KiB are filled with a |
| 77 | 77 | // specific byte pattern which is created by a logical OR of lower |
| 78 | 78 | // regions |
| 79 | 79 | int extended; |
| 80 | 80 | |
| 81 | | /* Determines whether this is a GRAM. */ |
| 81 | /* Determines whether this is a GRAM. */ |
| 82 | 82 | int writable; |
| 83 | 83 | |
| 84 | | /* Determines whether there is a rollover at the end of the address space. */ |
| 84 | /* Determines whether there is a rollover at the end of the address space. */ |
| 85 | 85 | int rollover; |
| 86 | | |
| 86 | |
| 87 | 87 | /* Ready callback. This line is usually connected to the READY pin of the CPU. */ |
| 88 | 88 | devcb_resolved_write_line gromready; |
| 89 | 89 | }; |
| r9498 | r9499 | |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | /* |
| 107 | | Indicates whether this chip will react on the next read/write data |
| 108 | | access. We do not have a tri-state handling on the read handlers, so this |
| 109 | | serves to avoid the read access. |
| 107 | Indicates whether this chip will react on the next read/write data |
| 108 | access. We do not have a tri-state handling on the read handlers, so this |
| 109 | serves to avoid the read access. |
| 110 | 110 | */ |
| 111 | | int is_selected(running_device *chip) |
| 111 | int is_selected(running_device *chip) |
| 112 | 112 | { |
| 113 | 113 | ti99grom_state *grom = get_safe_token(chip); |
| 114 | 114 | return (((grom->address >> 13)&0x07)==grom->ident); |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | 117 | /* |
| 118 | | Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is |
| 119 | | defined by the offset (0 or 1). This is the enhanced read function with |
| 120 | | Z state. |
| 118 | Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is |
| 119 | defined by the offset (0 or 1). This is the enhanced read function with |
| 120 | Z state. |
| 121 | 121 | */ |
| 122 | 122 | READ8Z_DEVICE_HANDLER( ti99grom_rz ) |
| 123 | 123 | { |
| 124 | 124 | ti99grom_state *grom = get_safe_token(device); |
| 125 | | |
| 125 | |
| 126 | 126 | if (offset & 2) |
| 127 | 127 | { |
| 128 | | if (((grom->address >> 13)&0x07)!=grom->ident) |
| 128 | if (((grom->address >> 13)&0x07)!=grom->ident) |
| 129 | 129 | return; |
| 130 | 130 | |
| 131 | 131 | /* When reading, reset the hi/lo flag byte for writing. */ |
| r9498 | r9499 | |
| 149 | 149 | } |
| 150 | 150 | else |
| 151 | 151 | { |
| 152 | | if (((grom->address >> 13)&0x07)==grom->ident) |
| 152 | if (((grom->address >> 13)&0x07)==grom->ident) |
| 153 | 153 | { |
| 154 | 154 | /* GROMs are buffered. Data is retrieved from a buffer, */ |
| 155 | 155 | /* while the buffer is replaced with the next cell content. */ |
| 156 | 156 | *value = grom->buffer; |
| 157 | | |
| 157 | |
| 158 | 158 | /* Get next value, put it in buffer. Note that the GROM */ |
| 159 | 159 | /* wraps at 8K boundaries. */ |
| 160 | 160 | UINT16 addr = grom->address-(grom->ident<<13); |
| 161 | | |
| 161 | |
| 162 | 162 | if (!grom->extended && ((grom->address&0x1fff)>=0x1800)) |
| 163 | 163 | grom->buffer = grom->memptr[addr-0x1000] | grom->memptr[addr-0x0800]; |
| 164 | 164 | else |
| r9498 | r9499 | |
| 176 | 176 | } |
| 177 | 177 | |
| 178 | 178 | /* |
| 179 | | Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is |
| 180 | | defined by the offset (0 or 1). |
| 179 | Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is |
| 180 | defined by the offset (0 or 1). |
| 181 | 181 | */ |
| 182 | 182 | READ8_DEVICE_HANDLER( ti99grom_r ) |
| 183 | 183 | { |
| 184 | 184 | UINT8 reply = 0; |
| 185 | | ti99grom_rz(device, offset, &reply); |
| 185 | ti99grom_rz(device, offset, &reply); |
| 186 | 186 | return reply; |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | 189 | |
| 190 | 190 | /* |
| 191 | | Writing to the chip. Represents an access with M=0, GS*=0. The MO bit is |
| 192 | | defined by the offset (0 or 1). |
| 191 | Writing to the chip. Represents an access with M=0, GS*=0. The MO bit is |
| 192 | defined by the offset (0 or 1). |
| 193 | 193 | */ |
| 194 | 194 | WRITE8_DEVICE_HANDLER( ti99grom_w ) |
| 195 | 195 | { |
| r9498 | r9499 | |
| 209 | 209 | /* Accept low byte (2nd write) */ |
| 210 | 210 | grom->address = (grom->address & 0xFF00) | data; |
| 211 | 211 | /* Setting the address causes a new prefetch */ |
| 212 | | if (is_selected(device)) |
| 212 | if (is_selected(device)) |
| 213 | 213 | { |
| 214 | 214 | grom->buffer = grom->memptr[grom->address-(grom->ident<<13)]; |
| 215 | | } |
| 215 | } |
| 216 | 216 | grom->waddr_LSB = FALSE; |
| 217 | 217 | } |
| 218 | 218 | else |
| r9498 | r9499 | |
| 235 | 235 | write_addr = ((grom->address + 0x1fff) & 0x1FFF) | (grom->address & 0xE000); |
| 236 | 236 | else |
| 237 | 237 | write_addr = (grom->address - 1) & 0xFFFF; |
| 238 | | |
| 238 | |
| 239 | 239 | // UINT16 addr = grom->address-(grom->ident<<13); |
| 240 | 240 | if (grom->extended || ((grom->address&0x1fff)<0x1800)) |
| 241 | 241 | grom->memptr[write_addr-(grom->ident<<13)] = data; |
| 242 | | } |
| 242 | } |
| 243 | 243 | grom->raddr_LSB = grom->waddr_LSB = FALSE; |
| 244 | 244 | } |
| 245 | 245 | |
| r9498 | r9499 | |
| 260 | 260 | |
| 261 | 261 | grom->writable = gromconf->writeable; |
| 262 | 262 | grom->ident = gromconf->ident; |
| 263 | | |
| 263 | |
| 264 | 264 | grom->extended = (gromconf->size==0x1800)? TRUE : FALSE; |
| 265 | 265 | |
| 266 | 266 | grom->rollover = gromconf->rollover; |
| r9498 | r9499 | |
| 280 | 280 | const ti99grom_config* gromconf = (const ti99grom_config*)get_config(device); |
| 281 | 281 | ti99grom_state *grom = get_safe_token(device); |
| 282 | 282 | grom->address = 0; |
| 283 | | grom->raddr_LSB = FALSE; |
| 283 | grom->raddr_LSB = FALSE; |
| 284 | 284 | grom->waddr_LSB = FALSE; |
| 285 | 285 | grom->buffer = 0; |
| 286 | 286 | |
| r9498 | r9499 | |
| 291 | 291 | grom->memptr = memory_region(device->machine, gromconf->region); |
| 292 | 292 | |
| 293 | 293 | // TODO: Check whether this may be 0 for console GROMs. |
| 294 | | // assert (grom->memptr!=NULL); |
| 294 | // assert (grom->memptr!=NULL); |
| 295 | 295 | |
| 296 | 296 | grom->memptr += gromconf->offset; |
| 297 | 297 | |
src/mess/machine/ti99/gromport.c
| r9498 | r9499 | |
| 53 | 53 | |
| 54 | 54 | // GROM buffer size. |
| 55 | 55 | int grom_size; |
| 56 | | |
| 56 | |
| 57 | 57 | // ROM buffer size. All banks have equal sizes. |
| 58 | 58 | int rom_size; |
| 59 | | |
| 59 | |
| 60 | 60 | // RAM buffer size. All banks have equal sizes. |
| 61 | 61 | int ram_size; |
| 62 | 62 | |
| 63 | | // GROM buffer. |
| 63 | // GROM buffer. |
| 64 | 64 | UINT8 *grom_ptr; |
| 65 | 65 | |
| 66 | | // ROM buffer. |
| 66 | // ROM buffer. |
| 67 | 67 | UINT8 *rom_ptr; |
| 68 | 68 | |
| 69 | 69 | // ROM buffer for the second bank of paged cartridges. |
| r9498 | r9499 | |
| 72 | 72 | // RAM buffer. The persistence service is done by the cartridge system. |
| 73 | 73 | // The RAM space is a consecutive space; all banks are in one buffer. |
| 74 | 74 | UINT8 *ram_ptr; |
| 75 | | |
| 75 | |
| 76 | 76 | /* GK support. */ |
| 77 | | UINT16 grom_address; |
| 77 | UINT16 grom_address; |
| 78 | 78 | int waddr_LSB; |
| 79 | 79 | }; |
| 80 | 80 | typedef struct _cartridge_t cartridge_t; |
| r9498 | r9499 | |
| 109 | 109 | // If we only have one cartridge inserted, we don't want to get a |
| 110 | 110 | // selection option, so we just mirror the memory contents. |
| 111 | 111 | int next_free_slot; |
| 112 | | |
| 112 | |
| 113 | 113 | /* GK support. */ |
| 114 | 114 | int gk_slot; |
| 115 | 115 | int gk_guest_slot; |
| 116 | | |
| 116 | |
| 117 | 117 | /* Legacy support. */ |
| 118 | 118 | // Counts the number of slots which currently contain legacy format |
| 119 | 119 | // cartridge images. |
| r9498 | r9499 | |
| 122 | 122 | // Counts the number of slots which currently contain new format |
| 123 | 123 | // cartridge images. |
| 124 | 124 | int multi_slots; |
| 125 | | |
| 125 | |
| 126 | 126 | /* Used to cache the switch settings. */ |
| 127 | 127 | UINT8 gk_switch[8]; |
| 128 | 128 | |
| 129 | 129 | /* Ready line */ |
| 130 | 130 | devcb_resolved_write_line ready; |
| 131 | | |
| 131 | |
| 132 | 132 | } ti99_multicart_state; |
| 133 | 133 | |
| 134 | 134 | #define AUTO -1 |
| r9498 | r9499 | |
| 156 | 156 | |
| 157 | 157 | /* Function to disassemble this cartridge. */ |
| 158 | 158 | assmfct *disassemble; |
| 159 | | |
| 159 | |
| 160 | 160 | /* Points to the (max 5) GROM devices. */ |
| 161 | 161 | running_device *grom[5]; |
| 162 | 162 | }; |
| r9498 | r9499 | |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | 191 | /* |
| 192 | | The console writes the values in this array to cache them. |
| 192 | The console writes the values in this array to cache them. |
| 193 | 193 | */ |
| 194 | 194 | void set_gk_switches(running_device *cartsys, int number, int value) |
| 195 | 195 | { |
| r9498 | r9499 | |
| 274 | 274 | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 275 | 275 | running_device *pcb = cartslot->subdevice("pcb"); |
| 276 | 276 | ti99_pcb_t *pcb_def; |
| 277 | | |
| 277 | |
| 278 | 278 | void *socketcont; |
| 279 | 279 | int reslength; |
| 280 | | // int i; |
| 280 | // int i; |
| 281 | 281 | |
| 282 | 282 | int slotnumber = get_index_from_tagname(cartslot)-1; |
| 283 | 283 | assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS); |
| r9498 | r9499 | |
| 296 | 296 | if (socketcont != NULL) |
| 297 | 297 | { |
| 298 | 298 | cartridge->grom_ptr = (UINT8 *)socketcont; |
| 299 | | // printf("grom_socket = %lx\n", cartridge->grom_ptr); |
| 299 | // printf("grom_socket = %lx\n", cartridge->grom_ptr); |
| 300 | 300 | cartridge->grom_size = reslength; |
| 301 | 301 | } |
| 302 | 302 | |
| r9498 | r9499 | |
| 306 | 306 | { |
| 307 | 307 | cartridge->rom_ptr = (UINT8 *)socketcont; |
| 308 | 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]); |
| 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 | 310 | } |
| 311 | 311 | |
| 312 | 312 | socketcont = cartslot_get_socket(cartslot, "rom2_socket"); |
| r9498 | r9499 | |
| 332 | 332 | if (cartridge->grom_size > 0x4000) pcb_def->grom[2] = pcb->subdevice("grom_5"); |
| 333 | 333 | if (cartridge->grom_size > 0x6000) pcb_def->grom[3] = pcb->subdevice("grom_6"); |
| 334 | 334 | if (cartridge->grom_size > 0x8000) pcb_def->grom[4] = pcb->subdevice("grom_7"); |
| 335 | | |
| 335 | |
| 336 | 336 | return cartridge; |
| 337 | 337 | } |
| 338 | 338 | |
| r9498 | r9499 | |
| 389 | 389 | if (cartridge->rom_ptr!=NULL) |
| 390 | 390 | { |
| 391 | 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); |
| 392 | *value = (cartridge->rom_ptr)[offset & 0x1fff]; |
| 393 | // printf("read cartridge rom space (length %04x) %04x = %02x\n", cartridge->rom_size, offset, *value); |
| 394 | 394 | } |
| 395 | 395 | } |
| 396 | 396 | |
| r9498 | r9499 | |
| 420 | 420 | { |
| 421 | 421 | int slotnumber; |
| 422 | 422 | int i; |
| 423 | | // cartridge_t *cart; |
| 423 | // cartridge_t *cart; |
| 424 | 424 | running_device *cartsys = image->owner(); |
| 425 | 425 | ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 426 | 426 | |
| r9498 | r9499 | |
| 654 | 654 | // BNKS1 LDCR R1,0 Switch Banks |
| 655 | 655 | // SRL R0,1 Restore Bank Number (optional) |
| 656 | 656 | // RT |
| 657 | | printf("Superspace: CRU accessed at %04x\n", offset); |
| 657 | logerror("Superspace: CRU accessed at %04x\n", offset); |
| 658 | 658 | if ((offset & 1) == 0 || offset > 7) |
| 659 | 659 | *value = 0; |
| 660 | 660 | |
| r9498 | r9499 | |
| 669 | 669 | cartridge_t *cartridge = pcb->cartridge; |
| 670 | 670 | // data is bit |
| 671 | 671 | // offset is address |
| 672 | | printf("Superspace: CRU accessed at %04x\n", offset); |
| 672 | logerror("Superspace: CRU accessed at %04x\n", offset); |
| 673 | 673 | if (offset < 8) |
| 674 | 674 | { |
| 675 | 675 | if (data != 0) |
| r9498 | r9499 | |
| 853 | 853 | } |
| 854 | 854 | |
| 855 | 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. |
| 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 | 858 | */ |
| 859 | 859 | static void set_paged379i_bank(cartridge_t *cartridge, int rompage) |
| 860 | 860 | { |
| r9498 | r9499 | |
| 982 | 982 | if (bit != 0) |
| 983 | 983 | { |
| 984 | 984 | page = page-(bit/2); // 4 page flags per 8 bits |
| 985 | | } |
| 985 | } |
| 986 | 986 | *value = 1 << (page*2+1); |
| 987 | 987 | } |
| 988 | 988 | } |
| r9498 | r9499 | |
| 1096 | 1096 | ******************************************************************************/ |
| 1097 | 1097 | |
| 1098 | 1098 | /* |
| 1099 | | Get the pointer to the GROM data from the cartridge. Called by the GROM. |
| 1099 | Get the pointer to the GROM data from the cartridge. Called by the GROM. |
| 1100 | 1100 | */ |
| 1101 | 1101 | static UINT8 *get_grom_ptr(running_device *device) |
| 1102 | 1102 | { |
| r9498 | r9499 | |
| 1123 | 1123 | case DEVINFO_INT_INLINE_CONFIG_BYTES: |
| 1124 | 1124 | info->i = 0; |
| 1125 | 1125 | break; |
| 1126 | | |
| 1127 | | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1126 | |
| 1127 | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1128 | 1128 | info->machine_config = MACHINE_CONFIG_NAME(ti99_cart_common); |
| 1129 | 1129 | break; |
| 1130 | 1130 | |
| r9498 | r9499 | |
| 1191 | 1191 | strcpy(info->s, "TI99 empty cartridge"); |
| 1192 | 1192 | break; |
| 1193 | 1193 | |
| 1194 | | // Don't create GROMs |
| 1195 | | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1194 | // Don't create GROMs |
| 1195 | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1196 | 1196 | break; |
| 1197 | | |
| 1197 | |
| 1198 | 1198 | default: |
| 1199 | 1199 | DEVICE_GET_INFO_CALL(ti99_cart_common); |
| 1200 | 1200 | break; |
| r9498 | r9499 | |
| 1215 | 1215 | break; |
| 1216 | 1216 | |
| 1217 | 1217 | case TI99CART_FCT_ASSM: |
| 1218 | | info->f = (genf *) assemble_paged; |
| 1218 | info->f = (genf *) assemble_paged; |
| 1219 | 1219 | break; |
| 1220 | 1220 | |
| 1221 | 1221 | case TI99CARTINFO_FCT_6000_R: |
| r9498 | r9499 | |
| 1253 | 1253 | case TI99CARTINFO_FCT_6000_W: |
| 1254 | 1254 | info->f = (genf *) write_cart_minimem; |
| 1255 | 1255 | break; |
| 1256 | | |
| 1256 | |
| 1257 | 1257 | case DEVINFO_STR_NAME: |
| 1258 | 1258 | strcpy(info->s, "TI99 MiniMemory cartridge pcb"); |
| 1259 | 1259 | break; |
| r9498 | r9499 | |
| 1288 | 1288 | info->f = (genf *) write_cart_cru; |
| 1289 | 1289 | break; |
| 1290 | 1290 | |
| 1291 | | // Don't create GROMs |
| 1292 | | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1291 | // Don't create GROMs |
| 1292 | case DEVINFO_PTR_MACHINE_CONFIG: |
| 1293 | 1293 | break; |
| 1294 | 1294 | |
| 1295 | 1295 | case DEVINFO_STR_NAME: |
| r9498 | r9499 | |
| 1446 | 1446 | static DEVICE_IMAGE_LOAD( ti99_cartridge ) |
| 1447 | 1447 | { |
| 1448 | 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); |
| 1449 | // running_device *cartsys = image.device().owner(); |
| 1450 | // ti99_multicart_state *cartslots = get_safe_token(cartsys); |
| 1451 | 1451 | |
| 1452 | 1452 | int result; |
| 1453 | 1453 | |
| r9498 | r9499 | |
| 1486 | 1486 | static DEVICE_IMAGE_UNLOAD( ti99_cartridge ) |
| 1487 | 1487 | { |
| 1488 | 1488 | running_device *pcbdev; |
| 1489 | | // ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(image.device().owner())->token(); |
| 1489 | // ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(image.device().owner())->token(); |
| 1490 | 1490 | |
| 1491 | 1491 | if (downcast<legacy_device_base *>(&image.device())->token() == NULL) |
| 1492 | 1492 | { |
| r9498 | r9499 | |
| 1553 | 1553 | cartslots->cartridge[i].pcb = NULL; |
| 1554 | 1554 | clear_slot(device, i); |
| 1555 | 1555 | } |
| 1556 | | |
| 1556 | |
| 1557 | 1557 | devcb_write_line ready = DEVCB_LINE(cartconf->ready); |
| 1558 | 1558 | |
| 1559 | 1559 | devcb_resolve_write_line(&cartslots->ready, &ready, device); |
| 1560 | | |
| 1560 | |
| 1561 | 1561 | // The cartslot system is initialized now. The cartridges themselves |
| 1562 | 1562 | // need to check whether their parts are available. |
| 1563 | 1563 | } |
| r9498 | r9499 | |
| 1595 | 1595 | ti99_cart_gk_rz(device, offset, value); |
| 1596 | 1596 | return; |
| 1597 | 1597 | } |
| 1598 | | |
| 1598 | |
| 1599 | 1599 | /* Sanity check. Higher slots are always empty. */ |
| 1600 | 1600 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1601 | 1601 | return; |
| r9498 | r9499 | |
| 1608 | 1608 | |
| 1609 | 1609 | if (!slot_is_empty(device, slot)) |
| 1610 | 1610 | { |
| 1611 | | // printf("try it on slot %d\n", slot); |
| 1611 | // printf("try it on slot %d\n", slot); |
| 1612 | 1612 | ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token(); |
| 1613 | 1613 | (*pcbdef->read)(cart->pcb, offset, value); |
| 1614 | 1614 | } |
| r9498 | r9499 | |
| 1660 | 1660 | slot = cartslots->active_slot; |
| 1661 | 1661 | |
| 1662 | 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 |
| 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 | 1665 | // addresses. |
| 1666 | | // Unfortunately, TI's cartridge selection mechanism has an undesirable |
| 1666 | // Unfortunately, TI's cartridge selection mechanism has an undesirable |
| 1667 | 1667 | // side-effect which we work around in this implementation. |
| 1668 | 1668 | // When we have only one cartridge we would like to get only the option to |
| 1669 | 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 |
| 1670 | // would immediately cycle back to cartridge 1). However, the console |
| 1671 | 1671 | // routines always show the switch option when any two slots have different |
| 1672 | 1672 | // content, and this is the case with only one cartridge (slot 2 will then |
| 1673 | 1673 | // be filled with zeros). |
| r9498 | r9499 | |
| 1720 | 1720 | // 1001 1wbb bbbb bbr0 |
| 1721 | 1721 | |
| 1722 | 1722 | cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff)); |
| 1723 | | |
| 1723 | |
| 1724 | 1724 | // Handle the GRAM Kracker |
| 1725 | | // BTW, the GK does not have a readable address counter, but the console |
| 1725 | // BTW, the GK does not have a readable address counter, but the console |
| 1726 | 1726 | // GROMs will keep our addess counter up to date. That is |
| 1727 | 1727 | // exactly what happens in the real machine. |
| 1728 | 1728 | if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK)) |
| r9498 | r9499 | |
| 1732 | 1732 | } |
| 1733 | 1733 | |
| 1734 | 1734 | slot = cartslots->active_slot; |
| 1735 | | |
| 1735 | |
| 1736 | 1736 | // This fixes a minor issue: The selection mechanism of the console |
| 1737 | 1737 | // concludes that there are multiple cartridges plugged in when it |
| 1738 | 1738 | // checks the different GROM bases and finds different data. Empty |
| r9498 | r9499 | |
| 1745 | 1745 | // In that case we trick the OS to believe that the addressed |
| 1746 | 1746 | // cartridge appears at all locations which causes it to assume a |
| 1747 | 1747 | // standard single cartslot. |
| 1748 | | |
| 1748 | |
| 1749 | 1749 | if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1) |
| 1750 | 1750 | slot=0; |
| 1751 | | |
| 1751 | |
| 1752 | 1752 | if (slot < NUMBER_OF_CARTRIDGE_SLOTS) |
| 1753 | 1753 | { |
| 1754 | 1754 | // Select the cartridge which the multicart system is currently pointing at |
| r9498 | r9499 | |
| 1785 | 1785 | ti99_cart_cru_gk_rz(device, offset, value); |
| 1786 | 1786 | return; |
| 1787 | 1787 | } |
| 1788 | | |
| 1788 | |
| 1789 | 1789 | /* Sanity check. Higher slots are always empty. */ |
| 1790 | 1790 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1791 | 1791 | return; |
| r9498 | r9499 | |
| 1820 | 1820 | ti99_cart_cru_gk_w(device, offset, data); |
| 1821 | 1821 | return; |
| 1822 | 1822 | } |
| 1823 | | |
| 1823 | |
| 1824 | 1824 | /* Sanity check. Higher slots are always empty. */ |
| 1825 | 1825 | if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) |
| 1826 | 1826 | return; |
| r9498 | r9499 | |
| 1848 | 1848 | 06000 - 0ffff: GRAM 3-7 (alternatively, the guest GROMs appear here) |
| 1849 | 1849 | 10000 - 11fff: RAM 1 |
| 1850 | 1850 | 12000 - 13fff: RAM 2 |
| 1851 | | |
| 1851 | |
| 1852 | 1852 | The GK emulates GROMs, but without a readable address counter. Thus it |
| 1853 | 1853 | relies on the console GROMs being still in place (compare with the HSGPL). |
| 1854 | 1854 | Also, the GK does not implement a GROM buffer. |
| r9498 | r9499 | |
| 1874 | 1874 | if (get_gk_switch(cartsys, 2)==GK_GRAM0) |
| 1875 | 1875 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1876 | 1876 | } |
| 1877 | | |
| 1877 | |
| 1878 | 1878 | if ((gromkrackerbox->grom_address & 0xe000) == 0x2000) |
| 1879 | 1879 | { |
| 1880 | 1880 | // If the loader is turned on, return loader contents. |
| r9498 | r9499 | |
| 1899 | 1899 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1900 | 1900 | } |
| 1901 | 1901 | |
| 1902 | | if (((gromkrackerbox->grom_address & 0xe000) == 0x6000) || |
| 1902 | if (((gromkrackerbox->grom_address & 0xe000) == 0x6000) || |
| 1903 | 1903 | ((gromkrackerbox->grom_address & 0x8000) == 0x8000)) |
| 1904 | 1904 | { |
| 1905 | 1905 | // Cartridge space |
| 1906 | 1906 | // When a cartridge is installed, it overrides the GK contents |
| 1907 | | // but only if it has GROMs |
| 1907 | // but only if it has GROMs |
| 1908 | 1908 | int cartwithgrom = FALSE; |
| 1909 | 1909 | gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot]; |
| 1910 | 1910 | |
| r9498 | r9499 | |
| 1923 | 1923 | } |
| 1924 | 1924 | if (!cartwithgrom && get_gk_switch(cartsys, 1)==GK_NORMAL) |
| 1925 | 1925 | { |
| 1926 | | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1926 | *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address]; |
| 1927 | 1927 | } |
| 1928 | 1928 | } |
| 1929 | 1929 | |
| r9498 | r9499 | |
| 1949 | 1949 | |
| 1950 | 1950 | if ((offset & 0x0002)==0x0002) |
| 1951 | 1951 | { |
| 1952 | | // Set address |
| 1952 | // Set address |
| 1953 | 1953 | if (gromkrackerbox->waddr_LSB) |
| 1954 | 1954 | { |
| 1955 | 1955 | /* Accept low byte (2nd write) */ |
| r9498 | r9499 | |
| 1972 | 1972 | || (((gromkrackerbox->grom_address & 0xe000)==0x2000) && get_gk_switch(cartsys, 3)==GK_GRAM12 && (get_gk_switch(cartsys, 5)==GK_LDOFF)) |
| 1973 | 1973 | || (((gromkrackerbox->grom_address & 0xe000)==0x4000) && get_gk_switch(cartsys, 3)==GK_GRAM12) |
| 1974 | 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))) |
| 1975 | || (((gromkrackerbox->grom_address & 0x8000)==0x8000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1))) |
| 1976 | 1976 | { |
| 1977 | 1977 | (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address] = data; |
| 1978 | 1978 | } |
| 1979 | 1979 | } |
| 1980 | 1980 | // The GK GROM emulation does not wrap at 8K boundaries. |
| 1981 | 1981 | gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff; |
| 1982 | | |
| 1982 | |
| 1983 | 1983 | /* Reset the write address flipflop. */ |
| 1984 | 1984 | gromkrackerbox->waddr_LSB = FALSE; |
| 1985 | 1985 | } |
src/mess/machine/ti99/hsgpl.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | 2 | SNUG HSGPL card emulation. |
| 3 | 3 | Raphael Nabet, 2003. |
| 4 | | |
| 4 | |
| 5 | 5 | Rewritten as device |
| 6 | 6 | Michael Zapf, October 2010 |
| 7 | 7 | */ |
| r9498 | r9499 | |
| 81 | 81 | Note: Writing only works for areas set up as RAM. To write to the |
| 82 | 82 | FEEPROMs, you must used the algorithm specified by their respective |
| 83 | 83 | manufacturer. |
| 84 | | |
| 84 | |
| 85 | 85 | FIXME: Crashes when a cartridge is plugged in |
| 86 | 86 | */ |
| 87 | 87 | |
| 88 | 88 | #define CRU_BASE 0x1B00 |
| 89 | 89 | |
| 90 | 90 | #define RAMSIZE 0x020000 |
| 91 | | #define GRAMSIZE 0x020000 |
| 91 | #define GRAMSIZE 0x020000 |
| 92 | 92 | #define FEEPROM_SIZE 0x80000 |
| 93 | | #define FLROMSIZE 4*(FEEPROM_SIZE+2) + 1 |
| 93 | #define FLROMSIZE 4*(FEEPROM_SIZE+2) + 1 |
| 94 | 94 | |
| 95 | 95 | #define NVVERSION 0 |
| 96 | 96 | |
| r9498 | r9499 | |
| 102 | 102 | UINT8 *ram6; |
| 103 | 103 | UINT8 *gram; |
| 104 | 104 | UINT8 *flashrom; |
| 105 | | |
| 105 | |
| 106 | 106 | int current_grom_port; |
| 107 | | |
| 107 | |
| 108 | 108 | int dsr_enabled; |
| 109 | 109 | int gram_enabled; |
| 110 | 110 | int bank_enabled; |
| r9498 | r9499 | |
| 115 | 115 | int led_on; |
| 116 | 116 | int mbx_enabled; |
| 117 | 117 | int ram_enabled; |
| 118 | | |
| 118 | |
| 119 | 119 | int flash_mode; |
| 120 | | |
| 120 | |
| 121 | 121 | int current_bank; |
| 122 | | |
| 122 | |
| 123 | 123 | /* GROM emulation */ |
| 124 | 124 | int raddr_LSB, waddr_LSB; |
| 125 | 125 | int grom_address; |
| 126 | | |
| 126 | |
| 127 | 127 | } hsgpl_state; |
| 128 | 128 | |
| 129 | 129 | INLINE hsgpl_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 210 | 210 | |
| 211 | 211 | //activecpu_adjust_icount(-4); |
| 212 | 212 | |
| 213 | | // 1001 10bb bbbb bba0 |
| 213 | // 1001 10bb bbbb bba0 |
| 214 | 214 | port = card->current_grom_port = (offset & 0x3fc) >> 2; |
| 215 | 215 | |
| 216 | 216 | if (offset & 2) |
| r9498 | r9499 | |
| 237 | 237 | { |
| 238 | 238 | *value = card->gram[card->grom_address + 0x10000*port]; |
| 239 | 239 | } |
| 240 | | else |
| 240 | else |
| 241 | 241 | { |
| 242 | 242 | if (port < 8) |
| 243 | 243 | { |
| r9498 | r9499 | |
| 252 | 252 | { |
| 253 | 253 | *value = at29c040a_r(card->gromb, card->grom_address + 0x10000*(port-8)); |
| 254 | 254 | } |
| 255 | | else |
| 255 | else |
| 256 | 256 | { |
| 257 | 257 | if (port < 24) |
| 258 | 258 | { |
| r9498 | r9499 | |
| 265 | 265 | /* The HSGPL manual says 32-47, but this is incorrect */ |
| 266 | 266 | *value = at29c040a_r(card->rom6, card->grom_address + 0x10000*(port-24)); |
| 267 | 267 | } |
| 268 | | else |
| 268 | else |
| 269 | 269 | { |
| 270 | 270 | if (port==32 || port==33) |
| 271 | 271 | { |
| r9498 | r9499 | |
| 289 | 289 | } |
| 290 | 290 | } |
| 291 | 291 | // The address auto-increment should be done even when the card is |
| 292 | | // offline |
| 292 | // offline |
| 293 | 293 | card->grom_address++; |
| 294 | 294 | card->raddr_LSB = card->waddr_LSB = FALSE; |
| 295 | 295 | } |
| r9498 | r9499 | |
| 305 | 305 | |
| 306 | 306 | //activecpu_adjust_icount(-4); |
| 307 | 307 | |
| 308 | | // 1001 11bb bbbb bba0 |
| 308 | // 1001 11bb bbbb bba0 |
| 309 | 309 | port = card->current_grom_port = (offset & 0x3fc) >> 2; |
| 310 | 310 | |
| 311 | 311 | if (offset & 2) |
| r9498 | r9499 | |
| 325 | 325 | } |
| 326 | 326 | } |
| 327 | 327 | else |
| 328 | | { |
| 328 | { |
| 329 | 329 | if (card->card_enabled) |
| 330 | 330 | { |
| 331 | 331 | /* write GPL data */ |
| r9498 | r9499 | |
| 347 | 347 | { |
| 348 | 348 | at29c040a_w(card->gromb, card->grom_address + 0x10000*(port-8), data); |
| 349 | 349 | } |
| 350 | | else |
| 350 | else |
| 351 | 351 | { |
| 352 | 352 | if (port < 24) |
| 353 | 353 | { |
| r9498 | r9499 | |
| 360 | 360 | /* The HSGPL manual says 32-47, but this is incorrect */ |
| 361 | 361 | at29c040a_w(card->rom6, card->grom_address + 0x10000*(port-24), data); |
| 362 | 362 | } |
| 363 | | else |
| 363 | else |
| 364 | 364 | { |
| 365 | 365 | if (port==32 || port==33) |
| 366 | 366 | { |
| r9498 | r9499 | |
| 397 | 397 | if (card->dsr_enabled) |
| 398 | 398 | { |
| 399 | 399 | *value = at29c040a_r(card->dsr, (offset-0x4000) + 0x2000 * card->dsr_page); |
| 400 | | // logerror("hsgpl: read dsr %04x[%02x] -> %02x\n", offset, card->dsr_page, *value); |
| 400 | // logerror("hsgpl: read dsr %04x[%02x] -> %02x\n", offset, card->dsr_page, *value); |
| 401 | 401 | } |
| 402 | 402 | } |
| 403 | | |
| 403 | |
| 404 | 404 | static READ8Z_DEVICE_HANDLER ( hsgpl_cartspace_rz ) |
| 405 | 405 | { |
| 406 | 406 | hsgpl_state *card = get_safe_token(device); |
| 407 | 407 | |
| 408 | 408 | if (!card->card_enabled || card->flash_mode) |
| 409 | 409 | { |
| 410 | | // logerror("hsgpl cart read ignored (enable=%02x)\n", card->card_enabled); |
| 410 | // logerror("hsgpl cart read ignored (enable=%02x)\n", card->card_enabled); |
| 411 | 411 | return; |
| 412 | 412 | } |
| 413 | 413 | |
| r9498 | r9499 | |
| 416 | 416 | if ((port < 2) && (card->ram_enabled)) |
| 417 | 417 | { |
| 418 | 418 | *value = card->ram6[(offset-0x6000) + 0x2000*card->current_bank + 0x8000*port]; |
| 419 | | // logerror("hsgpl cart ram read %04x -> %02x\n", offset, *value); |
| 419 | // logerror("hsgpl cart ram read %04x -> %02x\n", offset, *value); |
| 420 | 420 | return; |
| 421 | 421 | } |
| 422 | 422 | |
| 423 | 423 | if (port < 16) |
| 424 | 424 | { |
| 425 | 425 | *value = at29c040a_r(card->rom6, (offset-0x6000) + 0x2000*card->current_bank + 0x8000*port); |
| 426 | | // logerror("hsgpl cart read %04x -> %02x\n", offset, *value); |
| 426 | // logerror("hsgpl cart read %04x -> %02x\n", offset, *value); |
| 427 | 427 | } |
| 428 | 428 | else |
| 429 | 429 | { |
| r9498 | r9499 | |
| 441 | 441 | static WRITE8_DEVICE_HANDLER ( hsgpl_cartspace_w ) |
| 442 | 442 | { |
| 443 | 443 | hsgpl_state *card = get_safe_token(device); |
| 444 | | |
| 444 | |
| 445 | 445 | if (!card->card_enabled || card->flash_mode) |
| 446 | 446 | { |
| 447 | | logerror("hsgpl cart write ignored: card_enabled=%02x\n", card->card_enabled); |
| 447 | logerror("hsgpl cart write ignored: card_enabled=%02x\n", card->card_enabled); |
| 448 | 448 | return; |
| 449 | 449 | } |
| 450 | | |
| 450 | |
| 451 | 451 | int port = card->current_grom_port; |
| 452 | | // logerror("hsgpl cart write %04x -> %02x\n", offset, data); |
| 452 | // logerror("hsgpl cart write %04x -> %02x\n", offset, data); |
| 453 | 453 | |
| 454 | | if (card->bank_enabled) |
| 454 | if (card->bank_enabled) |
| 455 | 455 | { |
| 456 | 456 | card->current_bank = (offset>>1) & 3; |
| 457 | | // logerror("hsgpl cart select bank %02x\n", card->current_bank); |
| 457 | // logerror("hsgpl cart select bank %02x\n", card->current_bank); |
| 458 | 458 | return; /* right??? */ |
| 459 | 459 | } |
| 460 | 460 | |
| r9498 | r9499 | |
| 481 | 481 | // feeprom is normally written to using GPL ports, and I don't know |
| 482 | 482 | // writing through >6000 page is enabled |
| 483 | 483 | /* |
| 484 | | at29c040a_w(feeprom_rom6, 1 + 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data); |
| 485 | | at29c040a_w(feeprom_rom6, 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data >> 8); |
| 484 | at29c040a_w(feeprom_rom6, 1 + 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data); |
| 485 | at29c040a_w(feeprom_rom6, 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data >> 8); |
| 486 | 486 | */ |
| 487 | 487 | } |
| 488 | 488 | else |
| r9498 | r9499 | |
| 505 | 505 | */ |
| 506 | 506 | static READ8Z_DEVICE_HANDLER ( data_rz ) |
| 507 | 507 | { |
| 508 | | if ((offset & 0xe000)==0x4000) |
| 508 | if ((offset & 0xe000)==0x4000) |
| 509 | 509 | { |
| 510 | 510 | hsgpl_dsrspace_rz(device, offset, value); |
| 511 | 511 | } |
| 512 | | |
| 513 | | if ((offset & 0xe000)==0x6000) |
| 512 | |
| 513 | if ((offset & 0xe000)==0x6000) |
| 514 | 514 | { |
| 515 | 515 | hsgpl_cartspace_rz(device, offset, value); |
| 516 | 516 | } |
| 517 | | |
| 518 | | // 1001 1wbb bbbb bba0 |
| 517 | |
| 518 | // 1001 1wbb bbbb bba0 |
| 519 | 519 | if ((offset & 0xfc01)==0x9800) |
| 520 | 520 | { |
| 521 | 521 | hsgpl_grom_rz(device, offset, value); |
| r9498 | r9499 | |
| 527 | 527 | */ |
| 528 | 528 | static WRITE8_DEVICE_HANDLER ( data_w ) |
| 529 | 529 | { |
| 530 | | if ((offset & 0xe000)==0x6000) |
| 530 | if ((offset & 0xe000)==0x6000) |
| 531 | 531 | { |
| 532 | 532 | hsgpl_cartspace_w(device, offset, data); |
| 533 | 533 | } |
| 534 | | |
| 535 | | // 1001 1wbb bbbb bba0 |
| 534 | |
| 535 | // 1001 1wbb bbbb bba0 |
| 536 | 536 | if ((offset & 0xfc01)==0x9c00) |
| 537 | 537 | { |
| 538 | 538 | hsgpl_grom_w(device, offset, data); |
| 539 | 539 | } |
| 540 | 540 | } |
| 541 | 541 | |
| 542 | | static ti99_peb_card hsgpl_card = |
| 542 | static ti99_peb_card hsgpl_card = |
| 543 | 543 | { |
| 544 | 544 | data_rz, |
| 545 | 545 | data_w, |
| 546 | 546 | NULL, |
| 547 | | cru_w, |
| 548 | | NULL, NULL, NULL, NULL |
| 547 | cru_w, |
| 548 | NULL, NULL, NULL, NULL |
| 549 | 549 | }; |
| 550 | 550 | |
| 551 | 551 | static DEVICE_START( hsgpl ) |
| r9498 | r9499 | |
| 566 | 566 | hsgpl_state *card = get_safe_token(device); |
| 567 | 567 | logerror("hsgpl: stop\n"); |
| 568 | 568 | free(card->flashrom); |
| 569 | | if (card->ram6) |
| 569 | if (card->ram6) |
| 570 | 570 | { |
| 571 | 571 | free(card->ram6); |
| 572 | 572 | free(card->gram); |
| r9498 | r9499 | |
| 577 | 577 | { |
| 578 | 578 | logerror("hsgpl: reset\n"); |
| 579 | 579 | hsgpl_state *card = get_safe_token(device); |
| 580 | | |
| 580 | |
| 581 | 581 | /* If the card is selected in the menu, register the card */ |
| 582 | 582 | if (input_port_read(device->machine, "EXTCARD") & (EXT_HSGPL_ON | EXT_HSGPL_FLASH)) |
| 583 | 583 | { |
| 584 | | running_device *peb = device->owner(); |
| 584 | running_device *peb = device->owner(); |
| 585 | 585 | int success = mount_card(peb, device, &hsgpl_card, get_pebcard_config(device)->slot); |
| 586 | | if (!success) |
| 586 | if (!success) |
| 587 | 587 | { |
| 588 | 588 | logerror("hsgpl: Failed to mount.\n"); |
| 589 | 589 | return; |
| r9498 | r9499 | |
| 609 | 609 | card->flash_mode = (input_port_read(device->machine, "EXTCARD") & EXT_HSGPL_FLASH); |
| 610 | 610 | if (card->flash_mode) logerror("hsgpl: flash mode\n"); |
| 611 | 611 | else logerror("hsgpl: full mode\n"); |
| 612 | | |
| 613 | | if (card->ram6==NULL) |
| 612 | |
| 613 | if (card->ram6==NULL) |
| 614 | 614 | { |
| 615 | 615 | card->ram6 = (UINT8*)malloc(RAMSIZE); |
| 616 | 616 | card->gram = (UINT8*)malloc(GRAMSIZE); |
| r9498 | r9499 | |
| 629 | 629 | if (read_or_write==0) |
| 630 | 630 | { |
| 631 | 631 | logerror("hsgpl: device nvram load %s\n", astring_c(hsname)); |
| 632 | | |
| 632 | |
| 633 | 633 | filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_READ, &nvfile); |
| 634 | 634 | if (filerr != FILERR_NONE) |
| 635 | 635 | { |
| 636 | | logerror("hsgpl: Could not restore NVRAM\n"); |
| 636 | logerror("hsgpl: Could not restore NVRAM\n"); |
| 637 | 637 | return; |
| 638 | 638 | } |
| 639 | 639 | |
| r9498 | r9499 | |
| 643 | 643 | mame_fclose(nvfile); |
| 644 | 644 | return; |
| 645 | 645 | } |
| 646 | | |
| 646 | |
| 647 | 647 | if (card->flashrom[0] != NVVERSION) |
| 648 | 648 | { |
| 649 | 649 | logerror("hsgpl: Wrong NVRAM image version: %d\n", card->flashrom[0]); |
| r9498 | r9499 | |
| 656 | 656 | { |
| 657 | 657 | logerror("hsgpl: device nvram save %s\n", astring_c(hsname)); |
| 658 | 658 | // Check dirty flags |
| 659 | | if (at29c040a_is_dirty(card->dsr) || |
| 659 | if (at29c040a_is_dirty(card->dsr) || |
| 660 | 660 | at29c040a_is_dirty(card->rom6) || |
| 661 | 661 | at29c040a_is_dirty(card->groma) || |
| 662 | 662 | at29c040a_is_dirty(card->gromb)) |
| 663 | 663 | { |
| 664 | 664 | card->flashrom[0] = NVVERSION; |
| 665 | 665 | filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &nvfile); |
| 666 | | |
| 666 | |
| 667 | 667 | if (filerr != FILERR_NONE) |
| 668 | 668 | { |
| 669 | | logerror("hsgpl: Could not save NVRAM\n"); |
| 669 | logerror("hsgpl: Could not save NVRAM\n"); |
| 670 | 670 | } |
| 671 | 671 | else |
| 672 | 672 | { |
| r9498 | r9499 | |
| 686 | 686 | } |
| 687 | 687 | |
| 688 | 688 | /* |
| 689 | | Get the pointer to the memory data from the HSGPL card. Called by the FEEPROM. |
| 689 | Get the pointer to the memory data from the HSGPL card. Called by the FEEPROM. |
| 690 | 690 | */ |
| 691 | 691 | static UINT8 *get_mem_ptr(running_device *device) |
| 692 | 692 | { |
src/mess/machine/ti99/genboard.c
| r9498 | r9499 | |
| 1 | 1 | /*************************************************************************** |
| 2 | | Geneve 9640 system board |
| 3 | | |
| 4 | | Michael Zapf, October 2010 |
| 2 | Geneve 9640 system board |
| 3 | |
| 4 | Michael Zapf, October 2010 |
| 5 | 5 | ***************************************************************************/ |
| 6 | 6 | |
| 7 | 7 | #include "emu.h" |
| r9498 | r9499 | |
| 26 | 26 | /* Mouse support */ |
| 27 | 27 | int last_mx; |
| 28 | 28 | int last_my; |
| 29 | | |
| 29 | |
| 30 | 30 | /* Joystick support */ |
| 31 | 31 | int joySel; |
| 32 | 32 | |
| 33 | 33 | /* Keyboard support */ |
| 34 | | UINT8 keyQueue[KEYQUEUESIZE]; |
| 34 | UINT8 keyQueue[KEYQUEUESIZE]; |
| 35 | 35 | int keyQueueHead; |
| 36 | 36 | int keyQueueLen; |
| 37 | 37 | int keyInBuf; |
| 38 | 38 | int keyReset; |
| 39 | | UINT32 keyStateSave[4]; |
| 39 | UINT32 keyStateSave[4]; |
| 40 | 40 | int keyNumLockState; |
| 41 | 41 | int keyCtrlState; |
| 42 | 42 | int keyAltState; |
| r9498 | r9499 | |
| 45 | 45 | int keyFakeUnshiftState; |
| 46 | 46 | int keyAutoRepeatKey; |
| 47 | 47 | int keyAutoRepeatTimer; |
| 48 | | |
| 48 | |
| 49 | 49 | /* Mode flags */ |
| 50 | 50 | int palvideo; // bit 5 + |
| 51 | 51 | int capslock; // bit 7 + |
| 52 | 52 | int keyboard_clock; // bit 8 + |
| 53 | 53 | int keep_keybuf; // bit 9 keyclear - |
| 54 | | int zero_wait; // bit 15 |
| 55 | | |
| 54 | int zero_wait; // bit 15 |
| 55 | |
| 56 | 56 | /* GROM simulation */ |
| 57 | 57 | int grom_address; |
| 58 | 58 | int gromraddr_LSB; |
| 59 | 59 | int gromwaddr_LSB; |
| 60 | | |
| 60 | |
| 61 | 61 | /* Memory */ |
| 62 | 62 | UINT8 *sram; |
| 63 | 63 | UINT8 *dram; |
| 64 | 64 | UINT8 *eprom; |
| 65 | | |
| 65 | |
| 66 | 66 | /* Mapper */ |
| 67 | 67 | int geneve_mode; // + |
| 68 | 68 | int direct_mode; // mapmode - |
| r9498 | r9499 | |
| 71 | 71 | int cartridge6_writable; // protect - |
| 72 | 72 | int cartridge7_writable; // protect - |
| 73 | 73 | int map[8]; |
| 74 | | |
| 74 | |
| 75 | 75 | int line_count; |
| 76 | | |
| 76 | |
| 77 | 77 | /* Devices */ |
| 78 | | running_device *cpu; |
| 79 | | running_device *video; |
| 78 | running_device *cpu; |
| 79 | running_device *video; |
| 80 | 80 | running_device *tms9901; |
| 81 | | running_device *clock; |
| 82 | | running_device *peribox; |
| 83 | | running_device *sound; |
| 81 | running_device *clock; |
| 82 | running_device *peribox; |
| 83 | running_device *sound; |
| 84 | 84 | |
| 85 | 85 | } genboard_state; |
| 86 | 86 | |
| r9498 | r9499 | |
| 91 | 91 | 0x1d, /* right control */ |
| 92 | 92 | 0x38, /* alt gr */ |
| 93 | 93 | /* extra codes are 0x5b for Left Windows, 0x5c for Right Windows, 0x5d |
| 94 | | for Menu, 0x5e for power, 0x5f for sleep, 0x63 for wake, but I doubt |
| 95 | | any Geneve program would take advantage of these. */ |
| 96 | | |
| 94 | for Menu, 0x5e for power, 0x5f for sleep, 0x63 for wake, but I doubt |
| 95 | any Geneve program would take advantage of these. */ |
| 96 | |
| 97 | 97 | /* extended key that is equivalent to a non-extended key |
| 98 | | with shift off */ |
| 98 | with shift off */ |
| 99 | 99 | 0x35, /* pad slash */ |
| 100 | | |
| 100 | |
| 101 | 101 | /* extended keys that are equivalent to non-extended keys |
| 102 | | with numlock off */ |
| 102 | with numlock off */ |
| 103 | 103 | 0x47, /* home */ |
| 104 | 104 | 0x48, /* up */ |
| 105 | 105 | 0x49, /* page up */ |
| r9498 | r9499 | |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | /**************************************************************************** |
| 147 | | GROM simulation. The Geneve board simulated GROM circuits within its gate |
| 148 | | array. |
| 147 | GROM simulation. The Geneve board simulated GROM circuits within its gate |
| 148 | array. |
| 149 | 149 | *****************************************************************************/ |
| 150 | 150 | |
| 151 | 151 | /* |
| 152 | | Simulates GROM. The real Geneve does not use GROMs but simulates them |
| 153 | | within the gate array. Unlike with real GROMs, no address wrapping occurs, |
| 154 | | and the complete 64K space is available. |
| 152 | Simulates GROM. The real Geneve does not use GROMs but simulates them |
| 153 | within the gate array. Unlike with real GROMs, no address wrapping occurs, |
| 154 | and the complete 64K space is available. |
| 155 | 155 | */ |
| 156 | 156 | static READ8_DEVICE_HANDLER( read_grom ) |
| 157 | 157 | { |
| r9498 | r9499 | |
| 159 | 159 | UINT8 reply; |
| 160 | 160 | if (offset & 0x0002) |
| 161 | 161 | { |
| 162 | | // GROM address handling |
| 162 | // GROM address handling |
| 163 | 163 | board->gromwaddr_LSB = FALSE; |
| 164 | | |
| 164 | |
| 165 | 165 | if (board->gromraddr_LSB) |
| 166 | 166 | { |
| 167 | 167 | reply = board->grom_address & 0xff; |
| r9498 | r9499 | |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | 188 | /* |
| 189 | | Simulates GROM. The real Geneve does not use GROMs but simulates them |
| 190 | | within the gate array. |
| 189 | Simulates GROM. The real Geneve does not use GROMs but simulates them |
| 190 | within the gate array. |
| 191 | 191 | */ |
| 192 | 192 | static WRITE8_DEVICE_HANDLER( write_grom ) |
| 193 | 193 | { |
| r9498 | r9499 | |
| 206 | 206 | { |
| 207 | 207 | board->grom_address = (board->grom_address & 0x00ff) | ((UINT16)data<<8); |
| 208 | 208 | board->gromwaddr_LSB = TRUE; |
| 209 | | } |
| 209 | } |
| 210 | 210 | } |
| 211 | 211 | else |
| 212 | 212 | { // write GPL data |
| r9498 | r9499 | |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | 220 | /**************************************************************************** |
| 221 | | Mapper |
| 221 | Mapper |
| 222 | 222 | *****************************************************************************/ |
| 223 | 223 | |
| 224 | 224 | READ8_DEVICE_HANDLER( geneve_r ) |
| r9498 | r9499 | |
| 227 | 227 | UINT8 value = 0; |
| 228 | 228 | int page; |
| 229 | 229 | |
| 230 | | // Premature access. The CPU reads the start vector before RESET. |
| 230 | // Premature access. The CPU reads the start vector before RESET. |
| 231 | 231 | if (board->peribox==NULL) return 0; |
| 232 | | |
| 232 | |
| 233 | 233 | if (!board->zero_wait) |
| 234 | 234 | cpu_adjust_icount(board->cpu, -4); |
| 235 | 235 | |
| 236 | 236 | UINT32 physaddr; |
| 237 | | |
| 237 | |
| 238 | 238 | if (board->geneve_mode) |
| 239 | 239 | { |
| 240 | 240 | // TODO: shortcut offset & 0xffc0 = 0xf100 |
| r9498 | r9499 | |
| 302 | 302 | // ++++ ++-- ---- ---+ |
| 303 | 303 | // 1001 0000 0000 0000 |
| 304 | 304 | // 0x17000 represents the proper AMA/B/C setting; will be masked away currently |
| 305 | | ti99_peb_data_rz(board->peribox, offset | 0x17000, &value); |
| 305 | ti99_peb_data_rz(board->peribox, offset | 0x17000, &value); |
| 306 | 306 | return value; |
| 307 | 307 | } |
| 308 | 308 | if ((offset & 0xfc01)==0x9800) |
| r9498 | r9499 | |
| 314 | 314 | return value; |
| 315 | 315 | } |
| 316 | 316 | } |
| 317 | | |
| 318 | | page = (offset & 0xe000) >> 13; |
| 319 | 317 | |
| 318 | page = (offset & 0xe000) >> 13; |
| 319 | |
| 320 | 320 | if (board->direct_mode) |
| 321 | 321 | { |
| 322 | 322 | physaddr = 0x1e0000; // points to boot eprom |
| r9498 | r9499 | |
| 338 | 338 | physaddr = (board->map[page] << 13); |
| 339 | 339 | } |
| 340 | 340 | } |
| 341 | | |
| 342 | | physaddr |= (offset & 0x1fff); |
| 343 | | |
| 341 | |
| 342 | physaddr |= (offset & 0x1fff); |
| 343 | |
| 344 | 344 | if ((physaddr & 0x180000)==0x000000) |
| 345 | 345 | { |
| 346 | 346 | // DRAM. One wait state. |
| r9498 | r9499 | |
| 351 | 351 | if ((physaddr & 0x180000)==0x080000) |
| 352 | 352 | { |
| 353 | 353 | // Memex in PEB |
| 354 | | // 0 1aaa xxxx xxxx xxxx xxxx |
| 355 | | ti99_peb_data_rz(board->peribox, physaddr, &value); |
| 354 | // 0 1aaa xxxx xxxx xxxx xxxx |
| 355 | ti99_peb_data_rz(board->peribox, physaddr, &value); |
| 356 | 356 | return value; |
| 357 | 357 | } |
| 358 | 358 | if ((physaddr & 0x180000)==0x100000) |
| 359 | 359 | { |
| 360 | | // 1 0aaa xxxx xxxx xxxx xxxx p-box address block |
| 360 | // 1 0aaa xxxx xxxx xxxx xxxx p-box address block |
| 361 | 361 | // Cards in PEB (aaa = AMC, AMB, AMA) |
| 362 | | ti99_peb_data_rz(board->peribox, physaddr, &value); |
| 362 | ti99_peb_data_rz(board->peribox, physaddr, &value); |
| 363 | 363 | return value; |
| 364 | 364 | } |
| 365 | 365 | if ((physaddr & 0x1f0000)==0x1d0000) |
| r9498 | r9499 | |
| 374 | 374 | // mirrored for f0, f2, f4, ...; f1, f3, f5, ... |
| 375 | 375 | value = board->eprom[physaddr & 0x003fff]; |
| 376 | 376 | return value; |
| 377 | | } |
| 377 | } |
| 378 | 378 | |
| 379 | | return 0; |
| 379 | return 0; |
| 380 | 380 | } |
| 381 | 381 | /* |
| 382 | 382 | Geneve mode: |
| r9498 | r9499 | |
| 390 | 390 | 8008 / ffff: key_r |
| 391 | 391 | 8010 / fff0: clock_r |
| 392 | 392 | 8800 / fffd: v9938_r |
| 393 | | 9000 / ffc0: speech_r |
| 393 | 9000 / ffc0: speech_r |
| 394 | 394 | 9800 / ffc0: grom_r |
| 395 | 395 | |
| 396 | 396 | */ |
| r9498 | r9499 | |
| 402 | 402 | int page; |
| 403 | 403 | |
| 404 | 404 | if (board->peribox==NULL) return; |
| 405 | | |
| 405 | |
| 406 | 406 | if (!board->zero_wait) |
| 407 | 407 | cpu_adjust_icount(board->cpu, -4); |
| 408 | | |
| 408 | |
| 409 | 409 | if (board->geneve_mode) |
| 410 | 410 | { |
| 411 | 411 | if ((offset & 0xfff1)==0xf100) |
| r9498 | r9499 | |
| 474 | 474 | // speech |
| 475 | 475 | // ++++ ++-- ---- ---+ |
| 476 | 476 | // 1001 0100 0000 0000 |
| 477 | | ti99_peb_data_w(board->peribox, offset | 0x17000, data); |
| 477 | ti99_peb_data_w(board->peribox, offset | 0x17000, data); |
| 478 | 478 | return; |
| 479 | 479 | } |
| 480 | 480 | if ((offset & 0xfc01)==0x9c00) |
| r9498 | r9499 | |
| 521 | 521 | physaddr = (board->map[page] << 13); |
| 522 | 522 | } |
| 523 | 523 | |
| 524 | | physaddr |= offset & 0x1fff; |
| 525 | | |
| 524 | physaddr |= offset & 0x1fff; |
| 525 | |
| 526 | 526 | if ((physaddr & 0x180000)==0x000000) |
| 527 | 527 | { |
| 528 | 528 | // DRAM write. One wait state. |
| r9498 | r9499 | |
| 533 | 533 | if ((physaddr & 0x180000)==0x080000) |
| 534 | 534 | { |
| 535 | 535 | // Memex in PEB |
| 536 | | ti99_peb_data_w(board->peribox, physaddr, data); |
| 536 | ti99_peb_data_w(board->peribox, physaddr, data); |
| 537 | 537 | return; |
| 538 | 538 | } |
| 539 | 539 | if ((physaddr & 0x180000)==0x100000) |
| 540 | 540 | { |
| 541 | 541 | // Classic cards in PEB |
| 542 | | ti99_peb_data_w(board->peribox, physaddr, data); |
| 542 | ti99_peb_data_w(board->peribox, physaddr, data); |
| 543 | 543 | return; |
| 544 | | } |
| 544 | } |
| 545 | 545 | if ((physaddr & 0x1f0000)==0x1d0000) |
| 546 | 546 | { |
| 547 | 547 | // SRAM write |
| r9498 | r9499 | |
| 577 | 577 | 1 010. .... .... .... .... p-box AMA=1 AMB=0 (128 KiB) |
| 578 | 578 | 1 0110 .... .... .... .... p-box AMA=1 AMB=1 AMC=0 (64 KiB) |
| 579 | 579 | |
| 580 | | 1 0111 00.. .... .... .... p-box address block 0xxx, 2xxx |
| 580 | 1 0111 00.. .... .... .... p-box address block 0xxx, 2xxx |
| 581 | 581 | 1 0111 010. .... .... .... p-box address block 4xxx (DSR) |
| 582 | 582 | 1 0111 011. .... .... .... p-box address block 6xxx |
| 583 | | 1 0111 100. .... .... .... p-box address block 8xxx |
| 583 | 1 0111 100. .... .... .... p-box address block 8xxx |
| 584 | 584 | 1 0111 101. .... .... .... p-box address block axxx |
| 585 | 585 | 1 0111 11.. .... .... .... p-box address block cxxx, exxx |
| 586 | 586 | |
| r9498 | r9499 | |
| 592 | 592 | */ |
| 593 | 593 | |
| 594 | 594 | /**************************************************************************** |
| 595 | | CRU handling |
| 595 | CRU handling |
| 596 | 596 | *****************************************************************************/ |
| 597 | 597 | |
| 598 | 598 | #define CRU_CONTROL_BASE 0x1ee0 |
| r9498 | r9499 | |
| 604 | 604 | int addroff = (offset + 0x0800) << 1; |
| 605 | 605 | int rising_edge = FALSE; |
| 606 | 606 | int falling_edge = FALSE; |
| 607 | | |
| 607 | |
| 608 | 608 | if ((addroff & 0x1fe0) == CRU_CONTROL_BASE) |
| 609 | 609 | { |
| 610 | 610 | int bit = (addroff & 0x0001e)>>1; |
| r9498 | r9499 | |
| 620 | 620 | rising_edge = (!board->keyboard_clock && data); |
| 621 | 621 | board->keyboard_clock = data; |
| 622 | 622 | if (rising_edge) |
| 623 | | read_key_if_possible(board); |
| 623 | read_key_if_possible(board); |
| 624 | 624 | break; |
| 625 | 625 | case 9: |
| 626 | 626 | rising_edge = (!board->keep_keybuf && data); |
| r9498 | r9499 | |
| 642 | 642 | tms9901_set_single_int(board->tms9901, 8, 0); |
| 643 | 643 | board->keyInBuf = 0; |
| 644 | 644 | } |
| 645 | | } |
| 645 | } |
| 646 | 646 | break; |
| 647 | 647 | case 10: |
| 648 | 648 | board->geneve_mode = data; |
| r9498 | r9499 | |
| 678 | 678 | genboard_state *board = get_safe_token(device); |
| 679 | 679 | int addroff = (offset + 0x0100) << 4; |
| 680 | 680 | |
| 681 | | // TMS9995-internal CRU locations (1ee0-1efe) are handled within the 99xxcore |
| 681 | // TMS9995-internal CRU locations (1ee0-1efe) are handled within the 99xxcore |
| 682 | 682 | // implementation (read_single_cru), so we don't arrive here |
| 683 | 683 | ti99_peb_cru_rz(board->peribox, addroff, &value); |
| 684 | 684 | return value; |
| 685 | 685 | } |
| 686 | 686 | |
| 687 | 687 | /**************************************************************************** |
| 688 | | Keyboard support |
| 688 | Keyboard support |
| 689 | 689 | *****************************************************************************/ |
| 690 | 690 | |
| 691 | 691 | UINT8 get_recent_key(running_device *device) |
| r9498 | r9499 | |
| 756 | 756 | |
| 757 | 757 | // Release Fake Shift/Unshift if another key is pressed |
| 758 | 758 | // We do so if a key is released, though it is actually |
| 759 | | // required only if it is a modifier key |
| 759 | // required only if it is a modifier key |
| 760 | 760 | /*if (pressed)*/ |
| 761 | 761 | //{ |
| 762 | 762 | if (board->keyFakeShiftState) |
| r9498 | r9499 | |
| 923 | 923 | } |
| 924 | 924 | |
| 925 | 925 | /**************************************************************************** |
| 926 | | Mouse support |
| 926 | Mouse support |
| 927 | 927 | ****************************************************************************/ |
| 928 | 928 | |
| 929 | 929 | static void poll_mouse(running_device *device) |
| r9498 | r9499 | |
| 963 | 963 | } |
| 964 | 964 | |
| 965 | 965 | /**************************************************************************** |
| 966 | | TMS9901 and attached devices handling |
| 966 | TMS9901 and attached devices handling |
| 967 | 967 | ****************************************************************************/ |
| 968 | 968 | |
| 969 | 969 | /* |
| r9498 | r9499 | |
| 1108 | 1108 | }, |
| 1109 | 1109 | |
| 1110 | 1110 | { /* write handlers */ |
| 1111 | | W9901_PE_bus_reset, |
| 1112 | | W9901_VDP_reset, |
| 1113 | | W9901_joySel, |
| 1114 | | NULL, |
| 1115 | | NULL, |
| 1116 | | NULL, |
| 1117 | | W9901_keyboardReset, |
| 1118 | | W9901_ext_mem_wait_states, |
| 1119 | | NULL, |
| 1120 | | W9901_VDP_wait_states, |
| 1121 | | NULL, |
| 1122 | | NULL, |
| 1123 | | NULL, |
| 1124 | | NULL, |
| 1125 | | NULL, |
| 1126 | | NULL |
| 1111 | W9901_PE_bus_reset, |
| 1112 | W9901_VDP_reset, |
| 1113 | W9901_joySel, |
| 1114 | NULL, |
| 1115 | NULL, |
| 1116 | NULL, |
| 1117 | W9901_keyboardReset, |
| 1118 | W9901_ext_mem_wait_states, |
| 1119 | NULL, |
| 1120 | W9901_VDP_wait_states, |
| 1121 | NULL, |
| 1122 | NULL, |
| 1123 | NULL, |
| 1124 | NULL, |
| 1125 | NULL, |
| 1126 | NULL |
| 1127 | 1127 | }, |
| 1128 | 1128 | |
| 1129 | 1129 | /* interrupt handler */ |
| r9498 | r9499 | |
| 1177 | 1177 | static MACHINE_CONFIG_FRAGMENT( genboard ) |
| 1178 | 1178 | MDRV_MM58274C_ADD("mm58274c", geneve_mm58274c_interface) |
| 1179 | 1179 | MACHINE_CONFIG_END |
| 1180 | | |
| 1180 | |
| 1181 | 1181 | static DEVICE_START( genboard ) |
| 1182 | 1182 | { |
| 1183 | 1183 | logerror("Starting Geneve board\n"); |
| r9498 | r9499 | |
| 1187 | 1187 | board->peribox = device->siblingdevice("peribox"); |
| 1188 | 1188 | board->cpu = device->siblingdevice("maincpu"); |
| 1189 | 1189 | board->sound = device->siblingdevice("soundgen"); |
| 1190 | | |
| 1190 | |
| 1191 | 1191 | board->clock = device->subdevice("mm58274c"); |
| 1192 | 1192 | |
| 1193 | 1193 | board->sram = (UINT8*)malloc(SRAM_SIZE); |
| r9498 | r9499 | |
| 1199 | 1199 | assert(board->eprom); |
| 1200 | 1200 | board->geneve_mode = 0; |
| 1201 | 1201 | board->direct_mode = 1; |
| 1202 | | |
| 1202 | |
| 1203 | 1203 | memset(board->sram, 0x00, SRAM_SIZE); |
| 1204 | 1204 | memset(board->dram, 0x00, DRAM_SIZE); |
| 1205 | 1205 | } |
| r9498 | r9499 | |
| 1231 | 1231 | board->last_mx = 0; |
| 1232 | 1232 | board->last_my = 0; |
| 1233 | 1233 | board->line_count = 0; |
| 1234 | | |
| 1234 | |
| 1235 | 1235 | board->palvideo = 0; |
| 1236 | 1236 | board->capslock = 0; |
| 1237 | 1237 | board->keyboard_clock = 0; |
| 1238 | 1238 | board->keep_keybuf = 0; |
| 1239 | | board->zero_wait = 1; |
| 1240 | | |
| 1239 | board->zero_wait = 1; |
| 1240 | |
| 1241 | 1241 | board->geneve_mode = 0; |
| 1242 | 1242 | board->direct_mode = 1; |
| 1243 | 1243 | board->cartridge_size_8K = 0; |
| r9498 | r9499 | |
| 1245 | 1245 | board->cartridge6_writable = 0; |
| 1246 | 1246 | board->cartridge7_writable = 0; |
| 1247 | 1247 | for (int i=0; i < 8; i++) board->map[i] = 0; |
| 1248 | | |
| 1248 | |
| 1249 | 1249 | if (input_port_read(device->machine, "BOOTROM")==0) |
| 1250 | 1250 | { |
| 1251 | 1251 | board->eprom = memory_region(device->machine, "maincpu") + offset_altrom_geneve; |
src/mess/machine/ti99/sgcpu.c
| r9498 | r9499 | |
| 1 | 1 | /*************************************************************************** |
| 2 | | |
| 3 | | SGCPU board |
| 4 | | including decoder/mapper |
| 5 | | |
| 6 | | This component implements the address decoder and mapper logic from the |
| 7 | | SGCPU expansion card (inofficially called TI-99/4P). |
| 8 | | |
| 9 | | Michael Zapf, October 2010 |
| 10 | | |
| 11 | | TODO: Check for wait states |
| 2 | |
| 3 | SGCPU board |
| 4 | including decoder/mapper |
| 5 | |
| 6 | This component implements the address decoder and mapper logic from the |
| 7 | SGCPU expansion card (inofficially called TI-99/4P). |
| 8 | |
| 9 | Michael Zapf, October 2010 |
| 10 | |
| 11 | TODO: Check for wait states |
| 12 | 12 | ***************************************************************************/ |
| 13 | 13 | |
| 14 | 14 | #include "emu.h" |
| r9498 | r9499 | |
| 34 | 34 | |
| 35 | 35 | /* AMS RAM (1 Mib) */ |
| 36 | 36 | UINT16 *ram; |
| 37 | | |
| 37 | |
| 38 | 38 | /* Scratch pad ram (1 KiB) */ |
| 39 | 39 | UINT16 *scratchpad; |
| 40 | | |
| 40 | |
| 41 | 41 | /* True if SGCPU DSR is enabled */ |
| 42 | 42 | int internal_dsr; |
| 43 | 43 | |
| r9498 | r9499 | |
| 56 | 56 | UINT8 lowbyte; |
| 57 | 57 | UINT8 highbyte; |
| 58 | 58 | UINT8 latch; |
| 59 | | |
| 59 | |
| 60 | 60 | /* Mapper registers */ |
| 61 | 61 | UINT8 mapper[16]; |
| 62 | | |
| 62 | |
| 63 | 63 | running_device *cpu; |
| 64 | 64 | running_device *soundchip; |
| 65 | 65 | running_device *video; |
| 66 | 66 | running_device *cassette; |
| 67 | 67 | running_device *peribox; |
| 68 | | |
| 68 | |
| 69 | 69 | int keyCol; |
| 70 | 70 | int alphaLockLine; |
| 71 | | |
| 71 | |
| 72 | 72 | } sgcpu_state; |
| 73 | 73 | |
| 74 | 74 | |
| r9498 | r9499 | |
| 88 | 88 | #define SAMS_CRU_BASE 0x1e00 |
| 89 | 89 | |
| 90 | 90 | /* |
| 91 | | CRU write (there is no read here) |
| 91 | CRU write (there is no read here) |
| 92 | 92 | */ |
| 93 | 93 | WRITE8_DEVICE_HANDLER( sgcpu_cru_w ) |
| 94 | 94 | { |
| 95 | 95 | sgcpu_state *sgcpu = get_safe_token(device); |
| 96 | 96 | int addroff = (offset + 0x0400)<<1; |
| 97 | 97 | |
| 98 | | if ((addroff & 0xff00)==MAP_CRU_BASE) |
| 98 | if ((addroff & 0xff00)==MAP_CRU_BASE) |
| 99 | 99 | { |
| 100 | 100 | if ((addroff & 0x000e)==0) sgcpu->internal_dsr = data; |
| 101 | 101 | if ((addroff & 0x000e)==2) sgcpu->internal_rom6 = data; |
| 102 | | if ((addroff & 0x000e)==4) |
| 102 | if ((addroff & 0x000e)==4) |
| 103 | 103 | { |
| 104 | 104 | ti99_peb_senila(sgcpu->peribox, data); |
| 105 | 105 | } |
| 106 | | if ((addroff & 0x000e)==6) |
| 106 | if ((addroff & 0x000e)==6) |
| 107 | 107 | { |
| 108 | 108 | ti99_peb_senilb(sgcpu->peribox, data); |
| 109 | 109 | } |
| 110 | 110 | // TODO: more CRU bits? 8=Fast timing / a=KBENA |
| 111 | 111 | return; |
| 112 | 112 | } |
| 113 | | if ((addroff & 0xff00)==SAMS_CRU_BASE) |
| 113 | if ((addroff & 0xff00)==SAMS_CRU_BASE) |
| 114 | 114 | { |
| 115 | 115 | if ((addroff & 0x000e)==0) sgcpu->access_mapper = data; |
| 116 | 116 | if ((addroff & 0x000e)==2) sgcpu->map_mode = data; |
| r9498 | r9499 | |
| 133 | 133 | |
| 134 | 134 | /* |
| 135 | 135 | Memory read. The SAMS card has two address areas: The memory is at locations |
| 136 | | 0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e |
| 137 | | (only even addresses). |
| 136 | 0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e |
| 137 | (only even addresses). |
| 138 | 138 | */ |
| 139 | 139 | static READ16_DEVICE_HANDLER( sgcpu_samsmem_r ) |
| 140 | 140 | { |
| 141 | | sgcpu_state *sgcpu = get_safe_token(device); |
| 141 | sgcpu_state *sgcpu = get_safe_token(device); |
| 142 | 142 | UINT32 address = 0; |
| 143 | 143 | int addroff = offset << 1; |
| 144 | 144 | |
| r9498 | r9499 | |
| 146 | 146 | if (sgcpu->map_mode) |
| 147 | 147 | address = (sgcpu->mapper[(addroff>>12) & 0x000f] << 12) + (addroff & 0x0fff); |
| 148 | 148 | else // transparent mode |
| 149 | | address = addroff; |
| 150 | | |
| 151 | | return sgcpu->ram[address>>1]; |
| 149 | address = addroff; |
| 150 | |
| 151 | return sgcpu->ram[address>>1]; |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | /* |
| 155 | | Memory write |
| 155 | Memory write |
| 156 | 156 | */ |
| 157 | 157 | static WRITE16_DEVICE_HANDLER( sgcpu_samsmem_w ) |
| 158 | 158 | { |
| 159 | | sgcpu_state *sgcpu = get_safe_token(device); |
| 159 | sgcpu_state *sgcpu = get_safe_token(device); |
| 160 | 160 | UINT32 address = 0; |
| 161 | 161 | int addroff = offset << 1; |
| 162 | | |
| 162 | |
| 163 | 163 | // select memory expansion |
| 164 | 164 | if (sgcpu->map_mode) |
| 165 | 165 | address = (sgcpu->mapper[(addroff>>12) & 0x000f] << 12) + (addroff & 0x0fff); |
| 166 | 166 | else // transparent mode |
| 167 | | address = addroff; |
| 168 | | |
| 169 | | COMBINE_DATA(&sgcpu->ram[address>>1]); |
| 167 | address = addroff; |
| 168 | |
| 169 | COMBINE_DATA(&sgcpu->ram[address>>1]); |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | /*************************************************************************** |
| r9498 | r9499 | |
| 182 | 182 | |
| 183 | 183 | ti99_peb_data_rz(sgcpu->peribox, addroff+1, &sgcpu->latch); |
| 184 | 184 | sgcpu->lowbyte = sgcpu->latch; |
| 185 | | |
| 185 | |
| 186 | 186 | // Takes three cycles |
| 187 | 187 | cpu_adjust_icount(sgcpu->cpu, -3); |
| 188 | 188 | |
| 189 | 189 | ti99_peb_data_rz(sgcpu->peribox, addroff, &hbyte); |
| 190 | 190 | sgcpu->highbyte = hbyte; |
| 191 | | |
| 191 | |
| 192 | 192 | // Takes three cycles |
| 193 | 193 | cpu_adjust_icount(sgcpu->cpu, -3); |
| 194 | 194 | |
| 195 | 195 | // use the latch and the currently read byte and put it on the 16bit bus |
| 196 | | // printf("read address = %04x, value = %04x, memmask = %4x\n", addroff, (hbyte<<8) | sgcpu->latch, mem_mask); |
| 196 | // printf("read address = %04x, value = %04x, memmask = %4x\n", addroff, (hbyte<<8) | sgcpu->latch, mem_mask); |
| 197 | 197 | return (hbyte<<8) | sgcpu->latch ; |
| 198 | 198 | } |
| 199 | 199 | |
| r9498 | r9499 | |
| 204 | 204 | static WRITE16_DEVICE_HANDLER( sgcpu_datamux_w ) |
| 205 | 205 | { |
| 206 | 206 | sgcpu_state *sgcpu = get_safe_token(device); |
| 207 | | UINT16 addroff = (offset << 1); |
| 208 | | // printf("write address = %04x, value = %04x, memmask = %4x\n", addroff, data, mem_mask); |
| 209 | | |
| 207 | UINT16 addroff = (offset << 1); |
| 208 | // printf("write address = %04x, value = %04x, memmask = %4x\n", addroff, data, mem_mask); |
| 209 | |
| 210 | 210 | // read more about the datamux in datamux.c |
| 211 | | |
| 211 | |
| 212 | 212 | // byte-only transfer, high byte |
| 213 | 213 | // we use the previously read low byte to complete |
| 214 | 214 | if (mem_mask == 0xff00) |
| 215 | 215 | data = data | sgcpu->lowbyte; |
| 216 | | |
| 217 | | // byte-only transfer, low byte |
| 218 | | // we use the previously read high byte to complete |
| 216 | |
| 217 | // byte-only transfer, low byte |
| 218 | // we use the previously read high byte to complete |
| 219 | 219 | if (mem_mask == 0x00ff) |
| 220 | 220 | data = data | (sgcpu->highbyte << 8); |
| 221 | 221 | |
| r9498 | r9499 | |
| 224 | 224 | |
| 225 | 225 | // Takes three cycles |
| 226 | 226 | cpu_adjust_icount(sgcpu->cpu,-3); |
| 227 | | |
| 227 | |
| 228 | 228 | // Write to the PEB |
| 229 | 229 | ti99_peb_data_w(sgcpu->peribox, addroff, (data>>8) & 0xff); |
| 230 | | |
| 230 | |
| 231 | 231 | // Takes three cycles |
| 232 | 232 | cpu_adjust_icount(sgcpu->cpu,-3); |
| 233 | 233 | } |
| r9498 | r9499 | |
| 237 | 237 | */ |
| 238 | 238 | READ16_DEVICE_HANDLER( sgcpu_r ) |
| 239 | 239 | { |
| 240 | | sgcpu_state *sgcpu = get_safe_token(device); |
| 240 | sgcpu_state *sgcpu = get_safe_token(device); |
| 241 | 241 | if (sgcpu->cpu == NULL) return 0; |
| 242 | 242 | |
| 243 | 243 | int addroff = offset << 1; |
| 244 | 244 | UINT16 zone = addroff & 0xe000; |
| 245 | 245 | UINT16 value = 0; |
| 246 | | |
| 246 | |
| 247 | 247 | if (zone==0x0000) |
| 248 | 248 | { |
| 249 | 249 | // ROM0 |
| r9498 | r9499 | |
| 255 | 255 | value = sgcpu_samsmem_r(device, offset, mem_mask); |
| 256 | 256 | return value; |
| 257 | 257 | } |
| 258 | | |
| 258 | |
| 259 | 259 | if (zone==0x4000) |
| 260 | 260 | { |
| 261 | 261 | if (sgcpu->internal_dsr) |
| 262 | 262 | { |
| 263 | | value = sgcpu->dsr[(addroff & 0x1fff)>>1]; |
| 263 | value = sgcpu->dsr[(addroff & 0x1fff)>>1]; |
| 264 | 264 | return value; |
| 265 | 265 | } |
| 266 | 266 | else |
| r9498 | r9499 | |
| 272 | 272 | } |
| 273 | 273 | } |
| 274 | 274 | } |
| 275 | | |
| 275 | |
| 276 | 276 | if (zone==0x6000 && sgcpu->internal_rom6) |
| 277 | 277 | { |
| 278 | 278 | if (sgcpu->rom6_bank==0) |
| r9498 | r9499 | |
| 301 | 301 | // Video: 8800, 8802 |
| 302 | 302 | if ((addroff & 0xfffd)==0x8800) |
| 303 | 303 | { |
| 304 | | value = ti_v9938_r16(sgcpu->video, offset, mem_mask); |
| 304 | value = ti_v9938_r16(sgcpu->video, offset, mem_mask); |
| 305 | 305 | return value; |
| 306 | 306 | } |
| 307 | 307 | } |
| 308 | | |
| 308 | |
| 309 | 309 | // If we are here, check the peribox via the datamux |
| 310 | 310 | // catch-all for unmapped zones |
| 311 | 311 | value = sgcpu_datamux_r(device, offset, mem_mask); |
| r9498 | r9499 | |
| 317 | 317 | */ |
| 318 | 318 | WRITE16_DEVICE_HANDLER( sgcpu_w ) |
| 319 | 319 | { |
| 320 | | sgcpu_state *sgcpu = get_safe_token(device); |
| 320 | sgcpu_state *sgcpu = get_safe_token(device); |
| 321 | 321 | if (sgcpu->cpu == NULL) return; |
| 322 | 322 | |
| 323 | | // cpu_adjust_icount(sgcpu->cpu, -4); |
| 324 | | |
| 323 | // cpu_adjust_icount(sgcpu->cpu, -4); |
| 324 | |
| 325 | 325 | int addroff = offset << 1; |
| 326 | 326 | UINT16 zone = addroff & 0xe000; |
| 327 | | |
| 327 | |
| 328 | 328 | if (zone==0x0000) |
| 329 | 329 | { |
| 330 | 330 | // ROM0 |
| r9498 | r9499 | |
| 337 | 337 | sgcpu_samsmem_w(device, offset, data, mem_mask); |
| 338 | 338 | return; |
| 339 | 339 | } |
| 340 | | |
| 340 | |
| 341 | 341 | if (zone==0x4000) |
| 342 | 342 | { |
| 343 | 343 | if (sgcpu->internal_dsr) |
| r9498 | r9499 | |
| 383 | 383 | return; |
| 384 | 384 | } |
| 385 | 385 | } |
| 386 | | |
| 386 | |
| 387 | 387 | // If we are here, check the peribox via the datamux |
| 388 | 388 | // catch-all for unmapped zones |
| 389 | 389 | sgcpu_datamux_w(device, offset, data, mem_mask); |
| 390 | 390 | } |
| 391 | 391 | |
| 392 | 392 | /*************************************************************************** |
| 393 | | Control lines |
| 393 | Control lines |
| 394 | 394 | ****************************************************************************/ |
| 395 | 395 | /* |
| 396 | | Handles the EXTINT line. This one is directly connected to the 9901. |
| 396 | Handles the EXTINT line. This one is directly connected to the 9901. |
| 397 | 397 | */ |
| 398 | 398 | WRITE_LINE_DEVICE_HANDLER( card_extint ) |
| 399 | 399 | { |
| r9498 | r9499 | |
| 419 | 419 | } |
| 420 | 420 | |
| 421 | 421 | /*************************************************************************** |
| 422 | | Keyboard/tape control |
| 422 | Keyboard/tape control |
| 423 | 423 | ****************************************************************************/ |
| 424 | 424 | static const char *keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3" }; |
| 425 | 425 | |
| r9498 | r9499 | |
| 456 | 456 | int answer; |
| 457 | 457 | |
| 458 | 458 | answer = ((input_port_read(device->machine, keynames[sgcpu->keyCol >> 1]) >> ((sgcpu->keyCol & 1) * 8)) << 3) & 0xF8; |
| 459 | | |
| 459 | |
| 460 | 460 | if (sgcpu->alphaLockLine == FALSE) |
| 461 | 461 | answer &= ~(input_port_read(device->machine, "ALPHA") << 3); |
| 462 | | |
| 462 | |
| 463 | 463 | return answer; |
| 464 | 464 | } |
| 465 | 465 | |
| r9498 | r9499 | |
| 602 | 602 | |
| 603 | 603 | static DEVICE_START( sgcpu ) |
| 604 | 604 | { |
| 605 | | // // printf("Starting mapper\n"); |
| 605 | // // printf("Starting mapper\n"); |
| 606 | 606 | sgcpu_state *sgcpu = get_safe_token(device); |
| 607 | 607 | sgcpu->cpu = device->machine->device("maincpu"); |
| 608 | 608 | sgcpu->peribox = device->machine->device("peribox"); |
| 609 | 609 | sgcpu->soundchip = device->machine->device("soundgen"); |
| 610 | 610 | sgcpu->video = device->machine->device("video"); |
| 611 | 611 | sgcpu->cassette = device->machine->device("cassette"); |
| 612 | | |
| 612 | |
| 613 | 613 | assert(sgcpu->cpu && sgcpu->peribox && sgcpu->soundchip && sgcpu->video && sgcpu->cassette); |
| 614 | | |
| 614 | |
| 615 | 615 | sgcpu->ram = (UINT16*)malloc(0x080000); |
| 616 | 616 | sgcpu->scratchpad = (UINT16*)malloc(0x0400); |
| 617 | | |
| 617 | |
| 618 | 618 | UINT16 *rom = (UINT16*)memory_region(device->machine, "maincpu"); |
| 619 | 619 | sgcpu->rom0 = rom + 0x2000; |
| 620 | | sgcpu->dsr = rom + 0x6000; |
| 621 | | sgcpu->rom6a = rom + 0x3000; |
| 622 | | sgcpu->rom6b = rom + 0x7000; |
| 620 | sgcpu->dsr = rom + 0x6000; |
| 621 | sgcpu->rom6a = rom + 0x3000; |
| 622 | sgcpu->rom6b = rom + 0x7000; |
| 623 | 623 | } |
| 624 | 624 | |
| 625 | 625 | static DEVICE_STOP( sgcpu ) |
src/mess/machine/ti99/ti_fdc.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | | TI Standard Floppy Disk Controller |
| 3 | | September 2010 |
| 4 | | |
| 5 | | Michael Zapf |
| 2 | TI Standard Floppy Disk Controller |
| 3 | September 2010 |
| 4 | |
| 5 | Michael Zapf |
| 6 | 6 | */ |
| 7 | 7 | #include "emu.h" |
| 8 | 8 | #include "peribox.h" |
| r9498 | r9499 | |
| 24 | 24 | { |
| 25 | 25 | /* Holds the status of the DRQ and IRQ lines. */ |
| 26 | 26 | int DRQ_IRQ_status; |
| 27 | | |
| 27 | |
| 28 | 28 | /* When TRUE, card is accessible. Indicated by a LED. */ |
| 29 | 29 | int selected; |
| 30 | 30 | |
| r9498 | r9499 | |
| 36 | 36 | |
| 37 | 37 | /* When TRUE the CPU is halted while DRQ/IRQ are true. */ |
| 38 | 38 | int hold; |
| 39 | | |
| 39 | |
| 40 | 40 | /* Indicates which drive has been selected. Values are 0, 1, 2, and 4. */ |
| 41 | 41 | // 000 = no drive |
| 42 | 42 | // 001 = drive 1 |
| r9498 | r9499 | |
| 48 | 48 | int SIDSEL; |
| 49 | 49 | |
| 50 | 50 | /* count 4.23s from rising edge of motor_on */ |
| 51 | | emu_timer *motor_on_timer; |
| 52 | | |
| 51 | emu_timer *motor_on_timer; |
| 52 | |
| 53 | 53 | /* Link to the FDC1771 controller on the board. */ |
| 54 | | running_device *controller; |
| 54 | running_device *controller; |
| 55 | 55 | |
| 56 | 56 | /* DSR ROM */ |
| 57 | 57 | UINT8 *rom; |
| 58 | 58 | |
| 59 | 59 | /* Callback lines to the main system. */ |
| 60 | 60 | ti99_peb_connect lines; |
| 61 | | |
| 61 | |
| 62 | 62 | } ti99_fdc_state; |
| 63 | 63 | |
| 64 | 64 | /* Those defines are required because the WD17xx DEVICE_START implementation |
| r9498 | r9499 | |
| 81 | 81 | |
| 82 | 82 | Emulation is faulty because the CPU is actually stopped in the midst of |
| 83 | 83 | instruction, at the end of the memory access |
| 84 | | |
| 85 | | TODO: This has to be replaced by the proper READY handling that is already |
| 86 | | prepared here. (Requires READY handling by the CPU.) |
| 84 | |
| 85 | TODO: This has to be replaced by the proper READY handling that is already |
| 86 | prepared here. (Requires READY handling by the CPU.) |
| 87 | 87 | */ |
| 88 | 88 | static void fdc_handle_hold(running_device *device) |
| 89 | 89 | { |
| 90 | | ti99_fdc_state *card = get_safe_token(device); |
| 90 | ti99_fdc_state *card = get_safe_token(device); |
| 91 | 91 | line_state state; |
| 92 | | |
| 92 | |
| 93 | 93 | if (card->hold && (!card->DRQ_IRQ_status) && card->DVENA) |
| 94 | 94 | state = ASSERT_LINE; |
| 95 | 95 | else |
| 96 | 96 | state = CLEAR_LINE; |
| 97 | | |
| 98 | | // TODO: use READY |
| 97 | |
| 98 | // TODO: use READY |
| 99 | 99 | cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state); |
| 100 | 100 | } |
| 101 | 101 | |
| r9498 | r9499 | |
| 123 | 123 | /*************************************************************************/ |
| 124 | 124 | |
| 125 | 125 | /* |
| 126 | | The CRU read handler. |
| 126 | The CRU read handler. |
| 127 | 127 | bit 0: HLD pin |
| 128 | 128 | bit 1-3: drive n active |
| 129 | 129 | bit 4: 0: motor strobe on |
| r9498 | r9499 | |
| 133 | 133 | */ |
| 134 | 134 | static READ8Z_DEVICE_HANDLER( cru_r ) |
| 135 | 135 | { |
| 136 | | ti99_fdc_state *card = get_safe_token(device); |
| 136 | ti99_fdc_state *card = get_safe_token(device); |
| 137 | 137 | |
| 138 | 138 | if ((offset & 0xff00)==CRU_BASE) |
| 139 | 139 | { |
| r9498 | r9499 | |
| 144 | 144 | // deliver bits 0-7 |
| 145 | 145 | // TODO: HLD pin |
| 146 | 146 | // The DVENA state is returned inverted |
| 147 | | if (card->DVENA) reply |= ((card->DSEL)<<1); |
| 147 | if (card->DVENA) reply |= ((card->DSEL)<<1); |
| 148 | 148 | else reply |= 0x10; |
| 149 | 149 | reply |= 0x40; |
| 150 | 150 | if (card->SIDSEL) reply |= 0x80; |
| 151 | 151 | } |
| 152 | 152 | *value = reply; |
| 153 | | printf("fdc read cru %04x = %02x\n", offset, reply); |
| 154 | 153 | } |
| 155 | 154 | } |
| 156 | 155 | |
| 157 | 156 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 158 | 157 | { |
| 159 | | ti99_fdc_state *card = get_safe_token(device); |
| 158 | ti99_fdc_state *card = get_safe_token(device); |
| 160 | 159 | int drive, drivebit; |
| 161 | 160 | |
| 162 | 161 | if ((offset & 0xff00)==CRU_BASE) |
| 163 | 162 | { |
| 164 | | printf("fdc write cru %04x = %02x\n", offset, data); |
| 165 | | |
| 166 | 163 | int bit = (offset >> 1) & 0x07; |
| 167 | 164 | switch (bit) |
| 168 | 165 | { |
| r9498 | r9499 | |
| 180 | 177 | } |
| 181 | 178 | card->strobe_motor = data; |
| 182 | 179 | break; |
| 183 | | |
| 180 | |
| 184 | 181 | case 2: |
| 185 | 182 | /* Set disk ready/hold (bit 2) */ |
| 186 | 183 | // 0: ignore IRQ and DRQ |
| 187 | | // 1: TMS9900 is stopped until IRQ or DRQ are set |
| 188 | | // OR the motor stops rotating - rotates for 4.23s after write |
| 189 | | // to CRU bit 1 |
| 190 | | // This is not emulated and could cause the TI99 to lock up |
| 184 | // 1: TMS9900 is stopped until IRQ or DRQ are set |
| 185 | // OR the motor stops rotating - rotates for 4.23s after write |
| 186 | // to CRU bit 1 |
| 187 | // This is not emulated and could cause the TI99 to lock up |
| 191 | 188 | card->hold = data; |
| 192 | 189 | fdc_handle_hold(device); |
| 193 | 190 | break; |
| r9498 | r9499 | |
| 202 | 199 | /* Select drive X (bits 4-6) */ |
| 203 | 200 | drive = bit-4; /* drive # (0-2) */ |
| 204 | 201 | drivebit = 1<<drive; |
| 205 | | |
| 202 | |
| 206 | 203 | if (data) |
| 207 | 204 | { |
| 208 | 205 | if (!(card->DSEL & drivebit)) /* select drive */ |
| 209 | 206 | { |
| 210 | 207 | if (card->DSEL != 0) |
| 211 | | logerror("ti_fdc: Multiple drives selected, %02x\n", card->DSEL); |
| 208 | logerror("ti_fdc: Multiple drives selected, %02x\n", card->DSEL); |
| 212 | 209 | card->DSEL |= drivebit; |
| 213 | 210 | wd17xx_set_drive(card->controller, drive); |
| 214 | 211 | /*wd17xx_set_side(DSKside);*/ |
| r9498 | r9499 | |
| 217 | 214 | else |
| 218 | 215 | card->DSEL &= ~drivebit; |
| 219 | 216 | break; |
| 220 | | |
| 217 | |
| 221 | 218 | case 7: |
| 222 | 219 | /* Select side of disk (bit 7) */ |
| 223 | 220 | card->SIDSEL = data; |
| 224 | 221 | wd17xx_set_side(card->controller, data); |
| 225 | 222 | break; |
| 226 | | } |
| 223 | } |
| 227 | 224 | } |
| 228 | 225 | } |
| 229 | 226 | |
| r9498 | r9499 | |
| 232 | 229 | */ |
| 233 | 230 | static READ8Z_DEVICE_HANDLER( data_r ) |
| 234 | 231 | { |
| 235 | | ti99_fdc_state *card = get_safe_token(device); |
| 232 | ti99_fdc_state *card = get_safe_token(device); |
| 236 | 233 | |
| 237 | 234 | if (card->selected) |
| 238 | 235 | { |
| 239 | | if ((offset & 0xe000)==0x4000) |
| 236 | if ((offset & 0xe000)==0x4000) |
| 240 | 237 | { |
| 241 | 238 | // only use the even addresses from 1ff0 to 1ff6. |
| 242 | 239 | // Note that data is inverted. |
| r9498 | r9499 | |
| 249 | 246 | reply = card->rom[offset & 0x1fff]; |
| 250 | 247 | |
| 251 | 248 | *value = reply; |
| 252 | | printf("fdc read %04x = %02x, %c\n", offset, *value, (char)*value); |
| 253 | 249 | } |
| 254 | 250 | } |
| 255 | 251 | } |
| r9498 | r9499 | |
| 259 | 255 | */ |
| 260 | 256 | static WRITE8_DEVICE_HANDLER( data_w ) |
| 261 | 257 | { |
| 262 | | ti99_fdc_state *card = get_safe_token(device); |
| 258 | ti99_fdc_state *card = get_safe_token(device); |
| 263 | 259 | if (card->selected) |
| 264 | 260 | { |
| 265 | | if ((offset & 0xe000)==0x4000) |
| 261 | if ((offset & 0xe000)==0x4000) |
| 266 | 262 | { |
| 267 | | printf("fdc write %04x = %02x\n", offset, data); |
| 268 | 263 | // only use the even addresses from 1ff8 to 1ffe. |
| 269 | 264 | // Note that data is inverted. |
| 270 | 265 | // 0101 1111 1111 1xx0 |
| r9498 | r9499 | |
| 280 | 275 | static WRITE_LINE_DEVICE_HANDLER( ti_fdc_intrq_w ) |
| 281 | 276 | { |
| 282 | 277 | running_device *carddev = device->owner(); |
| 283 | | ti99_fdc_state *card = get_safe_token(carddev); |
| 278 | ti99_fdc_state *card = get_safe_token(carddev); |
| 284 | 279 | |
| 285 | 280 | if (state) |
| 286 | 281 | { |
| r9498 | r9499 | |
| 300 | 295 | static WRITE_LINE_DEVICE_HANDLER( ti_fdc_drq_w ) |
| 301 | 296 | { |
| 302 | 297 | running_device *carddev = device->owner(); |
| 303 | | ti99_fdc_state *card = get_safe_token(carddev); |
| 298 | ti99_fdc_state *card = get_safe_token(carddev); |
| 304 | 299 | |
| 305 | 300 | if (state) |
| 306 | 301 | card->DRQ_IRQ_status |= fdc_DRQ; |
| r9498 | r9499 | |
| 316 | 311 | static TIMER_CALLBACK(motor_on_timer_callback) |
| 317 | 312 | { |
| 318 | 313 | running_device *device = (running_device *)ptr; |
| 319 | | ti99_fdc_state *card = get_safe_token(device); |
| 314 | ti99_fdc_state *card = get_safe_token(device); |
| 320 | 315 | card->DVENA = 0; |
| 321 | 316 | fdc_handle_hold(device); |
| 322 | 317 | } |
| r9498 | r9499 | |
| 329 | 324 | { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, NULL } |
| 330 | 325 | }; |
| 331 | 326 | |
| 332 | | static ti99_peb_card fdc_card = |
| 327 | static ti99_peb_card fdc_card = |
| 333 | 328 | { |
| 334 | 329 | data_r, |
| 335 | 330 | data_w, |
| 336 | 331 | cru_r, |
| 337 | 332 | cru_w, |
| 338 | | |
| 339 | | NULL, NULL, NULL, NULL |
| 333 | |
| 334 | NULL, NULL, NULL, NULL |
| 340 | 335 | }; |
| 341 | 336 | |
| 342 | 337 | static DEVICE_START( ti99_fdc ) |
| 343 | 338 | { |
| 344 | 339 | ti99_fdc_state *card = (ti99_fdc_state*)downcast<legacy_device_base *>(device)->token(); |
| 345 | | |
| 340 | |
| 346 | 341 | /* Resolve the callbacks to the PEB */ |
| 347 | 342 | peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config(); |
| 348 | 343 | devcb_resolve_write_line(&card->lines.ready, &topeb->ready, device); |
| r9498 | r9499 | |
| 350 | 345 | card->motor_on_timer = timer_alloc(device->machine, motor_on_timer_callback, (void *)device); |
| 351 | 346 | |
| 352 | 347 | astring *region = new astring(); |
| 353 | | astring_assemble_3(region, device->tag(), ":", fdc_region); |
| 348 | astring_assemble_3(region, device->tag(), ":", fdc_region); |
| 354 | 349 | card->rom = memory_region(device->machine, astring_c(region)); |
| 355 | 350 | card->controller = device->subdevice("fd1771"); |
| 356 | 351 | } |
| r9498 | r9499 | |
| 367 | 362 | /* If the card is selected in the menu, register the card */ |
| 368 | 363 | if (input_port_read(device->machine, "DISKCTRL") == DISK_TIFDC) |
| 369 | 364 | { |
| 370 | | running_device *peb = device->owner(); |
| 365 | running_device *peb = device->owner(); |
| 371 | 366 | int success = mount_card(peb, device, &fdc_card, get_pebcard_config(device)->slot); |
| 372 | 367 | if (!success) return; |
| 373 | 368 | |
src/mess/machine/ti99/tn_usbsm.c
| r9498 | r9499 | |
| 20 | 20 | either that the LSByte of a word is accessed first or that the MSByte of a word |
| 21 | 21 | is accessed first. The former is true with ti-99/4(a), the latter with the |
| 22 | 22 | tms9995 CPU used by Geneve and ti-99/8. |
| 23 | | |
| 23 | |
| 24 | 24 | TODO: |
| 25 | 25 | * Test SmartMedia support |
| 26 | 26 | * Implement USB controller and assorted USB devices |
| r9498 | r9499 | |
| 40 | 40 | |
| 41 | 41 | #define CRU_BASE 0x1600 |
| 42 | 42 | |
| 43 | | typedef ti99_pebcard_config tn_usbsm_config; |
| 43 | typedef ti99_pebcard_config tn_usbsm_config; |
| 44 | 44 | |
| 45 | 45 | typedef struct _tn_usbsm_state |
| 46 | 46 | { |
| r9498 | r9499 | |
| 53 | 53 | int tms9995_mode; |
| 54 | 54 | |
| 55 | 55 | UINT8 input_latch; |
| 56 | | |
| 56 | |
| 57 | 57 | UINT8 output_latch; |
| 58 | 58 | UINT16 *ram; |
| 59 | | |
| 59 | |
| 60 | 60 | /* Callback lines to the main system. */ |
| 61 | 61 | ti99_peb_connect lines; |
| 62 | | |
| 62 | |
| 63 | 63 | } tn_usbsm_state; |
| 64 | 64 | |
| 65 | 65 | enum |
| r9498 | r9499 | |
| 82 | 82 | static UINT16 usbsm_mem_16_r(running_device *device, offs_t offset) |
| 83 | 83 | { |
| 84 | 84 | UINT16 reply = 0; |
| 85 | | tn_usbsm_state *card = get_safe_token(device); |
| 85 | tn_usbsm_state *card = get_safe_token(device); |
| 86 | 86 | |
| 87 | 87 | if (offset < 0x2800) |
| 88 | 88 | { /* 0x4000-0x4fff range */ |
| r9498 | r9499 | |
| 115 | 115 | */ |
| 116 | 116 | static void usbsm_mem_16_w(running_device *device, offs_t offset, UINT16 data) |
| 117 | 117 | { |
| 118 | | tn_usbsm_state *card = get_safe_token(device); |
| 118 | tn_usbsm_state *card = get_safe_token(device); |
| 119 | 119 | |
| 120 | 120 | if (offset < 0x2800) |
| 121 | 121 | { /* 0x4000-0x4fff range */ |
| r9498 | r9499 | |
| 160 | 160 | */ |
| 161 | 161 | static READ8Z_DEVICE_HANDLER( cru_rz ) |
| 162 | 162 | { |
| 163 | | tn_usbsm_state *card = get_safe_token(device); |
| 163 | tn_usbsm_state *card = get_safe_token(device); |
| 164 | 164 | |
| 165 | 165 | if ((offset & 0xff00)==CRU_BASE) |
| 166 | 166 | { |
| 167 | 167 | UINT8 reply = 0; |
| 168 | 168 | running_device *smartmedia = card->smartmedia; |
| 169 | 169 | offset &= 3; |
| 170 | | |
| 170 | |
| 171 | 171 | if (offset == 0) |
| 172 | 172 | { |
| 173 | 173 | // bit |
| r9498 | r9499 | |
| 176 | 176 | // 2 >1x04 1: USB Host controller suspended. |
| 177 | 177 | // 3 >1x06 1: USB Device controller suspended. |
| 178 | 178 | // 4 >1x08 0: Strata FEEPROM is busy. |
| 179 | | // 1: Strata FEEPROM is ready. |
| 179 | // 1: Strata FEEPROM is ready. |
| 180 | 180 | // 5 >1x0A 0: SmartMedia card is busy. |
| 181 | | // 1: SmartMedia card absent or ready. |
| 181 | // 1: SmartMedia card absent or ready. |
| 182 | 182 | // 6 >1x0C 0: No SmartMedia card present. |
| 183 | | // 1: A card is in the connector. |
| 183 | // 1: A card is in the connector. |
| 184 | 184 | // 7 >1x0E 0: SmartMedia card is protected. |
| 185 | | // 1: Card absent or not protected. |
| 186 | | |
| 185 | // 1: Card absent or not protected. |
| 186 | |
| 187 | 187 | reply = 0x33; |
| 188 | 188 | if (!smartmedia_present(smartmedia)) |
| 189 | 189 | reply |= 0xc0; |
| r9498 | r9499 | |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | 197 | /* |
| 198 | | CRU write |
| 198 | CRU write |
| 199 | 199 | */ |
| 200 | 200 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 201 | 201 | { |
| 202 | | tn_usbsm_state *card = get_safe_token(device); |
| 202 | tn_usbsm_state *card = get_safe_token(device); |
| 203 | 203 | |
| 204 | 204 | if ((offset & 0xff00)==CRU_BASE) |
| 205 | 205 | { |
| r9498 | r9499 | |
| 210 | 210 | case 0: |
| 211 | 211 | card->selected = data; |
| 212 | 212 | break; |
| 213 | | |
| 213 | |
| 214 | 214 | case 1: /* enable I/O registers */ |
| 215 | 215 | case 2: /* enable interrupts */ |
| 216 | 216 | case 3: /* enable SmartMedia card */ |
| r9498 | r9499 | |
| 236 | 236 | else |
| 237 | 237 | card->feeprom_page &= ~ (1 << (bit-5)); |
| 238 | 238 | break; |
| 239 | | |
| 239 | |
| 240 | 240 | case 16: /* SRAM page */ |
| 241 | 241 | case 17: |
| 242 | 242 | case 18: |
| r9498 | r9499 | |
| 259 | 259 | */ |
| 260 | 260 | static READ8Z_DEVICE_HANDLER( data_rz ) |
| 261 | 261 | { |
| 262 | | tn_usbsm_state *card = get_safe_token(device); |
| 262 | tn_usbsm_state *card = get_safe_token(device); |
| 263 | 263 | |
| 264 | | if (((offset & 0xe000)==0x4000) && card->selected) |
| 264 | if (((offset & 0xe000)==0x4000) && card->selected) |
| 265 | 265 | { |
| 266 | 266 | if (card->tms9995_mode ? (!(offset & 1)) : (offset & 1)) |
| 267 | 267 | { /* first read triggers 16-bit read cycle */ |
| 268 | 268 | card->input_latch = usbsm_mem_16_r(device, offset >> 1); |
| 269 | 269 | } |
| 270 | | |
| 270 | |
| 271 | 271 | /* return latched input */ |
| 272 | 272 | *value = (offset & 1) ? card->input_latch : (card->input_latch >> 8); |
| 273 | 273 | } |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | 276 | /* |
| 277 | | Memory write. The controller is 16 bit, so we need to demultiplex again. |
| 277 | Memory write. The controller is 16 bit, so we need to demultiplex again. |
| 278 | 278 | */ |
| 279 | 279 | static WRITE8_DEVICE_HANDLER( data_w ) |
| 280 | 280 | { |
| 281 | | tn_usbsm_state *card = get_safe_token(device); |
| 281 | tn_usbsm_state *card = get_safe_token(device); |
| 282 | 282 | |
| 283 | | if (((offset & 0xe000)==0x4000) && card->selected) |
| 283 | if (((offset & 0xe000)==0x4000) && card->selected) |
| 284 | 284 | { |
| 285 | 285 | /* latch write */ |
| 286 | 286 | if (offset & 1) |
| 287 | 287 | card->output_latch = (card->output_latch & 0xff00) | data; |
| 288 | 288 | else |
| 289 | 289 | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 290 | | |
| 290 | |
| 291 | 291 | if ((card->tms9995_mode)? (offset & 1) : (!(offset & 1))) |
| 292 | 292 | { /* second write triggers 16-bit write cycle */ |
| 293 | 293 | usbsm_mem_16_w(device, offset >> 1, card->output_latch); |
| 294 | | } |
| 294 | } |
| 295 | 295 | } |
| 296 | 296 | } |
| 297 | 297 | |
| 298 | 298 | /**************************************************************************/ |
| 299 | 299 | |
| 300 | | static ti99_peb_card tn_usbsm_card = |
| 300 | static ti99_peb_card tn_usbsm_card = |
| 301 | 301 | { |
| 302 | 302 | data_rz, data_w, // memory access read/write |
| 303 | 303 | cru_rz, cru_w, // CRU access |
| 304 | | NULL, NULL, // SENILA/B access |
| 304 | NULL, NULL, // SENILA/B access |
| 305 | 305 | NULL, NULL // 16 bit access (none here) |
| 306 | 306 | }; |
| 307 | 307 | |
| r9498 | r9499 | |
| 322 | 322 | tn_usbsm_state *card = (tn_usbsm_state*)downcast<legacy_device_base *>(device)->token(); |
| 323 | 323 | /* Register the card */ |
| 324 | 324 | running_device *peb = device->owner(); |
| 325 | | |
| 325 | |
| 326 | 326 | if (input_port_read(device->machine, "HDCTRL") & HD_USB) |
| 327 | 327 | { |
| 328 | 328 | int success = mount_card(peb, device, &tn_usbsm_card, get_pebcard_config(device)->slot); |
| 329 | 329 | if (!success) return; |
| 330 | | |
| 330 | |
| 331 | 331 | card->feeprom_page = 0; |
| 332 | 332 | card->sram_page = 0; |
| 333 | 333 | card->cru_register = 0; |
src/mess/machine/ti99/evpc.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | | SNUG Enhanced Video Processor Card (evpc) |
| 2 | SNUG Enhanced Video Processor Card (evpc) |
| 3 | 3 | based on v9938 (may also be equipped with v9958) |
| 4 | 4 | Can be used with TI-99/4A as an add-on card; internal VDP must be removed |
| 5 | 5 | |
| 6 | 6 | The SGCPU ("TI-99/4P") only runs with EVPC. |
| 7 | | Michael Zapf |
| 8 | | Rewritten as device |
| 9 | | October 2010 |
| 7 | Michael Zapf |
| 8 | Rewritten as device |
| 9 | October 2010 |
| 10 | 10 | */ |
| 11 | 11 | #include "emu.h" |
| 12 | 12 | #include "peribox.h" |
| r9498 | r9499 | |
| 21 | 21 | |
| 22 | 22 | typedef struct _evpc_palette |
| 23 | 23 | { |
| 24 | | UINT8 read_index, write_index, mask; |
| 24 | UINT8 read_index, write_index, mask; |
| 25 | 25 | int read; |
| 26 | 26 | int state; |
| 27 | 27 | struct { UINT8 red, green, blue; } color[0x100]; |
| r9498 | r9499 | |
| 31 | 31 | typedef struct _ti99_evpc_state |
| 32 | 32 | { |
| 33 | 33 | int selected; |
| 34 | | UINT8 *dsrrom; |
| 34 | UINT8 *dsrrom; |
| 35 | 35 | int RAMEN; |
| 36 | 36 | int dsr_page; |
| 37 | | UINT8 *novram; /* NOVRAM area */ |
| 37 | UINT8 *novram; /* NOVRAM area */ |
| 38 | 38 | evpc_palette palette; |
| 39 | 39 | ti99_peb_connect lines; |
| 40 | | |
| 40 | |
| 41 | 41 | } ti99_evpc_state; |
| 42 | 42 | |
| 43 | 43 | INLINE ti99_evpc_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 95 | 95 | */ |
| 96 | 96 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 97 | 97 | { |
| 98 | | ti99_evpc_state *card = get_safe_token(device); |
| 98 | ti99_evpc_state *card = get_safe_token(device); |
| 99 | 99 | |
| 100 | 100 | if ((offset & 0xff00)==EVPC_CRU_BASE) |
| 101 | 101 | { |
| r9498 | r9499 | |
| 105 | 105 | case 0: |
| 106 | 106 | card->selected = data; |
| 107 | 107 | break; |
| 108 | | |
| 108 | |
| 109 | 109 | case 1: |
| 110 | 110 | if (data) |
| 111 | 111 | card->dsr_page |= 1; |
| 112 | 112 | else |
| 113 | 113 | card->dsr_page &= ~1; |
| 114 | 114 | break; |
| 115 | | |
| 115 | |
| 116 | 116 | case 2: |
| 117 | 117 | break; |
| 118 | | |
| 118 | |
| 119 | 119 | case 3: |
| 120 | 120 | card->RAMEN = data; |
| 121 | 121 | break; |
| 122 | | |
| 122 | |
| 123 | 123 | case 4: |
| 124 | 124 | if (data) |
| 125 | 125 | card->dsr_page |= 4; |
| 126 | 126 | else |
| 127 | 127 | card->dsr_page &= ~4; |
| 128 | 128 | break; |
| 129 | | |
| 129 | |
| 130 | 130 | case 5: |
| 131 | 131 | if (data) |
| 132 | 132 | card->dsr_page |= 2; |
| 133 | 133 | else |
| 134 | 134 | card->dsr_page &= ~2; |
| 135 | 135 | break; |
| 136 | | |
| 136 | |
| 137 | 137 | case 6: |
| 138 | 138 | break; |
| 139 | | |
| 139 | |
| 140 | 140 | case 7: |
| 141 | 141 | break; |
| 142 | 142 | } |
| r9498 | r9499 | |
| 151 | 151 | */ |
| 152 | 152 | static READ8Z_DEVICE_HANDLER( data_rz ) |
| 153 | 153 | { |
| 154 | | ti99_evpc_state *card = get_safe_token(device); |
| 154 | ti99_evpc_state *card = get_safe_token(device); |
| 155 | 155 | |
| 156 | 156 | if (card->selected) |
| 157 | 157 | { |
| 158 | | if (card->dsrrom==NULL) |
| 158 | if (card->dsrrom==NULL) |
| 159 | 159 | { |
| 160 | 160 | logerror("evpc: no dsrrom\n"); |
| 161 | 161 | return; |
| 162 | 162 | } |
| 163 | | |
| 163 | |
| 164 | 164 | if ((offset & 0xe000)==0x4000) |
| 165 | 165 | { |
| 166 | 166 | if ((offset & 0x1ff0)==0x1ff0) |
| r9498 | r9499 | |
| 172 | 172 | /* Palette Read Address Register */ |
| 173 | 173 | *value = card->palette.write_index; |
| 174 | 174 | break; |
| 175 | | |
| 175 | |
| 176 | 176 | case 2: |
| 177 | 177 | /* Palette Read Color Value */ |
| 178 | 178 | if (card->palette.read) |
| r9498 | r9499 | |
| 197 | 197 | } |
| 198 | 198 | } |
| 199 | 199 | break; |
| 200 | | |
| 200 | |
| 201 | 201 | case 4: |
| 202 | 202 | /* Palette Read Pixel Mask */ |
| 203 | 203 | *value = card->palette.mask; |
| r9498 | r9499 | |
| 260 | 260 | card->palette.state = 0; |
| 261 | 261 | card->palette.read = 0; |
| 262 | 262 | break; |
| 263 | | |
| 263 | |
| 264 | 264 | case 10: |
| 265 | 265 | /* Palette Write Color Value */ |
| 266 | 266 | logerror("EVPC palette color write\n"); |
| r9498 | r9499 | |
| 287 | 287 | //evpc_palette.dirty = 1; |
| 288 | 288 | } |
| 289 | 289 | break; |
| 290 | | |
| 290 | |
| 291 | 291 | case 12: |
| 292 | 292 | /* Palette Write Pixel Mask */ |
| 293 | 293 | logerror("EVPC palette mask write\n"); |
| 294 | 294 | card->palette.mask = data; |
| 295 | 295 | break; |
| 296 | | |
| 296 | |
| 297 | 297 | case 14: |
| 298 | 298 | /* Palette Write Address Register for Color Value */ |
| 299 | 299 | logerror("EVPC palette address write (for read access)\n"); |
| r9498 | r9499 | |
| 318 | 318 | } |
| 319 | 319 | } |
| 320 | 320 | |
| 321 | | static ti99_peb_card evpc_card = |
| 321 | static ti99_peb_card evpc_card = |
| 322 | 322 | { |
| 323 | 323 | data_rz, |
| 324 | 324 | data_w, |
| 325 | 325 | cru_rz, |
| 326 | 326 | cru_w, |
| 327 | | |
| 328 | | NULL, NULL, NULL, NULL |
| 327 | |
| 328 | NULL, NULL, NULL, NULL |
| 329 | 329 | }; |
| 330 | 330 | |
| 331 | 331 | static DEVICE_START( ti99_evpc ) |
| 332 | 332 | { |
| 333 | | ti99_evpc_state *card = get_safe_token(device); |
| 333 | ti99_evpc_state *card = get_safe_token(device); |
| 334 | 334 | card->novram = (UINT8*)malloc(256); // need that already now for NVRAM handling |
| 335 | | |
| 335 | |
| 336 | 336 | /* Resolve the callbacks to the PEB */ |
| 337 | 337 | peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config(); |
| 338 | 338 | devcb_resolve_write_line(&card->lines.ready, &topeb->ready, device); |
| r9498 | r9499 | |
| 341 | 341 | static DEVICE_STOP( ti99_evpc ) |
| 342 | 342 | { |
| 343 | 343 | logerror("ti99_evpc: stop\n"); |
| 344 | | ti99_evpc_state *card = get_safe_token(device); |
| 344 | ti99_evpc_state *card = get_safe_token(device); |
| 345 | 345 | free(card->novram); |
| 346 | 346 | } |
| 347 | 347 | |
| 348 | 348 | static DEVICE_RESET( ti99_evpc ) |
| 349 | 349 | { |
| 350 | 350 | logerror("ti99_evpc: reset\n"); |
| 351 | | ti99_evpc_state *card = get_safe_token(device); |
| 351 | ti99_evpc_state *card = get_safe_token(device); |
| 352 | 352 | astring *region = new astring(); |
| 353 | 353 | |
| 354 | 354 | /* If the card is selected in the menu, register the card */ |
| 355 | | running_device *peb = device->owner(); |
| 355 | running_device *peb = device->owner(); |
| 356 | 356 | int success = mount_card(peb, device, &evpc_card, get_pebcard_config(device)->slot); |
| 357 | | if (!success) |
| 357 | if (!success) |
| 358 | 358 | { |
| 359 | 359 | logerror("evpc: Could not mount card.\n"); |
| 360 | 360 | return; |
| 361 | 361 | } |
| 362 | 362 | card->RAMEN = 0; |
| 363 | 363 | card->dsr_page = 0; |
| 364 | | |
| 365 | | astring_assemble_3(region, device->tag(), ":", evpc_region); |
| 366 | | |
| 364 | |
| 365 | astring_assemble_3(region, device->tag(), ":", evpc_region); |
| 366 | |
| 367 | 367 | card->dsrrom = memory_region(device->machine, astring_c(region)); |
| 368 | 368 | } |
| 369 | 369 | |
| r9498 | r9499 | |
| 378 | 378 | if (read_or_write==0) |
| 379 | 379 | { |
| 380 | 380 | logerror("evpc: device nvram load %s\n", astring_c(hsname)); |
| 381 | | |
| 381 | |
| 382 | 382 | filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_READ, &nvfile); |
| 383 | 383 | if (filerr == FILERR_NONE) |
| 384 | 384 | { |
| r9498 | r9499 | |
| 391 | 391 | { |
| 392 | 392 | logerror("evpc: device nvram save %s\n", astring_c(hsname)); |
| 393 | 393 | filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &nvfile); |
| 394 | | |
| 394 | |
| 395 | 395 | if (filerr == FILERR_NONE) |
| 396 | 396 | { |
| 397 | 397 | if (mame_fwrite(nvfile, card->novram, 256) != 256) |
src/mess/machine/ti99/videowrp.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | 2 | TI-99/4(A) and /8 Video subsystem |
| 3 | | This device actually wraps the naked video chip implementation |
| 3 | This device actually wraps the naked video chip implementation |
| 4 | 4 | |
| 5 | 5 | EVPC (Enhanced Video Processor Card) from SNUG |
| 6 | 6 | based on v9938 (may also be equipped with v9958) |
| r9498 | r9499 | |
| 16 | 16 | |
| 17 | 17 | typedef struct _ti99_video_state |
| 18 | 18 | { |
| 19 | | address_space *space; |
| 19 | address_space *space; |
| 20 | 20 | running_device *cpu; |
| 21 | 21 | int chip; |
| 22 | 22 | } ti99_video_state; |
| r9498 | r9499 | |
| 42 | 42 | */ |
| 43 | 43 | READ16_DEVICE_HANDLER( ti_tms991x_r16 ) |
| 44 | 44 | { |
| 45 | | ti99_video_state *video = get_safe_token(device); |
| 46 | | // cpu_adjust_icount(video->cpu, -4); |
| 45 | ti99_video_state *video = get_safe_token(device); |
| 46 | // cpu_adjust_icount(video->cpu, -4); |
| 47 | 47 | |
| 48 | 48 | if (offset & 1) |
| 49 | 49 | { /* read VDP status */ |
| r9498 | r9499 | |
| 60 | 60 | */ |
| 61 | 61 | READ8Z_DEVICE_HANDLER( ti8_tms991x_rz ) |
| 62 | 62 | { |
| 63 | | ti99_video_state *video = get_safe_token(device); |
| 64 | | // cpu_adjust_icount(video->cpu, -4); |
| 63 | ti99_video_state *video = get_safe_token(device); |
| 64 | // cpu_adjust_icount(video->cpu, -4); |
| 65 | 65 | |
| 66 | 66 | if (offset & 2) |
| 67 | 67 | { /* read VDP status */ |
| r9498 | r9499 | |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | /* |
| 77 | | Memory read (EVPC) |
| 77 | Memory read (EVPC) |
| 78 | 78 | */ |
| 79 | 79 | READ16_DEVICE_HANDLER( ti_v9938_r16 ) |
| 80 | 80 | { |
| 81 | | ti99_video_state *video = get_safe_token(device); |
| 82 | | // cpu_adjust_icount(video->cpu, -4); |
| 81 | ti99_video_state *video = get_safe_token(device); |
| 82 | // cpu_adjust_icount(video->cpu, -4); |
| 83 | 83 | |
| 84 | 84 | if (offset & 1) |
| 85 | 85 | { /* read VDP status */ |
| r9498 | r9499 | |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | 94 | /* |
| 95 | | Memory write |
| 95 | Memory write |
| 96 | 96 | */ |
| 97 | 97 | WRITE16_DEVICE_HANDLER( ti_tms991x_w16 ) |
| 98 | 98 | { |
| 99 | | ti99_video_state *video = get_safe_token(device); |
| 100 | | // cpu_adjust_icount(video->cpu, -4); |
| 99 | ti99_video_state *video = get_safe_token(device); |
| 100 | // cpu_adjust_icount(video->cpu, -4); |
| 101 | 101 | |
| 102 | 102 | if (offset & 1) |
| 103 | 103 | { /* write VDP address */ |
| r9498 | r9499 | |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | /* |
| 113 | | Memory write (TI-99/8) |
| 113 | Memory write (TI-99/8) |
| 114 | 114 | */ |
| 115 | 115 | WRITE8_DEVICE_HANDLER( ti8_tms991x_w ) |
| 116 | 116 | { |
| 117 | | ti99_video_state *video = get_safe_token(device); |
| 118 | | // cpu_adjust_icount(video->cpu, -4); |
| 117 | ti99_video_state *video = get_safe_token(device); |
| 118 | // cpu_adjust_icount(video->cpu, -4); |
| 119 | 119 | |
| 120 | 120 | if (offset & 2) |
| 121 | 121 | { /* write VDP address */ |
| r9498 | r9499 | |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | 130 | /* |
| 131 | | Memory write (EVPC) |
| 131 | Memory write (EVPC) |
| 132 | 132 | */ |
| 133 | 133 | WRITE16_DEVICE_HANDLER ( ti_v9938_w16 ) |
| 134 | 134 | { |
| 135 | | ti99_video_state *video = get_safe_token(device); |
| 136 | | // cpu_adjust_icount(video->cpu, -4); |
| 135 | ti99_video_state *video = get_safe_token(device); |
| 136 | // cpu_adjust_icount(video->cpu, -4); |
| 137 | 137 | |
| 138 | 138 | switch (offset & 3) |
| 139 | 139 | { |
| r9498 | r9499 | |
| 157 | 157 | } |
| 158 | 158 | |
| 159 | 159 | /* |
| 160 | | Video write (Geneve) |
| 160 | Video write (Geneve) |
| 161 | 161 | */ |
| 162 | 162 | WRITE8_DEVICE_HANDLER ( gen_v9938_w ) |
| 163 | 163 | { |
| 164 | | ti99_video_state *video = get_safe_token(device); |
| 165 | | // cpu_adjust_icount(video->cpu, -4); |
| 164 | ti99_video_state *video = get_safe_token(device); |
| 165 | // cpu_adjust_icount(video->cpu, -4); |
| 166 | 166 | |
| 167 | 167 | switch (offset & 6) |
| 168 | 168 | { |
| r9498 | r9499 | |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | 188 | /* |
| 189 | | Video read (Geneve). |
| 189 | Video read (Geneve). |
| 190 | 190 | */ |
| 191 | 191 | READ8Z_DEVICE_HANDLER( gen_v9938_rz ) |
| 192 | 192 | { |
| 193 | | ti99_video_state *video = get_safe_token(device); |
| 194 | | // cpu_adjust_icount(video->cpu, -4); |
| 195 | | |
| 193 | ti99_video_state *video = get_safe_token(device); |
| 194 | // cpu_adjust_icount(video->cpu, -4); |
| 195 | |
| 196 | 196 | if (offset & 2) |
| 197 | 197 | { /* read VDP status */ |
| 198 | 198 | *value = v9938_0_status_r(video->space, 0); |
| r9498 | r9499 | |
| 205 | 205 | |
| 206 | 206 | READ16_DEVICE_HANDLER ( ti_video_rnop ) |
| 207 | 207 | { |
| 208 | | ti99_video_state *video = get_safe_token(device); |
| 208 | ti99_video_state *video = get_safe_token(device); |
| 209 | 209 | cpu_adjust_icount(video->cpu, -4); |
| 210 | 210 | return 0; |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | WRITE16_DEVICE_HANDLER ( ti_video_wnop ) |
| 214 | 214 | { |
| 215 | | ti99_video_state *video = get_safe_token(device); |
| 215 | ti99_video_state *video = get_safe_token(device); |
| 216 | 216 | cpu_adjust_icount(video->cpu, -4); |
| 217 | 217 | } |
| 218 | 218 | /**************************************************************************/ |
| r9498 | r9499 | |
| 220 | 220 | |
| 221 | 221 | void video_update_mouse( running_device *device, int delta_x, int delta_y, int buttons) |
| 222 | 222 | { |
| 223 | | ti99_video_state *video = get_safe_token(device); |
| 223 | ti99_video_state *video = get_safe_token(device); |
| 224 | 224 | // TODO: V9938 to be devicified |
| 225 | 225 | if (video->chip==TI_V9938) |
| 226 | 226 | v9938_update_mouse_state(0, delta_x, delta_y, buttons & 3); |
| r9498 | r9499 | |
| 231 | 231 | |
| 232 | 232 | static DEVICE_START( ti99_video ) |
| 233 | 233 | { |
| 234 | | ti99_video_state *video = get_safe_token(device); |
| 234 | ti99_video_state *video = get_safe_token(device); |
| 235 | 235 | const ti99_video_config* conf = (const ti99_video_config*)get_config(device); |
| 236 | | |
| 236 | |
| 237 | 237 | video->cpu = device->machine->device("maincpu"); |
| 238 | 238 | video->space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM); |
| 239 | 239 | |
| r9498 | r9499 | |
| 246 | 246 | running_machine *machine = device->machine; |
| 247 | 247 | VIDEO_START_CALL(generic_bitmapped); |
| 248 | 248 | v9938_init(machine, 0, *machine->primary_screen, machine->generic.tmpbitmap, |
| 249 | | MODEL_V9938, 0x20000, conf->callback); /* v38 with 128 kb of video RAM */ |
| 249 | MODEL_V9938, 0x20000, conf->callback); /* v38 with 128 kb of video RAM */ |
| 250 | 250 | } |
| 251 | 251 | } |
| 252 | 252 | |
src/mess/machine/ti99/speech8.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | 2 | TI-99/8 Speech synthesizer subsystem |
| 3 | | |
| 4 | | The TI-99/8 contains a speech synthesizer inside the console, so we cannot |
| 5 | | reuse the spchsyn implementation of the P-Box speech synthesizer. |
| 6 | | |
| 3 | |
| 4 | The TI-99/8 contains a speech synthesizer inside the console, so we cannot |
| 5 | reuse the spchsyn implementation of the P-Box speech synthesizer. |
| 6 | |
| 7 | 7 | Note that this subsystem also contains the speech roms. |
| 8 | 8 | */ |
| 9 | 9 | #include "emu.h" |
| r9498 | r9499 | |
| 16 | 16 | |
| 17 | 17 | typedef struct _ti99_speech8_state |
| 18 | 18 | { |
| 19 | | running_device *vsp; |
| 20 | | UINT8 *speechrom_data; /* pointer to speech ROM data */ |
| 19 | running_device *vsp; |
| 20 | UINT8 *speechrom_data; /* pointer to speech ROM data */ |
| 21 | 21 | int load_pointer; /* which 4-bit nibble will be affected by load address */ |
| 22 | 22 | int ROM_bits_count; /* current bit position in ROM */ |
| 23 | | UINT32 speechROMaddr; /* 18 bit pointer in ROM */ |
| 23 | UINT32 speechROMaddr; /* 18 bit pointer in ROM */ |
| 24 | 24 | UINT32 speechROMlen; /* length of data pointed by speechrom_data, from 0 to 2^18 */ |
| 25 | | |
| 25 | |
| 26 | 26 | } ti99_speech8_state; |
| 27 | 27 | |
| 28 | 28 | INLINE ti99_speech8_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 39 | 39 | static int ti99_spchroms_read(running_device *vspdev, int count) |
| 40 | 40 | { |
| 41 | 41 | running_device *device = vspdev->owner(); |
| 42 | | ti99_speech8_state *spsys = get_safe_token(device); |
| 42 | ti99_speech8_state *spsys = get_safe_token(device); |
| 43 | 43 | |
| 44 | 44 | int val; |
| 45 | 45 | |
| r9498 | r9499 | |
| 82 | 82 | static void ti99_spchroms_load_address(running_device *vspdev, int data) |
| 83 | 83 | { |
| 84 | 84 | running_device *device = vspdev->owner(); |
| 85 | | ti99_speech8_state *spsys = get_safe_token(device); |
| 85 | ti99_speech8_state *spsys = get_safe_token(device); |
| 86 | 86 | // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. |
| 87 | 87 | // This code does not care about this. |
| 88 | 88 | spsys->speechROMaddr = ((spsys->speechROMaddr & ~(0xf << spsys->load_pointer)) |
| r9498 | r9499 | |
| 97 | 97 | static void ti99_spchroms_read_and_branch(running_device *vspdev) |
| 98 | 98 | { |
| 99 | 99 | running_device *device = vspdev->owner(); |
| 100 | | ti99_speech8_state *spsys = get_safe_token(device); |
| 100 | ti99_speech8_state *spsys = get_safe_token(device); |
| 101 | 101 | // tms5220 data sheet says that if more than one speech ROM (tms6100) is present, |
| 102 | 102 | // there is a bus contention. This code does not care about this. */ |
| 103 | 103 | if (spsys->speechROMaddr < spsys->speechROMlen-1) |
| r9498 | r9499 | |
| 120 | 120 | */ |
| 121 | 121 | READ8Z_DEVICE_HANDLER( ti998spch_rz ) |
| 122 | 122 | { |
| 123 | | ti99_speech8_state *spsys = get_safe_token(device); |
| 124 | | |
| 125 | | if ((offset & 0xfc01)==0x9000) |
| 123 | ti99_speech8_state *spsys = get_safe_token(device); |
| 124 | |
| 125 | if ((offset & 0xfc01)==0x9000) |
| 126 | 126 | { |
| 127 | | cpu_adjust_icount(device->machine->device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */ |
| 127 | cpu_adjust_icount(device->machine->device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */ |
| 128 | 128 | *value = tms5220_status_r(spsys->vsp, offset) & 0xff; |
| 129 | 129 | } |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | /* |
| 133 | | Memory write |
| 133 | Memory write |
| 134 | 134 | */ |
| 135 | 135 | WRITE8_DEVICE_HANDLER( ti998spch_w ) |
| 136 | 136 | { |
| 137 | | ti99_speech8_state *spsys = get_safe_token(device); |
| 137 | ti99_speech8_state *spsys = get_safe_token(device); |
| 138 | 138 | |
| 139 | | if ((offset & 0xfc01)==0x9400) |
| 139 | if ((offset & 0xfc01)==0x9400) |
| 140 | 140 | { |
| 141 | 141 | cpu_adjust_icount(device->machine->device("maincpu"),-(54+3)); /* this is just an approx. minimum, it can be much more */ |
| 142 | | |
| 142 | |
| 143 | 143 | /* RN: the stupid design of the tms5220 core means that ready is cleared */ |
| 144 | 144 | /* when there are 15 bytes in FIFO. It should be 16. Of course, if */ |
| 145 | 145 | /* it were the case, we would need to store the value on the bus, */ |
| r9498 | r9499 | |
| 149 | 149 | attotime time_to_ready = double_to_attotime(tms5220_time_to_ready(spsys->vsp)); |
| 150 | 150 | int cycles_to_ready = device->machine->device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready); |
| 151 | 151 | logerror("time to ready: %f -> %d\n", attotime_to_double(time_to_ready), (int) cycles_to_ready); |
| 152 | | |
| 152 | |
| 153 | 153 | cpu_adjust_icount(device->machine->device("maincpu"),-cycles_to_ready); |
| 154 | 154 | timer_set(device->machine, attotime_zero, NULL, 0, NULL); |
| 155 | | } |
| 155 | } |
| 156 | 156 | tms5220_data_w(spsys->vsp, offset, data); |
| 157 | 157 | } |
| 158 | 158 | } |
| r9498 | r9499 | |
| 175 | 175 | ti99_speech8_state *spsys = (ti99_speech8_state*)downcast<legacy_device_base *>(device)->token(); |
| 176 | 176 | |
| 177 | 177 | astring *region = new astring(); |
| 178 | | astring_assemble_3(region, device->tag(), ":", speech8_region); |
| 179 | | |
| 178 | astring_assemble_3(region, device->tag(), ":", speech8_region); |
| 179 | |
| 180 | 180 | spsys->speechrom_data = memory_region(device->machine, astring_c(region)); |
| 181 | 181 | spsys->speechROMlen = memory_region_length(device->machine, astring_c(region)); |
| 182 | 182 | spsys->speechROMaddr = 0; |
| r9498 | r9499 | |
| 186 | 186 | |
| 187 | 187 | static WRITE_LINE_DEVICE_HANDLER( speech8_ready ) |
| 188 | 188 | { |
| 189 | | // ti99_speech8_state *spsys = (ti99_speech8_state*)downcast<legacy_device_base *>(device->owner())->token(); |
| 189 | // ti99_speech8_state *spsys = (ti99_speech8_state*)downcast<legacy_device_base *>(device->owner())->token(); |
| 190 | 190 | logerror("speech8: READY called by VSP\n"); |
| 191 | 191 | } |
| 192 | 192 | |
src/mess/machine/ti99/tn_ide.c
| r9498 | r9499 | |
| 18 | 18 | |
| 19 | 19 | Rewritten as device |
| 20 | 20 | Michael Zapf, September 2010 |
| 21 | | |
| 22 | | FIXME: idecont assumes that there is only one drive that is called |
| 21 | |
| 22 | FIXME: idecont assumes that there is only one drive that is called |
| 23 | 23 | "harddisk" at the root level |
| 24 | 24 | */ |
| 25 | 25 | #include "emu.h" |
| r9498 | r9499 | |
| 32 | 32 | |
| 33 | 33 | #define CRU_BASE 0x1000 |
| 34 | 34 | |
| 35 | | typedef ti99_pebcard_config tn_ide_config; |
| 35 | typedef ti99_pebcard_config tn_ide_config; |
| 36 | 36 | |
| 37 | 37 | enum |
| 38 | 38 | { /* 0xff for 2 mbytes, 0x3f for 512kbytes, 0x03 for 32 kbytes */ |
| r9498 | r9499 | |
| 62 | 62 | int sram_enable_dip; |
| 63 | 63 | int cru_register; |
| 64 | 64 | int cur_page; |
| 65 | | |
| 65 | |
| 66 | 66 | int tms9995_mode; |
| 67 | | |
| 68 | | UINT8 input_latch; |
| 69 | | UINT8 output_latch; |
| 70 | | |
| 67 | |
| 68 | UINT8 input_latch; |
| 69 | UINT8 output_latch; |
| 70 | |
| 71 | 71 | UINT8 *ram; |
| 72 | | |
| 72 | |
| 73 | 73 | /* Callback lines to the main system. */ |
| 74 | 74 | ti99_peb_connect lines; |
| 75 | | |
| 75 | |
| 76 | 76 | } tn_ide_state; |
| 77 | 77 | |
| 78 | 78 | INLINE tn_ide_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 87 | 87 | */ |
| 88 | 88 | static READ8Z_DEVICE_HANDLER( cru_rz ) |
| 89 | 89 | { |
| 90 | | tn_ide_state *card = get_safe_token(device); |
| 90 | tn_ide_state *card = get_safe_token(device); |
| 91 | 91 | UINT8 reply = 0; |
| 92 | 92 | if ((offset & 0xff00)==CRU_BASE) |
| 93 | 93 | { |
| 94 | 94 | int bit = (offset >> 4) & 7; |
| 95 | | |
| 95 | |
| 96 | 96 | if (bit==0) |
| 97 | 97 | { |
| 98 | 98 | reply = card->cru_register & 0x30; |
| r9498 | r9499 | |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | 111 | /* |
| 112 | | CRU write |
| 112 | CRU write |
| 113 | 113 | */ |
| 114 | 114 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 115 | 115 | { |
| 116 | | tn_ide_state *card = get_safe_token(device); |
| 116 | tn_ide_state *card = get_safe_token(device); |
| 117 | 117 | |
| 118 | 118 | if ((offset & 0xff00)==CRU_BASE) |
| 119 | 119 | { |
| r9498 | r9499 | |
| 122 | 122 | { |
| 123 | 123 | case 0: /* turn card on: handled by core */ |
| 124 | 124 | card->selected = data; |
| 125 | | |
| 125 | |
| 126 | 126 | case 1: /* enable SRAM or registers in 0x4000-0x40ff */ |
| 127 | 127 | card->sram_enable = data; |
| 128 | 128 | break; |
| 129 | | |
| 129 | |
| 130 | 130 | case 2: /* enable SRAM page switching */ |
| 131 | 131 | case 3: /* force SRAM page 0 */ |
| 132 | 132 | case 4: /* enable SRAM in 0x6000-0x7000 ("RAMBO" mode) */ |
| r9498 | r9499 | |
| 137 | 137 | card->cru_register |= 1 << bit; |
| 138 | 138 | else |
| 139 | 139 | card->cru_register &= ~(1 << bit); |
| 140 | | |
| 140 | |
| 141 | 141 | if (bit == 6) |
| 142 | 142 | devcb_call_write_line(&card->lines.inta, (card->cru_register & cru_reg_int_en) && card->ide_irq); |
| 143 | | |
| 143 | |
| 144 | 144 | if ((bit == 6) || (bit == 7)) |
| 145 | 145 | if ((card->cru_register & cru_reg_int_en) && !(card->cru_register & cru_reg_reset)) |
| 146 | 146 | card->ide->reset(); |
| r9498 | r9499 | |
| 154 | 154 | */ |
| 155 | 155 | static READ8Z_DEVICE_HANDLER( data_rz ) |
| 156 | 156 | { |
| 157 | | tn_ide_state *card = get_safe_token(device); |
| 157 | tn_ide_state *card = get_safe_token(device); |
| 158 | 158 | UINT8 reply = 0; |
| 159 | 159 | |
| 160 | | if (((offset & 0xe000)==0x4000) && card->selected) |
| 160 | if (((offset & 0xe000)==0x4000) && card->selected) |
| 161 | 161 | { |
| 162 | 162 | int addr = offset & 0x1fff; |
| 163 | | |
| 163 | |
| 164 | 164 | if ((addr <= 0xff) && (card->sram_enable == card->sram_enable_dip)) |
| 165 | 165 | { /* registers */ |
| 166 | 166 | switch ((addr >> 5) & 0x3) |
| r9498 | r9499 | |
| 186 | 186 | { /* first read triggers 16-bit read cycle */ |
| 187 | 187 | card->input_latch = (! (addr & 0x10)) ? ide_bus_r(card->ide, 0, (addr >> 1) & 0x7) : 0; |
| 188 | 188 | } |
| 189 | | |
| 189 | |
| 190 | 190 | /* return latched input */ |
| 191 | 191 | /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/ |
| 192 | 192 | /* return latched input - bytes are swapped in 2004 IDE card */ |
| r9498 | r9499 | |
| 197 | 197 | { /* first read triggers 16-bit read cycle */ |
| 198 | 198 | card->input_latch = (! (addr & 0x10)) ? ide_bus_r(card->ide, 1, (addr >> 1) & 0x7) : 0; |
| 199 | 199 | } |
| 200 | | |
| 200 | |
| 201 | 201 | /* return latched input */ |
| 202 | 202 | /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/ |
| 203 | 203 | /* return latched input - bytes are swapped in 2004 IDE card */ |
| r9498 | r9499 | |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | 219 | /* |
| 220 | | Memory write. The controller is 16 bit, so we need to demultiplex again. |
| 220 | Memory write. The controller is 16 bit, so we need to demultiplex again. |
| 221 | 221 | */ |
| 222 | 222 | static WRITE8_DEVICE_HANDLER( data_w ) |
| 223 | 223 | { |
| 224 | | tn_ide_state *card = get_safe_token(device); |
| 224 | tn_ide_state *card = get_safe_token(device); |
| 225 | 225 | |
| 226 | | if (((offset & 0xe000)==0x4000) && card->selected) |
| 226 | if (((offset & 0xe000)==0x4000) && card->selected) |
| 227 | 227 | { |
| 228 | 228 | if (card->cru_register & cru_reg_page_switching) |
| 229 | 229 | { |
| 230 | 230 | card->cur_page = (offset >> 1) & page_mask; |
| 231 | 231 | } |
| 232 | | |
| 232 | |
| 233 | 233 | int addr = offset & 0x1fff; |
| 234 | | |
| 234 | |
| 235 | 235 | if ((addr <= 0xff) && (card->sram_enable == card->sram_enable_dip)) |
| 236 | 236 | { /* registers */ |
| 237 | 237 | switch ((addr >> 5) & 0x3) |
| r9498 | r9499 | |
| 253 | 253 | rtc65271_rtc_w(card->rtc, 0, data); |
| 254 | 254 | break; |
| 255 | 255 | case 2: /* IDE registers set 1 (CS1Fx) */ |
| 256 | | /* |
| 257 | | if (addr & 1) |
| 258 | | card->output_latch = (card->output_latch & 0xff00) | data; |
| 259 | | else |
| 260 | | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 256 | /* |
| 257 | if (addr & 1) |
| 258 | card->output_latch = (card->output_latch & 0xff00) | data; |
| 259 | else |
| 260 | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 261 | 261 | */ |
| 262 | 262 | /* latch write - bytes are swapped in 2004 IDE card */ |
| 263 | 263 | if (addr & 1) |
| 264 | 264 | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 265 | 265 | else |
| 266 | 266 | card->output_latch = (card->output_latch & 0xff00) | data; |
| 267 | | |
| 267 | |
| 268 | 268 | if (card->tms9995_mode ? (addr & 1) : (!(addr & 1))) |
| 269 | 269 | { /* second write triggers 16-bit write cycle */ |
| 270 | 270 | ide_bus_w(card->ide, 0, (addr >> 1) & 0x7, card->output_latch); |
| r9498 | r9499 | |
| 272 | 272 | break; |
| 273 | 273 | case 3: /* IDE registers set 2 (CS3Fx) */ |
| 274 | 274 | /* |
| 275 | | if (addr & 1) |
| 276 | | card->output_latch = (card->output_latch & 0xff00) | data; |
| 277 | | else |
| 278 | | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 275 | if (addr & 1) |
| 276 | card->output_latch = (card->output_latch & 0xff00) | data; |
| 277 | else |
| 278 | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 279 | 279 | */ |
| 280 | 280 | /* latch write - bytes are swapped in 2004 IDE card */ |
| 281 | 281 | if (addr & 1) |
| 282 | 282 | card->output_latch = (card->output_latch & 0x00ff) | (data << 8); |
| 283 | 283 | else |
| 284 | 284 | card->output_latch = (card->output_latch & 0xff00) | data; |
| 285 | | |
| 285 | |
| 286 | 286 | if (card->tms9995_mode ? (addr & 1) : (!(addr & 1))) |
| 287 | 287 | { /* second write triggers 16-bit write cycle */ |
| 288 | 288 | ide_bus_w(card->ide, 1, (addr >> 1) & 0x7, card->output_latch); |
| r9498 | r9499 | |
| 305 | 305 | |
| 306 | 306 | /**************************************************************************/ |
| 307 | 307 | |
| 308 | | static ti99_peb_card tn_ide_card = |
| 308 | static ti99_peb_card tn_ide_card = |
| 309 | 309 | { |
| 310 | 310 | data_rz, data_w, // memory access read/write |
| 311 | 311 | cru_rz, cru_w, // CRU access |
| 312 | | NULL, NULL, // SENILA/B access |
| 312 | NULL, NULL, // SENILA/B access |
| 313 | 313 | NULL, NULL // 16 bit access (none here) |
| 314 | 314 | }; |
| 315 | 315 | |
| r9498 | r9499 | |
| 342 | 342 | tn_ide_state *card = get_safe_token(device); |
| 343 | 343 | card->rtc = device->subdevice("ide_rtc"); |
| 344 | 344 | card->ide = device->subdevice("ide"); |
| 345 | | |
| 345 | |
| 346 | 346 | peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config(); |
| 347 | 347 | devcb_resolve_write_line(&card->lines.inta, &topeb->inta, device); |
| 348 | 348 | |
| r9498 | r9499 | |
| 358 | 358 | { |
| 359 | 359 | tn_ide_state *card = get_safe_token(device); |
| 360 | 360 | running_device *peb = device->owner(); |
| 361 | | |
| 361 | |
| 362 | 362 | if (input_port_read(device->machine, "HDCTRL") & HD_IDE) |
| 363 | 363 | { |
| 364 | 364 | int success = mount_card(peb, device, &tn_ide_card, get_pebcard_config(device)->slot); |
| 365 | 365 | if (!success) return; |
| 366 | | |
| 366 | |
| 367 | 367 | card->cur_page = 0; |
| 368 | 368 | card->sram_enable = 0; |
| 369 | 369 | card->cru_register = 0; |
src/mess/machine/ti99/datamux.c
| r9498 | r9499 | |
| 1 | 1 | /*************************************************************************** |
| 2 | | |
| 3 | | TI-99/4(A) databus multiplexer circuit |
| 4 | | |
| 5 | | The DMUX is used to convert the 16-bit databus of the TMS9900 into |
| 6 | | an 8-bit databus. The processor writes a 16 bit word which is split |
| 7 | | by this circuit into two bytes that are sent serially over the 8-bit bus. |
| 8 | | In the opposite direction, one 16-bit read request from the CPU is |
| 9 | | translated into two 8-bit read requests (odd address / even address) from |
| 10 | | this datamux. Its 8-bit latch (LS373) holds the first byte, while the |
| 11 | | datamux puts the CPU on hold, gets the second byte, and routes that second |
| 12 | | byte to the D0-D7 lines, while the latch now puts the first byte on D8-D15. |
| 13 | | Since we get two memory accesses each time, there are twice as many |
| 14 | | wait states than for a direct 16-bit access (order LSB, MSB). |
| 15 | | |
| 16 | | In addition, since the TMS 9900 also supports byte operations, every write |
| 17 | | operation is automatically preceded by a read operation, so this adds even |
| 18 | | more delays. |
| 19 | 2 | |
| 20 | | Within the TI-99/4(A) console, only the internal ROM and the small internal |
| 21 | | RAM ("scratch pad RAM") are directly connected to the 16-bit bus. All other |
| 22 | | devices (video, audio, speech, GROM, and the complete P-Box system are |
| 23 | | connected to the datamux. |
| 24 | | |
| 25 | | The TMS9995 which is used in the Geneve has an internal multiplex, and |
| 26 | | the byte order is reversed: MSB, LSB |
| 27 | | |
| 28 | | ROM = 4K * 16 bit (8 KiB) system ROM (kind of BIOS, plus the GPL interpreter) |
| 29 | | RAM = 128 * 16 bit (256 byte) system RAM ("scratch pad") |
| 3 | TI-99/4(A) databus multiplexer circuit |
| 30 | 4 | |
| 31 | | Many users (me too) used to solder a 16K * 16 bit (32 KiB) SRAM circuit into |
| 32 | | the console, before the datamux, decoded to 0x2000-0x3fff and 0xa000-0xffff. |
| 33 | | (This expansion was also called 0-waitstate, since it could be accessed |
| 34 | | with the full databus width, and the datamux did not create waitstates.) |
| 35 | | |
| 36 | | +---+ +-------+ |
| 37 | | | |===##========##== D0-D7 ==========##===============|TMS9918| Video |
| 38 | | | | || || || +-------+ |
| 39 | | | T | +-----+ +-----+ LS245 +----+ |
| 40 | | | M | | ROM | | RAM | +----+ |
| 41 | | | S | +-----+ +-----+ || | : |
| 42 | | | |---||-||-----||-||----------------||-|---------------------: |
| 43 | | | 9 | || || A0 - A14 || | A0 : Sound |
| 44 | | | 9 |---||--------||-------------------||-|----------+ -A15 : GROM |
| 45 | | | 0 | || || LS373 +-+ || | +----A15-+----------: Cartridges |
| 46 | | | 0 | || || ##========|<|===## | | : Speech |
| 47 | | | | || || || +-+ +-+ || | | : Expansion |
| 48 | | | |===## D8-D15 ##===##==|>|=====|===##=|=|=========== D0-D7 =: cards |
| 49 | | +---+ +-+ | | | : |
| 50 | | ^ LS244| | | | |
| 51 | | | | +--+---+-++ |
| 52 | | | +--------| DMUX | |
| 53 | | +--- READY -------------------------+------+ |
| 5 | The DMUX is used to convert the 16-bit databus of the TMS9900 into |
| 6 | an 8-bit databus. The processor writes a 16 bit word which is split |
| 7 | by this circuit into two bytes that are sent serially over the 8-bit bus. |
| 8 | In the opposite direction, one 16-bit read request from the CPU is |
| 9 | translated into two 8-bit read requests (odd address / even address) from |
| 10 | this datamux. Its 8-bit latch (LS373) holds the first byte, while the |
| 11 | datamux puts the CPU on hold, gets the second byte, and routes that second |
| 12 | byte to the D0-D7 lines, while the latch now puts the first byte on D8-D15. |
| 13 | Since we get two memory accesses each time, there are twice as many |
| 14 | wait states than for a direct 16-bit access (order LSB, MSB). |
| 54 | 15 | |
| 55 | | Databus width |
| 56 | | :------------- 16 bit ---------------|---------- 8 bit -----: |
| 57 | | |
| 58 | | A0=MSB; A15=LSB |
| 59 | | D0=MSB; D15=LSB |
| 60 | | |
| 61 | | We integrate the 16 bit memory expansion in this datamux component |
| 62 | | (pretending that the memory expansion was soldered on top of the datamux) |
| 16 | In addition, since the TMS 9900 also supports byte operations, every write |
| 17 | operation is automatically preceded by a read operation, so this adds even |
| 18 | more delays. |
| 19 | |
| 20 | Within the TI-99/4(A) console, only the internal ROM and the small internal |
| 21 | RAM ("scratch pad RAM") are directly connected to the 16-bit bus. All other |
| 22 | devices (video, audio, speech, GROM, and the complete P-Box system are |
| 23 | connected to the datamux. |
| 24 | |
| 25 | The TMS9995 which is used in the Geneve has an internal multiplex, and |
| 26 | the byte order is reversed: MSB, LSB |
| 27 | |
| 28 | ROM = 4K * 16 bit (8 KiB) system ROM (kind of BIOS, plus the GPL interpreter) |
| 29 | RAM = 128 * 16 bit (256 byte) system RAM ("scratch pad") |
| 30 | |
| 31 | Many users (me too) used to solder a 16K * 16 bit (32 KiB) SRAM circuit into |
| 32 | the console, before the datamux, decoded to 0x2000-0x3fff and 0xa000-0xffff. |
| 33 | (This expansion was also called 0-waitstate, since it could be accessed |
| 34 | with the full databus width, and the datamux did not create waitstates.) |
| 35 | |
| 36 | +---+ +-------+ |
| 37 | | |===##========##== D0-D7 ==========##===============|TMS9918| Video |
| 38 | | | || || || +-------+ |
| 39 | | T | +-----+ +-----+ LS245 +----+ |
| 40 | | M | | ROM | | RAM | +----+ |
| 41 | | S | +-----+ +-----+ || | : |
| 42 | | |---||-||-----||-||----------------||-|---------------------: |
| 43 | | 9 | || || A0 - A14 || | A0 : Sound |
| 44 | | 9 |---||--------||-------------------||-|----------+ -A15 : GROM |
| 45 | | 0 | || || LS373 +-+ || | +----A15-+----------: Cartridges |
| 46 | | 0 | || || ##========|<|===## | | : Speech |
| 47 | | | || || || +-+ +-+ || | | : Expansion |
| 48 | | |===## D8-D15 ##===##==|>|=====|===##=|=|=========== D0-D7 =: cards |
| 49 | +---+ +-+ | | | : |
| 50 | ^ LS244| | | | |
| 51 | | | +--+---+-++ |
| 52 | | +--------| DMUX | |
| 53 | +--- READY -------------------------+------+ |
| 54 | |
| 55 | Databus width |
| 56 | :------------- 16 bit ---------------|---------- 8 bit -----: |
| 57 | |
| 58 | A0=MSB; A15=LSB |
| 59 | D0=MSB; D15=LSB |
| 60 | |
| 61 | We integrate the 16 bit memory expansion in this datamux component |
| 62 | (pretending that the memory expansion was soldered on top of the datamux) |
| 63 | 63 | ***************************************************************************/ |
| 64 | 64 | |
| 65 | 65 | #include "emu.h" |
| r9498 | r9499 | |
| 71 | 71 | typedef struct _attached_device |
| 72 | 72 | { |
| 73 | 73 | /* The device. */ |
| 74 | | running_device *device; |
| 75 | | |
| 74 | running_device *device; |
| 75 | |
| 76 | 76 | /* Address bits involved */ |
| 77 | | UINT16 address_mask; |
| 77 | UINT16 address_mask; |
| 78 | 78 | |
| 79 | 79 | /* Value of the address bits which are involved for selecting for read. */ |
| 80 | 80 | UINT16 select; |
| 81 | 81 | |
| 82 | 82 | /* Value of the address bits which are involved for selecting for write. */ |
| 83 | 83 | UINT16 write_select; |
| 84 | | |
| 84 | |
| 85 | 85 | /* Read access. */ |
| 86 | 86 | databus_read_function read_byte; |
| 87 | | |
| 87 | |
| 88 | 88 | /* Write access. */ |
| 89 | 89 | databus_write_function write_byte; |
| 90 | 90 | |
| 91 | 91 | /* Setting which determined if this device is mounted or not. */ |
| 92 | 92 | const char *setting; |
| 93 | | |
| 93 | |
| 94 | 94 | /* Bits which must be set in the setting. */ |
| 95 | 95 | UINT8 set; |
| 96 | | |
| 96 | |
| 97 | 97 | /* Bits which must not be set in the setting. */ |
| 98 | 98 | UINT8 unset; |
| 99 | 99 | } attached_device; |
| r9498 | r9499 | |
| 102 | 102 | { |
| 103 | 103 | /* All devices that are attached to the 8-bit bus. */ |
| 104 | 104 | attached_device component[MAXDEV]; |
| 105 | | |
| 105 | |
| 106 | 106 | /* Latch which stores the first byte */ |
| 107 | 107 | UINT8 latch; |
| 108 | | |
| 108 | |
| 109 | 109 | // Intermediate storage which holds the low byte of the previous read cycle. |
| 110 | | // In reality, the TMS9900 adds the low byte to the 16 bit memory word |
| 110 | // In reality, the TMS9900 adds the low byte to the 16 bit memory word |
| 111 | 111 | // from the previous read-before-write cycle, but this is not yet handled |
| 112 | 112 | // by the TMS9900 emulation. TODO: rewrite TMS9900 |
| 113 | 113 | UINT8 lowbyte; |
| 114 | 114 | UINT8 highbyte; |
| 115 | | |
| 115 | |
| 116 | 116 | /* Memory expansion (internal, 16 bit). */ |
| 117 | 117 | UINT16 *ram16b; |
| 118 | | |
| 118 | |
| 119 | 119 | /* Use the memory expansion? */ |
| 120 | 120 | int use32k; |
| 121 | | |
| 121 | |
| 122 | 122 | /* Management function */ |
| 123 | 123 | int devindex; |
| 124 | 124 | } datamux_state; |
| r9498 | r9499 | |
| 134 | 134 | static void dmux_mount_device(running_device *dmuxdev, running_device *busdevice, UINT16 address_mask, UINT16 address_bits, UINT16 write_sel, databus_read_function read, databus_write_function write) |
| 135 | 135 | { |
| 136 | 136 | datamux_state *dmux = get_safe_token(dmuxdev); |
| 137 | | int index = dmux->devindex++; |
| 137 | int index = dmux->devindex++; |
| 138 | 138 | if (index < MAXDEV) |
| 139 | 139 | { |
| 140 | 140 | if (dmux->component[index].device == NULL) |
| r9498 | r9499 | |
| 144 | 144 | dmux->component[index].select = address_bits; |
| 145 | 145 | dmux->component[index].write_select = write_sel; |
| 146 | 146 | dmux->component[index].read_byte = read; |
| 147 | | dmux->component[index].write_byte = write; |
| 147 | dmux->component[index].write_byte = write; |
| 148 | 148 | // printf("registering the device at position %d\n", index); |
| 149 | 149 | } |
| 150 | 150 | } |
| r9498 | r9499 | |
| 153 | 153 | logerror("ti99_dmux: Tried to mount too many devices to the DMUX. (Just a bug.)\n"); |
| 154 | 154 | } |
| 155 | 155 | } |
| 156 | | /* |
| 157 | | static void dmux_unmount_device(running_device *dmuxdev, running_device *busdevice) |
| 158 | | { |
| 159 | | datamux_state *dmux = get_safe_token(dmuxdev); |
| 160 | | for (int index = 0; index < MAXDEV; index++) |
| 161 | | { |
| 162 | | if (dmux->component[index].device == busdevice) |
| 163 | | { |
| 164 | | dmux->component[index].device = NULL; |
| 165 | | return; |
| 166 | | } |
| 167 | | } |
| 168 | | printf("Failed to uninstall device from dmux\n"); |
| 169 | | } |
| 170 | | */ |
| 156 | |
| 171 | 157 | /*************************************************************************** |
| 172 | 158 | DEVICE ACCESSOR FUNCTIONS |
| 173 | 159 | ***************************************************************************/ |
| 174 | 160 | |
| 175 | 161 | /* |
| 176 | | Read access. We are using two loops because the delay between both |
| 162 | Read access. We are using two loops because the delay between both |
| 177 | 163 | accesses must not occur within the loop. So we have one access on the bus, |
| 178 | 164 | a delay, and then the second access (each one with possibly many attached |
| 179 | 165 | devices) |
| r9498 | r9499 | |
| 186 | 172 | |
| 187 | 173 | // Looks ugly, but this is close to the real thing. If the 16bit |
| 188 | 174 | // memory expansion is installed in the console, and the access hits its |
| 189 | | // space, just respond to the memory access and don't bother the |
| 175 | // space, just respond to the memory access and don't bother the |
| 190 | 176 | // datamux in any way. In particular, do not make the datamux insert wait |
| 191 | 177 | // states. |
| 192 | 178 | if (dmux->use32k) |
| r9498 | r9499 | |
| 197 | 183 | |
| 198 | 184 | if (base != 0) |
| 199 | 185 | { |
| 200 | | UINT16 reply = dmux->ram16b[offset-base]; |
| 186 | UINT16 reply = dmux->ram16b[offset-base]; |
| 201 | 187 | // Store the prefetch |
| 202 | | dmux->lowbyte = reply & 0x00ff; |
| 203 | | dmux->highbyte = (reply & 0xff00)>>8; |
| 204 | | return reply; |
| 188 | dmux->lowbyte = reply & 0x00ff; |
| 189 | dmux->highbyte = (reply & 0xff00)>>8; |
| 190 | return reply; |
| 205 | 191 | } |
| 206 | 192 | } |
| 207 | | |
| 193 | |
| 208 | 194 | for (int i=0; i < MAXDEV; i++) |
| 209 | 195 | { |
| 210 | 196 | attached_device *adev = &dmux->component[i]; |
| r9498 | r9499 | |
| 222 | 208 | // hope we don't have two devices answering... |
| 223 | 209 | // consider something like a logical OR and maybe some artificial smoke |
| 224 | 210 | } |
| 225 | | } |
| 226 | | |
| 211 | } |
| 212 | |
| 227 | 213 | // Takes three cycles |
| 228 | 214 | cpu_adjust_icount(device->machine->device("maincpu"),-3); |
| 229 | 215 | |
| r9498 | r9499 | |
| 241 | 227 | } |
| 242 | 228 | } |
| 243 | 229 | } |
| 244 | | } |
| 230 | } |
| 245 | 231 | |
| 246 | 232 | // Takes three cycles |
| 247 | 233 | cpu_adjust_icount(device->machine->device("maincpu"),-3); |
| r9498 | r9499 | |
| 256 | 242 | WRITE16_DEVICE_HANDLER( ti99_dmux_w ) |
| 257 | 243 | { |
| 258 | 244 | datamux_state *dmux = get_safe_token(device); |
| 259 | | UINT16 addr = (offset << 1); |
| 260 | | |
| 261 | | // The handling of byte writing is done in MESS using mem_mask. |
| 245 | UINT16 addr = (offset << 1); |
| 246 | |
| 247 | // The handling of byte writing is done in MESS using mem_mask. |
| 262 | 248 | // If the mem_mask is ff00, the CPU is about to write the high byte. This |
| 263 | | // is not the true story, since the real CPU never writes half a word. |
| 264 | | // In reality, the TMS9900 performs a read-before-write, stores the word |
| 249 | // is not the true story, since the real CPU never writes half a word. |
| 250 | // In reality, the TMS9900 performs a read-before-write, stores the word |
| 265 | 251 | // internally, and replaces the high or low byte when it is about to write |
| 266 | | // a byte to an even or odd address, respectively. Then it writes the |
| 252 | // a byte to an even or odd address, respectively. Then it writes the |
| 267 | 253 | // complete new word. |
| 268 | 254 | // Example: Memory locations 0x6000 contains the word 0x1234 (BE). If we |
| 269 | 255 | // write a 0x56 to 0x6000, the CPU first reads 0x6000, stores the 0x1234, |
| r9498 | r9499 | |
| 271 | 257 | |
| 272 | 258 | // Until the TMS9900 emulation is corrected in this way, we are using |
| 273 | 259 | // the DMUX in place of the internal buffer. |
| 274 | | |
| 275 | | // printf("write addr=%04x memmask=%04x value=%04x\n", addr, mem_mask, data); |
| 260 | |
| 261 | // printf("write addr=%04x memmask=%04x value=%04x\n", addr, mem_mask, data); |
| 276 | 262 | if (mem_mask == 0xff00) |
| 277 | 263 | data = data | dmux->lowbyte; |
| 278 | | |
| 264 | |
| 279 | 265 | if (mem_mask == 0x00ff) |
| 280 | 266 | data = data | (dmux->highbyte << 8); |
| 281 | 267 | |
| r9498 | r9499 | |
| 293 | 279 | return; |
| 294 | 280 | } |
| 295 | 281 | } |
| 296 | | |
| 282 | |
| 297 | 283 | for (int i=0; i < MAXDEV; i++) |
| 298 | 284 | { |
| 299 | 285 | attached_device *adev = &dmux->component[i]; |
| r9498 | r9499 | |
| 327 | 313 | } |
| 328 | 314 | } |
| 329 | 315 | } |
| 330 | | } |
| 316 | } |
| 331 | 317 | |
| 332 | 318 | // Takes three cycles |
| 333 | 319 | cpu_adjust_icount(device->machine->device("maincpu"),-3); |
| r9498 | r9499 | |
| 362 | 348 | |
| 363 | 349 | for (int index = 0; index < MAXDEV; index++) |
| 364 | 350 | { |
| 365 | | dmux->component[index].device = NULL; |
| 351 | dmux->component[index].device = NULL; |
| 366 | 352 | } |
| 367 | 353 | |
| 368 | 354 | if (dmux->ram16b==NULL) dmux->ram16b = (UINT16*)malloc(32768); |
| r9498 | r9499 | |
| 374 | 360 | running_device *dev = device->machine->device(cons[i].name); |
| 375 | 361 | if (dev!=NULL) |
| 376 | 362 | { |
| 377 | | UINT32 set = 0; |
| 363 | UINT32 set = 0; |
| 378 | 364 | if (cons[i].setting!=NULL) |
| 379 | 365 | set = input_port_read(device->machine, cons[i].setting); |
| 380 | | |
| 366 | |
| 381 | 367 | if (((set & cons[i].set)==cons[i].set)&&((set & cons[i].unset)==0)) |
| 382 | 368 | { |
| 383 | 369 | dmux_mount_device(device, dev, cons[i].address_mask, cons[i].select_pattern, cons[i].write_select, cons[i].read, cons[i].write); |
src/mess/machine/ti99/hfdc.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | | Myarc Hard and Floppy Disk Controller |
| 3 | | Michael Zapf |
| 2 | Myarc Hard and Floppy Disk Controller |
| 3 | Michael Zapf |
| 4 | 4 | */ |
| 5 | 5 | #include "emu.h" |
| 6 | 6 | #include "peribox.h" |
| r9498 | r9499 | |
| 19 | 19 | #define HFDC_MAX_FLOPPY 4 |
| 20 | 20 | #define HFDC_MAX_HARD 4 |
| 21 | 21 | |
| 22 | | #define TAPE_ADDR 0x0fc0 |
| 23 | | #define HDC_R_ADDR 0x0fd0 |
| 24 | | #define HDC_W_ADDR 0x0fd2 |
| 25 | | #define CLK_ADDR 0x0fe0 |
| 26 | | #define RAM_ADDR 0x1000 |
| 22 | #define TAPE_ADDR 0x0fc0 |
| 23 | #define HDC_R_ADDR 0x0fd0 |
| 24 | #define HDC_W_ADDR 0x0fd2 |
| 25 | #define CLK_ADDR 0x0fe0 |
| 26 | #define RAM_ADDR 0x1000 |
| 27 | 27 | |
| 28 | 28 | typedef ti99_pebcard_config ti99_hfdc_config; |
| 29 | 29 | |
| r9498 | r9499 | |
| 37 | 37 | |
| 38 | 38 | /* Clock divider bit 0. Unused in this emulation. */ |
| 39 | 39 | int CD0; |
| 40 | | |
| 40 | |
| 41 | 41 | /* Clock divider bit 1. Unused in this emulation. */ |
| 42 | 42 | int CD1; |
| 43 | | |
| 43 | |
| 44 | 44 | /* count 4.23s from rising edge of motor_on */ |
| 45 | | emu_timer *motor_on_timer; |
| 46 | | |
| 45 | emu_timer *motor_on_timer; |
| 46 | |
| 47 | 47 | /* Link to the HDC9234 controller on the board. */ |
| 48 | | running_device *controller; |
| 48 | running_device *controller; |
| 49 | 49 | |
| 50 | 50 | /* Link to the clock chip on the board. */ |
| 51 | | running_device *clock; |
| 52 | | |
| 51 | running_device *clock; |
| 52 | |
| 53 | 53 | /* Determines whether we have access to the CRU bits. */ |
| 54 | 54 | int cru_select; |
| 55 | | |
| 55 | |
| 56 | 56 | /* IRQ state */ |
| 57 | 57 | int irq; |
| 58 | | |
| 58 | |
| 59 | 59 | /* DMA in Progress state */ |
| 60 | 60 | int dip; |
| 61 | | |
| 61 | |
| 62 | 62 | /* Output 1 latch */ |
| 63 | | UINT8 output1_latch; |
| 63 | UINT8 output1_latch; |
| 64 | 64 | |
| 65 | 65 | /* Output 2 latch */ |
| 66 | | UINT8 output2_latch; |
| 67 | | |
| 66 | UINT8 output2_latch; |
| 67 | |
| 68 | 68 | /* Connected floppy drives. */ |
| 69 | | running_device *floppy_unit[HFDC_MAX_FLOPPY]; |
| 70 | | |
| 69 | running_device *floppy_unit[HFDC_MAX_FLOPPY]; |
| 70 | |
| 71 | 71 | /* Connected harddisk drives. */ |
| 72 | | running_device *harddisk_unit[HFDC_MAX_HARD]; |
| 72 | running_device *harddisk_unit[HFDC_MAX_HARD]; |
| 73 | 73 | |
| 74 | 74 | /* DMA address latch */ |
| 75 | | UINT32 dma_address; |
| 76 | | |
| 75 | UINT32 dma_address; |
| 76 | |
| 77 | 77 | /* DSR ROM */ |
| 78 | 78 | UINT8 *rom; |
| 79 | | |
| 79 | |
| 80 | 80 | /* ROM banks. */ |
| 81 | 81 | int rom_offset; |
| 82 | 82 | |
| 83 | 83 | /* HFDC RAM */ |
| 84 | | UINT8 *ram; |
| 85 | | |
| 86 | | /* RAM banks */ |
| 84 | UINT8 *ram; |
| 85 | |
| 86 | /* RAM banks */ |
| 87 | 87 | int ram_offset[4]; |
| 88 | | |
| 88 | |
| 89 | 89 | /* Callback lines to the main system. */ |
| 90 | 90 | ti99_peb_connect lines; |
| 91 | | |
| 91 | |
| 92 | 92 | } ti99_hfdc_state; |
| 93 | 93 | |
| 94 | 94 | INLINE ti99_hfdc_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 129 | 129 | xx04 DMA in progress |
| 130 | 130 | |
| 131 | 131 | Note that the cru line settings on the board do not match the |
| 132 | | description in the manual. 02 and 04 swap their positions (checked with |
| 132 | description in the manual. 02 and 04 swap their positions (checked with |
| 133 | 133 | board and schematics). Similarly, the dip switches |
| 134 | 134 | for the drive configurations are not correctly enumerated in the manual. |
| 135 | 135 | |
| r9498 | r9499 | |
| 150 | 150 | */ |
| 151 | 151 | static READ8Z_DEVICE_HANDLER( cru_r ) |
| 152 | 152 | { |
| 153 | | ti99_hfdc_state *card = get_safe_token(device); |
| 153 | ti99_hfdc_state *card = get_safe_token(device); |
| 154 | 154 | UINT8 reply; |
| 155 | | |
| 155 | |
| 156 | 156 | if ((offset & 0xff00)==CRU_BASE) |
| 157 | 157 | { |
| 158 | 158 | if ((offset & 0x00ff)==0) /* CRU bits 0-7 */ |
| r9498 | r9499 | |
| 161 | 161 | if (card->cru_select) |
| 162 | 162 | { |
| 163 | 163 | /* DIP switches. Logic levels are inverted (on->0, off->1). CRU |
| 164 | | bit order is the reverse of DIP-switch order, too (dip 1 -> bit 7, |
| 165 | | dip 8 -> bit 0). |
| 166 | | |
| 167 | | MZ: 00 should not be used since there is a bug in the |
| 168 | | DSR of the HFDC which causes problems with SD disks |
| 169 | | (controller tries DD and then fails to fall back to SD) */ |
| 164 | bit order is the reverse of DIP-switch order, too (dip 1 -> bit 7, |
| 165 | dip 8 -> bit 0). |
| 166 | |
| 167 | MZ: 00 should not be used since there is a bug in the |
| 168 | DSR of the HFDC which causes problems with SD disks |
| 169 | (controller tries DD and then fails to fall back to SD) */ |
| 170 | 170 | reply = ~(input_port_read(device->machine, "HFDCDIP")); |
| 171 | 171 | } |
| 172 | 172 | else |
| 173 | 173 | { |
| 174 | 174 | reply = 0; |
| 175 | | |
| 176 | | if (card->irq) reply |= 0x01; |
| 175 | |
| 176 | if (card->irq) reply |= 0x01; |
| 177 | 177 | if (card->dip) reply |= 0x02; |
| 178 | 178 | if (card->strobe_motor) reply |= 0x04; |
| 179 | 179 | } |
| r9498 | r9499 | |
| 194 | 194 | 04 Floppy Motor on / CD0 HIGH |
| 195 | 195 | 06 ROM page select 0 / CD1 |
| 196 | 196 | 08 ROM page select 1 / CRU input select |
| 197 | | 12/4/6/8/A RAM page select at 0x5400 |
| 197 | 12/4/6/8/A RAM page select at 0x5400 |
| 198 | 198 | 1C/E/0/2/4 RAM page select at 0x5800 |
| 199 | 199 | 26/8/A/C/E RAM page select at 0x5C00 |
| 200 | 200 | |
| 201 | 201 | RAM bank select: bank 0..31; 12 = LSB (accordingly for other two areas) |
| 202 | 202 | ROM bank select: bank 0..3; 06 = MSB, 07 = LSB |
| 203 | | Bit number = (CRU_rel_address - base_address)/2 |
| 203 | Bit number = (CRU_rel_address - base_address)/2 |
| 204 | 204 | CD0 and CD1 are Clock Divider selections for the Floppy Data Separator (FDC9216) |
| 205 | 205 | */ |
| 206 | 206 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 207 | 207 | { |
| 208 | | ti99_hfdc_state *card = get_safe_token(device); |
| 208 | ti99_hfdc_state *card = get_safe_token(device); |
| 209 | 209 | |
| 210 | 210 | if ((offset & 0xff00)==CRU_BASE) |
| 211 | 211 | { |
| r9498 | r9499 | |
| 254 | 254 | break; |
| 255 | 255 | |
| 256 | 256 | default: |
| 257 | | logerror("ti99/HFDC: Attempt to set undefined CRU bit %d\n", bit); |
| 257 | logerror("ti99/HFDC: Attempt to set undefined CRU bit %d\n", bit); |
| 258 | 258 | } |
| 259 | 259 | } |
| 260 | 260 | } |
| r9498 | r9499 | |
| 277 | 277 | |
| 278 | 278 | static READ8Z_DEVICE_HANDLER( data_r ) |
| 279 | 279 | { |
| 280 | | ti99_hfdc_state *card = get_safe_token(device); |
| 280 | ti99_hfdc_state *card = get_safe_token(device); |
| 281 | 281 | |
| 282 | 282 | if (card->selected && (offset & 0xe000)==0x4000) |
| 283 | 283 | { |
| r9498 | r9499 | |
| 292 | 292 | logerror("ti99/HFDC: Tape support not available (access to address %04x)\n", offset); |
| 293 | 293 | return; |
| 294 | 294 | } |
| 295 | | |
| 295 | |
| 296 | 296 | // HDC9234: 4fd0..4fdf / read: 4fd0,4 (mirror 8,c) |
| 297 | 297 | // read: 0100 1111 1101 xx00 |
| 298 | 298 | if ((offset & 0x1ff3)==HDC_R_ADDR) |
| r9498 | r9499 | |
| 300 | 300 | *value = smc92x4_r(card->controller, (offset>>2)&1); |
| 301 | 301 | return; |
| 302 | 302 | } |
| 303 | | |
| 303 | |
| 304 | 304 | if ((offset & 0x1fe1)==CLK_ADDR) |
| 305 | 305 | { |
| 306 | 306 | *value = mm58274c_r(card->clock, (offset & 0x001e) >> 1); |
| r9498 | r9499 | |
| 314 | 314 | return; |
| 315 | 315 | } |
| 316 | 316 | } |
| 317 | | |
| 317 | |
| 318 | 318 | // RAM: 0101 xxxx xxxx xxxx |
| 319 | 319 | if ((offset & 0x1000)==RAM_ADDR) |
| 320 | 320 | { |
| r9498 | r9499 | |
| 333 | 333 | */ |
| 334 | 334 | static WRITE8_DEVICE_HANDLER( data_w ) |
| 335 | 335 | { |
| 336 | | ti99_hfdc_state *card = get_safe_token(device); |
| 336 | ti99_hfdc_state *card = get_safe_token(device); |
| 337 | 337 | if (card->selected && (offset & 0xe000)==0x4000) |
| 338 | | { |
| 338 | { |
| 339 | 339 | // Tape: 4fc0...4fcf |
| 340 | 340 | if ((offset & 0x1ff0)==TAPE_ADDR) |
| 341 | 341 | { |
| 342 | 342 | logerror("ti99/HFDC: Tape support not available (access to address %04x)\n", offset); |
| 343 | 343 | return; |
| 344 | 344 | } |
| 345 | | |
| 345 | |
| 346 | 346 | // HDC9234: 4fd0..4fdf / write: 4fd2,6 (mirror a,e) |
| 347 | 347 | // write: 0100 1111 1101 xx10 |
| 348 | 348 | if ((offset & 0x1ff3)==HDC_W_ADDR) |
| r9498 | r9499 | |
| 350 | 350 | smc92x4_w(card->controller, (offset>>2)&1, data); |
| 351 | 351 | return; |
| 352 | 352 | } |
| 353 | | |
| 353 | |
| 354 | 354 | if ((offset & 0x1fe1)==CLK_ADDR) |
| 355 | 355 | { |
| 356 | 356 | mm58274c_w(card->clock, (offset & 0x001e) >> 1, data); |
| 357 | 357 | return; |
| 358 | 358 | } |
| 359 | | |
| 359 | |
| 360 | 360 | // RAM: 0101 xxxx xxxx xxxx |
| 361 | 361 | if ((offset & 0x1000)==RAM_ADDR) |
| 362 | 362 | { |
| r9498 | r9499 | |
| 375 | 375 | */ |
| 376 | 376 | static WRITE_LINE_DEVICE_HANDLER( intrq_w ) |
| 377 | 377 | { |
| 378 | | // Note that the callback functions deliver the calling device, which is |
| 378 | // Note that the callback functions deliver the calling device, which is |
| 379 | 379 | // the controller in this case. |
| 380 | | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 380 | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 381 | 381 | card->irq = state; |
| 382 | 382 | |
| 383 | 383 | /* Set INTA */ |
| r9498 | r9499 | |
| 396 | 396 | */ |
| 397 | 397 | static WRITE_LINE_DEVICE_HANDLER( dip_w ) |
| 398 | 398 | { |
| 399 | | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 399 | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 400 | 400 | card->dip = state; |
| 401 | 401 | } |
| 402 | 402 | |
| 403 | 403 | // device ok |
| 404 | 404 | static WRITE8_DEVICE_HANDLER( auxbus_out ) |
| 405 | 405 | { |
| 406 | | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 406 | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 407 | 407 | switch (offset) |
| 408 | 408 | { |
| 409 | 409 | case INPUT_STATUS: |
| 410 | 410 | logerror("ti99/HFDC: Invalid operation: S0=S1=0, but tried to write (expected: read drive status)\n"); |
| 411 | 411 | break; |
| 412 | | |
| 412 | |
| 413 | 413 | case OUTPUT_DMA_ADDR: |
| 414 | 414 | /* Value is dma address byte. Shift previous contents to the left. */ |
| 415 | 415 | card->dma_address = ((card->dma_address << 8) + (data&0xff))&0xffffff; |
| r9498 | r9499 | |
| 469 | 469 | } |
| 470 | 470 | |
| 471 | 471 | /* |
| 472 | | Select the HFDC hard disk unit |
| 473 | | This function implements the selection logic on the PCB (outside the |
| 474 | | controller chip) |
| 475 | | The HDC9234 allows up to four drives to be selected by the select lines. |
| 476 | | This is not enough for controlling four floppy drives and three hard |
| 477 | | drives, so the user programmable outputs are used to select the floppy |
| 478 | | drives. This selection happens completely outside of the controller, |
| 479 | | so we must implement it here. |
| 472 | Select the HFDC hard disk unit |
| 473 | This function implements the selection logic on the PCB (outside the |
| 474 | controller chip) |
| 475 | The HDC9234 allows up to four drives to be selected by the select lines. |
| 476 | This is not enough for controlling four floppy drives and three hard |
| 477 | drives, so the user programmable outputs are used to select the floppy |
| 478 | drives. This selection happens completely outside of the controller, |
| 479 | so we must implement it here. |
| 480 | 480 | */ |
| 481 | 481 | |
| 482 | 482 | static running_device *current_harddisk(running_device *controller) |
| r9498 | r9499 | |
| 496 | 496 | |
| 497 | 497 | static READ_LINE_DEVICE_HANDLER( auxbus_in ) |
| 498 | 498 | { |
| 499 | | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 499 | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 500 | 500 | running_device *drive; |
| 501 | 501 | UINT8 reply = 0; |
| 502 | 502 | |
| r9498 | r9499 | |
| 528 | 528 | UINT8 state; |
| 529 | 529 | drive = current_harddisk(device); |
| 530 | 530 | state = ti99_mfm_harddisk_status(drive); |
| 531 | | if (state & MFMHD_TRACK00) reply |= DS_TRK00; |
| 531 | if (state & MFMHD_TRACK00) reply |= DS_TRK00; |
| 532 | 532 | if (state & MFMHD_SEEKCOMP) reply |= DS_SKCOM; |
| 533 | 533 | if (state & MFMHD_WRFAULT) reply |= DS_WRFAULT; |
| 534 | 534 | if (state & MFMHD_INDEX) reply |= DS_INDEX; |
| r9498 | r9499 | |
| 543 | 543 | */ |
| 544 | 544 | static UINT8 hfdc_dma_read_callback(running_device *device) |
| 545 | 545 | { |
| 546 | | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 546 | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 547 | 547 | UINT8 value = card->ram[card->dma_address & 0x7fff]; |
| 548 | 548 | card->dma_address++; |
| 549 | 549 | return value; |
| r9498 | r9499 | |
| 554 | 554 | */ |
| 555 | 555 | static void hfdc_dma_write_callback(running_device *device, UINT8 data) |
| 556 | 556 | { |
| 557 | | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 557 | ti99_hfdc_state *card = get_safe_token(device->owner()); |
| 558 | 558 | card->ram[card->dma_address & 0x7fff] = data; |
| 559 | 559 | card->dma_address++; |
| 560 | 560 | } |
| r9498 | r9499 | |
| 633 | 633 | hfdc_harddisk_write_track |
| 634 | 634 | }; |
| 635 | 635 | |
| 636 | | static ti99_peb_card hfdc_card = |
| 636 | static ti99_peb_card hfdc_card = |
| 637 | 637 | { |
| 638 | 638 | data_r, |
| 639 | 639 | data_w, |
| 640 | 640 | cru_r, |
| 641 | 641 | cru_w, |
| 642 | | |
| 643 | | NULL, NULL, NULL, NULL |
| 642 | |
| 643 | NULL, NULL, NULL, NULL |
| 644 | 644 | }; |
| 645 | 645 | |
| 646 | 646 | static DEVICE_START( ti99_hfdc ) |
| 647 | 647 | { |
| 648 | 648 | ti99_hfdc_state *card = (ti99_hfdc_state*)downcast<legacy_device_base *>(device)->token(); |
| 649 | | |
| 649 | |
| 650 | 650 | /* Resolve the callbacks to the PEB */ |
| 651 | 651 | peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config(); |
| 652 | 652 | devcb_resolve_write_line(&card->lines.inta, &topeb->inta, device); |
| 653 | 653 | // The HFDC does not use READY; it has on-board RAM for DMA |
| 654 | | |
| 654 | |
| 655 | 655 | card->motor_on_timer = timer_alloc(device->machine, motor_on_timer_callback, (void *)device); |
| 656 | 656 | card->ram = NULL; |
| 657 | 657 | card->ram_offset[0] = 0x2000; // static bank |
| 658 | 658 | card->controller = device->subdevice("smc92x4"); |
| 659 | 659 | card->clock = device->subdevice("mm58274c"); |
| 660 | 660 | astring *region = new astring(); |
| 661 | | astring_assemble_3(region, device->tag(), ":", hfdc_region); |
| 661 | astring_assemble_3(region, device->tag(), ":", hfdc_region); |
| 662 | 662 | card->rom = memory_region(device->machine, astring_c(region)); |
| 663 | 663 | } |
| 664 | 664 | |
| r9498 | r9499 | |
| 677 | 677 | /* If the card is selected in the menu, register the card */ |
| 678 | 678 | if (input_port_read(device->machine, "DISKCTRL") == DISK_HFDC) |
| 679 | 679 | { |
| 680 | | running_device *peb = device->owner(); |
| 680 | running_device *peb = device->owner(); |
| 681 | 681 | int success = mount_card(peb, device, &hfdc_card, get_pebcard_config(device)->slot); |
| 682 | 682 | if (!success) return; |
| 683 | | |
| 683 | |
| 684 | 684 | // Allocate 32 KiB for on-board buffer memory |
| 685 | | if (card->ram==NULL) |
| 685 | if (card->ram==NULL) |
| 686 | 686 | { |
| 687 | 687 | card->ram = (UINT8*)malloc(32768); |
| 688 | | // memset(card->ram, 0, 32768); |
| 688 | // memset(card->ram, 0, 32768); |
| 689 | 689 | } |
| 690 | | |
| 690 | |
| 691 | 691 | if (input_port_read(device->machine, "HFDCDIP")&0x55) |
| 692 | 692 | ti99_set_80_track_drives(TRUE); |
| 693 | 693 | else |
| 694 | 694 | ti99_set_80_track_drives(FALSE); |
| 695 | | |
| 695 | |
| 696 | 696 | smc92x4_set_timing(card->controller, input_port_read(device->machine, "DRVSPD")); |
| 697 | | |
| 697 | |
| 698 | 698 | // Connect floppy drives to controller. Note that *this* is the |
| 699 | 699 | // controller, not the controller chip. The pcb contains a select |
| 700 | 700 | // logic. |
| r9498 | r9499 | |
| 702 | 702 | for (i = 0; i < 4; i++) |
| 703 | 703 | { |
| 704 | 704 | card->floppy_unit[i] = device->siblingdevice(flopname[i]); |
| 705 | | |
| 705 | |
| 706 | 706 | if (card->floppy_unit[i]!=NULL) |
| 707 | 707 | { |
| 708 | 708 | floppy_drive_set_controller(card->floppy_unit[i], device); |
| r9498 | r9499 | |
| 714 | 714 | logerror("hfdc: Image %s is null\n", flopname[i]); |
| 715 | 715 | } |
| 716 | 716 | } |
| 717 | | |
| 717 | |
| 718 | 718 | /* In the HFDC ROM, WDSx selects drive x; drive 0 is not used */ |
| 719 | 719 | for (i = 1; i < 4; i++) |
| 720 | 720 | { |
src/mess/machine/ti99/ti_rs232.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | 2 | TI-99 RS232 and Parallel interface card |
| 3 | | Currently this emulation does not interact with the serial interface |
| 4 | | on the host computer. Planned for a later release. |
| 5 | | As most serial applications require a feedback from the receiver's side |
| 6 | | the serial interface implementation will usually *not* work. |
| 7 | | |
| 8 | | TI99 RS232 card ('rs232') |
| 9 | | TMS9902 ('rs232:tms9902_0') |
| 10 | | TMS9902 ('rs232:tms9902_1') |
| 11 | | TI99 RS232 attached serial device ('rs232:serdev0') |
| 12 | | TI99 RS232 attached serial device ('rs232:serdev1') |
| 13 | | TI99 PIO attached parallel device ('rs232:piodev') |
| 14 | | |
| 3 | Currently this emulation does not interact with the serial interface |
| 4 | on the host computer. Planned for a later release. |
| 5 | As most serial applications require a feedback from the receiver's side |
| 6 | the serial interface implementation will usually *not* work. |
| 7 | |
| 8 | TI99 RS232 card ('rs232') |
| 9 | TMS9902 ('rs232:tms9902_0') |
| 10 | TMS9902 ('rs232:tms9902_1') |
| 11 | TI99 RS232 attached serial device ('rs232:serdev0') |
| 12 | TI99 RS232 attached serial device ('rs232:serdev1') |
| 13 | TI99 PIO attached parallel device ('rs232:piodev') |
| 14 | |
| 15 | 15 | */ |
| 16 | 16 | #include "emu.h" |
| 17 | 17 | #include "peribox.h" |
| r9498 | r9499 | |
| 27 | 27 | // Second card: Change CRU base to 0x1500 |
| 28 | 28 | // #define CRU_BASE 0x1500 |
| 29 | 29 | |
| 30 | | typedef ti99_pebcard_config ti_rs232_config; |
| 30 | typedef ti99_pebcard_config ti_rs232_config; |
| 31 | 31 | |
| 32 | 32 | typedef struct _ti_rs232_state |
| 33 | 33 | { |
| 34 | 34 | running_device *uart0, *uart1, *serdev0, *serdev1, *piodev; |
| 35 | 35 | |
| 36 | 36 | int selected; |
| 37 | | |
| 37 | |
| 38 | 38 | // PIO flags |
| 39 | 39 | int pio_direction; // a.k.a. PIOOC pio in output mode if 0 |
| 40 | 40 | int pio_handshakeout; |
| r9498 | r9499 | |
| 50 | 50 | int pio_readable; |
| 51 | 51 | int pio_writable; |
| 52 | 52 | int pio_write; // 1 if image is to be written to |
| 53 | | |
| 54 | | UINT8 *rom; |
| 55 | | |
| 53 | |
| 54 | UINT8 *rom; |
| 55 | |
| 56 | 56 | /* Keeps the state of the SENILA line. */ |
| 57 | 57 | UINT8 senila; |
| 58 | | |
| 58 | |
| 59 | 59 | /* Keeps the value put on the bus when SENILA becomes active. */ |
| 60 | | UINT8 ila; |
| 61 | | |
| 60 | UINT8 ila; |
| 61 | |
| 62 | 62 | /* Callback lines to the main system. */ |
| 63 | 63 | ti99_peb_connect lines; |
| 64 | | |
| 64 | |
| 65 | 65 | } ti_rs232_state; |
| 66 | 66 | |
| 67 | 67 | INLINE ti_rs232_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 110 | 110 | { |
| 111 | 111 | tms9902 = image.device().siblingdevice("tms9902_0"); |
| 112 | 112 | } |
| 113 | | else if (devnumber==1) |
| 113 | else if (devnumber==1) |
| 114 | 114 | { |
| 115 | 115 | tms9902 = image.device().siblingdevice("tms9902_1"); |
| 116 | 116 | } |
| r9498 | r9499 | |
| 119 | 119 | logerror("ti99/rs232: Could not find device tag number\n"); |
| 120 | 120 | return IMAGE_INIT_FAIL; |
| 121 | 121 | } |
| 122 | | |
| 122 | |
| 123 | 123 | if (image) |
| 124 | 124 | { |
| 125 | 125 | tms9902_set_cts(tms9902, 1); |
| r9498 | r9499 | |
| 140 | 140 | static DEVICE_IMAGE_LOAD( ti99_piodev ) |
| 141 | 141 | { |
| 142 | 142 | running_device *carddev = image.device().owner(); |
| 143 | | ti_rs232_state *card = get_safe_token(carddev); |
| 143 | ti_rs232_state *card = get_safe_token(carddev); |
| 144 | 144 | |
| 145 | 145 | /* tell whether the image is writable */ |
| 146 | 146 | card->pio_readable = !image.has_been_created(); |
| r9498 | r9499 | |
| 161 | 161 | static DEVICE_IMAGE_UNLOAD( ti99_piodev ) |
| 162 | 162 | { |
| 163 | 163 | running_device *carddev = image.device().owner(); |
| 164 | | ti_rs232_state *card = get_safe_token(carddev); |
| 164 | ti_rs232_state *card = get_safe_token(carddev); |
| 165 | 165 | |
| 166 | 166 | card->pio_writable = 0; |
| 167 | 167 | card->pio_handshakein = 1; /* receiver not ready */ |
| r9498 | r9499 | |
| 175 | 175 | */ |
| 176 | 176 | static READ8Z_DEVICE_HANDLER( cru_rz ) |
| 177 | 177 | { |
| 178 | | ti_rs232_state *card = get_safe_token(device); |
| 178 | ti_rs232_state *card = get_safe_token(device); |
| 179 | 179 | |
| 180 | 180 | if ((offset & 0xff00)==CRU_BASE) |
| 181 | 181 | { |
| r9498 | r9499 | |
| 195 | 195 | if (card->cts2) |
| 196 | 196 | reply |= 0x40; |
| 197 | 197 | if (card->led) |
| 198 | | reply |= 0x80; |
| 198 | reply |= 0x80; |
| 199 | 199 | *value = reply; |
| 200 | 200 | return; |
| 201 | 201 | } |
| r9498 | r9499 | |
| 213 | 213 | } |
| 214 | 214 | |
| 215 | 215 | /* |
| 216 | | CRU write |
| 216 | CRU write |
| 217 | 217 | */ |
| 218 | 218 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 219 | 219 | { |
| 220 | | ti_rs232_state *card = get_safe_token(device); |
| 220 | ti_rs232_state *card = get_safe_token(device); |
| 221 | 221 | |
| 222 | 222 | if ((offset & 0xff00)==CRU_BASE) |
| 223 | 223 | { |
| r9498 | r9499 | |
| 239 | 239 | case 0: |
| 240 | 240 | card->selected = data; |
| 241 | 241 | break; |
| 242 | | |
| 242 | |
| 243 | 243 | case 1: |
| 244 | 244 | card->pio_direction = data; |
| 245 | 245 | break; |
| 246 | | |
| 246 | |
| 247 | 247 | case 2: |
| 248 | 248 | if (data != card->pio_handshakeout) |
| 249 | 249 | { |
| r9498 | r9499 | |
| 284 | 284 | } |
| 285 | 285 | } |
| 286 | 286 | break; |
| 287 | | |
| 287 | |
| 288 | 288 | case 3: |
| 289 | 289 | card->pio_spareout = data; |
| 290 | 290 | break; |
| 291 | | |
| 291 | |
| 292 | 292 | case 4: |
| 293 | 293 | card->flag0 = data; |
| 294 | 294 | break; |
| 295 | | |
| 295 | |
| 296 | 296 | case 5: |
| 297 | 297 | card->cts1 = data; |
| 298 | 298 | break; |
| 299 | | |
| 299 | |
| 300 | 300 | case 6: |
| 301 | 301 | card->cts2 = data; |
| 302 | 302 | break; |
| 303 | | |
| 303 | |
| 304 | 304 | case 7: |
| 305 | 305 | card->led = data; |
| 306 | 306 | break; |
| r9498 | r9499 | |
| 314 | 314 | */ |
| 315 | 315 | static READ8Z_DEVICE_HANDLER( data_rz ) |
| 316 | 316 | { |
| 317 | | ti_rs232_state *card = get_safe_token(device); |
| 317 | ti_rs232_state *card = get_safe_token(device); |
| 318 | 318 | |
| 319 | 319 | if (card->senila) |
| 320 | 320 | { |
| r9498 | r9499 | |
| 328 | 328 | // lines are there. |
| 329 | 329 | card->ila = 0; |
| 330 | 330 | } |
| 331 | | if (((offset & 0xe000)==0x4000) && card->selected) |
| 331 | if (((offset & 0xe000)==0x4000) && card->selected) |
| 332 | 332 | { |
| 333 | 333 | if ((offset & 0x1000)==0x0000) |
| 334 | 334 | { |
| r9498 | r9499 | |
| 342 | 342 | } |
| 343 | 343 | |
| 344 | 344 | /* |
| 345 | | Memory write |
| 345 | Memory write |
| 346 | 346 | */ |
| 347 | 347 | static WRITE8_DEVICE_HANDLER( data_w ) |
| 348 | 348 | { |
| 349 | | ti_rs232_state *card = get_safe_token(device); |
| 349 | ti_rs232_state *card = get_safe_token(device); |
| 350 | 350 | |
| 351 | | if (((offset & 0xe000)==0x4000) && card->selected) |
| 351 | if (((offset & 0xe000)==0x4000) && card->selected) |
| 352 | 352 | { |
| 353 | 353 | if ((offset & 0x1001)==0x1000) |
| 354 | 354 | { |
| r9498 | r9499 | |
| 365 | 365 | static TMS9902_INT_CALLBACK( int_callback_0 ) |
| 366 | 366 | { |
| 367 | 367 | running_device *carddev = device->owner(); |
| 368 | | ti_rs232_state *card = get_safe_token(carddev); |
| 369 | | if (INT) |
| 370 | | card->ila |= SENILA_0_BIT; |
| 368 | ti_rs232_state *card = get_safe_token(carddev); |
| 369 | if (INT) |
| 370 | card->ila |= SENILA_0_BIT; |
| 371 | 371 | else |
| 372 | | card->ila &= ~SENILA_0_BIT; |
| 373 | | |
| 372 | card->ila &= ~SENILA_0_BIT; |
| 373 | |
| 374 | 374 | devcb_call_write_line(&card->lines.inta, INT); |
| 375 | 375 | } |
| 376 | 376 | |
| 377 | 377 | static TMS9902_INT_CALLBACK( int_callback_1 ) |
| 378 | 378 | { |
| 379 | 379 | running_device *carddev = device->owner(); |
| 380 | | ti_rs232_state *card = get_safe_token(carddev); |
| 381 | | if (INT) |
| 382 | | card->ila |= SENILA_1_BIT; |
| 380 | ti_rs232_state *card = get_safe_token(carddev); |
| 381 | if (INT) |
| 382 | card->ila |= SENILA_1_BIT; |
| 383 | 383 | else |
| 384 | | card->ila &= ~SENILA_1_BIT; |
| 385 | | |
| 384 | card->ila &= ~SENILA_1_BIT; |
| 385 | |
| 386 | 386 | devcb_call_write_line(&card->lines.inta, INT); |
| 387 | 387 | } |
| 388 | 388 | |
| r9498 | r9499 | |
| 434 | 434 | }; |
| 435 | 435 | |
| 436 | 436 | |
| 437 | | static ti99_peb_card tirs232_card = |
| 437 | static ti99_peb_card tirs232_card = |
| 438 | 438 | { |
| 439 | 439 | data_rz, data_w, // memory access read/write |
| 440 | 440 | cru_rz, cru_w, // CRU access |
| 441 | | senila, NULL, // SENILA/B access |
| 441 | senila, NULL, // SENILA/B access |
| 442 | 442 | NULL, NULL // 16 bit access (none here) |
| 443 | 443 | }; |
| 444 | 444 | |
| 445 | 445 | /* |
| 446 | | Defines the serial serdev. |
| 446 | Defines the serial serdev. |
| 447 | 447 | */ |
| 448 | 448 | DEVICE_GET_INFO( ti99_rs232_serdev ) |
| 449 | 449 | { |
| r9498 | r9499 | |
| 456 | 456 | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break; |
| 457 | 457 | |
| 458 | 458 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ti99_rs232_serdev ); break; |
| 459 | | // case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ti99_rs232_serdev ); break; |
| 459 | // case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ti99_rs232_serdev ); break; |
| 460 | 460 | case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( ti99_rs232_serdev ); break; |
| 461 | 461 | case DEVINFO_STR_NAME: strcpy( info->s, "TI99 RS232 attached serial device"); break; |
| 462 | 462 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Peripheral expansion"); break; |
| r9498 | r9499 | |
| 468 | 468 | } |
| 469 | 469 | |
| 470 | 470 | /* |
| 471 | | Defines the PIO (parallel IO) serdev |
| 471 | Defines the PIO (parallel IO) serdev |
| 472 | 472 | */ |
| 473 | 473 | DEVICE_GET_INFO( ti99_piodev ) |
| 474 | 474 | { |
| r9498 | r9499 | |
| 503 | 503 | peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config(); |
| 504 | 504 | |
| 505 | 505 | astring *region = new astring(); |
| 506 | | astring_assemble_3(region, device->tag(), ":", ser_region); |
| 506 | astring_assemble_3(region, device->tag(), ":", ser_region); |
| 507 | 507 | card->rom = memory_region(device->machine, astring_c(region)); |
| 508 | 508 | devcb_resolve_write_line(&card->lines.inta, &topeb->inta, device); |
| 509 | 509 | // READY and INTB are not used |
| r9498 | r9499 | |
| 523 | 523 | ti_rs232_state *card = (ti_rs232_state*)downcast<legacy_device_base *>(device)->token(); |
| 524 | 524 | /* Register the card */ |
| 525 | 525 | running_device *peb = device->owner(); |
| 526 | | |
| 526 | |
| 527 | 527 | if (input_port_read(device->machine, "SERIAL")==SERIAL_TI) |
| 528 | 528 | { |
| 529 | 529 | int success = mount_card(peb, device, &tirs232_card, get_pebcard_config(device)->slot); |
| r9498 | r9499 | |
| 545 | 545 | MDRV_TMS9902_ADD("tms9902_1", tms9902_params_1) |
| 546 | 546 | MDRV_DEVICE_ADD("serdev0", TI99_RS232, 0) |
| 547 | 547 | MDRV_DEVICE_ADD("serdev1", TI99_RS232, 0) |
| 548 | | MDRV_DEVICE_ADD("piodev", TI99_PIO, 0) |
| 548 | MDRV_DEVICE_ADD("piodev", TI99_PIO, 0) |
| 549 | 549 | MACHINE_CONFIG_END |
| 550 | 550 | |
| 551 | 551 | ROM_START( ti_rs232 ) |
src/mess/machine/ti99/peribox.c
| r9498 | r9499 | |
| 24 | 24 | June 2010: Reimplemented using device structure (MZ) (obsoletes 99_peb.c) |
| 25 | 25 | |
| 26 | 26 | Slots: |
| 27 | | |
| 27 | |
| 28 | 28 | REAR |
| 29 | 29 | +8V 1||2 +8V |
| 30 | 30 | GND 3||4 READY |
| r9498 | r9499 | |
| 35 | 35 | HOLD* 13||14 IAQHDA |
| 36 | 36 | SENILA* 15||16 SENILB* |
| 37 | 37 | INTA* 17||18 INTB* |
| 38 | | D7 19||20 GND |
| 38 | D7 19||20 GND |
| 39 | 39 | D5 21||22 D6 |
| 40 | 40 | D3 23||24 D4 |
| 41 | 41 | D1 25||26 D2 |
| r9498 | r9499 | |
| 44 | 44 | A12 31||32 A13 |
| 45 | 45 | A10 33||34 A11 |
| 46 | 46 | A8 35||36 A9 |
| 47 | | A6 37||38 A7 |
| 47 | A6 37||38 A7 |
| 48 | 48 | A4 39||40 A5 |
| 49 | 49 | A2 41||42 A3 |
| 50 | 50 | A0 43||44 A1 |
| 51 | | AMB 45||46 AMA |
| 51 | AMB 45||46 AMA |
| 52 | 52 | GND 47||48 AMC |
| 53 | 53 | GND 49||50 CLKOUT* |
| 54 | 54 | CRUCLK* 51||52 DBIN |
| r9498 | r9499 | |
| 60 | 60 | |
| 61 | 61 | < from box to console |
| 62 | 62 | > from console into box |
| 63 | | |
| 63 | |
| 64 | 64 | READYA < System ready (goes to READY, 10K pull-up to +5V) A low level puts the cpu on hold. |
| 65 | | RESET* > System reset (active low) |
| 66 | | SCLK nc System clock (not connected in interface card) |
| 67 | | LCP* nc CPU indicator 1=TI99 0=2nd generation (not connected in interface card) |
| 65 | RESET* > System reset (active low) |
| 66 | SCLK nc System clock (not connected in interface card) |
| 67 | LCP* nc CPU indicator 1=TI99 0=2nd generation (not connected in interface card) |
| 68 | 68 | BOOTPG* nc ? |
| 69 | | AUDIO < Input audio (to AUDIOIN in console) |
| 70 | | RDBENA* < Active low: enable flex cable data bus drivers (1K pull-up) |
| 71 | | PCBEN H PCB enable for burn-in (always High) |
| 72 | | HOLD* H Active low CPU hold request (always High) |
| 73 | | IAQHDA nc IAQ [or] HOLDA (logical or) |
| 74 | | SENILA* H(>) Interrupt level A sense enable (always High) |
| 75 | | SENILB* H(>) Interrupt level B sense enable (always High) |
| 76 | | INTA* < Interrupt level A (active low, goes to EXTINT*) |
| 77 | | INTB* nc Interrupt level B (not used) |
| 78 | | LOAD* nc Unmaskable interrupt (not carried by interface cable/card) |
| 79 | | D0-D7 <> Data bus (D0 most significant) |
| 69 | AUDIO < Input audio (to AUDIOIN in console) |
| 70 | RDBENA* < Active low: enable flex cable data bus drivers (1K pull-up) |
| 71 | PCBEN H PCB enable for burn-in (always High) |
| 72 | HOLD* H Active low CPU hold request (always High) |
| 73 | IAQHDA nc IAQ [or] HOLDA (logical or) |
| 74 | SENILA* H(>) Interrupt level A sense enable (always High) |
| 75 | SENILB* H(>) Interrupt level B sense enable (always High) |
| 76 | INTA* < Interrupt level A (active low, goes to EXTINT*) |
| 77 | INTB* nc Interrupt level B (not used) |
| 78 | LOAD* nc Unmaskable interrupt (not carried by interface cable/card) |
| 79 | D0-D7 <> Data bus (D0 most significant) |
| 80 | 80 | A0-A15 > Address bus (A0 most sig; A15 also used as CRUOUT) |
| 81 | 81 | AMA/B/C H Extra address bits (always high for TI-99/4x) |
| 82 | 82 | CLKOUT* > Inverted PHI3 clock, from TIM9904 clock generator |
| r9498 | r9499 | |
| 84 | 84 | DBIN > Active high = read memory. Drives the data bus buffers. |
| 85 | 85 | WE* > Write Enable pulse (derived from TMS9900 WE* pin) |
| 86 | 86 | CRUIN < CRU input bit to TMS9900 |
| 87 | | MEMEN* > Memory access enable (active low) |
| 87 | MEMEN* > Memory access enable (active low) |
| 88 | 88 | |
| 89 | 89 | |
| 90 | 90 | The obscure SENILx lines: |
| 91 | 91 | |
| 92 | | With SENILA* going low, a value shall be put on the data bus, |
| 93 | | representing the interrupt status bits. It can also be used to determine |
| 94 | | the source of the interrupt: The RS232 card (in its standard configuration) |
| 95 | | uses the data bus bits 0 and 1 for its two UARTs, while in the second |
| 96 | | configuration, it uses bits 4 and 5. Still note that the TI-99/4x does not make |
| 92 | With SENILA* going low, a value shall be put on the data bus, |
| 93 | representing the interrupt status bits. It can also be used to determine |
| 94 | the source of the interrupt: The RS232 card (in its standard configuration) |
| 95 | uses the data bus bits 0 and 1 for its two UARTs, while in the second |
| 96 | configuration, it uses bits 4 and 5. Still note that the TI-99/4x does not make |
| 97 | 97 | use of SENILA*. |
| 98 | 98 | |
| 99 | 99 | SENILB* / INTB* was planned to be used with disk controllers. The PHP1240 disk |
| 100 | 100 | controller puts the value of INTB* on D0 when SENILB* gets active (low) which |
| 101 | | reflects the INTRQ output pin of the WD1771. This signal is not used, however. |
| 101 | reflects the INTRQ output pin of the WD1771. This signal is not used, however. |
| 102 | 102 | Instead, the disk controller combines DRQ and IRQ and makes use of a READY/HOLD |
| 103 | 103 | control of the CPU. |
| 104 | 104 | |
| 105 | | Obviously, SENILA* and SENILB* should never be active at the same time, and |
| 106 | | neither should any memory access to a card be active at the same time, for in |
| 105 | Obviously, SENILA* and SENILB* should never be active at the same time, and |
| 106 | neither should any memory access to a card be active at the same time, for in |
| 107 | 107 | both cases, data bus lines may be set to different levels simultaneously. One |
| 108 | | possible application case is to turn off all cards in the box, lower SENILA*, |
| 108 | possible application case is to turn off all cards in the box, lower SENILA*, |
| 109 | 109 | and then do a read access in the memory area of any card in the P-Box (e.g. |
| 110 | 110 | 0x4000-0x5fff). Another possiblity is that the currently active card simply |
| 111 | 111 | does not respond to a certain memory access, and in this case the status bits |
| r9498 | r9499 | |
| 113 | 113 | |
| 114 | 114 | Also note that the SENILx lines access all cards in parallel, meaning that there |
| 115 | 115 | must be an agreement which cards may use which bits on the data bus. The lines |
| 116 | | do not depend on the card being active at that time. |
| 116 | do not depend on the card being active at that time. |
| 117 | 117 | */ |
| 118 | 118 | |
| 119 | 119 | #include "emu.h" |
| r9498 | r9499 | |
| 150 | 150 | |
| 151 | 151 | typedef struct _ti99_peb_slot |
| 152 | 152 | { |
| 153 | | running_device *card; |
| 154 | | ti99_peb_card *intf; |
| 153 | running_device *card; |
| 154 | ti99_peb_card *intf; |
| 155 | 155 | } ti99_peb_slot; |
| 156 | 156 | |
| 157 | 157 | typedef struct _ti99_peb_state |
| r9498 | r9499 | |
| 165 | 165 | UINT32 ready_state; |
| 166 | 166 | |
| 167 | 167 | int highest; |
| 168 | | |
| 168 | |
| 169 | 169 | // Callback to the main system |
| 170 | 170 | ti99_peb_connect lines; |
| 171 | | |
| 171 | |
| 172 | 172 | } ti99_peb_state; |
| 173 | 173 | |
| 174 | 174 | INLINE ti99_peb_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 227 | 227 | } |
| 228 | 228 | |
| 229 | 229 | /* |
| 230 | | Declares the callbacks above that are called from the cards. This instance |
| 231 | | is passed to the cards with MDRV_PBOXCARD_ADD and must be handled as a |
| 232 | | static_config. |
| 230 | Declares the callbacks above that are called from the cards. This instance |
| 231 | is passed to the cards with MDRV_PBOXCARD_ADD and must be handled as a |
| 232 | static_config. |
| 233 | 233 | */ |
| 234 | | const peb_callback_if peb_callback = |
| 235 | | { |
| 236 | | DEVCB_LINE( inta ), |
| 237 | | DEVCB_LINE( intb ), |
| 238 | | DEVCB_LINE( ready ) |
| 234 | const peb_callback_if peb_callback = |
| 235 | { |
| 236 | DEVCB_LINE( inta ), |
| 237 | DEVCB_LINE( intb ), |
| 238 | DEVCB_LINE( ready ) |
| 239 | 239 | }; |
| 240 | 240 | |
| 241 | 241 | /* |
| 242 | | Mount the PEB card. Although possible, this is not done by the box itself; |
| 243 | | instead, the card must call this function on the box. The advantage is |
| 244 | | that we can assign the same slot to different cards which are selected |
| 245 | | by dip switches. Only the card which is selected will register itself; the |
| 246 | | other cards are stillborn. |
| 247 | | Returns TRUE when the card could be mounted. |
| 242 | Mount the PEB card. Although possible, this is not done by the box itself; |
| 243 | instead, the card must call this function on the box. The advantage is |
| 244 | that we can assign the same slot to different cards which are selected |
| 245 | by dip switches. Only the card which is selected will register itself; the |
| 246 | other cards are stillborn. |
| 247 | Returns TRUE when the card could be mounted. |
| 248 | 248 | */ |
| 249 | 249 | int mount_card(running_device *device, running_device *cardptr, ti99_peb_card *cardintf, int slotindex) |
| 250 | 250 | { |
| r9498 | r9499 | |
| 265 | 265 | } |
| 266 | 266 | } |
| 267 | 267 | else |
| 268 | | logerror("ti99_peb: Invalid slot number %d\n", slotindex); |
| 268 | logerror("ti99_peb: Invalid slot number %d\n", slotindex); |
| 269 | 269 | return FALSE; |
| 270 | 270 | } |
| 271 | 271 | |
| r9498 | r9499 | |
| 324 | 324 | } |
| 325 | 325 | |
| 326 | 326 | /* |
| 327 | | For SGCPU |
| 327 | For SGCPU |
| 328 | 328 | */ |
| 329 | 329 | READ16Z_DEVICE_HANDLER( ti99_peb_data16_rz ) |
| 330 | 330 | { |
| r9498 | r9499 | |
| 338 | 338 | } |
| 339 | 339 | |
| 340 | 340 | /* |
| 341 | | For SGCPU |
| 341 | For SGCPU |
| 342 | 342 | */ |
| 343 | 343 | WRITE16_DEVICE_HANDLER( ti99_peb_data16_w ) |
| 344 | 344 | { |
| r9498 | r9499 | |
| 352 | 352 | } |
| 353 | 353 | |
| 354 | 354 | /* |
| 355 | | SENILx |
| 356 | | TODO: Check whether device is the correct pointer (seems to be wrong here, |
| 357 | | the device is usually the caller) |
| 355 | SENILx |
| 356 | TODO: Check whether device is the correct pointer (seems to be wrong here, |
| 357 | the device is usually the caller) |
| 358 | 358 | */ |
| 359 | 359 | WRITE_LINE_DEVICE_HANDLER( ti99_peb_senila ) |
| 360 | 360 | { |
| r9498 | r9499 | |
| 389 | 389 | |
| 390 | 390 | for (int slotindex=0; slotindex < MAXSLOTS; slotindex++) |
| 391 | 391 | unmount_card(device, slotindex); |
| 392 | | |
| 392 | |
| 393 | 393 | /* Resolve the callbacks to the console */ |
| 394 | 394 | devcb_write_line inta = DEVCB_LINE(pebconf->inta); |
| 395 | 395 | devcb_write_line intb = DEVCB_LINE(pebconf->intb); |
| r9498 | r9499 | |
| 409 | 409 | { |
| 410 | 410 | ti99_peb_state *peb = get_safe_token(device); |
| 411 | 411 | logerror("ti99_peb: reset\n"); |
| 412 | | peb->inta_state = 0; |
| 413 | | peb->intb_state = 0; |
| 412 | peb->inta_state = 0; |
| 413 | peb->intb_state = 0; |
| 414 | 414 | peb->ready_state = 0; |
| 415 | 415 | peb->highest = 0; |
| 416 | 416 | for (int i=0; i < MAXSLOTS; i++) unmount_card(device, i); |
| r9498 | r9499 | |
| 422 | 422 | MDRV_DEVICE_CONFIG( peb_callback ) |
| 423 | 423 | |
| 424 | 424 | /* |
| 425 | | We're emulating a "super box" with more than 8 slots. The original |
| 426 | | box had 8 slots, but that's a bit too limiting. |
| 427 | | This may become organized differently in future versions; for now |
| 428 | | we'll go this way. |
| 429 | | |
| 430 | | Slot 0 is the "Flex cable interface" / SGCPU / Geneve |
| 431 | | We assign the same slot number for some cards that cannot be used |
| 432 | | in parallel anyway. The config switch will determine which one to use. |
| 433 | | Future works: |
| 434 | | // WHTech SCSI controller |
| 435 | | // MDRV_PBOXCARD_ADD("SCSI", 4, scsi_intf) |
| 425 | We're emulating a "super box" with more than 8 slots. The original |
| 426 | box had 8 slots, but that's a bit too limiting. |
| 427 | This may become organized differently in future versions; for now |
| 428 | we'll go this way. |
| 436 | 429 | |
| 437 | | // Horizon Ramdisk |
| 438 | | // MDRV_PBOXCARD_ADD("HRD", 10, ramdisk_intf) |
| 439 | | */ |
| 430 | Slot 0 is the "Flex cable interface" / SGCPU / Geneve |
| 431 | We assign the same slot number for some cards that cannot be used |
| 432 | in parallel anyway. The config switch will determine which one to use. |
| 433 | Future works: |
| 434 | // WHTech SCSI controller |
| 435 | // MDRV_PBOXCARD_ADD("SCSI", 4, scsi_intf) |
| 440 | 436 | |
| 437 | // Horizon Ramdisk |
| 438 | // MDRV_PBOXCARD_ADD("HRD", 10, ramdisk_intf) |
| 439 | */ |
| 440 | |
| 441 | 441 | static MACHINE_CONFIG_FRAGMENT( ti99_peb ) |
| 442 | | MDRV_PBOXCARD_ADD( "mem_ti32k", TI32KMEM, 1 ) |
| 443 | | MDRV_PBOXCARD_ADD( "mem_sams1m", SAMSMEM, 1 ) |
| 444 | | MDRV_PBOXCARD_ADD( "mem_myarc512", MYARCMEM, 1 ) |
| 445 | | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 2 ) |
| 446 | | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 3 ) |
| 447 | | MDRV_PBOXCARD_ADD( "ide", TNIDE, 4 ) |
| 448 | | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 5 ) |
| 449 | | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 7 ) |
| 450 | | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 451 | | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 452 | | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 453 | | |
| 442 | MDRV_PBOXCARD_ADD( "mem_ti32k", TI32KMEM, 1 ) |
| 443 | MDRV_PBOXCARD_ADD( "mem_sams1m", SAMSMEM, 1 ) |
| 444 | MDRV_PBOXCARD_ADD( "mem_myarc512", MYARCMEM, 1 ) |
| 445 | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 2 ) |
| 446 | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 3 ) |
| 447 | MDRV_PBOXCARD_ADD( "ide", TNIDE, 4 ) |
| 448 | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 5 ) |
| 449 | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 7 ) |
| 450 | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 451 | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 452 | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 453 | |
| 454 | 454 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 455 | 455 | MDRV_MFMHD_3_DRIVES_ADD() |
| 456 | 456 | MACHINE_CONFIG_END |
| 457 | 457 | |
| 458 | 458 | static MACHINE_CONFIG_FRAGMENT( ti994a_peb ) |
| 459 | | MDRV_PBOXCARD_ADD( "mem_ti32k", TI32KMEM, 1 ) |
| 460 | | MDRV_PBOXCARD_ADD( "mem_sams1m", SAMSMEM, 1 ) |
| 461 | | MDRV_PBOXCARD_ADD( "mem_myarc512", MYARCMEM, 1 ) |
| 462 | | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 2 ) |
| 463 | | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 3 ) |
| 464 | | MDRV_PBOXCARD_ADD( "ide", TNIDE, 4 ) |
| 465 | | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 5 ) |
| 466 | | MDRV_PBOXCARD_ADD( "p_code_card", PCODEN, 6 ) |
| 467 | | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 7 ) |
| 468 | | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 469 | | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 470 | | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 471 | | |
| 459 | MDRV_PBOXCARD_ADD( "mem_ti32k", TI32KMEM, 1 ) |
| 460 | MDRV_PBOXCARD_ADD( "mem_sams1m", SAMSMEM, 1 ) |
| 461 | MDRV_PBOXCARD_ADD( "mem_myarc512", MYARCMEM, 1 ) |
| 462 | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 2 ) |
| 463 | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 3 ) |
| 464 | MDRV_PBOXCARD_ADD( "ide", TNIDE, 4 ) |
| 465 | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 5 ) |
| 466 | MDRV_PBOXCARD_ADD( "p_code_card", PCODEN, 6 ) |
| 467 | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 7 ) |
| 468 | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 469 | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 470 | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 471 | |
| 472 | 472 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 473 | 473 | MDRV_MFMHD_3_DRIVES_ADD() |
| 474 | 474 | MACHINE_CONFIG_END |
| 475 | 475 | |
| 476 | 476 | static MACHINE_CONFIG_FRAGMENT( ti99ev_peb ) |
| 477 | | MDRV_PBOXCARD_ADD( "mem_ti32k", TI32KMEM, 1 ) |
| 478 | | MDRV_PBOXCARD_ADD( "mem_sams1m", SAMSMEM, 1 ) |
| 479 | | MDRV_PBOXCARD_ADD( "mem_myarc512", MYARCMEM, 1 ) |
| 480 | | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 2 ) |
| 481 | | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 3 ) |
| 482 | | MDRV_PBOXCARD_ADD( "ide", TNIDE, 4 ) |
| 483 | | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 5 ) |
| 484 | | MDRV_PBOXCARD_ADD( "p_code_card", PCODEN, 6 ) |
| 485 | | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 7 ) |
| 486 | | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 487 | | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 488 | | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 489 | | MDRV_PBOXCARD_ADD( "evpc", EVPC, 9 ) |
| 490 | | |
| 477 | MDRV_PBOXCARD_ADD( "mem_ti32k", TI32KMEM, 1 ) |
| 478 | MDRV_PBOXCARD_ADD( "mem_sams1m", SAMSMEM, 1 ) |
| 479 | MDRV_PBOXCARD_ADD( "mem_myarc512", MYARCMEM, 1 ) |
| 480 | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 2 ) |
| 481 | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 3 ) |
| 482 | MDRV_PBOXCARD_ADD( "ide", TNIDE, 4 ) |
| 483 | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 5 ) |
| 484 | MDRV_PBOXCARD_ADD( "p_code_card", PCODEN, 6 ) |
| 485 | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 7 ) |
| 486 | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 487 | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 488 | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 489 | MDRV_PBOXCARD_ADD( "evpc", EVPC, 9 ) |
| 490 | |
| 491 | 491 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 492 | 492 | MDRV_MFMHD_3_DRIVES_ADD() |
| 493 | 493 | MACHINE_CONFIG_END |
| 494 | 494 | |
| 495 | 495 | |
| 496 | 496 | static MACHINE_CONFIG_FRAGMENT( ti998_peb ) |
| 497 | | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 1 ) |
| 498 | | MDRV_PBOXCARD_ADD( "ide", TNIDE, 2 ) |
| 499 | | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 3 ) |
| 500 | | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 501 | | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 502 | | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 503 | | |
| 497 | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 1 ) |
| 498 | MDRV_PBOXCARD_ADD( "ide", TNIDE, 2 ) |
| 499 | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 3 ) |
| 500 | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 8 ) |
| 501 | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 8 ) |
| 502 | MDRV_PBOXCARD_ADD( "bwg", BWG, 8 ) |
| 503 | |
| 504 | 504 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 505 | 505 | MDRV_MFMHD_3_DRIVES_ADD() |
| 506 | 506 | MACHINE_CONFIG_END |
| 507 | 507 | |
| 508 | 508 | static MACHINE_CONFIG_FRAGMENT( ti99sg_peb ) |
| 509 | | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 1 ) |
| 510 | | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 2 ) |
| 511 | | MDRV_PBOXCARD_ADD( "ide", TNIDE, 3 ) |
| 512 | | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 4 ) |
| 513 | | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 6 ) |
| 514 | | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 7 ) |
| 515 | | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 7 ) |
| 516 | | MDRV_PBOXCARD_ADD( "bwg", BWG, 7 ) |
| 517 | | MDRV_PBOXCARD_ADD( "evpc", EVPC, 8 ) |
| 518 | | |
| 509 | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 1 ) |
| 510 | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 2 ) |
| 511 | MDRV_PBOXCARD_ADD( "ide", TNIDE, 3 ) |
| 512 | MDRV_PBOXCARD_ADD( "hsgpl", HSGPL, 4 ) |
| 513 | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 6 ) |
| 514 | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 7 ) |
| 515 | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 7 ) |
| 516 | MDRV_PBOXCARD_ADD( "bwg", BWG, 7 ) |
| 517 | MDRV_PBOXCARD_ADD( "evpc", EVPC, 8 ) |
| 518 | |
| 519 | 519 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 520 | 520 | MDRV_MFMHD_3_DRIVES_ADD() |
| 521 | 521 | MACHINE_CONFIG_END |
| 522 | 522 | |
| 523 | 523 | static MACHINE_CONFIG_FRAGMENT( geneve_peb ) |
| 524 | | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 1 ) |
| 525 | | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 2 ) |
| 526 | | MDRV_PBOXCARD_ADD( "ide", TNIDE, 3 ) |
| 527 | | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 6 ) |
| 528 | | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 7 ) |
| 529 | | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 7 ) |
| 530 | | MDRV_PBOXCARD_ADD( "bwg", BWG, 7 ) |
| 531 | | |
| 524 | MDRV_PBOXCARD_ADD( "speech", TISPEECH, 1 ) |
| 525 | MDRV_PBOXCARD_ADD( "usbsmart", USBSMART, 2 ) |
| 526 | MDRV_PBOXCARD_ADD( "ide", TNIDE, 3 ) |
| 527 | MDRV_PBOXCARD_ADD( "rs232_card", TIRS232, 6 ) |
| 528 | MDRV_PBOXCARD_ADD( "ti_fdc", TIFDC, 7 ) |
| 529 | MDRV_PBOXCARD_ADD( "hfdc", HFDC, 7 ) |
| 530 | MDRV_PBOXCARD_ADD( "bwg", BWG, 7 ) |
| 531 | |
| 532 | 532 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 533 | 533 | MDRV_MFMHD_3_DRIVES_ADD() |
| 534 | 534 | MACHINE_CONFIG_END |
src/mess/machine/ti99/mapper8.c
| r9498 | r9499 | |
| 1 | 1 | /*************************************************************************** |
| 2 | | |
| 3 | | TI-99/8 Address decoder and mapper |
| 4 | | |
| 5 | | This component implements the address decoder and mapper logic from the |
| 6 | | TI-99/8 console. |
| 7 | | |
| 8 | | The TI-99/8 defines a "logical address map" with 64 KiB (according to the |
| 9 | | 16 address bits) and a "physical address map" with 16 MiB (according to the |
| 10 | | 24 address bits of the mapper). Note that the mapper only uses 16 outgoing |
| 11 | | address lines and multiplexes the address bytes. |
| 12 | | |
| 13 | | Note: The TI-99/8's internal codename was "Armadillo" |
| 14 | | |
| 15 | | Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode) |
| 16 | | |
| 17 | | 0 00ff0000 -> Unmapped; logical address 0000...0fff = ROM0 |
| 18 | | 1 00ff0000 -> Unmapped; logical address 1000...1fff = ROM0 |
| 19 | | 2 00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff |
| 20 | | 3 00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff |
| 21 | | 4 00ff4000 -> DSR space (internal / ioport) |
| 22 | | 5 00ff5000 -> DSR space (internal / ioport) |
| 23 | | 6 00ff6000 -> Cartridge space (6000..6fff) |
| 24 | | 7 00ff7000 -> Cartridge space (7000..7fff) |
| 25 | | 8 00ff0000 -> Unmapped; device ports (VDP) and SRAM |
| 26 | | 9 00ff0000 -> Unmapped; device ports (Speech, GROM) |
| 27 | | A 00002800 -> DRAM; a000 = 002800, afff = 0037ff |
| 28 | | B 00003800 -> DRAM; b000 = 003800, bfff = 0047ff |
| 29 | | C 00004800 -> DRAM; c000 = 004800, cfff = 0057ff |
| 30 | | D 00005800 -> DRAM; d000 = 005800, dfff = 0067ff |
| 31 | | E 00006800 -> DRAM; e000 = 006800, efff = 0077ff |
| 32 | | F 00007800 -> DRAM; f000 = 007800, ffff = 0087ff |
| 33 | 2 | |
| 34 | | Informations taken from |
| 35 | | [1] ARMADILLO PRODUCT SPECIFICATIONS |
| 36 | | [2] TI-99/8 Graphics Programming Language interpreter |
| 37 | | |
| 38 | | Michael Zapf, October 2010 |
| 39 | | |
| 3 | TI-99/8 Address decoder and mapper |
| 4 | |
| 5 | This component implements the address decoder and mapper logic from the |
| 6 | TI-99/8 console. |
| 7 | |
| 8 | The TI-99/8 defines a "logical address map" with 64 KiB (according to the |
| 9 | 16 address bits) and a "physical address map" with 16 MiB (according to the |
| 10 | 24 address bits of the mapper). Note that the mapper only uses 16 outgoing |
| 11 | address lines and multiplexes the address bytes. |
| 12 | |
| 13 | Note: The TI-99/8's internal codename was "Armadillo" |
| 14 | |
| 15 | Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode) |
| 16 | |
| 17 | 0 00ff0000 -> Unmapped; logical address 0000...0fff = ROM0 |
| 18 | 1 00ff0000 -> Unmapped; logical address 1000...1fff = ROM0 |
| 19 | 2 00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff |
| 20 | 3 00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff |
| 21 | 4 00ff4000 -> DSR space (internal / ioport) |
| 22 | 5 00ff5000 -> DSR space (internal / ioport) |
| 23 | 6 00ff6000 -> Cartridge space (6000..6fff) |
| 24 | 7 00ff7000 -> Cartridge space (7000..7fff) |
| 25 | 8 00ff0000 -> Unmapped; device ports (VDP) and SRAM |
| 26 | 9 00ff0000 -> Unmapped; device ports (Speech, GROM) |
| 27 | A 00002800 -> DRAM; a000 = 002800, afff = 0037ff |
| 28 | B 00003800 -> DRAM; b000 = 003800, bfff = 0047ff |
| 29 | C 00004800 -> DRAM; c000 = 004800, cfff = 0057ff |
| 30 | D 00005800 -> DRAM; d000 = 005800, dfff = 0067ff |
| 31 | E 00006800 -> DRAM; e000 = 006800, efff = 0077ff |
| 32 | F 00007800 -> DRAM; f000 = 007800, ffff = 0087ff |
| 33 | |
| 34 | Informations taken from |
| 35 | [1] ARMADILLO PRODUCT SPECIFICATIONS |
| 36 | [2] TI-99/8 Graphics Programming Language interpreter |
| 37 | |
| 38 | Michael Zapf, October 2010 |
| 39 | |
| 40 | 40 | ***************************************************************************/ |
| 41 | 41 | |
| 42 | 42 | #include "emu.h" |
| r9498 | r9499 | |
| 62 | 62 | typedef struct _log_addressed_device |
| 63 | 63 | { |
| 64 | 64 | /* The device. */ |
| 65 | | running_device *device; |
| 66 | | |
| 65 | running_device *device; |
| 66 | |
| 67 | 67 | /* Mode. */ |
| 68 | 68 | int mode; |
| 69 | 69 | |
| 70 | 70 | /* Stop. If true, stop the address decoder here and do not look for parallel devices. */ |
| 71 | 71 | int stop; |
| 72 | | |
| 72 | |
| 73 | 73 | /* Address bits involved */ |
| 74 | | UINT16 address_mask; |
| 74 | UINT16 address_mask; |
| 75 | 75 | |
| 76 | 76 | /* Value of the address bits which are involved for selecting for read. */ |
| 77 | 77 | UINT16 select; |
| 78 | 78 | |
| 79 | 79 | /* Value of the address bits which are involved for selecting for write. */ |
| 80 | 80 | UINT16 write_select; |
| 81 | | |
| 81 | |
| 82 | 82 | /* Read access. */ |
| 83 | 83 | mapper_read_function read_byte; |
| 84 | | |
| 84 | |
| 85 | 85 | /* Write access. */ |
| 86 | 86 | mapper_write_function write_byte; |
| 87 | 87 | |
| r9498 | r9499 | |
| 90 | 90 | typedef struct _phys_addressed_device |
| 91 | 91 | { |
| 92 | 92 | /* The device. */ |
| 93 | | running_device *device; |
| 94 | | |
| 93 | running_device *device; |
| 94 | |
| 95 | 95 | /* Stop. If true, stop the address decoder here and do not look for parallel devices. */ |
| 96 | 96 | int stop; |
| 97 | 97 | |
| 98 | 98 | /* Address bits involved */ |
| 99 | | UINT32 address_mask; |
| 99 | UINT32 address_mask; |
| 100 | 100 | |
| 101 | 101 | /* Value of the address bits which are involved for selecting for read. */ |
| 102 | | UINT32 select; |
| 102 | UINT32 select; |
| 103 | 103 | |
| 104 | 104 | /* Read access. */ |
| 105 | 105 | mapper_read_function read_byte; |
| 106 | | |
| 106 | |
| 107 | 107 | /* Write access. */ |
| 108 | 108 | mapper_write_function write_byte; |
| 109 | | |
| 109 | |
| 110 | 110 | } phys_addressed_device; |
| 111 | 111 | |
| 112 | 112 | typedef struct _mapper8_state |
| 113 | 113 | { |
| 114 | 114 | /* All devices that are attached to the 16-bit address bus. */ |
| 115 | 115 | log_addressed_device logcomp[MAXLOGDEV]; |
| 116 | | |
| 116 | |
| 117 | 117 | /* All devices that are attached to the 24-bit mapped address bus. */ |
| 118 | 118 | phys_addressed_device physcomp[MAXPHYSDEV]; |
| 119 | 119 | |
| 120 | 120 | /* The I/O port. */ |
| 121 | 121 | running_device *ioport; |
| 122 | | |
| 122 | |
| 123 | 123 | /* Select bit for the internal DSR. */ |
| 124 | 124 | int dsr_selected; |
| 125 | | |
| 125 | |
| 126 | 126 | /* 99/4A compatibility mode. Name is taken from the spec. If 1, 99/4A compatibility is active. */ |
| 127 | 127 | int CRUS; |
| 128 | | |
| 128 | |
| 129 | 129 | /* P-Code mode. Name is taken from the spec. If 0, P-Code libraries are available. */ |
| 130 | | // May be read as "Pascal and Text-to-speech GROM libraries ENable" |
| 130 | // May be read as "Pascal and Text-to-speech GROM libraries ENable" |
| 131 | 131 | // Note: this is negative logic. GROMs are present only for PTGEN=0 |
| 132 | 132 | int PTGEN; |
| 133 | | |
| 133 | |
| 134 | 134 | /* Address mapper registers. Each offset is selected by the first 4 bits |
| 135 | | of the logical address. */ |
| 135 | of the logical address. */ |
| 136 | 136 | UINT32 pas_offset[16]; |
| 137 | | |
| 137 | |
| 138 | 138 | /* SRAM area of the system. Directly connected to the address decoder. */ |
| 139 | 139 | UINT8 *sram; |
| 140 | | |
| 140 | |
| 141 | 141 | /* DRAM area of the system. Connected to the mapped address bus. */ |
| 142 | 142 | UINT8 *dram; |
| 143 | 143 | |
| 144 | 144 | /* ROM area of the system. Directly connected to the address decoder. */ |
| 145 | 145 | UINT8 *rom; |
| 146 | | |
| 146 | |
| 147 | 147 | /* Points to the next free slot in the list. */ |
| 148 | 148 | int logindex, physindex; |
| 149 | | |
| 149 | |
| 150 | 150 | } mapper8_state; |
| 151 | 151 | |
| 152 | 152 | |
| r9498 | r9499 | |
| 160 | 160 | static void mapper_mount_logical_device(running_device *mapperdev, running_device *busdevice, int mode, int stop, UINT16 address_mask, UINT16 address_bits, UINT16 write_sel, mapper_read_function read, mapper_write_function write) |
| 161 | 161 | { |
| 162 | 162 | mapper8_state *mapper = get_safe_token(mapperdev); |
| 163 | | int index = mapper->logindex++; |
| 163 | int index = mapper->logindex++; |
| 164 | 164 | if (index < MAXLOGDEV) |
| 165 | 165 | { |
| 166 | 166 | if (mapper->logcomp[index].device == NULL) |
| r9498 | r9499 | |
| 168 | 168 | mapper->logcomp[index].device = busdevice; |
| 169 | 169 | mapper->logcomp[index].mode = mode; |
| 170 | 170 | mapper->logcomp[index].stop = stop; |
| 171 | | |
| 171 | |
| 172 | 172 | mapper->logcomp[index].address_mask = address_mask; |
| 173 | 173 | mapper->logcomp[index].select = address_bits; |
| 174 | 174 | mapper->logcomp[index].write_select = write_sel; |
| 175 | 175 | mapper->logcomp[index].read_byte = read; |
| 176 | | mapper->logcomp[index].write_byte = write; |
| 176 | mapper->logcomp[index].write_byte = write; |
| 177 | 177 | // printf("registering the device at logical position %d, device %lx\n", index, busdevice); |
| 178 | 178 | } |
| 179 | 179 | } |
| r9498 | r9499 | |
| 186 | 186 | static void mapper_mount_physical_device(running_device *mapperdev, running_device *busdevice, int stop, UINT32 address_mask, UINT32 address_bits, mapper_read_function read, mapper_write_function write) |
| 187 | 187 | { |
| 188 | 188 | mapper8_state *mapper = get_safe_token(mapperdev); |
| 189 | | int index = mapper->physindex++; |
| 189 | int index = mapper->physindex++; |
| 190 | 190 | if (index < MAXPHYSDEV) |
| 191 | 191 | { |
| 192 | 192 | if (mapper->physcomp[index].device == NULL) |
| r9498 | r9499 | |
| 196 | 196 | mapper->physcomp[index].address_mask = address_mask; |
| 197 | 197 | mapper->physcomp[index].select = address_bits; |
| 198 | 198 | mapper->physcomp[index].read_byte = read; |
| 199 | | mapper->physcomp[index].write_byte = write; |
| 199 | mapper->physcomp[index].write_byte = write; |
| 200 | 200 | // printf("registering the device at physical position %d, device %lx\n", index, busdevice); |
| 201 | 201 | } |
| 202 | 202 | } |
| r9498 | r9499 | |
| 214 | 214 | { |
| 215 | 215 | mapper8_state *mapper = get_safe_token(device); |
| 216 | 216 | int found = FALSE; |
| 217 | | // printf("ti99_8: read access %04x ... ", offset); |
| 218 | | // Look for components responding to the logical address |
| 217 | // printf("ti99_8: read access %04x ... ", offset); |
| 218 | // Look for components responding to the logical address |
| 219 | 219 | for (int i=0; i < MAXLOGDEV; i++) |
| 220 | 220 | { |
| 221 | 221 | log_addressed_device *adev = &mapper->logcomp[i]; |
| r9498 | r9499 | |
| 223 | 223 | { |
| 224 | 224 | // Check for the mode |
| 225 | 225 | if (adev->mode == mapper->CRUS || (mapper->CRUS==0 && adev->mode==1 && mapper->PTGEN==FALSE)) |
| 226 | | { |
| 226 | { |
| 227 | 227 | if ((offset & adev->address_mask)==adev->select) |
| 228 | 228 | { |
| 229 | 229 | if (adev->device == MAP8_SRAM) |
| r9498 | r9499 | |
| 242 | 242 | found = TRUE; |
| 243 | 243 | } |
| 244 | 244 | else |
| 245 | | { |
| 245 | { |
| 246 | 246 | // device |
| 247 | 247 | if (adev->read_byte != NULL) |
| 248 | 248 | { |
| r9498 | r9499 | |
| 265 | 265 | mapper8_state *mapper = get_safe_token(device); |
| 266 | 266 | int found = FALSE; |
| 267 | 267 | |
| 268 | | // printf("ti99_8: write access %04x ... ", offset); |
| 268 | // printf("ti99_8: write access %04x ... ", offset); |
| 269 | 269 | for (int i=0; i < MAXLOGDEV; i++) |
| 270 | 270 | { |
| 271 | 271 | log_addressed_device *adev = &mapper->logcomp[i]; |
| r9498 | r9499 | |
| 273 | 273 | { |
| 274 | 274 | // Check for the mode |
| 275 | 275 | if (adev->mode == mapper->CRUS || (mapper->CRUS==0 && adev->mode==1 && mapper->PTGEN==FALSE)) |
| 276 | | { |
| 276 | { |
| 277 | 277 | if ((offset & adev->address_mask)==(adev->select | adev->write_select)) |
| 278 | 278 | { |
| 279 | 279 | if (adev->device == MAP8_SRAM) |
| r9498 | r9499 | |
| 290 | 290 | found = TRUE; |
| 291 | 291 | } |
| 292 | 292 | else |
| 293 | | { |
| 293 | { |
| 294 | 294 | if (adev->write_byte != NULL) |
| 295 | 295 | { |
| 296 | 296 | // printf("device "); |
| r9498 | r9499 | |
| 318 | 318 | |
| 319 | 319 | if (mapper->sram==NULL) // not initialized yet |
| 320 | 320 | return 0; |
| 321 | | |
| 321 | |
| 322 | 322 | found = check_logically_addressed_r(device, offset, &value); |
| 323 | 323 | |
| 324 | 324 | if (!found) |
| r9498 | r9499 | |
| 328 | 328 | // This means the logical address is transformed by the mapper. |
| 329 | 329 | UINT32 pas_address = mapper->pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff); |
| 330 | 330 | // printf("%08x ", pas_address); |
| 331 | | |
| 331 | |
| 332 | 332 | // So now let's do the same as above with physical addresses |
| 333 | 333 | for (int i=0; i < MAXPHYSDEV; i++) |
| 334 | 334 | { |
| r9498 | r9499 | |
| 362 | 362 | // printf("rom1a"); |
| 363 | 363 | } |
| 364 | 364 | else |
| 365 | | { |
| 365 | { |
| 366 | 366 | if (adev->device == MAP8_INTS) |
| 367 | 367 | { |
| 368 | 368 | // Interrupt sense |
| r9498 | r9499 | |
| 387 | 387 | } |
| 388 | 388 | if (found && adev->stop) break; |
| 389 | 389 | } |
| 390 | | |
| 390 | |
| 391 | 391 | if (!found) |
| 392 | 392 | { |
| 393 | | // Still not found? Then we route the physical address to the I/O port |
| 393 | // Still not found? Then we route the physical address to the I/O port |
| 394 | 394 | // which has the peribox attached |
| 395 | 395 | // printf("not mapped ... ioport"); |
| 396 | 396 | if (mapper->ioport!=NULL) |
| 397 | 397 | ti99_peb_data_rz(mapper->ioport, pas_address, &value); |
| 398 | 398 | // printf("ti99_8: io read %04x = %02x\n", offset, value); |
| 399 | | } |
| 399 | } |
| 400 | 400 | } |
| 401 | 401 | // printf(" %02x\n", value); |
| 402 | 402 | |
| 403 | | return value; |
| 403 | return value; |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | 406 | /* |
| r9498 | r9499 | |
| 412 | 412 | int found = FALSE; |
| 413 | 413 | if (mapper->sram==NULL) |
| 414 | 414 | return; |
| 415 | | // // printf("ti99_8: write %04x = %02x\n", offset, data); |
| 416 | | |
| 417 | | // Look for components responding to the logical address |
| 415 | // // printf("ti99_8: write %04x = %02x\n", offset, data); |
| 416 | |
| 417 | // Look for components responding to the logical address |
| 418 | 418 | found = check_logically_addressed_w(device, offset, data); |
| 419 | | |
| 419 | |
| 420 | 420 | if (!found) |
| 421 | 421 | { |
| 422 | 422 | // printf(" not logical ..."); |
| r9498 | r9499 | |
| 446 | 446 | found = TRUE; |
| 447 | 447 | } |
| 448 | 448 | else |
| 449 | | { |
| 449 | { |
| 450 | 450 | if (adev->device == MAP8_INTS) |
| 451 | 451 | { |
| 452 | 452 | // Interrupt sense |
| r9498 | r9499 | |
| 469 | 469 | } |
| 470 | 470 | if (found && adev->stop) break; |
| 471 | 471 | } |
| 472 | | |
| 472 | |
| 473 | 473 | if (!found) |
| 474 | 474 | { |
| 475 | | // Still not found? Then we route the physical address to the I/O port |
| 475 | // Still not found? Then we route the physical address to the I/O port |
| 476 | 476 | // which has the peribox attached |
| 477 | 477 | // printf("not mapped ... ioport"); |
| 478 | 478 | if (mapper->ioport!=NULL) |
| r9498 | r9499 | |
| 484 | 484 | } |
| 485 | 485 | |
| 486 | 486 | /* |
| 487 | | Reconfigure mapper. Writing to this address copies the values in the |
| 488 | | SRAM into the mapper and vice versa. |
| 489 | | Format: |
| 490 | | 0000 bbbl; bbb=bank, l=load |
| 487 | Reconfigure mapper. Writing to this address copies the values in the |
| 488 | SRAM into the mapper and vice versa. |
| 489 | Format: |
| 490 | 0000 bbbl; bbb=bank, l=load |
| 491 | 491 | */ |
| 492 | 492 | WRITE8_DEVICE_HANDLER( ti99_mapreg_w ) |
| 493 | 493 | { |
| 494 | 494 | mapper8_state *mapper = get_safe_token(device); |
| 495 | | |
| 495 | |
| 496 | 496 | if ((data & 0xf0)==0) |
| 497 | 497 | { |
| 498 | 498 | int bankindx = (data & 0x0e)>>1; |
| r9498 | r9499 | |
| 503 | 503 | for (int i=0; i < 16; i++) |
| 504 | 504 | { |
| 505 | 505 | int ptr = (bankindx << 6); |
| 506 | | mapper->pas_offset[i] = |
| 506 | mapper->pas_offset[i] = |
| 507 | 507 | (mapper->sram[i*4 + ptr] << 24) |
| 508 | 508 | + (mapper->sram[i*4 + ptr+1] << 16) |
| 509 | 509 | + (mapper->sram[i*4 + ptr+2] << 8) |
| 510 | 510 | + (mapper->sram[i*4 + ptr+3]); |
| 511 | | // // printf(" values (%04x) %02x %02x %02x %02x, ", i*4+ptr, mapper->sram[i*4 + ptr], mapper->sram[i*4 + ptr+1], mapper->sram[i*4 + ptr+2], mapper->sram[i*4 + ptr+3]); |
| 511 | // // printf(" values (%04x) %02x %02x %02x %02x, ", i*4+ptr, mapper->sram[i*4 + ptr], mapper->sram[i*4 + ptr+1], mapper->sram[i*4 + ptr+2], mapper->sram[i*4 + ptr+3]); |
| 512 | 512 | } |
| 513 | 513 | } |
| 514 | 514 | else |
| r9498 | r9499 | |
| 530 | 530 | /************************************************************************/ |
| 531 | 531 | |
| 532 | 532 | /* |
| 533 | | Internal DSR |
| 533 | Internal DSR |
| 534 | 534 | */ |
| 535 | 535 | READ8Z_DEVICE_HANDLER( ti998dsr_rz ) |
| 536 | 536 | { |
| r9498 | r9499 | |
| 544 | 544 | { |
| 545 | 545 | if (mapper->ioport!=NULL) |
| 546 | 546 | ti99_peb_data_rz(mapper->ioport, 0x4000 + (offset & 0x1fff), value); |
| 547 | | // printf("ti99_8: io1 read %04x = %02x\n", offset, *value); |
| 547 | // printf("ti99_8: io1 read %04x = %02x\n", offset, *value); |
| 548 | 548 | } |
| 549 | 549 | } |
| 550 | 550 | |
| 551 | 551 | |
| 552 | 552 | /* |
| 553 | | CRU handling. We handle the internal device at CRU address 0x2700 via |
| 554 | | this mapper component. |
| 553 | CRU handling. We handle the internal device at CRU address 0x2700 via |
| 554 | this mapper component. |
| 555 | 555 | */ |
| 556 | 556 | WRITE8_DEVICE_HANDLER( mapper8c_w ) |
| 557 | 557 | { |
| r9498 | r9499 | |
| 589 | 589 | |
| 590 | 590 | static DEVICE_START( mapper8 ) |
| 591 | 591 | { |
| 592 | | // // printf("Starting mapper\n"); |
| 592 | // // printf("Starting mapper\n"); |
| 593 | 593 | mapper8_state *mapper = get_safe_token(device); |
| 594 | 594 | mapper->sram = (UINT8*)malloc(SRAM_SIZE); |
| 595 | 595 | mapper->dram = (UINT8*)malloc(DRAM_SIZE); |
| r9498 | r9499 | |
| 597 | 597 | |
| 598 | 598 | int i = 0; |
| 599 | 599 | int done=FALSE; |
| 600 | | |
| 600 | |
| 601 | 601 | for (int index = 0; index < MAXLOGDEV; index++) |
| 602 | 602 | { |
| 603 | | mapper->logcomp[index].device = NULL; |
| 603 | mapper->logcomp[index].device = NULL; |
| 604 | 604 | } |
| 605 | 605 | |
| 606 | 606 | for (int index = 0; index < MAXPHYSDEV; index++) |
| 607 | 607 | { |
| 608 | | mapper->physcomp[index].device = NULL; |
| 608 | mapper->physcomp[index].device = NULL; |
| 609 | 609 | } |
| 610 | 610 | |
| 611 | 611 | // Need to connect the callbacks |
| 612 | 612 | mapper->ioport = device->siblingdevice("peribox"); |
| 613 | 613 | assert(mapper->ioport != NULL); |
| 614 | | |
| 614 | |
| 615 | 615 | mapper8_dev_config *cons = (mapper8_dev_config*)device->baseconfig().static_config(); |
| 616 | 616 | |
| 617 | 617 | mapper->logindex = 0; |
| 618 | 618 | mapper->physindex = 0; |
| 619 | | |
| 619 | |
| 620 | 620 | const char *list[6] = { SRAMNAME, ROM0NAME, ROM1NAME, ROM1ANAME, DRAMNAME, INTSNAME }; |
| 621 | 621 | while (!done) |
| 622 | 622 | { |
| r9498 | r9499 | |
| 633 | 633 | } |
| 634 | 634 | if (dev==NULL) |
| 635 | 635 | dev = device->machine->device(cons[i].name); |
| 636 | | |
| 636 | |
| 637 | 637 | if (dev!=NULL) |
| 638 | 638 | { |
| 639 | 639 | if (cons[i].mode != 3) |
| 640 | 640 | { |
| 641 | | mapper_mount_logical_device(device, (running_device*)dev, cons[i].mode, cons[i].stop, (UINT16)cons[i].address_mask, (UINT16)cons[i].select_pattern, (UINT16)cons[i].write_select, cons[i].read, cons[i].write); |
| 641 | mapper_mount_logical_device(device, (running_device*)dev, cons[i].mode, cons[i].stop, (UINT16)cons[i].address_mask, (UINT16)cons[i].select_pattern, (UINT16)cons[i].write_select, cons[i].read, cons[i].write); |
| 642 | 642 | } |
| 643 | 643 | else |
| 644 | 644 | { |
| 645 | | mapper_mount_physical_device(device, (running_device*)dev, cons[i].stop, cons[i].address_mask, cons[i].select_pattern, cons[i].read, cons[i].write); |
| 645 | mapper_mount_physical_device(device, (running_device*)dev, cons[i].stop, cons[i].address_mask, cons[i].select_pattern, cons[i].read, cons[i].write); |
| 646 | 646 | } |
| 647 | 647 | } |
| 648 | 648 | else |
| r9498 | r9499 | |
| 650 | 650 | i++; |
| 651 | 651 | } |
| 652 | 652 | } |
| 653 | | |
| 653 | |
| 654 | 654 | mapper->dsr_selected = FALSE; |
| 655 | 655 | mapper->CRUS = TRUE; |
| 656 | 656 | mapper->PTGEN = TRUE; |
| r9498 | r9499 | |
| 659 | 659 | static DEVICE_STOP( mapper8 ) |
| 660 | 660 | { |
| 661 | 661 | // printf("Stopping mapper\n"); |
| 662 | | mapper8_state *mapper = get_safe_token(device); |
| 662 | mapper8_state *mapper = get_safe_token(device); |
| 663 | 663 | free(mapper->sram); |
| 664 | 664 | free(mapper->dram); |
| 665 | 665 | } |
src/mess/machine/ti99/peribox.h
| r9498 | r9499 | |
| 23 | 23 | } ti99_peb_config; |
| 24 | 24 | |
| 25 | 25 | /* |
| 26 | | Callback interface. The callback functions are in the console and are |
| 27 | | accessed from the PEB. |
| 26 | Callback interface. The callback functions are in the console and are |
| 27 | accessed from the PEB. |
| 28 | 28 | */ |
| 29 | 29 | |
| 30 | 30 | #define MAXSLOTS 16 |
| 31 | 31 | |
| 32 | 32 | /* |
| 33 | | This interface is used by the PEB to communicate with the expansion cards. |
| 34 | | It actually forwards the accesses from the main system. |
| 33 | This interface is used by the PEB to communicate with the expansion cards. |
| 34 | It actually forwards the accesses from the main system. |
| 35 | 35 | */ |
| 36 | 36 | typedef struct _ti99_peb_card_interface |
| 37 | 37 | { |
| 38 | | void (*card_read_data)(running_device *card, offs_t offset, UINT8 *value); |
| 38 | void (*card_read_data)(running_device *card, offs_t offset, UINT8 *value); |
| 39 | 39 | void (*card_write_data)(running_device *card, offs_t offset, UINT8 value); |
| 40 | 40 | |
| 41 | | void (*card_read_cru)(running_device *card, offs_t offset, UINT8 *value); |
| 41 | void (*card_read_cru)(running_device *card, offs_t offset, UINT8 *value); |
| 42 | 42 | void (*card_write_cru)(running_device *card, offs_t offset, UINT8 value); |
| 43 | 43 | |
| 44 | 44 | void (*senila)(running_device *card, int value); |
| 45 | | void (*senilb)(running_device *card, int value); |
| 45 | void (*senilb)(running_device *card, int value); |
| 46 | 46 | |
| 47 | 47 | /* For SGCPU only ("expansion bus") */ |
| 48 | 48 | void (*card_read_data16)(running_device *card, offs_t offset, UINT16 *value); |
| 49 | | void (*card_write_data16)(running_device *card, offs_t offset, UINT16 value); |
| 50 | | |
| 49 | void (*card_write_data16)(running_device *card, offs_t offset, UINT16 value); |
| 50 | |
| 51 | 51 | } ti99_peb_card; |
| 52 | 52 | |
| 53 | 53 | /* |
| 54 | | Called from the expansion cards. These are the callbacks from the cards to |
| 55 | | the PEB (which forwards them to the main system). |
| 56 | | */ |
| 54 | Called from the expansion cards. These are the callbacks from the cards to |
| 55 | the PEB (which forwards them to the main system). |
| 56 | */ |
| 57 | 57 | typedef struct _peb_callback_if |
| 58 | 58 | { |
| 59 | | devcb_write_line inta; |
| 60 | | devcb_write_line intb; |
| 61 | | devcb_write_line ready; |
| 62 | | |
| 59 | devcb_write_line inta; |
| 60 | devcb_write_line intb; |
| 61 | devcb_write_line ready; |
| 62 | |
| 63 | 63 | } peb_callback_if; |
| 64 | 64 | |
| 65 | 65 | /* |
| 66 | | Used to call back the main system. Also imported by the cards. |
| 67 | | This structure holds the resolved callbacks within the PEB and the cards. |
| 66 | Used to call back the main system. Also imported by the cards. |
| 67 | This structure holds the resolved callbacks within the PEB and the cards. |
| 68 | 68 | */ |
| 69 | 69 | typedef struct _peb_connect |
| 70 | 70 | { |
| r9498 | r9499 | |
| 75 | 75 | } ti99_peb_connect; |
| 76 | 76 | |
| 77 | 77 | /* |
| 78 | | Accessor functions from the console. Note that we make use of the enhanced |
| 79 | | read handler. |
| 78 | Accessor functions from the console. Note that we make use of the enhanced |
| 79 | read handler. |
| 80 | 80 | */ |
| 81 | 81 | READ8Z_DEVICE_HANDLER( ti99_peb_data_rz ); |
| 82 | 82 | WRITE8_DEVICE_HANDLER( ti99_peb_data_w ); |
| r9498 | r9499 | |
| 89 | 89 | |
| 90 | 90 | |
| 91 | 91 | /* |
| 92 | | For SGCPU only. Actually the SGCPU uses an external cable to add the |
| 93 | | 8 data lines that are not included in the PEB |
| 92 | For SGCPU only. Actually the SGCPU uses an external cable to add the |
| 93 | 8 data lines that are not included in the PEB |
| 94 | 94 | */ |
| 95 | 95 | READ16Z_DEVICE_HANDLER( ti99_peb_data16_rz ); |
| 96 | 96 | WRITE16_DEVICE_HANDLER( ti99_peb_data16_w ); |
| 97 | 97 | |
| 98 | 98 | /* |
| 99 | | Value passed to the cards |
| 99 | Value passed to the cards |
| 100 | 100 | */ |
| 101 | 101 | typedef struct _ti99_pebcard_config |
| 102 | 102 | { |
| r9498 | r9499 | |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | /* |
| 113 | | Management functions |
| 113 | Management functions |
| 114 | 114 | */ |
| 115 | 115 | int mount_card(running_device *device, running_device *cardptr, ti99_peb_card *card, int slotindex); |
| 116 | 116 | void unmount_card(running_device *device, int slotindex); |
| r9498 | r9499 | |
| 128 | 128 | MDRV_DEVICE_ADD(_tag, PBOX4, 0) \ |
| 129 | 129 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta) \ |
| 130 | 130 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb) \ |
| 131 | | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 131 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 132 | 132 | |
| 133 | 133 | #define MDRV_PBOX4A_ADD(_tag, _inta, _intb, _ready) \ |
| 134 | 134 | MDRV_DEVICE_ADD(_tag, PBOX4A, 0) \ |
| 135 | 135 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta) \ |
| 136 | 136 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb) \ |
| 137 | | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 137 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 138 | 138 | |
| 139 | 139 | #define MDRV_PBOXEV_ADD(_tag, _inta, _intb, _ready) \ |
| 140 | 140 | MDRV_DEVICE_ADD(_tag, PBOXEV, 0) \ |
| 141 | 141 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta) \ |
| 142 | 142 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb) \ |
| 143 | | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 144 | | |
| 143 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 144 | |
| 145 | 145 | #define MDRV_PBOX8_ADD(_tag, _inta, _intb, _ready) \ |
| 146 | 146 | MDRV_DEVICE_ADD(_tag, PBOX8, 0) \ |
| 147 | 147 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta) \ |
| 148 | 148 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb) \ |
| 149 | | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 149 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 150 | 150 | |
| 151 | 151 | #define MDRV_PBOXSG_ADD(_tag, _inta, _intb, _ready) \ |
| 152 | 152 | MDRV_DEVICE_ADD(_tag, PBOXSG, 0) \ |
| 153 | 153 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta) \ |
| 154 | 154 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb) \ |
| 155 | | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 155 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 156 | 156 | |
| 157 | 157 | #define MDRV_PBOXGEN_ADD(_tag, _inta, _intb, _ready) \ |
| 158 | 158 | MDRV_DEVICE_ADD(_tag, PBOXGEN, 0) \ |
| 159 | 159 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta) \ |
| 160 | 160 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb) \ |
| 161 | | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 162 | | |
| 161 | MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready) |
| 162 | |
| 163 | 163 | #endif /* __PBOX__ */ |
src/mess/machine/ti99/bwg.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | | SNUG BwG Disk Controller |
| 2 | SNUG BwG Disk Controller |
| 3 | 3 | Based on WD1773 |
| 4 | 4 | Double Density, Double-sided |
| 5 | 5 | |
| r9498 | r9499 | |
| 14 | 14 | <http://home.t-online.de/home/harald.glaab/snug/bwg.pdf> |
| 15 | 15 | |
| 16 | 16 | Michael Zapf, September 2010 |
| 17 | | |
| 18 | | FIXME: IO error 50, CALLs ok |
| 17 | |
| 18 | FIXME: IO error 50, CALLs ok |
| 19 | 19 | */ |
| 20 | 20 | |
| 21 | 21 | #include "emu.h" |
| r9498 | r9499 | |
| 39 | 39 | { |
| 40 | 40 | /* Holds the status of the DRQ and IRQ lines. */ |
| 41 | 41 | int DRQ_IRQ_status; |
| 42 | | |
| 42 | |
| 43 | 43 | /* When TRUE, card is accessible. Indicated by a LED. */ |
| 44 | 44 | int selected; |
| 45 | 45 | |
| r9498 | r9499 | |
| 51 | 51 | |
| 52 | 52 | /* When TRUE the CPU is halted while DRQ/IRQ are true. */ |
| 53 | 53 | int hold; |
| 54 | | |
| 54 | |
| 55 | 55 | /* Indicates which drive has been selected. Values are 0, 1, 2, and 4. */ |
| 56 | 56 | // 000 = no drive |
| 57 | 57 | // 001 = drive 1 |
| r9498 | r9499 | |
| 64 | 64 | |
| 65 | 65 | /* ROM and RAM offset. */ |
| 66 | 66 | int rom_offset, ram_offset; |
| 67 | | |
| 67 | |
| 68 | 68 | /* Indicates whether the clock is mapped into the address space. */ |
| 69 | 69 | int rtc_enabled; |
| 70 | | |
| 70 | |
| 71 | 71 | /* count 4.23s from rising edge of motor_on */ |
| 72 | | emu_timer *motor_on_timer; |
| 73 | | |
| 72 | emu_timer *motor_on_timer; |
| 73 | |
| 74 | 74 | /* Link to the FDC1771 controller on the board. */ |
| 75 | | running_device *controller; |
| 75 | running_device *controller; |
| 76 | 76 | |
| 77 | 77 | /* Link to the real-time clock on the board. */ |
| 78 | | running_device *clock; |
| 78 | running_device *clock; |
| 79 | 79 | |
| 80 | 80 | /* DSR ROM */ |
| 81 | 81 | UINT8 *rom; |
| r9498 | r9499 | |
| 85 | 85 | |
| 86 | 86 | /* DIP swiches */ |
| 87 | 87 | UINT8 dip1, dip2, dip34; |
| 88 | | |
| 88 | |
| 89 | 89 | /* Callback lines to the main system. */ |
| 90 | 90 | ti99_peb_connect lines; |
| 91 | | |
| 91 | |
| 92 | 92 | } ti99_bwg_state; |
| 93 | 93 | |
| 94 | 94 | INLINE ti99_bwg_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 102 | 102 | |
| 103 | 103 | Emulation is faulty because the CPU is actually stopped in the midst of |
| 104 | 104 | instruction, at the end of the memory access |
| 105 | | |
| 106 | | TODO: This has to be replaced by the proper READY handling that is already |
| 107 | | prepared here. (Requires READY handling by the CPU.) |
| 105 | |
| 106 | TODO: This has to be replaced by the proper READY handling that is already |
| 107 | prepared here. (Requires READY handling by the CPU.) |
| 108 | 108 | */ |
| 109 | 109 | static void bwg_handle_hold(running_device *device) |
| 110 | 110 | { |
| 111 | | ti99_bwg_state *card = get_safe_token(device); |
| 111 | ti99_bwg_state *card = get_safe_token(device); |
| 112 | 112 | line_state state; |
| 113 | | |
| 113 | |
| 114 | 114 | if (card->hold && (!card->DRQ_IRQ_status) && card->DVENA) |
| 115 | 115 | state = ASSERT_LINE; |
| 116 | 116 | else |
| 117 | 117 | state = CLEAR_LINE; |
| 118 | | |
| 119 | | // TODO: use READY |
| 118 | |
| 119 | // TODO: use READY |
| 120 | 120 | cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state); |
| 121 | 121 | } |
| 122 | 122 | |
| r9498 | r9499 | |
| 160 | 160 | static WRITE_LINE_DEVICE_HANDLER( ti_bwg_intrq_w ) |
| 161 | 161 | { |
| 162 | 162 | running_device *carddev = device->owner(); |
| 163 | | ti99_bwg_state *card = get_safe_token(carddev); |
| 163 | ti99_bwg_state *card = get_safe_token(carddev); |
| 164 | 164 | |
| 165 | 165 | if (state) |
| 166 | 166 | { |
| r9498 | r9499 | |
| 180 | 180 | static WRITE_LINE_DEVICE_HANDLER( ti_bwg_drq_w ) |
| 181 | 181 | { |
| 182 | 182 | running_device *carddev = device->owner(); |
| 183 | | ti99_bwg_state *card = get_safe_token(carddev); |
| 183 | ti99_bwg_state *card = get_safe_token(carddev); |
| 184 | 184 | |
| 185 | 185 | if (state) |
| 186 | 186 | card->DRQ_IRQ_status |= bwg_DRQ; |
| r9498 | r9499 | |
| 196 | 196 | static TIMER_CALLBACK(motor_on_timer_callback) |
| 197 | 197 | { |
| 198 | 198 | running_device *device = (running_device *)ptr; |
| 199 | | ti99_bwg_state *card = get_safe_token(device); |
| 199 | ti99_bwg_state *card = get_safe_token(device); |
| 200 | 200 | card->DVENA = 0; |
| 201 | 201 | bwg_handle_hold(device); |
| 202 | 202 | } |
| r9498 | r9499 | |
| 214 | 214 | /* |
| 215 | 215 | CRU read handler. *=inverted. |
| 216 | 216 | bit 0: DSK4 connected* |
| 217 | | bit 1: DSK1 connected* |
| 218 | | bit 2: DSK2 connected* |
| 219 | | bit 3: DSK3 connected* |
| 220 | | bit 4: Dip 1 |
| 221 | | bit 5: Dip 2 |
| 222 | | bit 6: Dip 3 |
| 223 | | bit 7: Dip 4 |
| 217 | bit 1: DSK1 connected* |
| 218 | bit 2: DSK2 connected* |
| 219 | bit 3: DSK3 connected* |
| 220 | bit 4: Dip 1 |
| 221 | bit 5: Dip 2 |
| 222 | bit 6: Dip 3 |
| 223 | bit 7: Dip 4 |
| 224 | 224 | */ |
| 225 | 225 | static READ8Z_DEVICE_HANDLER( cru_r ) |
| 226 | 226 | { |
| 227 | | ti99_bwg_state *card = get_safe_token(device); |
| 227 | ti99_bwg_state *card = get_safe_token(device); |
| 228 | 228 | UINT8 reply = 0; |
| 229 | | |
| 229 | |
| 230 | 230 | if ((offset & 0xff00)==CRU_BASE) |
| 231 | 231 | { |
| 232 | 232 | if ((offset & 0x00ff)==0) |
| r9498 | r9499 | |
| 235 | 235 | // If we want to do that properly, we need to check the actually |
| 236 | 236 | // available drives (not the images!). But why should we connect less? |
| 237 | 237 | reply = 0x00; |
| 238 | | |
| 238 | |
| 239 | 239 | // DIP switches. Note that a closed switch means 0 |
| 240 | 240 | // xx01 1111 11 = nur dsk1; 10 = 1+2, 01=1/2/3, 00=1-4 |
| 241 | 241 | if (card->dip1) reply |= 0x10; |
| r9498 | r9499 | |
| 250 | 250 | |
| 251 | 251 | static WRITE8_DEVICE_HANDLER( cru_w ) |
| 252 | 252 | { |
| 253 | | ti99_bwg_state *card = get_safe_token(device); |
| 253 | ti99_bwg_state *card = get_safe_token(device); |
| 254 | 254 | int drive, drivebit; |
| 255 | 255 | |
| 256 | 256 | if ((offset & 0xff00)==CRU_BASE) |
| r9498 | r9499 | |
| 277 | 277 | case 2: |
| 278 | 278 | /* Set disk ready/hold (bit 2) */ |
| 279 | 279 | // 0: ignore IRQ and DRQ |
| 280 | | // 1: TMS9900 is stopped until IRQ or DRQ are set |
| 281 | | // OR the motor stops rotating - rotates for 4.23s after write |
| 282 | | // to CRU bit 1 |
| 283 | | // This is not emulated and could cause the TI99 to lock up |
| 280 | // 1: TMS9900 is stopped until IRQ or DRQ are set |
| 281 | // OR the motor stops rotating - rotates for 4.23s after write |
| 282 | // to CRU bit 1 |
| 283 | // This is not emulated and could cause the TI99 to lock up |
| 284 | 284 | card->hold = data; |
| 285 | 285 | bwg_handle_hold(device); |
| 286 | 286 | break; |
| r9498 | r9499 | |
| 293 | 293 | /* Select drive 3 (DSK4) (bit 8) */ |
| 294 | 294 | drive = (bit == 8) ? 3 : (bit - 4); /* drive # (0-3) */ |
| 295 | 295 | drivebit = 1<<drive; |
| 296 | | |
| 296 | |
| 297 | 297 | if (data) |
| 298 | 298 | { |
| 299 | 299 | if (!(card->DSEL & drivebit)) /* select drive */ |
| 300 | 300 | { |
| 301 | 301 | if (card->DSEL != 0) |
| 302 | | logerror("ti99/BwG: Multiple drives selected, %02x\n", card->DSEL); |
| 302 | logerror("ti99/BwG: Multiple drives selected, %02x\n", card->DSEL); |
| 303 | 303 | card->DSEL |= drivebit; |
| 304 | 304 | wd17xx_set_drive(card->controller, drive); |
| 305 | 305 | } |
| r9498 | r9499 | |
| 307 | 307 | else |
| 308 | 308 | card->DSEL &= ~drivebit; |
| 309 | 309 | break; |
| 310 | | |
| 310 | |
| 311 | 311 | case 7: |
| 312 | 312 | /* Select side of disk (bit 7) */ |
| 313 | 313 | card->SIDE = data; |
| r9498 | r9499 | |
| 334 | 334 | else |
| 335 | 335 | card->ram_offset = 0x0000; |
| 336 | 336 | break; |
| 337 | | |
| 337 | |
| 338 | 338 | case 14: |
| 339 | 339 | /* Override FDC with RTC (active high) */ |
| 340 | 340 | card->rtc_enabled = data; |
| 341 | 341 | break; |
| 342 | | |
| 342 | |
| 343 | 343 | case 15: |
| 344 | 344 | /* EPROM A14 */ |
| 345 | 345 | if (data) |
| r9498 | r9499 | |
| 347 | 347 | else |
| 348 | 348 | card->rom_offset &= ~0x4000; |
| 349 | 349 | break; |
| 350 | | |
| 350 | |
| 351 | 351 | case 3: |
| 352 | 352 | case 9: |
| 353 | 353 | case 12: |
| r9498 | r9499 | |
| 359 | 359 | |
| 360 | 360 | /* |
| 361 | 361 | Read a byte |
| 362 | | 4000 - 5bff: ROM (4 banks) |
| 363 | | |
| 364 | | rtc disabled: |
| 365 | | 5c00 - 5fef: RAM |
| 366 | | 5ff0 - 5fff: Controller (f0 = status, f2 = track, f4 = sector, f6 = data) |
| 362 | 4000 - 5bff: ROM (4 banks) |
| 367 | 363 | |
| 368 | | rtc enabled: |
| 369 | | 5c00 - 5fdf: RAM |
| 370 | | 5fe0 - 5fff: Clock (even addr) |
| 364 | rtc disabled: |
| 365 | 5c00 - 5fef: RAM |
| 366 | 5ff0 - 5fff: Controller (f0 = status, f2 = track, f4 = sector, f6 = data) |
| 367 | |
| 368 | rtc enabled: |
| 369 | 5c00 - 5fdf: RAM |
| 370 | 5fe0 - 5fff: Clock (even addr) |
| 371 | 371 | */ |
| 372 | 372 | |
| 373 | 373 | static READ8Z_DEVICE_HANDLER( data_r ) |
| 374 | 374 | { |
| 375 | | ti99_bwg_state *card = get_safe_token(device); |
| 375 | ti99_bwg_state *card = get_safe_token(device); |
| 376 | 376 | |
| 377 | 377 | if (card->selected) |
| 378 | 378 | { |
| 379 | | if ((offset & 0xe000)==0x4000) |
| 379 | if ((offset & 0xe000)==0x4000) |
| 380 | 380 | { |
| 381 | 381 | // 010x xxxx xxxx xxxx |
| 382 | 382 | if ((offset & 0x1c00)==0x1c00) |
| r9498 | r9499 | |
| 398 | 398 | { |
| 399 | 399 | if ((offset & 0x03f9)==0x03f0) |
| 400 | 400 | { |
| 401 | | // .... ..11 1111 0xx0 |
| 401 | // .... ..11 1111 0xx0 |
| 402 | 402 | // Note that the value is inverted again on the board, |
| 403 | 403 | // so we can drop the inversion |
| 404 | 404 | *value = wd17xx_r(card->controller, (offset >> 1)&0x03); |
| r9498 | r9499 | |
| 419 | 419 | |
| 420 | 420 | /* |
| 421 | 421 | Write a byte |
| 422 | | 4000 - 5bff: ROM, ignore write (4 banks) |
| 423 | | |
| 424 | | rtc disabled: |
| 425 | | 5c00 - 5fef: RAM |
| 426 | | 5ff0 - 5fff: Controller (f8 = command, fa = track, fc = sector, fe = data) |
| 422 | 4000 - 5bff: ROM, ignore write (4 banks) |
| 427 | 423 | |
| 428 | | rtc enabled: |
| 429 | | 5c00 - 5fdf: RAM |
| 430 | | 5fe0 - 5fff: Clock (even addr) |
| 424 | rtc disabled: |
| 425 | 5c00 - 5fef: RAM |
| 426 | 5ff0 - 5fff: Controller (f8 = command, fa = track, fc = sector, fe = data) |
| 427 | |
| 428 | rtc enabled: |
| 429 | 5c00 - 5fdf: RAM |
| 430 | 5fe0 - 5fff: Clock (even addr) |
| 431 | 431 | */ |
| 432 | 432 | static WRITE8_DEVICE_HANDLER( data_w ) |
| 433 | 433 | { |
| 434 | | ti99_bwg_state *card = get_safe_token(device); |
| 434 | ti99_bwg_state *card = get_safe_token(device); |
| 435 | 435 | |
| 436 | 436 | if (card->selected) |
| 437 | 437 | { |
| 438 | | if ((offset & 0xe000)==0x4000) |
| 438 | if ((offset & 0xe000)==0x4000) |
| 439 | 439 | { |
| 440 | 440 | // 010x xxxx xxxx xxxx |
| 441 | 441 | if ((offset & 0x1c00)==0x1c00) |
| r9498 | r9499 | |
| 445 | 445 | { |
| 446 | 446 | if ((offset & 0x03e1)==0x03e0) |
| 447 | 447 | { |
| 448 | | // .... ..11 111x xxx0 |
| 448 | // .... ..11 111x xxx0 |
| 449 | 449 | mm58274c_w(card->clock, (offset & 0x001e) >> 1, data); |
| 450 | 450 | } |
| 451 | 451 | else |
| r9498 | r9499 | |
| 457 | 457 | { |
| 458 | 458 | if ((offset & 0x03f9)==0x03f8) |
| 459 | 459 | { |
| 460 | | // .... ..11 1111 1xx0 |
| 460 | // .... ..11 1111 1xx0 |
| 461 | 461 | // Note that the value is inverted again on the board, |
| 462 | 462 | // so we can drop the inversion |
| 463 | 463 | wd17xx_w(card->controller, (offset >> 1)&0x03, data); |
| r9498 | r9499 | |
| 475 | 475 | static DEVICE_START( ti99_bwg ) |
| 476 | 476 | { |
| 477 | 477 | ti99_bwg_state *card = (ti99_bwg_state*)downcast<legacy_device_base *>(device)->token(); |
| 478 | | |
| 478 | |
| 479 | 479 | /* Resolve the callbacks to the PEB */ |
| 480 | 480 | peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config(); |
| 481 | 481 | devcb_resolve_write_line(&card->lines.ready, &topeb->ready, device); |
| r9498 | r9499 | |
| 484 | 484 | card->controller = device->subdevice("wd1773"); |
| 485 | 485 | card->clock = device->subdevice("mm58274c"); |
| 486 | 486 | astring *region = new astring(); |
| 487 | | astring_assemble_3(region, device->tag(), ":", bwg_region); |
| 487 | astring_assemble_3(region, device->tag(), ":", bwg_region); |
| 488 | 488 | card->rom = memory_region(device->machine, astring_c(region)); |
| 489 | 489 | card->ram = NULL; |
| 490 | 490 | } |
| r9498 | r9499 | |
| 496 | 496 | if (card->ram) free(card->ram); |
| 497 | 497 | } |
| 498 | 498 | |
| 499 | | static ti99_peb_card bwg_card = |
| 499 | static ti99_peb_card bwg_card = |
| 500 | 500 | { |
| 501 | 501 | data_r, |
| 502 | 502 | data_w, |
| 503 | 503 | cru_r, |
| 504 | | cru_w, |
| 505 | | NULL, NULL, NULL, NULL |
| 504 | cru_w, |
| 505 | NULL, NULL, NULL, NULL |
| 506 | 506 | }; |
| 507 | 507 | |
| 508 | 508 | static DEVICE_RESET( ti99_bwg ) |
| r9498 | r9499 | |
| 512 | 512 | /* If the card is selected in the menu, register the card */ |
| 513 | 513 | if (input_port_read(device->machine, "DISKCTRL") == DISK_BWG) |
| 514 | 514 | { |
| 515 | | running_device *peb = device->owner(); |
| 515 | running_device *peb = device->owner(); |
| 516 | 516 | int success = mount_card(peb, device, &bwg_card, get_pebcard_config(device)->slot); |
| 517 | 517 | if (!success) return; |
| 518 | | |
| 518 | |
| 519 | 519 | // Allocate 2 KiB for on-board buffer memory (6116 chip) |
| 520 | | if (card->ram==NULL) |
| 520 | if (card->ram==NULL) |
| 521 | 521 | { |
| 522 | 522 | card->ram = (UINT8*)malloc(2048); |
| 523 | 523 | memset(card->ram, 0, 2048); |
| 524 | 524 | } |
| 525 | | |
| 525 | |
| 526 | 526 | card->dip1 = input_port_read(device->machine, "BWGDIP1"); |
| 527 | 527 | card->dip2 = input_port_read(device->machine, "BWGDIP2"); |
| 528 | 528 | card->dip34 = input_port_read(device->machine, "BWGDIP34"); |
| r9498 | r9499 | |
| 531 | 531 | card->SIDE = 0; |
| 532 | 532 | card->DVENA = 0; |
| 533 | 533 | card->strobe_motor = 0; |
| 534 | | |
| 534 | |
| 535 | 535 | ti99_set_80_track_drives(FALSE); |
| 536 | 536 | |
| 537 | 537 | floppy_type_t flop = FLOPPY_STANDARD_5_25_DSDD_40; |
| r9498 | r9499 | |
| 541 | 541 | card->ram_offset = 0; |
| 542 | 542 | card->rom_offset = 0; |
| 543 | 543 | card->rtc_enabled = 0; |
| 544 | | |
| 545 | | wd17xx_dden_w(card->controller, CLEAR_LINE); // Correct? |
| 544 | |
| 545 | wd17xx_dden_w(card->controller, CLEAR_LINE); // Correct? |
| 546 | 546 | } |
| 547 | 547 | } |
| 548 | 548 | |
src/mess/machine/ti99/tiboard.c
| r9498 | r9499 | |
| 1 | 1 | /*************************************************************************** |
| 2 | | TI-99/4(A) and TI-99/8 main board |
| 3 | | |
| 4 | | Michael Zapf, October 2010 |
| 5 | | TODO: Find out whether device can be determined more easily in CRU functions |
| 2 | TI-99/4(A) and TI-99/8 main board |
| 3 | |
| 4 | Michael Zapf, October 2010 |
| 5 | TODO: Find out whether device can be determined more easily in CRU functions |
| 6 | 6 | ***************************************************************************/ |
| 7 | 7 | |
| 8 | 8 | #include "emu.h" |
| r9498 | r9499 | |
| 18 | 18 | { |
| 19 | 19 | /* Mode: Which console do we have? */ |
| 20 | 20 | int mode; |
| 21 | | |
| 21 | |
| 22 | 22 | /* Keyboard support */ |
| 23 | 23 | int keyCol; |
| 24 | 24 | int alphaLockLine; |
| 25 | | |
| 25 | |
| 26 | 26 | /* Devices */ |
| 27 | | running_device *cpu; |
| 28 | | running_device *video; |
| 27 | running_device *cpu; |
| 28 | running_device *video; |
| 29 | 29 | running_device *tms9901; |
| 30 | | running_device *peribox; |
| 31 | | running_device *sound; |
| 30 | running_device *peribox; |
| 31 | running_device *sound; |
| 32 | 32 | |
| 33 | | running_device *handset; |
| 34 | | running_device *mecmouse; |
| 35 | | running_device *gromport; |
| 33 | running_device *handset; |
| 34 | running_device *mecmouse; |
| 35 | running_device *gromport; |
| 36 | 36 | |
| 37 | 37 | } tiboard_state; |
| 38 | 38 | |
| r9498 | r9499 | |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | /**************************************************************************** |
| 60 | | TMS9901 and attached devices handling |
| 60 | TMS9901 and attached devices handling |
| 61 | 61 | ****************************************************************************/ |
| 62 | 62 | /* |
| 63 | 63 | VBL interrupt (mmm... actually, it happens when the beam enters the lower |
| r9498 | r9499 | |
| 68 | 68 | running_device *dev = device->machine->device("ti_board"); |
| 69 | 69 | tiboard_state *board = get_safe_token(dev); |
| 70 | 70 | |
| 71 | | TMS9928A_interrupt(device->machine); |
| 71 | TMS9928A_interrupt(device->machine); |
| 72 | 72 | |
| 73 | | if (board->handset != NULL) |
| 73 | if (board->handset != NULL) |
| 74 | 74 | ti99_handset_task(board->handset); |
| 75 | | if (board->mecmouse != NULL) |
| 75 | if (board->mecmouse != NULL) |
| 76 | 76 | mecmouse_poll(board->mecmouse); |
| 77 | 77 | } |
| 78 | 78 | |
| r9498 | r9499 | |
| 210 | 210 | answer = mecmouse_get_values(board->mecmouse); |
| 211 | 211 | else |
| 212 | 212 | answer = ((input_port_read(device->machine, keynames[board->keyCol >> 1]) >> ((board->keyCol & 1) * 8)) << 3) & 0xF8; |
| 213 | | |
| 213 | |
| 214 | 214 | if (board->alphaLockLine == FALSE) |
| 215 | 215 | answer &= ~(input_port_read(device->machine, "ALPHA") << 3); |
| 216 | | |
| 216 | |
| 217 | 217 | return answer; |
| 218 | 218 | } |
| 219 | 219 | |
| r9498 | r9499 | |
| 241 | 241 | } |
| 242 | 242 | |
| 243 | 243 | /* we don't take CS2 into account, as CS2 is a write-only unit */ |
| 244 | | // if (cassette_input(device->machine->device("cassette1")) > 0) |
| 245 | | // answer |= 8; |
| 244 | // if (cassette_input(device->machine->device("cassette1")) > 0) |
| 245 | // answer |= 8; |
| 246 | 246 | |
| 247 | 247 | return answer; |
| 248 | 248 | } |
| r9498 | r9499 | |
| 257 | 257 | running_device *dev = device->machine->device("ti_board"); |
| 258 | 258 | tiboard_state *board = get_safe_token(dev); |
| 259 | 259 | |
| 260 | | if (board->handset != NULL) |
| 260 | if (board->handset != NULL) |
| 261 | 261 | if (ti99_handset_get_clock(board->handset)) return 2; |
| 262 | 262 | return 0; |
| 263 | 263 | } |
| r9498 | r9499 | |
| 308 | 308 | tiboard_state *board = get_safe_token(dev); |
| 309 | 309 | |
| 310 | 310 | int index=5; |
| 311 | | |
| 311 | |
| 312 | 312 | if (board->mode==TI994A) |
| 313 | 313 | index=6; |
| 314 | | |
| 314 | |
| 315 | 315 | if (data) |
| 316 | 316 | board->keyCol |= 1 << (offset-2); |
| 317 | 317 | else |
| r9498 | r9499 | |
| 600 | 600 | }; |
| 601 | 601 | |
| 602 | 602 | /* |
| 603 | | Handles the EXTINT line. This one is directly connected to the 9901. |
| 603 | Handles the EXTINT line. This one is directly connected to the 9901. |
| 604 | 604 | */ |
| 605 | 605 | WRITE_LINE_DEVICE_HANDLER( console_extint ) |
| 606 | 606 | { |
| r9498 | r9499 | |
| 620 | 620 | /*************************************************************************** |
| 621 | 621 | DEVICE LIFECYCLE FUNCTIONS |
| 622 | 622 | ***************************************************************************/ |
| 623 | | |
| 623 | |
| 624 | 624 | static DEVICE_START( tiboard ) |
| 625 | 625 | { |
| 626 | 626 | tiboard_state *board = get_safe_token(device); |
| r9498 | r9499 | |
| 639 | 639 | tiboard_state *board = get_safe_token(device); |
| 640 | 640 | const tiboard_config* conf = (const tiboard_config*)get_config(device); |
| 641 | 641 | board->mode = conf->mode; |
| 642 | | |
| 642 | |
| 643 | 643 | /* clear keyboard interface state (probably overkill, but can't harm) */ |
| 644 | 644 | board->keyCol = 0; |
| 645 | 645 | board->alphaLockLine = 0; |
| r9498 | r9499 | |
| 650 | 650 | { |
| 651 | 651 | /* reset handset */ |
| 652 | 652 | tms9901_set_single_int(board->tms9901, 12, 0); |
| 653 | | |
| 653 | |
| 654 | 654 | if (input_port_read(device->machine, "HCI") & HCI_IR) |
| 655 | 655 | board->handset = device->siblingdevice("handset"); |
| 656 | 656 | } |
| 657 | 657 | |
| 658 | 658 | if (input_port_read(device->machine, "HCI") & HCI_MECMOUSE) |
| 659 | 659 | board->mecmouse = device->siblingdevice("mecmouse"); |
| 660 | | |
| 660 | |
| 661 | 661 | if (board->mode != TI998) |
| 662 | 662 | { |
| 663 | | set_gk_switches(board->gromport, 1, input_port_read(device->machine, "GKSWITCH1")); |
| 664 | | set_gk_switches(board->gromport, 2, input_port_read(device->machine, "GKSWITCH2")); |
| 665 | | set_gk_switches(board->gromport, 3, input_port_read(device->machine, "GKSWITCH3")); |
| 666 | | set_gk_switches(board->gromport, 4, input_port_read(device->machine, "GKSWITCH4")); |
| 663 | set_gk_switches(board->gromport, 1, input_port_read(device->machine, "GKSWITCH1")); |
| 664 | set_gk_switches(board->gromport, 2, input_port_read(device->machine, "GKSWITCH2")); |
| 665 | set_gk_switches(board->gromport, 3, input_port_read(device->machine, "GKSWITCH3")); |
| 666 | set_gk_switches(board->gromport, 4, input_port_read(device->machine, "GKSWITCH4")); |
| 667 | 667 | set_gk_switches(board->gromport, 5, input_port_read(device->machine, "GKSWITCH5")); |
| 668 | | } |
| 668 | } |
| 669 | 669 | } |
| 670 | 670 | |
| 671 | 671 | static const char DEVTEMPLATE_SOURCE[] = __FILE__; |
src/mess/machine/ti99/spchsyn.c
| r9498 | r9499 | |
| 1 | 1 | /* |
| 2 | 2 | TI-99 Speech synthesizer |
| 3 | | |
| 3 | |
| 4 | 4 | We emulate the Speech Synthesizer plugged onto a P-Box adapter. The original |
| 5 | | Speech Synthesizer device was provided as a box to be plugged into the |
| 5 | Speech Synthesizer device was provided as a box to be plugged into the |
| 6 | 6 | right side of the console. In order to be used with Geneve and SGCPU, the |
| 7 | 7 | speech synthesizer must be moved into the Peripheral Box. |
| 8 | | |
| 9 | | The Speech Synthesizer used for the TI was the TMS5200, aka TMC0285, a |
| 8 | |
| 9 | The Speech Synthesizer used for the TI was the TMS5200, aka TMC0285, a |
| 10 | 10 | predecessor of the TMS5220 which was used in other commercial products. |
| 11 | | |
| 11 | |
| 12 | 12 | Note that this adapter also contains the speech roms. |
| 13 | 13 | */ |
| 14 | 14 | #include "emu.h" |
| r9498 | r9499 | |
| 20 | 20 | #define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */ |
| 21 | 21 | #define speech_region "speech_region" |
| 22 | 22 | |
| 23 | | typedef ti99_pebcard_config ti99_speech_config; |
| 23 | typedef ti99_pebcard_config ti99_speech_config; |
| 24 | 24 | |
| 25 | 25 | typedef struct _ti99_speech_state |
| 26 | 26 | { |
| 27 | | running_device *vsp; |
| 28 | | UINT8 *speechrom_data; /* pointer to speech ROM data */ |
| 27 | running_device *vsp; |
| 28 | UINT8 *speechrom_data; /* pointer to speech ROM data */ |
| 29 | 29 | int load_pointer; /* which 4-bit nibble will be affected by load address */ |
| 30 | 30 | int ROM_bits_count; /* current bit position in ROM */ |
| 31 | | UINT32 speechROMaddr; /* 18 bit pointer in ROM */ |
| 31 | UINT32 speechROMaddr; /* 18 bit pointer in ROM */ |
| 32 | 32 | UINT32 speechROMlen; /* length of data pointed by speechrom_data, from 0 to 2^18 */ |
| 33 | 33 | ti99_peb_connect lines; |
| 34 | | |
| 34 | |
| 35 | 35 | } ti99_speech_state; |
| 36 | 36 | |
| 37 | 37 | INLINE ti99_speech_state *get_safe_token(running_device *device) |
| r9498 | r9499 | |
| 48 | 48 | static int ti99_spchroms_read(running_device *vspdev, int count) |
| 49 | 49 | { |
| 50 | 50 | running_device *device = vspdev->owner(); |
| 51 | | ti99_speech_state *adapter = get_safe_token(device); |
| 51 | ti99_speech_state *adapter = get_safe_token(device); |
| 52 | 52 | |
| 53 | 53 | int val; |
| 54 | 54 | |
| r9498 | r9499 | |
| 91 | 91 | static void ti99_spchroms_load_address(running_device *vspdev, int data) |
| 92 | 92 | { |
| 93 | 93 | running_device *device = vspdev->owner(); |
| 94 | | ti99_speech_state *adapter = get_safe_token(device); |
| 94 | ti99_speech_state *adapter = get_safe_token(device); |
| 95 | 95 | // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. |
| 96 | 96 | // This code does not care about this. |
| 97 | 97 | adapter->speechROMaddr = ((adapter->speechROMaddr & ~(0xf << adapter->load_pointer)) |
| r9498 | r9499 | |
| 106 | 106 | static void ti99_spchroms_read_and_branch(running_device *vspdev) |
| 107 | 107 | { |
| 108 | 108 | running_device *device = vspdev->owner(); |
| 109 | | ti99_speech_state *adapter = get_safe_token(device); |
| 109 | ti99_speech_state *adapter = get_safe_token(device); |
| 110 | 110 | // tms5220 data sheet says that if more than one speech ROM (tms6100) is present, |
| 111 | 111 | // there is a bus contention. This code does not care about this. */ |
| 112 | 112 | if (adapter->speechROMaddr < adapter->speechROMlen-1) |
| r9498 | r9499 | |
| 129 | 129 | */ |
| 130 | 130 | static READ8Z_DEVICE_HANDLER( speech_rz ) |
| 131 | 131 | { |
| 132 | | ti99_speech_state *adapter = get_safe_token(device); |
| 133 | | |
| 134 | | if ((offset & 0xfc01)==0x9000) |
| 132 | ti99_speech_state *adapter = get_safe_token(device); |
| 133 | |
| 134 | if ((offset & 0xfc01)==0x9000) |
| 135 | 135 | { |
| 136 | | cpu_adjust_icount(device->machine->device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */ |
| 136 | cpu_adjust_icount(device->machine->device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */ |
| 137 | 137 | *value = tms5220_status_r(adapter->vsp, offset) & 0xff; |
| 138 | 138 | } |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | /* |
| 142 | | Memory write |
| 142 | Memory write |
| 143 | 143 | */ |
| 144 | 144 | static WRITE8_DEVICE_HANDLER( speech_w ) |
| 145 | 145 | { |
| 146 | | ti99_speech_state *adapter = get_safe_token(device); |
| 146 | ti99_speech_state *adapter = get_safe_token(device); |
| 147 | 147 | |
| 148 | | if ((offset & 0xfc01)==0x9400) |
| 148 | if ((offset & 0xfc01)==0x9400) |
| 149 | 149 | { |
| 150 | 150 | cpu_adjust_icount(device->machine->device("maincpu"),-(54+3)); /* this is just an approx. minimum, it can be much more */ |
| 151 | | |
| 151 | |
| 152 | 152 | /* RN: the stupid design of the tms5220 core means that ready is cleared */ |
| 153 | 153 | /* when there are 15 bytes in FIFO. It should be 16. Of course, if */ |
| 154 | 154 | /* it were the case, we would need to store the value on the bus, */ |
| r9498 | r9499 | |
| 158 | 158 | attotime time_to_ready = double_to_attotime(tms5220_time_to_ready(adapter->vsp)); |
| 159 | 159 | int cycles_to_ready = device->machine->device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready); |
| 160 | 160 | logerror("time to ready: %f -> %d\n", attotime_to_double(time_to_ready), (int) cycles_to_ready); |
| 161 | | |
| 161 | |
| 162 | 162 | cpu_adjust_icount(device->machine->device("maincpu"),-cycles_to_ready); |
| 163 | 163 | timer_set(device->machine, attotime_zero, NULL, 0, NULL); |
| 164 | | } |
| 164 | } |
| 165 | 165 | tms5220_data_w(adapter->vsp, offset, data); |
| 166 | 166 | } |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | /**************************************************************************/ |
| 170 | 170 | |
| 171 | | static ti99_peb_card speech_adapter_card = |
| 171 | static ti99_peb_card speech_adapter_card = |
| 172 | 172 | { |
| 173 | 173 | speech_rz, speech_w, // memory access read/write |
| 174 | 174 | NULL, NULL, // CRU access (none here) |
| r9498 | r9499 | |
| 194 | 194 | ti99_speech_state *adapter = (ti99_speech_state*)downcast<legacy_device_base *>(device)->token(); |
| 195 | 195 | /* Register the adapter */ |
| 196 | 196 | running_device *peb = device->owner(); |
| 197 | | |
| 197 | |
| 198 | 198 | if (input_port_read(device->machine, "SPEECH")) |
| 199 | 199 | { |
| 200 | 200 | int success = mount_card(peb, device, &speech_adapter_card, get_pebcard_config(device)->slot); |
| 201 | | if (!success) |
| 201 | if (!success) |
| 202 | 202 | { |
| 203 | 203 | logerror("speech: Could not mount the speech synthesizer\n"); |
| 204 | 204 | return; |
| 205 | 205 | } |
| 206 | | |
| 206 | |
| 207 | 207 | astring *region = new astring(); |
| 208 | | astring_assemble_3(region, device->tag(), ":", speech_region); |
| 209 | | |
| 208 | astring_assemble_3(region, device->tag(), ":", speech_region); |
| 209 | |
| 210 | 210 | adapter->speechrom_data = memory_region(device->machine, astring_c(region)); |
| 211 | 211 | adapter->speechROMlen = memory_region_length(device->machine, astring_c(region)); |
| 212 | 212 | adapter->speechROMaddr = 0; |