trunk/src/mess/machine/ti99/mapper8.c
| r26230 | r26231 | |
| 2 | 2 | // copyright-holders:Michael Zapf |
| 3 | 3 | /*************************************************************************** |
| 4 | 4 | |
| 5 | | TI-99/8 Address decoder and mapper |
| 5 | TI-99/8 main board logic |
| 6 | 6 | |
| 7 | 7 | This component implements the address decoder and mapper logic from the |
| 8 | 8 | TI-99/8 console. |
| r26230 | r26231 | |
| 37 | 37 | [1] ARMADILLO PRODUCT SPECIFICATIONS |
| 38 | 38 | [2] TI-99/8 Graphics Programming Language interpreter |
| 39 | 39 | |
| 40 | Format of map table entry (not emulated) |
| 41 | |
| 42 | * bit 0: WTPROT: page is write protected if 1 |
| 43 | * bit 1: XPROT: page is execute protected if 1 |
| 44 | * bit 2: RDPROT: page is read protected if 1 |
| 45 | * bit 3: reserved, value is ignored |
| 46 | * bits 4-7: reserved, always forced to 0 |
| 47 | * bits 8-23: page base address in 24-bit virtual address space |
| 48 | |
| 49 | Format of mapper control register: |
| 50 | * bit 0-4: unused??? |
| 51 | * bit 5-6: map file to load/save (0 for file 0, 1 for file 1, etc.) |
| 52 | * bit 7: 0 -> load map file from RAM, 1 -> save map file to RAM |
| 53 | |
| 54 | Format of mapper status register (cleared by read): |
| 55 | * bit 0: WPE - Write-Protect Error |
| 56 | * bit 1: XCE - eXeCute Error |
| 57 | * bit 2: RPE - Read-Protect Error |
| 58 | * bits 3-7: unused??? |
| 59 | |
| 60 | Memory error interrupts are enabled by setting WTPROT/XPROT/RDPROT. When |
| 61 | an error occurs, the tms9901 INT1* pin is pulled low (active). The pin |
| 62 | remains low until the mapper status register is read. |
| 63 | |
| 64 | 24-bit address map: |
| 65 | * >000000->00ffff: console RAM |
| 66 | * >010000->feffff: expansion? |
| 67 | * >ff0000->ff0fff: empty??? |
| 68 | * >ff1000->ff3fff: unused??? |
| 69 | * >ff4000->ff5fff: DSR space |
| 70 | * >ff6000->ff7fff: cartridge space |
| 71 | * >ff8000->ff9fff(???): >4000 ROM (normally enabled with a write to CRU >2700) |
| 72 | * >ffa000->ffbfff(?): >2000 ROM |
| 73 | * >ffc000->ffdfff(?): >6000 ROM |
| 74 | |
| 75 | |
| 76 | CRU map: |
| 77 | Since the tms9995 supports full 15-bit CRU addresses, the >1000->17ff |
| 78 | (>2000->2fff) range was assigned to support up to 16 extra expansion slot. |
| 79 | The good thing with using >1000->17ff is the fact that older expansion |
| 80 | cards that only decode 12 address bits will think that addresses |
| 81 | >1000->17ff refer to internal TI99 peripherals (>000->7ff range), which |
| 82 | suppresses any risk of bus contention. |
| 83 | * >0000->001f (>0000->003e): tms9901 |
| 84 | - P4: 1 -> MMD (Memory Mapped Devices?) at >8000, ROM enabled |
| 85 | - P5: 1 -> no P-CODE GROMs |
| 86 | * >0800->17ff (>1000->2ffe): Peripheral CRU space |
| 87 | * >1380->13ff (>2700->27fe): Internal DSR, with two output bits: |
| 88 | - >2700: Internal DSR select (parts of Basic and various utilities) |
| 89 | - >2702: SBO -> hardware reset |
| 90 | |
| 91 | |
| 92 | Memory map (TMS9901 P4 == 1): |
| 93 | When TMS9901 P4 output is set, locations >8000->9fff are ignored by mapper. |
| 94 | * >8000->83ff: SRAM (>8000->80ff is used by the mapper DMA controller |
| 95 | to hold four map files) (r/w) |
| 96 | * >8400: sound port (w) |
| 97 | * >8410->87ff: SRAM (r/w) |
| 98 | * >8800: VDP data read port (r) |
| 99 | * >8802: VDP status read port (r) |
| 100 | * >8810: memory mapper status and control registers (r/w) |
| 101 | * >8c00: VDP data write port (w) |
| 102 | * >8c02: VDP address and register write port (w) |
| 103 | * >9000: speech synthesizer read port (r) |
| 104 | * >9400: speech synthesizer write port (w) |
| 105 | * >9800 GPL data read port (r) |
| 106 | * >9802 GPL address read port (r) |
| 107 | * >9c00 GPL data write port -- unused (w) |
| 108 | * >9c02 GPL address write port (w) |
| 109 | |
| 110 | |
| 111 | Memory map (TMS9901 P5 == 0): |
| 112 | When TMS9901 P5 output is cleared, locations >f840->f8ff(?) are ignored by |
| 113 | mapper. |
| 114 | * >f840: data port for P-code grom library 0 (r?) |
| 115 | * >f850: data port for P-code grom library 1 (r?) |
| 116 | * >f860: data port for P-code grom library 2 (r?) |
| 117 | * >f842: address port for P-code grom library 0 (r/w?) |
| 118 | * >f852: address port for P-code grom library 1 (r/w?) |
| 119 | * >f862: address port for P-code grom library 2 (r/w?) |
| 120 | |
| 40 | 121 | Michael Zapf, October 2010 |
| 41 | 122 | February 2012: Rewritten as class |
| 42 | 123 | |
| r26230 | r26231 | |
| 44 | 125 | |
| 45 | 126 | #include "mapper8.h" |
| 46 | 127 | |
| 47 | | #define VERBOSE 1 |
| 128 | #define TRACE_CRU 0 |
| 129 | #define TRACE_MEM 0 |
| 130 | #define TRACE_MAP 0 |
| 131 | #define TRACE_CONFIG 0 |
| 132 | |
| 48 | 133 | #define LOG logerror |
| 49 | 134 | |
| 50 | | ti998_mapper_device::ti998_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 51 | | : bus8z_device(mconfig, MAPPER8, "TI-99/8 Memory mapper", tag, owner, clock, "ti99_mapper8", __FILE__) |
| 52 | | { |
| 53 | | } |
| 135 | mainboard8_device::mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 136 | : bus8z_device(mconfig, MAINBOARD8, "TI-99/8 Main board", tag, owner, clock, "ti998_mainboard", __FILE__), |
| 137 | m_oso(*this, OSO_TAG) |
| 138 | { } |
| 54 | 139 | |
| 55 | 140 | /*************************************************************************** |
| 56 | 141 | CRU access |
| r26230 | r26231 | |
| 59 | 144 | #define HEXBUS_CRU_BASE 0x1700 |
| 60 | 145 | #define MAPPER_CRU_BASE 0x2700 |
| 61 | 146 | |
| 62 | | READ8Z_MEMBER(ti998_mapper_device::crureadz) |
| 147 | READ8Z_MEMBER(mainboard8_device::crureadz) |
| 63 | 148 | { |
| 64 | | if (VERBOSE>8) LOG("mapper8: read CRU %04x ignored\n", offset); |
| 149 | if (TRACE_CRU) LOG("mainboard_998: read CRU %04x ignored\n", offset); |
| 65 | 150 | // Nothing here. |
| 66 | 151 | } |
| 67 | 152 | |
| r26230 | r26231 | |
| 69 | 154 | CRU handling. We handle the internal device at CRU address 0x2700 via |
| 70 | 155 | this mapper component. |
| 71 | 156 | */ |
| 72 | | WRITE8_MEMBER(ti998_mapper_device::cruwrite) |
| 157 | WRITE8_MEMBER(mainboard8_device::cruwrite) |
| 73 | 158 | { |
| 74 | 159 | if ((offset & 0xff00)==MAPPER_CRU_BASE) |
| 75 | 160 | { |
| r26230 | r26231 | |
| 79 | 164 | case 0: |
| 80 | 165 | // Turn on/off the internal DSR |
| 81 | 166 | m_dsr_selected = (data!=0); |
| 82 | | if (VERBOSE>7) LOG("mapper8: DSR select = %d\n", data); |
| 167 | if (TRACE_CRU) LOG("mainboard_998: DSR select = %d\n", data); |
| 83 | 168 | break; |
| 84 | 169 | case 1: |
| 85 | | if (VERBOSE>2) LOG("mapper8: System reset by CRU request\n"); |
| 170 | if (TRACE_CRU) LOG("mainboard_998: System reset by CRU request\n"); |
| 86 | 171 | machine().schedule_soft_reset(); |
| 87 | 172 | break; |
| 88 | 173 | } |
| r26230 | r26231 | |
| 91 | 176 | |
| 92 | 177 | if ((offset & 0xff00)==HEXBUS_CRU_BASE) |
| 93 | 178 | { |
| 94 | | if (VERBOSE>5) LOG("mapper8: Set CRU>%04x (Hexbus) to %d\n",offset,data); |
| 179 | int bit = (offset & 0xff)>>1; |
| 180 | switch (bit) |
| 181 | { |
| 182 | case 0: |
| 183 | // Turn on/off the Hexbus DSR |
| 184 | m_hexbus_selected = (data!=0); |
| 185 | if (TRACE_CRU) LOG("mainboard_998: Hexbus select = %d\n", data); |
| 186 | break; |
| 187 | default: |
| 188 | if (TRACE_CRU) LOG("mainboard_998: Set CRU>%04x (Hexbus) to %d\n",offset,data); |
| 189 | break; |
| 190 | } |
| 95 | 191 | return; |
| 96 | 192 | } |
| 97 | 193 | |
| 98 | 194 | if ((offset & 0xff00)>=0x0100) |
| 99 | 195 | { |
| 100 | | if (VERBOSE>5) LOG("mapper8: Set CRU>%04x (unknown) to %d\n",offset,data); |
| 196 | if (TRACE_CRU) LOG("mainboard_998: Set CRU>%04x (unknown) to %d\n",offset,data); |
| 101 | 197 | return; |
| 102 | 198 | } |
| 103 | 199 | } |
| 104 | 200 | |
| 105 | | void ti998_mapper_device::CRUS_set(bool state) |
| 201 | void mainboard8_device::CRUS_set(bool state) |
| 106 | 202 | { |
| 107 | | if (VERBOSE>7) LOG("mapper8: set CRUS=%d\n", state); |
| 203 | if (TRACE_CRU) LOG("mainboard_998: set CRUS=%d\n", state); |
| 108 | 204 | m_CRUS = state; |
| 109 | 205 | } |
| 110 | 206 | |
| 111 | 207 | /* |
| 112 | 208 | Note that PTGEN is negative logic. We invert these semantics here. |
| 113 | 209 | */ |
| 114 | | void ti998_mapper_device::PTGE_set(bool state) |
| 210 | void mainboard8_device::PTGE_set(bool state) |
| 115 | 211 | { |
| 116 | | if (VERBOSE>7) LOG("mapper8: set PTGEN=%d\n", state? 1:0); |
| 212 | if (TRACE_CRU) LOG("mainboard_998: set PTGEN=%d\n", state? 1:0); |
| 117 | 213 | m_PTGE = state; |
| 118 | 214 | } |
| 119 | 215 | |
| r26230 | r26231 | |
| 124 | 220 | /* |
| 125 | 221 | This method is called via the address map. |
| 126 | 222 | */ |
| 127 | | READ8_MEMBER( ti998_mapper_device::readm ) |
| 223 | READ8_MEMBER( mainboard8_device::readm ) |
| 128 | 224 | { |
| 129 | 225 | UINT8 value = 0; |
| 130 | 226 | bool found = false; |
| 131 | | if (VERBOSE>5) LOG("mapper8: read from %04x\n", offset); |
| 227 | if (TRACE_MEM) LOG("mainboard_998: read from %04x\n", offset); |
| 132 | 228 | found = access_logical_r(space, offset, &value, mem_mask); |
| 133 | 229 | m_waitcount = 2; |
| 134 | 230 | |
| r26230 | r26231 | |
| 153 | 249 | return value; |
| 154 | 250 | } |
| 155 | 251 | |
| 156 | | WRITE8_MEMBER( ti998_mapper_device::writem ) |
| 252 | WRITE8_MEMBER( mainboard8_device::writem ) |
| 157 | 253 | { |
| 158 | 254 | bool found = false; |
| 159 | 255 | |
| r26230 | r26231 | |
| 189 | 285 | 8810 (TI99EM): mapper: ignore |
| 190 | 286 | ff4000 (PHYSIC): DSR |
| 191 | 287 | */ |
| 192 | | READ8Z_MEMBER( ti998_mapper_device::readz ) |
| 288 | READ8Z_MEMBER( mainboard8_device::readz ) |
| 193 | 289 | { |
| 194 | 290 | if ((offset & 0xffe000)==0xff4000) |
| 195 | 291 | { |
| 196 | 292 | if (m_dsr_selected) |
| 197 | 293 | { |
| 198 | 294 | // Starts at 0x4000 in the image |
| 199 | | *value = m_rom[0x4000 | (offset & 0x1fff)]; |
| 200 | | if (VERBOSE>7) LOG("mapper8: (DSR) %04x -> %02x\n", offset, *value); |
| 295 | *value = m_rom1[0x4000 | (offset & 0x1fff)]; |
| 296 | if (TRACE_MEM) LOG("mainboard_998: (intDSR) %04x -> %02x\n", offset, *value); |
| 201 | 297 | } |
| 298 | else |
| 299 | { |
| 300 | if (m_hexbus_selected) |
| 301 | { |
| 302 | if ((offset & 0x1ff0)==0x1ff0) |
| 303 | { |
| 304 | *value = m_oso->read(space, (offset>>1) & 0x0003); |
| 305 | } |
| 306 | else |
| 307 | { |
| 308 | // Starts at 0x6000 in the image |
| 309 | *value = m_rom1[0x6000 | (offset & 0x1fff)]; |
| 310 | if (TRACE_MEM) LOG("mainboard_998: (HexDSR) %04x -> %02x\n", offset, *value); |
| 311 | } |
| 312 | } |
| 313 | } |
| 202 | 314 | } |
| 203 | 315 | else |
| 204 | 316 | { |
| 205 | 317 | if (((offset & 0xfff0)==0xf870 && m_CRUS==false)||(((offset & 0xfff0)==0x8810 && m_CRUS==true))) |
| 206 | 318 | { |
| 207 | | if (VERBOSE>4) LOG("mapper8: read access to mapper ignored: %04x\n", offset); |
| 319 | if (TRACE_MEM) LOG("mainboard_998: read access to mapper ignored: %04x\n", offset); |
| 208 | 320 | } |
| 209 | 321 | } |
| 210 | 322 | } |
| r26230 | r26231 | |
| 214 | 326 | ff4000 (PHYSIC): DSR. ignore |
| 215 | 327 | |
| 216 | 328 | */ |
| 217 | | WRITE8_MEMBER( ti998_mapper_device::write ) |
| 329 | WRITE8_MEMBER( mainboard8_device::write ) |
| 218 | 330 | { |
| 219 | 331 | if ((offset & 0xffe000)==0xff4000) |
| 220 | 332 | { |
| 221 | | if (VERBOSE>4) LOG("mapper8: Write access to DSR space %06x ignored\n", offset); |
| 333 | if (m_hexbus_selected) |
| 334 | { |
| 335 | if ((offset & 0x1ff0)==0x1ff0) |
| 336 | { |
| 337 | m_oso->write(space, (offset>>1) & 0x0003, data); |
| 338 | } |
| 339 | else |
| 340 | { |
| 341 | LOG("mainboard_998: Write access to Hexbus DSR address %06x ignored\n", offset); |
| 342 | } |
| 343 | } |
| 344 | else |
| 345 | { |
| 346 | if (m_dsr_selected) |
| 347 | { |
| 348 | LOG("mainboard_998: Write access to internal DSR address %06x ignored\n", offset); |
| 349 | } |
| 350 | else |
| 351 | { |
| 352 | LOG("mainboard_998: Write access to unmapped DSR space at address %06x ignored\n", offset); |
| 353 | } |
| 354 | } |
| 222 | 355 | } |
| 223 | 356 | else |
| 224 | 357 | { |
| r26230 | r26231 | |
| 234 | 367 | SRAM into the mapper and vice versa. |
| 235 | 368 | Format: |
| 236 | 369 | 0000 bbbl; bbb=bank, l=load |
| 370 | |
| 371 | TODO: Emulate properly, making use of HOLD |
| 237 | 372 | */ |
| 238 | | void ti998_mapper_device::mapwrite(int offset, UINT8 data) |
| 373 | void mainboard8_device::mapwrite(int offset, UINT8 data) |
| 239 | 374 | { |
| 240 | 375 | if ((data & 0xf0)==0x00) |
| 241 | 376 | { |
| 242 | 377 | int bankindx = (data & 0x0e)>>1; |
| 243 | 378 | if (data & 1) |
| 244 | 379 | { |
| 245 | | if (VERBOSE>7) LOG("mapper8: load mapper from SRAM, bank %d\n", bankindx); |
| 380 | if (TRACE_MAP) LOG("mainboard_998: load mapper from SRAM, bank %d\n", bankindx); |
| 246 | 381 | // Load from SRAM |
| 247 | 382 | // In reality the CPU is put on HOLD during this transfer |
| 248 | 383 | for (int i=0; i < 16; i++) |
| r26230 | r26231 | |
| 250 | 385 | int ptr = (bankindx << 6); |
| 251 | 386 | m_pas_offset[i] = (m_sram[(i<<2) + ptr] << 24) | (m_sram[(i<<2)+ ptr+1] << 16) |
| 252 | 387 | | (m_sram[(i<<2) + ptr+2] << 8) | (m_sram[(i<<2) + ptr+3]); |
| 253 | | if (VERBOSE>7) LOG("mapper8: load %d=%08x\n", i, m_pas_offset[i]); |
| 388 | if (TRACE_MAP) LOG("mainboard_998: load %d=%08x\n", i, m_pas_offset[i]); |
| 254 | 389 | } |
| 255 | 390 | } |
| 256 | 391 | else |
| 257 | 392 | { |
| 258 | | if (VERBOSE>7) LOG("mapper8: store mapper to SRAM, bank %d\n", bankindx); |
| 393 | if (TRACE_MAP) LOG("mainboard_998: store mapper to SRAM, bank %d\n", bankindx); |
| 259 | 394 | // Store in SRAM |
| 260 | 395 | for (int i=0; i < 16; i++) |
| 261 | 396 | { |
| r26230 | r26231 | |
| 264 | 399 | m_sram[(i<<2) + ptr +1] = (m_pas_offset[i] >> 16)& 0xff; |
| 265 | 400 | m_sram[(i<<2) + ptr +2] = (m_pas_offset[i] >> 8)& 0xff; |
| 266 | 401 | m_sram[(i<<2) + ptr +3] = (m_pas_offset[i])& 0xff; |
| 267 | | if (VERBOSE>7) LOG("mapper8: save %d=%08x\n", i, m_pas_offset[i]); |
| 402 | if (TRACE_MAP) LOG("mainboard_998: save %d=%08x\n", i, m_pas_offset[i]); |
| 268 | 403 | } |
| 269 | 404 | } |
| 270 | 405 | } |
| r26230 | r26231 | |
| 274 | 409 | Lookup methods. |
| 275 | 410 | ***************************************************************************/ |
| 276 | 411 | |
| 277 | | bool ti998_mapper_device::access_logical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask ) |
| 412 | bool mainboard8_device::access_logical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask ) |
| 278 | 413 | { |
| 279 | 414 | bool found = false; |
| 280 | 415 | logically_addressed_device *ldev = m_logcomp.first(); |
| 281 | 416 | bus8z_device *bdev = NULL; |
| 282 | 417 | |
| 283 | | if (VERBOSE>8) LOG("mapper8: offset=%04x; CRUS=%d, PTGEN=%d\n", offset, m_CRUS? 1:0, m_PTGE? 0:1); |
| 418 | if (TRACE_MEM) LOG("mainboard_998: offset=%04x; CRUS=%d, PTGEN=%d\n", offset, m_CRUS? 1:0, m_PTGE? 0:1); |
| 284 | 419 | while (ldev != NULL) |
| 285 | 420 | { |
| 286 | | if (VERBOSE>5) LOG("mapper8: checking node=%s\n", ldev->m_config->name); |
| 421 | if (TRACE_MEM) LOG("mainboard_998: checking node=%s\n", ldev->m_config->name); |
| 287 | 422 | // Check the mode |
| 288 | 423 | if (((ldev->m_config->mode == NATIVE) && (m_CRUS==false)) |
| 289 | 424 | || ((ldev->m_config->mode == TI99EM) && (m_CRUS==true)) |
| r26230 | r26231 | |
| 295 | 430 | { |
| 296 | 431 | case MAP8_SRAM: |
| 297 | 432 | *value = m_sram[offset & ~ldev->m_config->address_mask]; |
| 298 | | if (VERBOSE>7) LOG("mapper8: (SRAM) %04x -> %02x\n", offset, *value); |
| 433 | if (TRACE_MEM) LOG("mainboard_998: (SRAM) %04x -> %02x\n", offset, *value); |
| 299 | 434 | break; |
| 300 | 435 | case MAP8_ROM0: |
| 301 | 436 | // Starts at 0000 |
| 302 | | *value = m_rom[offset & ~ldev->m_config->address_mask]; |
| 303 | | if (VERBOSE>7) LOG("mapper8: (ROM) %04x -> %02x\n", offset, *value); |
| 437 | *value = m_rom0[offset & ~ldev->m_config->address_mask]; |
| 438 | if (TRACE_MEM) LOG("mainboard_998: (ROM0) %04x -> %02x\n", offset, *value); |
| 304 | 439 | break; |
| 305 | 440 | case MAP8_DEV: |
| 306 | 441 | // device |
| 307 | 442 | bdev = static_cast<bus8z_device*>(ldev->m_device); |
| 308 | 443 | bdev->readz(space, offset, value, mem_mask); |
| 309 | | if (VERBOSE>7) LOG("mapper8: (dev %s) %04x -> %02x\n", ldev->m_config->name, offset, *value); |
| 444 | if (TRACE_MEM) LOG("mainboard_998: (dev %s) %04x -> %02x\n", ldev->m_config->name, offset, *value); |
| 310 | 445 | break; |
| 311 | 446 | default: |
| 312 | | if (VERBOSE>1) LOG("mapper8: Invalid kind for read access: %d\n", ldev->m_kind); |
| 447 | if (TRACE_MEM) LOG("mainboard_998: Invalid kind for read access: %d\n", ldev->m_kind); |
| 313 | 448 | } |
| 314 | 449 | found = true; |
| 315 | 450 | if (ldev->m_config->stop==STOP) break; |
| r26230 | r26231 | |
| 320 | 455 | return found; |
| 321 | 456 | } |
| 322 | 457 | |
| 323 | | bool ti998_mapper_device::access_logical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask ) |
| 458 | bool mainboard8_device::access_logical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask ) |
| 324 | 459 | { |
| 325 | 460 | bool found = false; |
| 326 | 461 | logically_addressed_device *ldev = m_logcomp.first(); |
| r26230 | r26231 | |
| 339 | 474 | { |
| 340 | 475 | case MAP8_SRAM: |
| 341 | 476 | m_sram[offset & ~ldev->m_config->address_mask] = data; |
| 342 | | if (VERBOSE>7) LOG("mapper8: (SRAM) %04x <- %02x\n", offset, data); |
| 477 | if (TRACE_MEM) LOG("mainboard_998: (SRAM) %04x <- %02x\n", offset, data); |
| 343 | 478 | break; |
| 344 | 479 | case MAP8_ROM0: |
| 345 | | if (VERBOSE>7) LOG("mapper8: (ROM) %04x <- %02x (ignored)\n", offset, data); |
| 480 | if (TRACE_MEM) LOG("mainboard_998: (ROM0) %04x <- %02x (ignored)\n", offset, data); |
| 346 | 481 | break; |
| 347 | 482 | case MAP8_DEV: |
| 348 | 483 | // device |
| 349 | 484 | bdev = static_cast<bus8z_device*>(ldev->m_device); |
| 350 | 485 | bdev->write(space, offset, data, mem_mask); |
| 351 | | if (VERBOSE>7) LOG("mapper8: (dev %s) %04x <- %02x\n", ldev->m_config->name, offset, data); |
| 486 | if (TRACE_MEM) LOG("mainboard_998: (dev %s) %04x <- %02x\n", ldev->m_config->name, offset, data); |
| 352 | 487 | break; |
| 353 | 488 | default: |
| 354 | | if (VERBOSE>1) LOG("mapper8: Invalid kind for write access: %d\n", ldev->m_kind); |
| 489 | if (TRACE_MEM) LOG("mainboard_998: Invalid kind for write access: %d\n", ldev->m_kind); |
| 355 | 490 | } |
| 356 | 491 | found = true; |
| 357 | 492 | if (ldev->m_config->stop==STOP) break; |
| r26230 | r26231 | |
| 363 | 498 | } |
| 364 | 499 | |
| 365 | 500 | |
| 366 | | void ti998_mapper_device::access_physical_r( address_space& space, offs_t pas_address, UINT8 *value, UINT8 mem_mask ) |
| 501 | void mainboard8_device::access_physical_r( address_space& space, offs_t pas_address, UINT8 *value, UINT8 mem_mask ) |
| 367 | 502 | { |
| 368 | 503 | physically_addressed_device *pdev = m_physcomp.first(); |
| 369 | 504 | bus8z_device *bdev = NULL; |
| r26230 | r26231 | |
| 376 | 511 | { |
| 377 | 512 | case MAP8_DRAM: |
| 378 | 513 | *value = m_dram[pas_address & ~pdev->m_config->address_mask]; |
| 379 | | if (VERBOSE>3) LOG("mapper8: (DRAM) %06x -> %02x\n", pas_address, *value); |
| 514 | if (TRACE_MEM) LOG("mainboard_998: (DRAM) %06x -> %02x\n", pas_address, *value); |
| 380 | 515 | break; |
| 381 | | case MAP8_ROM1: |
| 516 | case MAP8_ROM1A0: |
| 517 | // Starts at 0000 in the image, 8K |
| 518 | *value = m_rom1[pas_address & 0x1fff]; |
| 519 | if (TRACE_MEM) LOG("mainboard_998: (ROM) %06x -> %02x\n", pas_address, *value); |
| 520 | break; |
| 521 | case MAP8_ROM1C0: |
| 382 | 522 | // Starts at 2000 in the image, 8K |
| 383 | | *value = m_rom[0x2000 | (pas_address & 0x1fff)]; |
| 384 | | if (VERBOSE>3) LOG("mapper8: (ROM) %06x -> %02x\n", pas_address, *value); |
| 523 | *value = m_rom1[0x2000 | (pas_address & 0x1fff)]; |
| 524 | if (TRACE_MEM) LOG("mainboard_998: (ROM) %06x -> %02x\n", pas_address, *value); |
| 385 | 525 | break; |
| 386 | | case MAP8_ROM1A: |
| 387 | | // Starts at 6000 in the image, 8K |
| 388 | | *value = m_rom[0x6000 | (pas_address & 0x1fff)]; |
| 389 | | if (VERBOSE>3) LOG("mapper8: (ROM) %06x -> %02x\n", pas_address, *value); |
| 390 | | break; |
| 391 | 526 | case MAP8_INTS: |
| 392 | 527 | // Interrupt sense |
| 393 | | if (VERBOSE>1) LOG("ti99_8: ILSENSE not implemented.\n"); |
| 528 | LOG("mainboard_998: ILSENSE not implemented.\n"); |
| 394 | 529 | break; |
| 395 | 530 | case MAP8_DEV: |
| 396 | 531 | // devices |
| 397 | 532 | bdev = static_cast<bus8z_device*>(pdev->m_device); |
| 398 | 533 | bdev->readz(space, pas_address, value, mem_mask); |
| 399 | | if (VERBOSE>7) LOG("mapper8: (dev %s) %06x -> %02x\n", pdev->m_config->name, pas_address, *value); |
| 534 | if (TRACE_MEM) LOG("mainboard_998: (dev %s) %06x -> %02x\n", pdev->m_config->name, pas_address, *value); |
| 400 | 535 | break; |
| 401 | 536 | default: |
| 402 | | if (VERBOSE>1) LOG("mapper8: Invalid kind for physical read access: %d\n", pdev->m_kind); |
| 537 | LOG("mainboard_998: Invalid kind for physical read access: %d\n", pdev->m_kind); |
| 403 | 538 | } |
| 404 | 539 | if (pdev->m_config->stop==STOP) break; |
| 405 | 540 | } |
| r26230 | r26231 | |
| 407 | 542 | } |
| 408 | 543 | } |
| 409 | 544 | |
| 410 | | void ti998_mapper_device::access_physical_w( address_space& space, offs_t pas_address, UINT8 data, UINT8 mem_mask ) |
| 545 | void mainboard8_device::access_physical_w( address_space& space, offs_t pas_address, UINT8 data, UINT8 mem_mask ) |
| 411 | 546 | { |
| 412 | 547 | physically_addressed_device *pdev = m_physcomp.first(); |
| 413 | 548 | bus8z_device *bdev = NULL; |
| r26230 | r26231 | |
| 420 | 555 | { |
| 421 | 556 | case MAP8_DRAM: |
| 422 | 557 | m_dram[pas_address & ~pdev->m_config->address_mask] = data; |
| 423 | | if (VERBOSE>3) LOG("mapper8: (DRAM) %06x <- %02x\n", pas_address, data); |
| 558 | if (TRACE_MEM) LOG("mainboard_998: (DRAM) %06x <- %02x\n", pas_address, data); |
| 424 | 559 | break; |
| 425 | | case MAP8_ROM1: |
| 426 | | case MAP8_ROM1A: |
| 427 | | if (VERBOSE>7) LOG("mapper8: (ROM) %06x <- %02x (ignored)\n", pas_address, data); |
| 560 | case MAP8_ROM1A0: |
| 561 | case MAP8_ROM1C0: |
| 562 | if (TRACE_MEM) LOG("mainboard_998: (ROM1) %06x <- %02x (ignored)\n", pas_address, data); |
| 428 | 563 | break; |
| 429 | 564 | case MAP8_INTS: |
| 430 | 565 | // Interrupt sense |
| 431 | | if (VERBOSE>1) LOG("ti99_8: write to ilsense ignored\n"); |
| 566 | LOG("ti99_8: write to ilsense ignored\n"); |
| 432 | 567 | break; |
| 433 | 568 | case MAP8_DEV: |
| 434 | 569 | // devices |
| 435 | 570 | bdev = static_cast<bus8z_device*>(pdev->m_device); |
| 436 | | if (VERBOSE>7) LOG("mapper8: (dev %s) %06x <- %02x\n", pdev->m_config->name, pas_address, data); |
| 571 | if (TRACE_MEM) LOG("mainboard_998: (dev %s) %06x <- %02x\n", pdev->m_config->name, pas_address, data); |
| 437 | 572 | bdev->write(space, pas_address, data, mem_mask); |
| 438 | 573 | break; |
| 439 | 574 | default: |
| 440 | | if (VERBOSE>1) LOG("mapper8: Invalid kind for physical write access: %d\n", pdev->m_kind); |
| 575 | LOG("mainboard_998: Invalid kind for physical write access: %d\n", pdev->m_kind); |
| 441 | 576 | } |
| 442 | 577 | if (pdev->m_config->stop==STOP) break; |
| 443 | 578 | } |
| r26230 | r26231 | |
| 449 | 584 | The mapper is connected to the clock line in order to operate |
| 450 | 585 | the wait state counter. |
| 451 | 586 | */ |
| 452 | | void ti998_mapper_device::clock_in(int clock) |
| 587 | void mainboard8_device::clock_in(int clock) |
| 453 | 588 | { |
| 454 | 589 | if (clock==ASSERT_LINE && m_waitcount!=0) |
| 455 | 590 | { |
| r26230 | r26231 | |
| 468 | 603 | |
| 469 | 604 | Note that device_reset is too late; the initial context switch occurs earlier. |
| 470 | 605 | */ |
| 471 | | void ti998_mapper_device::device_start() |
| 606 | void mainboard8_device::device_start() |
| 472 | 607 | { |
| 473 | | if (VERBOSE>5) LOG("ti99_8: Starting mapper\n"); |
| 608 | LOG("ti99_8: Starting mapper\n"); |
| 474 | 609 | |
| 475 | 610 | // String values of the pseudo constants, used in the configuration. |
| 476 | | const char *const pseudodev[6] = { SRAMNAME, ROM0NAME, ROM1NAME, ROM1ANAME, DRAMNAME, INTSNAME }; |
| 611 | const char *const pseudodev[6] = { SRAMNAME, ROM0NAME, ROM1A0NAME, ROM1C0NAME, DRAMNAME, INTSNAME }; |
| 477 | 612 | |
| 478 | 613 | const mapper8_config *conf = reinterpret_cast<const mapper8_config *>(static_config()); |
| 479 | 614 | |
| r26230 | r26231 | |
| 482 | 617 | |
| 483 | 618 | m_sram = machine().root_device().memregion(SRAM_TAG)->base(); |
| 484 | 619 | m_dram = machine().root_device().memregion(DRAM_TAG)->base(); |
| 485 | | m_rom = machine().root_device().memregion("maincpu")->base(); |
| 620 | m_rom0 = machine().root_device().memregion(ROM0_TAG)->base(); |
| 621 | m_rom1 = machine().root_device().memregion(ROM1_TAG)->base(); |
| 486 | 622 | |
| 487 | 623 | // Clear the lists |
| 488 | 624 | m_logcomp.reset(); |
| r26230 | r26231 | |
| 521 | 657 | { |
| 522 | 658 | logically_addressed_device *ad = new logically_addressed_device(kind, (device_t*)dev, entry[i]); |
| 523 | 659 | m_logcomp.append(*ad); |
| 524 | | if (VERBOSE>6) LOG("mapper8: Device %s mounted into logical address space.\n", entry[i].name); |
| 660 | if (TRACE_CONFIG) LOG("mainboard_998: Device %s mounted into logical address space.\n", entry[i].name); |
| 525 | 661 | } |
| 526 | 662 | else |
| 527 | 663 | { |
| 528 | 664 | physically_addressed_device *ad = new physically_addressed_device(kind, (device_t*)dev, entry[i]); |
| 529 | 665 | m_physcomp.append(*ad); |
| 530 | | if (VERBOSE>6) LOG("mapper8: Device %s mounted into physical address space.\n", entry[i].name); |
| 666 | if (TRACE_CONFIG) LOG("mainboard_998: Device %s mounted into physical address space.\n", entry[i].name); |
| 531 | 667 | } |
| 532 | 668 | } |
| 533 | 669 | else |
| 534 | 670 | { |
| 535 | | if (VERBOSE>1) LOG("mapper8: Device %s not found.\n", entry[i].name); |
| 671 | if (TRACE_CONFIG) LOG("mainboard_998: Device %s not found.\n", entry[i].name); |
| 536 | 672 | } |
| 537 | 673 | } |
| 538 | 674 | } |
| 539 | 675 | } |
| 540 | | if (VERBOSE>4) LOG("Mapper logical device count = %d\n", m_logcomp.count()); |
| 541 | | if (VERBOSE>4) LOG("Mapper physical device count = %d\n", m_physcomp.count()); |
| 676 | if (TRACE_CONFIG) LOG("Mapper logical device count = %d\n", m_logcomp.count()); |
| 677 | if (TRACE_CONFIG) LOG("Mapper physical device count = %d\n", m_physcomp.count()); |
| 542 | 678 | |
| 543 | 679 | m_dsr_selected = false; |
| 544 | 680 | m_CRUS = true; |
| r26230 | r26231 | |
| 548 | 684 | for (int i=0; i < 16; i++) m_pas_offset[i] = 0; |
| 549 | 685 | } |
| 550 | 686 | |
| 551 | | void ti998_mapper_device::device_reset() |
| 687 | void mainboard8_device::device_reset() |
| 552 | 688 | { |
| 553 | 689 | m_dsr_selected = false; |
| 554 | 690 | m_CRUS = true; |
| r26230 | r26231 | |
| 561 | 697 | m_ready(ASSERT_LINE); |
| 562 | 698 | } |
| 563 | 699 | |
| 564 | | const device_type MAPPER8 = &device_creator<ti998_mapper_device>; |
| 700 | MACHINE_CONFIG_FRAGMENT( ti998_mainboard ) |
| 701 | MCFG_DEVICE_ADD(OSO_TAG, OSO, 0) |
| 702 | MACHINE_CONFIG_END |
| 703 | |
| 704 | machine_config_constructor mainboard8_device::device_mconfig_additions() const |
| 705 | { |
| 706 | return MACHINE_CONFIG_NAME( ti998_mainboard ); |
| 707 | } |
| 708 | |
| 709 | const device_type MAINBOARD8 = &device_creator<mainboard8_device>; |
| 710 | |
| 711 | /*************************************************************************** |
| 712 | |
| 713 | Custom chips of the TI-99/8 |
| 714 | OSO: Hexbus interface |
| 715 | |
| 716 | ****************************************************************************/ |
| 717 | |
| 718 | enum |
| 719 | { |
| 720 | HSKWT = 0x80 |
| 721 | }; |
| 722 | |
| 723 | ti998_oso_device::ti998_oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 724 | : device_t(mconfig, OSO, "OSO Hexbus interface", tag, owner, clock, "ti998_oso", __FILE__) |
| 725 | { |
| 726 | LOG("ti998/oso: Creating OSO\n"); |
| 727 | } |
| 728 | |
| 729 | READ8_MEMBER( ti998_oso_device::read ) |
| 730 | { |
| 731 | int value = 0; |
| 732 | offset &= 0x03; |
| 733 | LOG("ti998/oso: OSO chip read access %04x -> %02x\n", (offset<<1) | 0x5ff0, value); |
| 734 | switch (offset) |
| 735 | { |
| 736 | case 0: |
| 737 | // read 5FF8: read data register |
| 738 | break; |
| 739 | case 1: |
| 740 | // read 5FFA: read status register |
| 741 | // We return handshake_write=1 to prevent lock-ups (until the hexbus is properly implemented) |
| 742 | value = HSKWT; |
| 743 | break; |
| 744 | case 2: |
| 745 | // read 5FFC: read control register |
| 746 | break; |
| 747 | case 3: |
| 748 | // read 5FFE: read transmit register |
| 749 | break; |
| 750 | } |
| 751 | |
| 752 | return value; |
| 753 | } |
| 754 | |
| 755 | WRITE8_MEMBER( ti998_oso_device::write ) |
| 756 | { |
| 757 | offset &= 0x03; |
| 758 | LOG("ti998/oso: OSO chip write access %04x <- %02x\n", (offset<<1) | 0x5ff0, data); |
| 759 | } |
| 760 | |
| 761 | void ti998_oso_device::device_start() |
| 762 | { |
| 763 | } |
| 764 | |
| 765 | const device_type OSO = &device_creator<ti998_oso_device>; |
trunk/src/mess/drivers/ti99_8.c
| r26230 | r26231 | |
| 5 | 5 | The MESS TI-99/8 emulation driver |
| 6 | 6 | |
| 7 | 7 | The TI-99/8 was the envisaged successor to the TI-99/4A but never passed |
| 8 | | its prototype state. Only a few consoles were built. The ROMs were not |
| 9 | | even finalized, so the few available consoles may have different |
| 10 | | operating system versions. |
| 8 | its prototype state. Only a few dozens of consoles were built. The ROMs |
| 9 | were not even finalized, so the few available consoles have different |
| 10 | operating system versions and capabilities. |
| 11 | 11 | |
| 12 | | There is some preliminary info: |
| 13 | 12 | |
| 14 | | Name: Texas Instruments Computer TI-99/8 (no "Home") |
| 13 | Characteristics |
| 14 | --------------- |
| 15 | 15 | |
| 16 | | References: |
| 17 | | * machine room <http://...> |
| 18 | | * TI99/8 user manual |
| 19 | | * TI99/8 schematics |
| 20 | | * TI99/8 ROM source code |
| 21 | | * Message on TI99 yahoo group for CPU info |
| 16 | Name: "Texas Instruments Computer TI-99/8" (no "Home") |
| 22 | 17 | |
| 23 | | General: |
| 24 | | * a few dozen units were built in 1983, never released |
| 25 | | * CPU is a custom variant of tms9995 (part code MP9537): the 16-bit RAM and |
| 26 | | (presumably) the on-chip decrementer are disabled |
| 27 | | * 220kb(?) of ROM, including monitor, GPL interpreter, TI-extended basic |
| 28 | | II, and a P-code interpreter with a few utilities. More specifically: |
| 29 | | - 32kb system ROM with GPL interpreter, TI-extended basic II and a few |
| 30 | | utilities (no dump, but 90% of source code is available and has been |
| 31 | | compiled) |
| 32 | | - 18kb system GROMs, with monitor and TI-extended basic II (no dump, |
| 33 | | but source code is available and has been compiled) |
| 34 | | - 4(???)kb DSR ROM for hexbus (no dump) |
| 18 | Inofficial nickname: "Armadillo" |
| 35 | 19 | |
| 36 | | 32 KiB speech ROM: Contents are the same as used in the TI-99/4A speech |
| 37 | | synthesizer, although the speech chip is slightly newer (MZ: verified |
| 38 | | on a real system 07-2013) |
| 20 | CPU: Single-CPU system using a TMS9995, but as a variant named MP9537. This |
| 21 | variant does not offer on-chip RAM or decrementer. |
| 39 | 22 | |
| 40 | | - 12(???)kb ROM with PCode interpreter (no dump) |
| 41 | | - 2(3???)*48kb of GROMs with PCode data files (no dump) |
| 42 | | * 2kb SRAM (16 bytes of which are hidden), 64kb DRAM (expandable to almost |
| 43 | | 16MBytes), 16kb vdp RAM |
| 44 | | * tms9118 vdp (similar to tms9918a, slightly different bus interface and |
| 45 | | timings) |
| 46 | | * I/O |
| 47 | | - 50-key keyboard, plus 2 optional joysticks |
| 48 | | - sound and speech (both ti99/4(a)-like) |
| 49 | | - Hex-Bus |
| 50 | | - Cassette |
| 51 | | * cartridge port on the top |
| 52 | | * 50-pin(?) expansion port on the back |
| 53 | | * Programs can enable/disable the ROM and memory mapped register areas. |
| 23 | Video: TMS9118 Video Display Processor with 16 KiB RAM. The 9118 has the |
| 24 | same capabilities as the 9918/28 in the TI-99/4A, except for the |
| 25 | missing GROM clock (which must be provided separately) and the |
| 26 | different DRAM type (2 chips TMS 4416 16K*4). Delivers a 60 Hz |
| 27 | interrupt to the CPU via the PSI. |
| 54 | 28 | |
| 55 | | Mapper: |
| 56 | | Mapper has 4kb page size (-> 16 pages per map file), 32 bits per page |
| 57 | | entry. Address bits A0-A3 are the page index, whereas bits A4-A15 are the |
| 58 | | offset in the page. Physical address space is 16Mbytes. All pages are 4 |
| 59 | | kBytes in length, and they can start anywhere in the 24-bit physical |
| 60 | | address space. The mapper can load any of 4 map files from SRAM by DMA. |
| 61 | | Map file 0 is used by BIOS, file 1 by memory XOPs(?), file 2 by P-code |
| 62 | | interpreter(???). |
| 29 | Keyboard: 50-key keyboard, slightly different to the TI-99/4A, but also with |
| 30 | modifiers Control, Function, Shift, Caps Lock. Connects to the TMS 9901 |
| 31 | PSI like in the TI-99/4A, but the pin assignment and key matrix |
| 32 | are different: |
| 33 | - P0-P3: column select |
| 34 | - INT6*-INT11*: row inputs (INT6* is only used for joystick fire) |
| 63 | 35 | |
| 64 | | Format of map table entry: |
| 65 | | * bit 0: WTPROT: page is write protected if 1 |
| 66 | | * bit 1: XPROT: page is execute protected if 1 |
| 67 | | * bit 2: RDPROT: page is read protected if 1 |
| 68 | | * bit 3: reserved, value is ignored |
| 69 | | * bits 4-7: reserved, always forced to 0 |
| 70 | | * bits 8-23: page base address in 24-bit virtual address space |
| 36 | Cassette: Identical to TI-99/4A, except that the CS2 unit is not implemented |
| 71 | 37 | |
| 72 | | Format of mapper control register: |
| 73 | | * bit 0-4: unused??? |
| 74 | | * bit 5-6: map file to load/save (0 for file 0, 1 for file 1, etc.) |
| 75 | | * bit 7: 0 -> load map file from RAM, 1 -> save map file to RAM |
| 38 | Sound: SN94624 as used in the TI-99/4A |
| 76 | 39 | |
| 77 | | Format of mapper status register (cleared by read): |
| 78 | | * bit 0: WPE - Write-Protect Error |
| 79 | | * bit 1: XCE - eXeCute Error |
| 80 | | * bit 2: RPE - Read-Protect Error |
| 81 | | * bits 3-7: unused??? |
| 40 | Speech: TMS5200C, a rare variant of the TMS52xx family. Compatible to the |
| 41 | speech data for the separate speech synthesizer for the TI-99/4A. |
| 42 | Speech ROMs CD2325A, CD2326A (total 128K*1) |
| 82 | 43 | |
| 83 | | Memory error interrupts are enabled by setting WTPROT/XPROT/RDPROT. When |
| 84 | | an error occurs, the tms9901 INT1* pin is pulled low (active). The pin |
| 85 | | remains low until the mapper status register is read. |
| 44 | ROM: TMS4764 (8K*8), called "ROM0" in the specifications [1] |
| 45 | TMS47256 (32K*8), called "ROM1" [1] |
| 46 | TMS47128 (16K*8), "P-Code ROM" (only available in late prototypes) |
| 47 | See below for contents |
| 86 | 48 | |
| 87 | | 24-bit address map: |
| 88 | | * >000000->00ffff: console RAM |
| 89 | | * >010000->feffff: expansion? |
| 90 | | * >ff0000->ff0fff: empty??? |
| 91 | | * >ff1000->ff3fff: unused??? |
| 92 | | * >ff4000->ff5fff: DSR space |
| 93 | | * >ff6000->ff7fff: cartridge space |
| 94 | | * >ff8000->ff9fff(???): >4000 ROM (normally enabled with a write to CRU >2700) |
| 95 | | * >ffa000->ffbfff(?): >2000 ROM |
| 96 | | * >ffc000->ffdfff(?): >6000 ROM |
| 49 | GROMs: TI-specific ROM circuits with internal address counter and 6 KiB |
| 50 | capacity (see grom.c) |
| 51 | 3 GROMs (system GROMs, access via port at logical address F830) |
| 52 | 8 GROMs (Pascal / Text-to-speech GROMs, port at logical address F840) |
| 53 | 8 GROMs (Pascal GROMs, port at logical address F850) |
| 54 | 3 GROMs (Pascal GROMs, access via port at logical address F860) |
| 55 | (total of 132 KiB GROM) |
| 97 | 56 | |
| 57 | RAM: 1 TMS4016 (SRAM 2K*8) |
| 58 | 8 TMS4164 (DRAM 64K*1) |
| 98 | 59 | |
| 99 | | CRU map: |
| 100 | | Since the tms9995 supports full 15-bit CRU addresses, the >1000->17ff |
| 101 | | (>2000->2fff) range was assigned to support up to 16 extra expansion slot. |
| 102 | | The good thing with using >1000->17ff is the fact that older expansion |
| 103 | | cards that only decode 12 address bits will think that addresses |
| 104 | | >1000->17ff refer to internal TI99 peripherals (>000->7ff range), which |
| 105 | | suppresses any risk of bus contention. |
| 106 | | * >0000->001f (>0000->003e): tms9901 |
| 107 | | - P4: 1 -> MMD (Memory Mapped Devices?) at >8000, ROM enabled |
| 108 | | - P5: 1 -> no P-CODE GROMs |
| 109 | | * >0800->17ff (>1000->2ffe): Peripheral CRU space |
| 110 | | * >1380->13ff (>2700->27fe): Internal DSR, with two output bits: |
| 111 | | - >2700: Internal DSR select (parts of Basic and various utilities) |
| 112 | | - >2702: SBO -> hardware reset |
| 60 | PSI: (programmable system interface) TMS9901 with connections to |
| 61 | keyboard, joystick port, cassette port, and external interrupt lines |
| 62 | (video, peripheral devices) |
| 113 | 63 | |
| 64 | External connectors: |
| 65 | - Joystick port (compatible to TI-99/4A joystick slot) |
| 66 | - Cassette port |
| 67 | - Cartridge port (compatible to TI-99/4A cartridge slot, but vertically |
| 68 | orientated, so cartridges are plugged in from the top) |
| 69 | - I/O port (not compatible to TI-99/4A I/O port, needs a special P-Box |
| 70 | card called "Armadillo interface") |
| 71 | - Hexbus port (new peripheral system, also seen with later TI designs) |
| 72 | - Video port (composite) |
| 114 | 73 | |
| 115 | | Memory map (TMS9901 P4 == 1): |
| 116 | | When TMS9901 P4 output is set, locations >8000->9fff are ignored by mapper. |
| 117 | | * >8000->83ff: SRAM (>8000->80ff is used by the mapper DMA controller |
| 118 | | to hold four map files) (r/w) |
| 119 | | * >8400: sound port (w) |
| 120 | | * >8410->87ff: SRAM (r/w) |
| 121 | | * >8800: VDP data read port (r) |
| 122 | | * >8802: VDP status read port (r) |
| 123 | | * >8810: memory mapper status and control registers (r/w) |
| 124 | | * >8c00: VDP data write port (w) |
| 125 | | * >8c02: VDP address and register write port (w) |
| 126 | | * >9000: speech synthesizer read port (r) |
| 127 | | * >9400: speech synthesizer write port (w) |
| 128 | | * >9800 GPL data read port (r) |
| 129 | | * >9802 GPL address read port (r) |
| 130 | | * >9c00 GPL data write port -- unused (w) |
| 131 | | * >9c02 GPL address write port (w) |
| 74 | Custom chips: Five custom chips contain mapping and selection logic |
| 75 | - "Vaquerro": Logical address space decoder |
| 76 | - "Mofetta" : Physical address space decoder |
| 77 | - "Amigo" : Mapper |
| 78 | - "Pollo" : DRAM controller |
| 79 | - "Oso" : Hexbus interface |
| 132 | 80 | |
| 81 | Modes: |
| 82 | - Compatibility mode (TI-99/4A mode): Memory-mapped devices are |
| 83 | placed at the same location as found in the TI-99/4A, thereby |
| 84 | providing a good downward compatibility. |
| 85 | The console starts up in compatibility mode. |
| 86 | - Native mode (Armadillo mode): Devices are located at positions above |
| 87 | 0xF000 that allow for a contiguous usage of memory. |
| 133 | 88 | |
| 134 | | Memory map (TMS9901 P5 == 0): |
| 135 | | When TMS9901 P5 output is cleared, locations >f840->f8ff(?) are ignored by |
| 136 | | mapper. |
| 137 | | * >f840: data port for P-code grom library 0 (r?) |
| 138 | | * >f880: data port for P-code grom library 1 (r?) |
| 139 | | * >f8c0: data port for P-code grom library 2 (r?) |
| 140 | | * >f842: address port for P-code grom library 0 (r/w?) |
| 141 | | * >f882: address port for P-code grom library 1 (r/w?) |
| 142 | | * >f8c2: address port for P-code grom library 2 (r/w?) |
| 143 | 89 | |
| 90 | ROM contents |
| 91 | ------------ |
| 92 | The ROM0 chip is accessible at addresses 0000-1FFF in the logical address |
| 93 | space of the compatibility mode. It contains the GPL interpreter. In |
| 94 | native mode the ROM0 chip is invisible. |
| 144 | 95 | |
| 145 | | Cassette interface: |
| 146 | | Identical to ti99/4(a), except that the CS2 unit is not implemented. |
| 96 | ROM0 |
| 97 | offset Logical address Name |
| 98 | ----------------------------------- |
| 99 | 0000 0000-1FFF ROM0 |
| 147 | 100 | |
| 148 | 101 | |
| 149 | | Keyboard interface: |
| 150 | | The keyboard interface uses the console tms9901 PSI, but the pin assignment |
| 151 | | and key matrix are different from both 99/4 and 99/4a. |
| 152 | | - P0-P3: column select |
| 153 | | - INT6*-INT11*: row inputs (int6* is only used for joystick fire) |
| 102 | The ROM1 chip contains 32 KiB of various system software. It is located in |
| 103 | the physical address space, so it must be mapped into the logical address |
| 104 | space by defining an appropriate map. |
| 154 | 105 | |
| 155 | | ROM file contents: |
| 156 | | 0000-1fff ROM0 0x0000 (logical address) |
| 157 | | 2000-3fff ROM1 0xffa000 - 0xffbfff |
| 158 | | 4000-5fff DSR1 0xff4000 (TTS) |
| 159 | | 6000-7fff ROM1a 0xffc000 - 0xffdfff |
| 160 | | 8000-9fff DSR2 0xff4000 (missing; Hexbus?) |
| 106 | ROM1 |
| 107 | offset Physical address Name |
| 108 | ---------------------------------------------------------- |
| 109 | 0000 FFA000-FFDFFF ROM1 |
| 110 | 4000 FF4000-FF5FFF @CRU>2700 Text-to-speech ROM/DSR |
| 111 | 6000 FF4000-FF5FFF @CRU>1700 Hexbus DSR |
| 161 | 112 | |
| 113 | The DSR portions have to be selected via the CRU bits >1700 or >2700. |
| 114 | |
| 115 | |
| 116 | Mapper |
| 117 | ------ |
| 118 | The mapper uses 4K pages (unlike the Geneve mapper with 8K pages) which |
| 119 | are defined by a 32 bit word. The address bits A0-A3 serve as the page |
| 120 | index, whereas bits A4-A15 are the offset in the page. |
| 121 | From the 32 bits, 24 bits define the physical address, so this allows for |
| 122 | a maximum of 16 MiB of mapped-addressable memory. |
| 123 | |
| 124 | See more about the mapper in the file mapper8.c. |
| 125 | |
| 126 | |
| 127 | Availability of ROMs and documentation |
| 128 | -------------------------------------- |
| 129 | By written consent, TI granted free use of all software and documentation |
| 130 | concerning the TI-99/8, including all specifications, ROMs, and source code |
| 131 | of ROMs. |
| 132 | |
| 133 | |
| 134 | Acknowledgements |
| 135 | ---------------- |
| 136 | Special thanks go to Ciro Barile of the TI99 Italian User Club |
| 137 | (www.ti99iuc.it): By his courtesy we have a consistent dump of ROMs for |
| 138 | one of the most evolved versions of the TI-99/8 with |
| 139 | |
| 140 | - complete GROM set (with Pascal) |
| 141 | - complete ROM set (with Hexbus DSR and TTS) |
| 142 | - complete speech ROM set |
| 143 | |
| 144 | Also, by applying test programs on his real console, many unclear |
| 145 | specifications were resolved. |
| 146 | |
| 147 | |
| 148 | References |
| 149 | ---------- |
| 150 | [1] Texas Instruments: Armadillo Product Specifications, July 1983 |
| 151 | [2] Source code (Assembler and GPL) of the TI-99/8 ROMs and GROMs |
| 152 | [3] Schematics of the TI-99/8 |
| 153 | |
| 154 | |
| 155 | Implementation |
| 156 | -------------- |
| 157 | Initial version by Raphael Nabet, 2003. |
| 158 | |
| 159 | February 2012: Rewritten as class [Michael Zapf] |
| 160 | November 2013: Included new dumps [Michael Zapf] |
| 161 | |
| 162 | 162 | =========================================================================== |
| 163 | 163 | Known Issues (MZ, 2010-11-07) |
| 164 | 164 | |
| r26230 | r26231 | |
| 172 | 172 | emulation for those. Thus you can currently only use cassette to load and |
| 173 | 173 | save programs. You MUST not plug in any floppy controller when you intend to |
| 174 | 174 | start XB II. Other cartridges (like Editor/Assembler) |
| 175 | | seem to be not affected by this problem and can make use of the floppy |
| 175 | seem to be unaffected by this problem and can make use of the floppy |
| 176 | 176 | controllers. |
| 177 | 177 | Technical detail: The designers of XB II seem to have decided to put PABs |
| 178 | 178 | (Peripheral access block; contains pointers to buffers, the file name, and |
| r26230 | r26231 | |
| 184 | 184 | as if XB II does not properly handle this situation and may lock up |
| 185 | 185 | (sometimes it starts up, but file access is still not possible). |
| 186 | 186 | |
| 187 | TODO: Emulate a Hexbus floppy. |
| 188 | |
| 187 | 189 | - Multiple cartridges are not shown in the startup screen; only one |
| 188 | 190 | cartridge is presented. You have to manually select the cartridges with the |
| 189 | 191 | dip switch. |
| r26230 | r26231 | |
| 192 | 194 | mapper shadows the NVRAM of the cartridge. You will lose the contents when |
| 193 | 195 | you turn off the machine. |
| 194 | 196 | |
| 195 | | Raphael Nabet, 2003. |
| 196 | | |
| 197 | | February 2012: Rewritten as class |
| 198 | | Michael Zapf |
| 199 | | |
| 200 | 197 | *****************************************************************************/ |
| 201 | 198 | |
| 202 | 199 | |
| r26230 | r26231 | |
| 217 | 214 | #include "machine/ti99/gromport.h" |
| 218 | 215 | #include "machine/ti99/joyport.h" |
| 219 | 216 | |
| 220 | | #define VERBOSE 1 |
| 217 | // Debugging |
| 218 | #define TRACE_READY 0 |
| 219 | #define TRACE_INTERRUPTS 0 |
| 220 | #define TRACE_CRU 0 |
| 221 | 221 | #define LOG logerror |
| 222 | 222 | |
| 223 | /* |
| 224 | READY bits. |
| 225 | */ |
| 226 | enum |
| 227 | { |
| 228 | READY_GROM = 1, |
| 229 | READY_MAPPER = 2, |
| 230 | READY_PBOX = 4, |
| 231 | READY_SOUND = 8, |
| 232 | READY_CART = 16, |
| 233 | READY_SPEECH = 32 |
| 234 | }; |
| 235 | |
| 223 | 236 | class ti99_8_state : public driver_device |
| 224 | 237 | { |
| 225 | 238 | public: |
| 226 | 239 | ti99_8_state(const machine_config &mconfig, device_type type, const char *tag) |
| 227 | 240 | : driver_device(mconfig, type, tag), |
| 241 | m_cpu(*this, "maincpu"), |
| 242 | m_tms9901(*this, TMS9901_TAG), |
| 243 | m_gromport(*this, GROMPORT_TAG), |
| 244 | m_peribox(*this, PERIBOX_TAG), |
| 245 | m_mainboard(*this, MAINBOARD8_TAG), |
| 246 | m_joyport(*this, JOYPORT_TAG), |
| 247 | m_video(*this, VIDEO_SYSTEM_TAG), |
| 228 | 248 | m_cassette(*this, "cassette") { } |
| 229 | 249 | |
| 230 | | // CRU (Communication Register Unit) handling |
| 231 | | DECLARE_READ8_MEMBER(cruread); |
| 232 | | DECLARE_WRITE8_MEMBER(cruwrite); |
| 250 | // Machine management |
| 251 | DECLARE_MACHINE_START(ti99_8); |
| 252 | DECLARE_MACHINE_RESET(ti99_8); |
| 233 | 253 | |
| 234 | | DECLARE_WRITE8_MEMBER(external_operation); |
| 254 | // Processor connections with the main board |
| 255 | DECLARE_READ8_MEMBER( cruread ); |
| 256 | DECLARE_WRITE8_MEMBER( cruwrite ); |
| 257 | DECLARE_WRITE8_MEMBER( external_operation ); |
| 258 | DECLARE_WRITE_LINE_MEMBER( clock_out ); |
| 235 | 259 | |
| 236 | | // Forwarding interrupts to the CPU or CRU |
| 237 | | DECLARE_WRITE_LINE_MEMBER( console_ready ); |
| 260 | // Connections from outside towards the CPU (callbacks) |
| 238 | 261 | DECLARE_WRITE_LINE_MEMBER( console_ready_mapper ); |
| 262 | DECLARE_WRITE_LINE_MEMBER( console_ready_sound ); |
| 263 | DECLARE_WRITE_LINE_MEMBER( console_ready_pbox ); |
| 264 | DECLARE_WRITE_LINE_MEMBER( console_ready_cart ); |
| 265 | DECLARE_WRITE_LINE_MEMBER( console_ready_grom ); |
| 266 | DECLARE_WRITE_LINE_MEMBER( console_ready_speech ); |
| 239 | 267 | DECLARE_WRITE_LINE_MEMBER( console_reset ); |
| 240 | | |
| 241 | | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT2 ); |
| 242 | 268 | DECLARE_WRITE_LINE_MEMBER( extint ); |
| 243 | 269 | DECLARE_WRITE_LINE_MEMBER( notconnected ); |
| 244 | 270 | |
| 271 | // Connections with the system interface chip 9901 |
| 272 | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT2 ); |
| 273 | |
| 274 | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT12 ); |
| 275 | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT2_from_v9938); |
| 276 | |
| 245 | 277 | // Connections with the system interface TMS9901 |
| 246 | 278 | DECLARE_READ8_MEMBER(read_by_9901); |
| 247 | 279 | DECLARE_WRITE_LINE_MEMBER(keyC0); |
| r26230 | r26231 | |
| 255 | 287 | DECLARE_WRITE_LINE_MEMBER(cassette_motor); |
| 256 | 288 | DECLARE_WRITE8_MEMBER(tms9901_interrupt); |
| 257 | 289 | |
| 258 | | DECLARE_WRITE_LINE_MEMBER( clock_out ); |
| 259 | | virtual void machine_start(); |
| 260 | | virtual void machine_reset(); |
| 261 | | |
| 262 | | // Some values to keep |
| 263 | | tms9995_device *m_cpu; |
| 264 | | tms9901_device *m_tms9901; |
| 265 | | gromport_device *m_gromport; |
| 266 | | peribox_device *m_peribox; |
| 267 | | ti998_mapper_device *m_mapper; |
| 268 | | joyport_device* m_joyport; |
| 269 | | ti_video_device* m_video; |
| 270 | | |
| 271 | | int m_firstjoy; // First joystick. 14 for TI-99/8 |
| 272 | | |
| 273 | | int m_ready_line, m_ready_line1; |
| 274 | | |
| 275 | 290 | private: |
| 276 | | /* Keyboard support */ |
| 291 | // Keyboard support |
| 277 | 292 | void set_keyboard_column(int number, int data); |
| 278 | 293 | int m_keyboard_column; |
| 279 | | //int m_alphalock_line; |
| 294 | |
| 295 | // READY handling |
| 296 | int m_nready_combined; |
| 297 | int m_nready_prev; |
| 298 | void console_ready_join(int id, int state); |
| 299 | |
| 300 | // Connected devices |
| 301 | required_device<tms9995_device> m_cpu; |
| 302 | required_device<tms9901_device> m_tms9901; |
| 303 | required_device<gromport_device> m_gromport; |
| 304 | required_device<peribox_device> m_peribox; |
| 305 | required_device<mainboard8_device> m_mainboard; |
| 306 | required_device<joyport_device> m_joyport; |
| 307 | required_device<ti_video_device> m_video; |
| 280 | 308 | required_device<cassette_image_device> m_cassette; |
| 281 | 309 | }; |
| 282 | 310 | |
| r26230 | r26231 | |
| 285 | 313 | job to the mapper completely. |
| 286 | 314 | */ |
| 287 | 315 | static ADDRESS_MAP_START(memmap, AS_PROGRAM, 8, ti99_8_state) |
| 288 | | AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(MAPPER_TAG, ti998_mapper_device, readm, writem ) |
| 316 | AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(MAINBOARD8_TAG, mainboard8_device, readm, writem ) |
| 289 | 317 | ADDRESS_MAP_END |
| 290 | 318 | |
| 291 | 319 | /* |
| r26230 | r26231 | |
| 408 | 436 | /***************************************************************************** |
| 409 | 437 | Components |
| 410 | 438 | ******************************************************************************/ |
| 439 | #define region_sysgrom "sysgrom" |
| 411 | 440 | |
| 412 | 441 | static GROM_CONFIG(grom0_config) |
| 413 | 442 | { |
| 414 | | false, 0, region_grom, 0x0000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ |
| 443 | false, 0, region_sysgrom, 0x0000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ |
| 415 | 444 | }; |
| 416 | 445 | |
| 417 | 446 | static GROM_CONFIG(grom1_config) |
| 418 | 447 | { |
| 419 | | false, 1, region_grom, 0x2000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ |
| 448 | false, 1, region_sysgrom, 0x2000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ |
| 420 | 449 | }; |
| 421 | 450 | |
| 422 | 451 | static GROM_CONFIG(grom2_config) |
| 423 | 452 | { |
| 424 | | false, 2, region_grom, 0x4000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ |
| 453 | false, 2, region_sysgrom, 0x4000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ |
| 425 | 454 | }; |
| 426 | 455 | |
| 427 | 456 | /**************************************************** |
| r26230 | r26231 | |
| 429 | 458 | Do some macro tricks to keep writing effort low |
| 430 | 459 | *****************************************************/ |
| 431 | 460 | |
| 432 | | #define pascal0_region "pascal0_region" |
| 433 | | #define pascal12_region "pascal12_region" |
| 461 | #define region_gromlib1 "gromlib1" |
| 462 | #define region_gromlib2 "gromlib2" |
| 463 | #define region_gromlib3 "gromlib3" |
| 434 | 464 | |
| 435 | | #define MCFG_GROM_LIBRARY_ADD(_tag, _config) \ |
| 465 | #define MCFG_GROM_LIBRARY_ADD8(_tag, _config) \ |
| 436 | 466 | MCFG_DEVICE_ADD(#_tag "0", GROM, 0) \ |
| 437 | 467 | MCFG_DEVICE_CONFIG(_config##0) \ |
| 438 | 468 | MCFG_DEVICE_ADD(#_tag "1", GROM, 0) \ |
| r26230 | r26231 | |
| 450 | 480 | MCFG_DEVICE_ADD(#_tag "7", GROM, 0) \ |
| 451 | 481 | MCFG_DEVICE_CONFIG(_config##7) |
| 452 | 482 | |
| 483 | #define MCFG_GROM_LIBRARY_ADD3(_tag, _config) \ |
| 484 | MCFG_DEVICE_ADD(#_tag "0", GROM, 0) \ |
| 485 | MCFG_DEVICE_CONFIG(_config##0) \ |
| 486 | MCFG_DEVICE_ADD(#_tag "1", GROM, 0) \ |
| 487 | MCFG_DEVICE_CONFIG(_config##1) \ |
| 488 | MCFG_DEVICE_ADD(#_tag "2", GROM, 0) \ |
| 489 | MCFG_DEVICE_CONFIG(_config##2) |
| 490 | |
| 453 | 491 | #define GROM_LIBRARY_CONFIG(_conf, _region) \ |
| 454 | 492 | static GROM_CONFIG(_conf##0) \ |
| 455 | | { false, 0, _region, 0x0000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 493 | { false, 0, _region, 0x0000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 456 | 494 | static GROM_CONFIG(_conf##1) \ |
| 457 | | { false, 1, _region, 0x2000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 495 | { false, 1, _region, 0x2000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 458 | 496 | static GROM_CONFIG(_conf##2) \ |
| 459 | | { false, 2, _region, 0x4000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 497 | { false, 2, _region, 0x4000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 460 | 498 | static GROM_CONFIG(_conf##3) \ |
| 461 | | { false, 3, _region, 0x6000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 499 | { false, 3, _region, 0x6000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 462 | 500 | static GROM_CONFIG(_conf##4) \ |
| 463 | | { false, 4, _region, 0x8000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 501 | { false, 4, _region, 0x8000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 464 | 502 | static GROM_CONFIG(_conf##5) \ |
| 465 | | { false, 5, _region, 0xa000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 503 | { false, 5, _region, 0xa000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 466 | 504 | static GROM_CONFIG(_conf##6) \ |
| 467 | | { false, 6, _region, 0xc000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; \ |
| 505 | { false, 6, _region, 0xc000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; \ |
| 468 | 506 | static GROM_CONFIG(_conf##7) \ |
| 469 | | { false, 7, _region, 0xe000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), GROMFREQ }; |
| 507 | { false, 7, _region, 0xe000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_grom), GROMFREQ }; |
| 470 | 508 | |
| 471 | | GROM_LIBRARY_CONFIG(pascal0, pascal0_region) |
| 472 | | GROM_LIBRARY_CONFIG(pascal1, pascal12_region) |
| 473 | | GROM_LIBRARY_CONFIG(pascal2, pascal12_region) |
| 509 | GROM_LIBRARY_CONFIG(pascal1, region_gromlib1) |
| 510 | GROM_LIBRARY_CONFIG(pascal2, region_gromlib2) |
| 511 | GROM_LIBRARY_CONFIG(pascal3, region_gromlib3) |
| 474 | 512 | |
| 475 | 513 | static GROMPORT_CONFIG(console_cartslot) |
| 476 | 514 | { |
| 477 | | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), |
| 515 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_cart), |
| 478 | 516 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_reset) |
| 479 | 517 | }; |
| 480 | 518 | |
| r26230 | r26231 | |
| 482 | 520 | { |
| 483 | 521 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, extint), // INTA |
| 484 | 522 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, notconnected), // INTB |
| 485 | | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), // READY |
| 523 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_pbox), // READY |
| 486 | 524 | 0x70000 // Address bus prefix (AMA/AMB/AMC) |
| 487 | 525 | }; |
| 488 | 526 | |
| r26230 | r26231 | |
| 494 | 532 | // Similar to the bus8z_devices, just let the mapper, the gromport, and the p-box |
| 495 | 533 | // decide whether they want to change the value at the CRU address |
| 496 | 534 | // Also, we translate the bit addresses to base addresses |
| 497 | | m_mapper->crureadz(space, offset<<4, &value); |
| 535 | m_mainboard->crureadz(space, offset<<4, &value); |
| 498 | 536 | m_gromport->crureadz(space, offset<<4, &value); |
| 499 | 537 | m_peribox->crureadz(space, offset<<4, &value); |
| 500 | 538 | |
| 501 | | if (VERBOSE>8) LOG("ti99_8: CRU %04x -> %02x\n", offset<<4, value); |
| 539 | if (TRACE_CRU) LOG("ti99_8: CRU %04x -> %02x\n", offset<<4, value); |
| 502 | 540 | return value; |
| 503 | 541 | } |
| 504 | 542 | |
| 505 | 543 | WRITE8_MEMBER( ti99_8_state::cruwrite ) |
| 506 | 544 | { |
| 507 | | if (VERBOSE>8) LOG("ti99_8: CRU %04x <- %x\n", offset<<1, data); |
| 508 | | m_mapper->cruwrite(space, offset<<1, data); |
| 545 | if (TRACE_CRU) LOG("ti99_8: CRU %04x <- %x\n", offset<<1, data); |
| 546 | m_mainboard->cruwrite(space, offset<<1, data); |
| 509 | 547 | m_gromport->cruwrite(space, offset<<1, data); |
| 510 | 548 | m_peribox->cruwrite(space, offset<<1, data); |
| 511 | 549 | } |
| r26230 | r26231 | |
| 539 | 577 | // bit 6-7: keyboard status bits 0 through 1 |
| 540 | 578 | |
| 541 | 579 | // |K|K|-|-|-|I2|I1|C| |
| 542 | | if (m_keyboard_column >= m_firstjoy) |
| 580 | if (m_keyboard_column >= 14) |
| 543 | 581 | { |
| 544 | 582 | // TI-99/8's wiring differs from the TI-99/4A |
| 545 | 583 | joyst = m_joyport->read_port(); |
| r26230 | r26231 | |
| 563 | 601 | |
| 564 | 602 | // |0|0|0|0|0|K|K|K| |
| 565 | 603 | |
| 566 | | if (m_keyboard_column >= m_firstjoy) |
| 604 | if (m_keyboard_column >= 14) |
| 567 | 605 | { |
| 568 | 606 | joyst = m_joyport->read_port(); |
| 569 | 607 | answer = joyst << 1; |
| r26230 | r26231 | |
| 600 | 638 | if (data != 0) m_keyboard_column |= 1 << number; |
| 601 | 639 | else m_keyboard_column &= ~(1 << number); |
| 602 | 640 | |
| 603 | | if (m_keyboard_column >= m_firstjoy) |
| 641 | if (m_keyboard_column >= 14) |
| 604 | 642 | { |
| 605 | | m_joyport->write_port(m_keyboard_column - m_firstjoy + 1); |
| 643 | m_joyport->write_port(m_keyboard_column - 13); |
| 606 | 644 | } |
| 607 | 645 | } |
| 608 | 646 | |
| r26230 | r26231 | |
| 631 | 669 | */ |
| 632 | 670 | WRITE_LINE_MEMBER( ti99_8_state::CRUS ) |
| 633 | 671 | { |
| 634 | | m_mapper->CRUS_set(state==ASSERT_LINE); |
| 672 | m_mainboard->CRUS_set(state==ASSERT_LINE); |
| 635 | 673 | if (state==ASSERT_LINE) |
| 636 | 674 | { |
| 637 | 675 | m_gromport->set_grom_base(0x9800, 0xfbf1); |
| r26230 | r26231 | |
| 647 | 685 | */ |
| 648 | 686 | WRITE_LINE_MEMBER( ti99_8_state::PTGEN ) |
| 649 | 687 | { |
| 650 | | m_mapper->PTGE_set(state==CLEAR_LINE); |
| 688 | m_mainboard->PTGE_set(state==CLEAR_LINE); |
| 651 | 689 | } |
| 652 | 690 | |
| 653 | 691 | /* |
| r26230 | r26231 | |
| 720 | 758 | */ |
| 721 | 759 | WRITE_LINE_MEMBER( ti99_8_state::set_tms9901_INT2 ) |
| 722 | 760 | { |
| 723 | | if (VERBOSE>6) LOG("ti99_8: VDP int 2 on tms9901, level=%02x\n", state); |
| 761 | if (TRACE_INTERRUPTS) LOG("ti99_8: VDP int 2 on tms9901, level=%02x\n", state); |
| 724 | 762 | m_tms9901->set_single_int(2, state); |
| 725 | 763 | } |
| 726 | 764 | |
| r26230 | r26231 | |
| 728 | 766 | Links to external devices |
| 729 | 767 | ***********************************************************/ |
| 730 | 768 | |
| 769 | /* |
| 770 | We combine the incoming READY signals and propagate them to the CPU. |
| 771 | An alternative would be to let the CPU get the READY state, but this would |
| 772 | be a much higher overhead, as this happens in each clock tick. |
| 773 | */ |
| 774 | void ti99_8_state::console_ready_join(int id, int state) |
| 775 | { |
| 776 | if (state==CLEAR_LINE) |
| 777 | m_nready_combined |= id; |
| 778 | else |
| 779 | m_nready_combined &= ~id; |
| 731 | 780 | |
| 732 | | WRITE_LINE_MEMBER( ti99_8_state::console_ready ) |
| 781 | if (TRACE_READY) |
| 782 | { |
| 783 | if (m_nready_prev != m_nready_combined) LOG("ti99_8: READY bits = %04x\n", ~m_nready_combined); |
| 784 | } |
| 785 | |
| 786 | m_nready_prev = m_nready_combined; |
| 787 | m_cpu->set_ready(m_nready_combined==0); |
| 788 | } |
| 789 | |
| 790 | /* |
| 791 | Connections to the READY line. This might look a bit ugly; we need an |
| 792 | implementation of a "Wired AND" device. |
| 793 | */ |
| 794 | WRITE_LINE_MEMBER( ti99_8_state::console_ready_grom ) |
| 733 | 795 | { |
| 734 | | if (VERBOSE>6) LOG("ti99_8: READY level=%02x\n", state); |
| 735 | | m_ready_line = state; |
| 796 | console_ready_join(READY_GROM, state); |
| 797 | } |
| 736 | 798 | |
| 737 | | m_cpu->set_ready((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE); |
| 799 | WRITE_LINE_MEMBER( ti99_8_state::console_ready_mapper ) |
| 800 | { |
| 801 | console_ready_join(READY_MAPPER, state); |
| 738 | 802 | } |
| 739 | 803 | |
| 804 | WRITE_LINE_MEMBER( ti99_8_state::console_ready_pbox ) |
| 805 | { |
| 806 | console_ready_join(READY_PBOX, state); |
| 807 | } |
| 808 | |
| 809 | WRITE_LINE_MEMBER( ti99_8_state::console_ready_sound ) |
| 810 | { |
| 811 | console_ready_join(READY_SOUND, state); |
| 812 | } |
| 813 | |
| 814 | WRITE_LINE_MEMBER( ti99_8_state::console_ready_cart ) |
| 815 | { |
| 816 | console_ready_join(READY_CART, state); |
| 817 | } |
| 818 | |
| 819 | WRITE_LINE_MEMBER( ti99_8_state::console_ready_speech ) |
| 820 | { |
| 821 | console_ready_join(READY_SPEECH, state); |
| 822 | } |
| 823 | |
| 740 | 824 | /* |
| 741 | 825 | The RESET line leading to a reset of the CPU. |
| 742 | 826 | */ |
| r26230 | r26231 | |
| 749 | 833 | } |
| 750 | 834 | } |
| 751 | 835 | |
| 752 | | /* |
| 753 | | Memory access over the mapper also operates |
| 754 | | the READY line, and the mapper raises READY depending on the clock pulse. |
| 755 | | So we must make sure this does not interfere. |
| 756 | | */ |
| 757 | | WRITE_LINE_MEMBER( ti99_8_state::console_ready_mapper ) |
| 758 | | { |
| 759 | | if (VERBOSE>6) LOG("ti99_8: READY level (mapper) = %02x\n", state); |
| 760 | | m_ready_line1 = state; |
| 761 | | m_cpu->set_ready((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE); |
| 762 | | } |
| 763 | | |
| 764 | 836 | WRITE_LINE_MEMBER( ti99_8_state::extint ) |
| 765 | 837 | { |
| 766 | | if (VERBOSE>6) LOG("ti99_8: EXTINT level = %02x\n", state); |
| 838 | if (TRACE_READY) LOG("ti99_8: EXTINT level = %02x\n", state); |
| 767 | 839 | if (m_tms9901 != NULL) |
| 768 | 840 | m_tms9901->set_single_int(1, state); |
| 769 | 841 | } |
| 770 | 842 | |
| 771 | 843 | WRITE_LINE_MEMBER( ti99_8_state::notconnected ) |
| 772 | 844 | { |
| 773 | | if (VERBOSE>6) LOG("ti99_8: Setting a not connected line ... ignored\n"); |
| 845 | if (TRACE_READY) LOG("ti99_8: Setting a not connected line ... ignored\n"); |
| 774 | 846 | } |
| 775 | 847 | |
| 776 | 848 | static TMS9928A_INTERFACE(ti99_8_tms9118a_interface) |
| r26230 | r26231 | |
| 782 | 854 | WRITE8_MEMBER( ti99_8_state::external_operation ) |
| 783 | 855 | { |
| 784 | 856 | static const char* extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" }; |
| 785 | | if (VERBOSE>1) LOG("External operation %s not implemented on TI-99 board\n", extop[offset]); |
| 857 | if (offset == IDLE_OP) return; |
| 858 | else |
| 859 | { |
| 860 | LOG("ti99_4x: External operation %s not implemented on TI-99/8 board\n", extop[offset]); |
| 861 | } |
| 786 | 862 | } |
| 787 | 863 | |
| 788 | 864 | /* |
| r26230 | r26231 | |
| 790 | 866 | */ |
| 791 | 867 | WRITE_LINE_MEMBER( ti99_8_state::clock_out ) |
| 792 | 868 | { |
| 793 | | m_mapper->clock_in(state); |
| 869 | m_mainboard->clock_in(state); |
| 794 | 870 | } |
| 795 | 871 | |
| 796 | 872 | /*****************************************************************************/ |
| r26230 | r26231 | |
| 813 | 889 | |
| 814 | 890 | static TI_SOUND_CONFIG( sound_conf ) |
| 815 | 891 | { |
| 816 | | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready) // READY |
| 892 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_sound) // READY |
| 817 | 893 | }; |
| 818 | 894 | |
| 819 | 895 | /* |
| r26230 | r26231 | |
| 836 | 912 | Access to the mapper registers is done directly in the mapper, not via |
| 837 | 913 | this list. |
| 838 | 914 | |
| 839 | | NOTE: The available system software contradicts the specification |
| 840 | | concerning the Pascal ports. While the specs define f840 as "Text-to-speech |
| 841 | | library" and f850 and f860 as two libraries for Pascal, the operating |
| 842 | | system defines f840 as Pascal lib 0, f880 as Pascal lib 1, and f8c0 as |
| 843 | | Pascal lib 2. |
| 844 | | |
| 845 | 915 | TODO: This should (must) be improved in terms of performance. Every single |
| 846 | 916 | memory access goes through the mapper. Either we use an ordered search list, |
| 847 | 917 | or we order the entries according to their frequency. |
| 848 | 918 | (I did this right now, putting the Pascal GROMs at the end.) |
| 849 | 919 | We should think about a set entry where devices with the same address |
| 850 | | are collected as one single entry (think about the Pascal lib with 24 GROMs, |
| 851 | | every eight of them on the same address). |
| 920 | are collected as one single entry (think about the Pascal lib with 21 GROMs, |
| 921 | twice eight and once three of them on the same address). |
| 852 | 922 | */ |
| 853 | 923 | |
| 854 | | #define PASCAL_GROM_LIB(_tag, _addr) \ |
| 924 | #define PASCAL_GROM_LIB8(_tag, _addr) \ |
| 855 | 925 | { _tag "0", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \ |
| 856 | 926 | { _tag "1", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \ |
| 857 | 927 | { _tag "2", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \ |
| r26230 | r26231 | |
| 861 | 931 | { _tag "6", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \ |
| 862 | 932 | { _tag "7", PATGEN, CONT, _addr, 0xfff1, 0x0000 } |
| 863 | 933 | |
| 934 | #define PASCAL_GROM_LIB3(_tag, _addr) \ |
| 935 | { _tag "0", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \ |
| 936 | { _tag "1", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \ |
| 937 | { _tag "2", PATGEN, CONT, _addr, 0xfff1, 0x0000 } |
| 864 | 938 | |
| 939 | |
| 865 | 940 | static const mapper8_list_entry mapper_devices[] = |
| 866 | 941 | { |
| 867 | 942 | // TI-99/4A mode (CRUS=1) |
| r26230 | r26231 | |
| 870 | 945 | // (99/4A supports 256 libraries) |
| 871 | 946 | // at 9800, 9804, 9808, 980c. Address counter access is at 9802,6,a,e. Write access +0400. |
| 872 | 947 | { ROM0NAME, TI99EM, STOP, 0x0000, 0xe000, 0x0000 }, // 0000-1fff |
| 873 | | |
| 874 | 948 | { TISOUND_TAG, TI99EM, STOP, 0x8400, 0xfff1, 0x0000 }, // 8400-840f |
| 875 | 949 | { VIDEO_SYSTEM_TAG, TI99EM, STOP, 0x8800, 0xfff1, 0x0400 }, // 8800,8802 / 8c00,8c02 |
| 876 | 950 | { SPEECH_TAG, TI99EM, STOP, 0x9000, 0xfff1, 0x0400 }, // 9000-900f / 9400-940f |
| 877 | 951 | { SRAMNAME, TI99EM, STOP, 0x8000, 0xf800, 0x0000 }, // 8000-87ff; must follow the sound generator |
| 878 | | { MAPPER_TAG, TI99EM, STOP, 0x8810, 0xfff0, 0x0000 }, |
| 952 | { MAINBOARD8_TAG, TI99EM, STOP, 0x8810, 0xfff0, 0x0000 }, |
| 879 | 953 | |
| 880 | 954 | { GROM0_TAG, TI99EM, CONT, 0x9800, 0xfff1, 0x0400 }, // 9800,2,4,...e/9c00,2,4,...e |
| 881 | 955 | { GROM1_TAG, TI99EM, CONT, 0x9800, 0xfff1, 0x0400 }, // dto. |
| r26230 | r26231 | |
| 893 | 967 | { TISOUND_TAG, NATIVE, STOP, 0xf800, 0xfff1, 0x0000 }, // f800-f80e (even addresses) |
| 894 | 968 | { VIDEO_SYSTEM_TAG, NATIVE, STOP, 0xf810, 0xfff1, 0x0000 }, // f810,2 (unlike 99/4A, no different read/write ports) |
| 895 | 969 | { SPEECH_TAG, NATIVE, STOP, 0xf820, 0xfff1, 0x0000 }, // f820-f82f |
| 896 | | { MAPPER_TAG, NATIVE, STOP, 0xf870, 0xfff0, 0x0000 }, |
| 970 | { MAINBOARD8_TAG, NATIVE, STOP, 0xf870, 0xfff0, 0x0000 }, |
| 897 | 971 | |
| 898 | 972 | { GROM0_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 }, // f830-f83e (4 banks), no different read/write ports |
| 899 | 973 | { GROM1_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 }, |
| 900 | 974 | { GROM2_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 }, |
| 901 | 975 | { GROMPORT_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 }, |
| 902 | 976 | |
| 903 | | PASCAL_GROM_LIB("pascal0_grom", 0xf840), |
| 904 | | PASCAL_GROM_LIB("pascal1_grom", 0xf880), // lib1 and 2 are zeroed. We don't have good dumps for them yet. |
| 905 | | PASCAL_GROM_LIB("pascal2_grom", 0xf8c0), // Anyway, we keep them in order to check whether/when they are accessed. |
| 977 | PASCAL_GROM_LIB8("pascal1_grom", 0xf840), |
| 978 | PASCAL_GROM_LIB8("pascal2_grom", 0xf850), |
| 979 | PASCAL_GROM_LIB3("pascal3_grom", 0xf860), |
| 906 | 980 | |
| 907 | 981 | // Physical (need to pack this in here as well to keep config simple) |
| 908 | 982 | // but these lines will be put into a separate list |
| 909 | 983 | { DRAMNAME, PHYSIC, STOP, 0x000000, 0xff0000, 0x000000 }, // 000000-00ffff 64 KiB DRAM |
| 910 | | { MAPPER_TAG, PHYSIC, CONT, 0xff4000, 0xffe000, 0x000000 }, // ff4000-ff5fff Internal DSR |
| 984 | { MAINBOARD8_TAG, PHYSIC, CONT, 0xff4000, 0xffe000, 0x000000 }, // ff4000-ff5fff Internal DSR |
| 911 | 985 | { GROMPORT_TAG, PHYSIC, STOP, 0xff6000, 0xffe000, 0x000000 }, // ff6000-ff7fff Cartridge ROM space |
| 912 | 986 | { GROMPORT_TAG, PHYSIC, STOP, 0xff8000, 0xffe000, 0x000000 }, // ff8000-ff9fff Cartridge ROM space |
| 913 | | { ROM1NAME, PHYSIC, STOP, 0xffa000, 0xffe000, 0x000000 }, // ffa000-ffbfff ROM1 |
| 914 | | { ROM1ANAME, PHYSIC, STOP, 0xffc000, 0xffe000, 0x000000 }, // ffc000-ffdfff ROM1 |
| 987 | { ROM1A0NAME, PHYSIC, STOP, 0xffa000, 0xffe000, 0x000000 }, // ffa000-ffbfff ROM1 |
| 988 | { ROM1C0NAME, PHYSIC, STOP, 0xffc000, 0xffe000, 0x000000 }, // ffc000-ffdfff ROM1 |
| 915 | 989 | { INTSNAME, PHYSIC, STOP, 0xffe000, 0xfffff0, 0x000000 }, // ffe000-ffe00f Interrupt level sense |
| 916 | 990 | { PERIBOX_TAG, PHYSIC, STOP, 0x000000, 0x000000, 0x000000 }, // Peripheral Expansion Box |
| 917 | 991 | |
| r26230 | r26231 | |
| 926 | 1000 | |
| 927 | 1001 | static SPEECH8_CONFIG( speech_config ) |
| 928 | 1002 | { |
| 929 | | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready), // READY |
| 1003 | DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, console_ready_speech), // READY |
| 930 | 1004 | }; |
| 931 | 1005 | |
| 932 | 1006 | static JOYPORT_CONFIG( joyport8_60 ) |
| r26230 | r26231 | |
| 941 | 1015 | 50 |
| 942 | 1016 | }; |
| 943 | 1017 | |
| 944 | | void ti99_8_state::machine_start() |
| 1018 | MACHINE_START_MEMBER(ti99_8_state,ti99_8) |
| 945 | 1019 | { |
| 946 | | m_cpu = static_cast<tms9995_device*>(machine().device("maincpu")); |
| 947 | | m_tms9901 = static_cast<tms9901_device*>(machine().device(TMS9901_TAG)); |
| 948 | | m_gromport = static_cast<gromport_device*>(machine().device(GROMPORT_TAG)); |
| 949 | | m_peribox = static_cast<peribox_device*>(machine().device(PERIBOX_TAG)); |
| 950 | | m_mapper = static_cast<ti998_mapper_device*>(machine().device(MAPPER_TAG)); |
| 951 | | m_joyport = static_cast<joyport_device*>(machine().device(JOYPORT_TAG)); |
| 952 | | m_video = static_cast<ti_video_device*>(machine().device(VIDEO_SYSTEM_TAG)); |
| 953 | | |
| 1020 | m_nready_combined = 0; |
| 954 | 1021 | m_peribox->senila(CLEAR_LINE); |
| 955 | 1022 | m_peribox->senilb(CLEAR_LINE); |
| 956 | | m_firstjoy = 14; |
| 957 | 1023 | } |
| 958 | 1024 | |
| 959 | | void ti99_8_state::machine_reset() |
| 1025 | MACHINE_RESET_MEMBER(ti99_8_state, ti99_8) |
| 960 | 1026 | { |
| 961 | 1027 | m_cpu->set_hold(CLEAR_LINE); |
| 962 | 1028 | |
| 963 | 1029 | // Pulling down the line on RESET configures the CPU to insert one wait |
| 964 | 1030 | // state on external memory accesses |
| 965 | | |
| 966 | | // RN: enable automatic wait state generation |
| 967 | | // in January 83 99/8 schematics sheet 9: the delay logic |
| 968 | | // seems to keep READY low for one cycle when RESET* is |
| 969 | | // asserted, but the timings are completely wrong this way |
| 970 | | |
| 971 | 1031 | m_cpu->set_ready(CLEAR_LINE); |
| 972 | 1032 | |
| 973 | 1033 | // But we assert the line here so that the system starts running |
| 974 | | m_ready_line = m_ready_line1 = ASSERT_LINE; |
| 1034 | m_nready_combined = 0; |
| 975 | 1035 | m_gromport->set_grom_base(0x9800, 0xfff1); |
| 976 | 1036 | } |
| 977 | 1037 | |
| r26230 | r26231 | |
| 979 | 1039 | /* basic machine hardware */ |
| 980 | 1040 | /* TMS9995-MP9537 CPU @ 10.7 MHz */ |
| 981 | 1041 | MCFG_TMS99xx_ADD("maincpu", TMS9995, 10738635, memmap, crumap, ti99_8_processor_config) |
| 1042 | MCFG_MACHINE_START_OVERRIDE(ti99_8_state, ti99_8 ) |
| 1043 | MCFG_MACHINE_RESET_OVERRIDE(ti99_8_state, ti99_8 ) |
| 982 | 1044 | |
| 983 | 1045 | /* Video hardware */ |
| 984 | 1046 | MCFG_TI998_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9118, ti99_8_tms9118a_interface) |
| 985 | 1047 | |
| 986 | 1048 | /* Main board */ |
| 987 | 1049 | MCFG_TMS9901_ADD( TMS9901_TAG, tms9901_wiring_ti99_8, 2684658.75 ) |
| 988 | | MCFG_MAPPER8_ADD( MAPPER_TAG, mapper_conf ) |
| 1050 | MCFG_MAINBOARD8_ADD( MAINBOARD8_TAG, mapper_conf ) |
| 989 | 1051 | MCFG_TI99_GROMPORT_ADD( GROMPORT_TAG, console_cartslot ) |
| 990 | 1052 | |
| 991 | 1053 | /* Peripheral expansion box */ |
| r26230 | r26231 | |
| 1006 | 1068 | MCFG_GROM_ADD( GROM2_TAG, grom2_config ) |
| 1007 | 1069 | |
| 1008 | 1070 | /* Pascal GROM libraries. */ |
| 1009 | | MCFG_GROM_LIBRARY_ADD(pascal0_grom, pascal0) |
| 1010 | | MCFG_GROM_LIBRARY_ADD(pascal1_grom, pascal1) |
| 1011 | | MCFG_GROM_LIBRARY_ADD(pascal2_grom, pascal2) |
| 1071 | MCFG_GROM_LIBRARY_ADD8(pascal1_grom, pascal1) |
| 1072 | MCFG_GROM_LIBRARY_ADD8(pascal2_grom, pascal2) |
| 1073 | MCFG_GROM_LIBRARY_ADD3(pascal3_grom, pascal3) |
| 1012 | 1074 | |
| 1013 | 1075 | /* Devices */ |
| 1014 | 1076 | MCFG_TISPEECH8_ADD(SPEECH_TAG, speech_config) |
| r26230 | r26231 | |
| 1022 | 1084 | /* basic machine hardware */ |
| 1023 | 1085 | /* TMS9995-MP9537 CPU @ 10.7 MHz */ |
| 1024 | 1086 | MCFG_TMS99xx_ADD("maincpu", TMS9995, 10738635, memmap, crumap, ti99_8_processor_config) |
| 1087 | MCFG_MACHINE_START_OVERRIDE(ti99_8_state, ti99_8 ) |
| 1088 | MCFG_MACHINE_RESET_OVERRIDE(ti99_8_state, ti99_8 ) |
| 1025 | 1089 | |
| 1026 | 1090 | /* Video hardware */ |
| 1027 | 1091 | MCFG_TI998_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9129, ti99_8_tms9118a_interface) |
| 1028 | 1092 | |
| 1029 | 1093 | /* Main board */ |
| 1030 | 1094 | MCFG_TMS9901_ADD( TMS9901_TAG, tms9901_wiring_ti99_8, 2684658.75 ) |
| 1031 | | MCFG_MAPPER8_ADD( MAPPER_TAG, mapper_conf ) |
| 1095 | MCFG_MAINBOARD8_ADD( MAINBOARD8_TAG, mapper_conf ) |
| 1032 | 1096 | MCFG_TI99_GROMPORT_ADD( GROMPORT_TAG, console_cartslot ) |
| 1033 | 1097 | |
| 1034 | 1098 | /* Peripheral expansion box */ |
| r26230 | r26231 | |
| 1048 | 1112 | MCFG_GROM_ADD( GROM1_TAG, grom1_config ) |
| 1049 | 1113 | MCFG_GROM_ADD( GROM2_TAG, grom2_config ) |
| 1050 | 1114 | |
| 1051 | | /* Pascal GROMs libraries. */ |
| 1052 | | MCFG_GROM_LIBRARY_ADD(pascal0_grom, pascal0) |
| 1053 | | MCFG_GROM_LIBRARY_ADD(pascal1_grom, pascal1) |
| 1054 | | MCFG_GROM_LIBRARY_ADD(pascal2_grom, pascal2) |
| 1115 | /* Pascal GROM libraries. */ |
| 1116 | MCFG_GROM_LIBRARY_ADD8(pascal1_grom, pascal1) |
| 1117 | MCFG_GROM_LIBRARY_ADD8(pascal2_grom, pascal2) |
| 1118 | MCFG_GROM_LIBRARY_ADD3(pascal3_grom, pascal3) |
| 1055 | 1119 | |
| 1056 | 1120 | /* Devices */ |
| 1057 | 1121 | MCFG_TISPEECH8_ADD(SPEECH_TAG, speech_config) |
| r26230 | r26231 | |
| 1064 | 1128 | ROM loading |
| 1065 | 1129 | */ |
| 1066 | 1130 | ROM_START(ti99_8) |
| 1067 | | /*CPU memory space*/ |
| 1068 | | ROM_REGION(0x8000,"maincpu",0) |
| 1069 | | ROM_LOAD("998rom.bin", 0x0000, 0x8000, CRC(b7a06ffd) SHA1(17dc8529fa808172fc47089982efb0bf0548c80c)) /* system ROMs */ |
| 1131 | // Logical (CPU) memory space: ROM0 |
| 1132 | ROM_REGION(0x2000, ROM0_TAG, 0) |
| 1133 | ROM_LOAD("u4_rom0.bin", 0x0000, 0x2000, CRC(901eb8d6) SHA1(13190c5e834baa9c0a70066b566cfcef438ed88a)) |
| 1070 | 1134 | |
| 1071 | | /*GROM memory space*/ |
| 1072 | | ROM_REGION(0x10000, region_grom, 0) |
| 1073 | | ROM_LOAD("998grom.bin", 0x0000, 0x6000, CRC(c63806bc) SHA1(cbfa8b04b4aefbbd9a713c54267ad4dd179c13a3)) /* system GROMs */ |
| 1135 | // Physical memory space: ROM1 |
| 1136 | ROM_REGION(0x8000, ROM1_TAG, 0) |
| 1137 | ROM_LOAD("u25_rom1.bin", 0x0000, 0x8000, CRC(5df17dfa) SHA1(134ae025f1b43f8e0e2aef4278f9d0c9fcffd68e)) |
| 1074 | 1138 | |
| 1075 | | /* Pascal GROMs. Sadly, P-System fails to start. */ |
| 1076 | | ROM_REGION(0x10000, pascal0_region, 0) |
| 1077 | | ROM_LOAD_OPTIONAL("998pascal.bin", 0x0000, 0x10000, CRC(1389589e) SHA1(42942b99ed355a2c091cc480b15f5329156e6b03)) |
| 1139 | // Speech ROMs |
| 1140 | ROM_REGION(0x8000, SPEECH_TAG, 0) |
| 1141 | ROM_LOAD("cd2325a.vsm", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe)) |
| 1142 | ROM_LOAD("cd2326a.vsm", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020)) |
| 1078 | 1143 | |
| 1079 | | // Still need good dumps; so far, stay with 0 |
| 1080 | | ROM_REGION(0x10000, pascal12_region, 0) |
| 1081 | | ROM_FILL(0x0000, 0x10000, 0x00) |
| 1144 | // System GROMs. 3 chips @ f830 |
| 1145 | // The schematics do not enumerate the circuits but only show "circuits on board" (COB) |
| 1146 | // so we name the roms as gID_port.bin |
| 1147 | ROM_REGION(0x6000, region_sysgrom, 0) |
| 1148 | ROM_LOAD("g0_f830.bin", 0x0000, 0x1800, CRC(1026db60) SHA1(7327095bf4f390476e69d9fd8424e98ea1f2325a)) |
| 1149 | ROM_LOAD("g1_f830.bin", 0x2000, 0x1800, CRC(93a43d65) SHA1(19be8a07d674bc7554c2bc9c7a5725d81e888e6e)) |
| 1150 | ROM_LOAD("g2_f830.bin", 0x4000, 0x1800, CRC(06f2b901) SHA1(f65e0fcb2c63e230b4a9563c72f91259b94ce955)) |
| 1082 | 1151 | |
| 1083 | | /* Built-in RAM */ |
| 1152 | // TTS & Pascal library. 8 chips @ f840 |
| 1153 | ROM_REGION(0x10000, region_gromlib1, 0) |
| 1154 | ROM_LOAD("g0_f840.bin", 0x0000, 0x1800, CRC(44501071) SHA1(4b5ef7f1aa43a87e7ae4f02090944be5c39b1f26)) |
| 1155 | ROM_LOAD("g1_f840.bin", 0x2000, 0x1800, CRC(5a271d9e) SHA1(bb95befa2ffba2cc17ac437386e069e8ff621248)) |
| 1156 | ROM_LOAD("g2_f840.bin", 0x4000, 0x1800, CRC(d52502df) SHA1(17063e33ee8709d0df8030f38bb92c4322d55e1e)) |
| 1157 | ROM_LOAD("g3_f840.bin", 0x6000, 0x1800, CRC(86c12396) SHA1(119b6df9211b5399245e017721fc51b88b60879f)) |
| 1158 | ROM_LOAD("g4_f840.bin", 0x8000, 0x1800, CRC(f17a2ef8) SHA1(dcb044f71d7f8a165b41f39e35a368d8f2d63b67)) |
| 1159 | ROM_LOAD("g5_f840.bin", 0xA000, 0x1800, CRC(7dc41301) SHA1(dff714da68de352db93fba309db8e5a8ae7cab1a)) |
| 1160 | ROM_LOAD("g6_f840.bin", 0xC000, 0x1800, CRC(7e310a90) SHA1(e927d8b3f8b32aa4fb9f7d080d5262c566a77fc7)) |
| 1161 | ROM_LOAD("g7_f840.bin", 0xE000, 0x1800, CRC(3a9d20df) SHA1(1e6f9f8ec7df4b997a7579be742d0a7d54bc8763)) |
| 1162 | |
| 1163 | // Pascal library. 8 chips @ f850 |
| 1164 | ROM_REGION(0x10000, region_gromlib2, 0) |
| 1165 | ROM_LOAD("g0_f850.bin", 0x0000, 0x1800, CRC(ec59a428) SHA1(be6d47a3497130f22b771c28af50abe632744d70)) |
| 1166 | ROM_LOAD("g1_f850.bin", 0x2000, 0x1800, CRC(7d64a842) SHA1(d5884bb2af21c8027311478ee506beac6f46203d)) |
| 1167 | ROM_LOAD("g2_f850.bin", 0x4000, 0x1800, CRC(e5ed8900) SHA1(03826882ce10fb5a6b3a9ccc85d3d1fe51979d0b)) |
| 1168 | ROM_LOAD("g3_f850.bin", 0x6000, 0x1800, CRC(87aaf19e) SHA1(fdbe163773b8a30fa6b9508e679be6fa4f99bf7a)) |
| 1169 | ROM_LOAD("g4_f850.bin", 0x8000, 0x1800, CRC(d3e789a5) SHA1(5ab06aa75ca694b1035ce5ac0bebacc928721388)) |
| 1170 | ROM_LOAD("g5_f850.bin", 0xA000, 0x1800, CRC(49fd90bd) SHA1(44b2cef29c2d5304a0dcfedbdcdf9f21f2201bf9)) |
| 1171 | ROM_LOAD("g6_f850.bin", 0xC000, 0x1800, CRC(31bac4ab) SHA1(e29049f0597d5de0bfd5c9c7bfea902abe858010)) |
| 1172 | ROM_LOAD("g7_f850.bin", 0xE000, 0x1800, CRC(71534098) SHA1(75e87123efde885e27dd749e07cb189eb2cc45a8)) |
| 1173 | |
| 1174 | // Pascal library. 3 chips @ f860 |
| 1175 | ROM_REGION(0x6000, region_gromlib3, 0) |
| 1176 | ROM_LOAD("g0_f860.bin", 0x0000, 0x1800, CRC(9b7ec501) SHA1(223cc0070429e4a8e3d9fe10f5f660f011fe8fa9)) |
| 1177 | ROM_LOAD("g1_f860.bin", 0x2000, 0x1800, CRC(fc87de25) SHA1(4695b7f979f59a01ec16c55e4587c3379482b658)) |
| 1178 | ROM_LOAD("g2_f860.bin", 0x4000, 0x1800, CRC(e833e350) SHA1(6ffe501981a1112be1af596a489d96e287fc6be5)) |
| 1179 | |
| 1180 | // Built-in RAM |
| 1084 | 1181 | ROM_REGION(SRAM_SIZE, SRAM_TAG, 0) |
| 1085 | 1182 | ROM_FILL(0x0000, SRAM_SIZE, 0x00) |
| 1086 | 1183 | |