trunk/src/emu/machine/i8089.c
| r24864 | r24865 | |
| 11 | 11 | // MACROS/CONSTANTS |
| 12 | 12 | //************************************************************************** |
| 13 | 13 | |
| 14 | | #define VERBOSE 1 |
| 14 | #define VERBOSE 1 |
| 15 | #define VERBOSE_DMA 1 |
| 15 | 16 | |
| 17 | // channel control register fields |
| 18 | #define CC_TMC ((m_r[CC].w >> 0) & 0x07) // terminate on masked compare |
| 19 | #define CC_TBC ((m_r[CC].w >> 3) & 0x03) // terminate on byte count |
| 20 | #define CC_TX ((m_r[CC].w >> 5) & 0x03) // terminate on external signal |
| 21 | #define CC_TS ((m_r[CC].w >> 7) & 0x01) // terminate on single transfer |
| 22 | #define CC_CHAIN ((m_r[CC].w >> 8) & 0x01) // chaining |
| 23 | #define CC_LOCK ((m_r[CC].w >> 9) & 0x01) // actuate lock |
| 24 | #define CC_SOURCE ((m_r[CC].w >> 10) & 0x01) // source register |
| 25 | #define CC_SYNC ((m_r[CC].w >> 11) & 0x03) // synchronization |
| 26 | #define CC_TRANS ((m_r[CC].w >> 13) & 0x01) // translation |
| 27 | #define CC_FUNC ((m_r[CC].w >> 14) & 0x03) // function |
| 16 | 28 | |
| 29 | |
| 17 | 30 | //************************************************************************** |
| 18 | 31 | // I/O CHANNEL |
| 19 | 32 | //************************************************************************** |
| r24864 | r24865 | |
| 149 | 162 | |
| 150 | 163 | i8089_device *m_iop; |
| 151 | 164 | |
| 165 | // dma |
| 166 | void terminate_dma(int offset); |
| 167 | |
| 168 | bool m_xfer_pending; |
| 169 | UINT16 m_dma_value; |
| 170 | int m_dma_state; |
| 171 | |
| 172 | // dma state |
| 173 | enum |
| 174 | { |
| 175 | DMA_IDLE, |
| 176 | DMA_WAIT_FOR_SOURCE_DRQ, |
| 177 | DMA_FETCH, |
| 178 | DMA_TRANSLATE, |
| 179 | DMA_WAIT_FOR_DEST_DRQ, |
| 180 | DMA_STORE, |
| 181 | DMA_STORE_BYTE_HIGH, |
| 182 | DMA_COMPARE, |
| 183 | DMA_TERMINATE |
| 184 | }; |
| 185 | |
| 152 | 186 | // register |
| 153 | 187 | enum |
| 154 | 188 | { |
| r24864 | r24865 | |
| 179 | 213 | device_t(mconfig, I8089_CHANNEL, "Intel 8089 I/O Channel", tag, owner, clock, "i8089_channel", __FILE__), |
| 180 | 214 | device_execute_interface(mconfig, *this), |
| 181 | 215 | m_icount(0), |
| 182 | | m_write_sintr(*this) |
| 216 | m_write_sintr(*this), |
| 217 | m_xfer_pending(false), |
| 218 | m_dma_value(0), |
| 219 | m_dma_state(DMA_IDLE) |
| 183 | 220 | { |
| 184 | 221 | } |
| 185 | 222 | |
| r24864 | r24865 | |
| 195 | 232 | m_write_sintr.resolve_safe(); |
| 196 | 233 | |
| 197 | 234 | // register for save states |
| 235 | save_item(NAME(m_xfer_pending)); |
| 236 | save_item(NAME(m_dma_value)); |
| 237 | save_item(NAME(m_dma_state)); |
| 238 | |
| 198 | 239 | for (int i = 0; i < ARRAY_LENGTH(m_r); i++) |
| 199 | 240 | { |
| 200 | 241 | save_item(NAME(m_r[i].w), i); |
| r24864 | r24865 | |
| 204 | 245 | |
| 205 | 246 | void i8089_channel::device_reset() |
| 206 | 247 | { |
| 248 | m_xfer_pending = false; |
| 249 | |
| 207 | 250 | // initialize registers |
| 208 | 251 | for (int i = 0; i < ARRAY_LENGTH(m_r); i++) |
| 209 | 252 | { |
| r24864 | r24865 | |
| 257 | 300 | |
| 258 | 301 | UINT16 i8089_channel::imm16() |
| 259 | 302 | { |
| 260 | | UINT8 imm16 = m_iop->read_word(m_r[TP].w); |
| 303 | UINT16 imm16 = m_iop->read_word(m_r[TP].w); |
| 261 | 304 | m_r[TP].w += 2; |
| 262 | 305 | return imm16; |
| 263 | 306 | } |
| 264 | 307 | |
| 308 | // adjust task pointer and continue execution |
| 309 | void i8089_channel::terminate_dma(int offset) |
| 310 | { |
| 311 | logerror("%s('%s'): terminating dma transfer\n", shortname(), tag()); |
| 312 | m_r[TP].w += offset; |
| 313 | m_r[PSW].w |= 1 << 2; |
| 314 | m_r[PSW].w &= ~(1 << 6); |
| 315 | m_dma_state = DMA_IDLE; |
| 316 | } |
| 317 | |
| 265 | 318 | void i8089_channel::execute_run() |
| 266 | 319 | { |
| 267 | 320 | do |
| r24864 | r24865 | |
| 269 | 322 | // active transfer? |
| 270 | 323 | if (BIT(m_r[PSW].w, 6)) |
| 271 | 324 | { |
| 272 | | m_icount = 0; |
| 325 | // new transfer? |
| 326 | if (BIT(m_r[PSW].w, 2)) |
| 327 | { |
| 328 | // we are no longer executing task blocks |
| 329 | m_r[PSW].w &= ~(1 << 2); |
| 330 | m_xfer_pending = false; |
| 331 | |
| 332 | if (VERBOSE) |
| 333 | { |
| 334 | logerror("%s('%s'): ---- starting dma transfer ----\n", shortname(), tag()); |
| 335 | logerror("%s('%s'): ga = %06x, gb = %06x, gc = %06x\n", shortname(), tag(), m_r[GA].w, m_r[GB].w, m_r[GC].w); |
| 336 | logerror("%s('%s'): bc = %04x, cc = %04x, mc = %04x\n", shortname(), tag(), m_r[BC].w, m_r[CC].w, m_r[MC].w); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | // todo: port transfers |
| 341 | if (CC_FUNC != 0x03) |
| 342 | fatalerror("%s('%s'): port transfer\n", shortname(), tag()); |
| 343 | |
| 344 | switch (m_dma_state) |
| 345 | { |
| 346 | case DMA_IDLE: |
| 347 | if (VERBOSE_DMA) |
| 348 | logerror("%s('%s'): entering state: DMA_IDLE (bc = %04x)\n", shortname(), tag(), m_r[BC].w); |
| 349 | |
| 350 | // synchronize on source? |
| 351 | if (CC_SYNC == 0x01) |
| 352 | m_dma_state = DMA_WAIT_FOR_SOURCE_DRQ; |
| 353 | else |
| 354 | m_dma_state = DMA_FETCH; |
| 355 | break; |
| 356 | |
| 357 | case DMA_WAIT_FOR_SOURCE_DRQ: |
| 358 | fatalerror("%s('%s'): wait for source drq not supported\n", shortname(), tag()); |
| 359 | break; |
| 360 | |
| 361 | case DMA_FETCH: |
| 362 | if (VERBOSE_DMA) |
| 363 | logerror("%s('%s'): entering state: DMA_FETCH", shortname(), tag()); |
| 364 | |
| 365 | // source is 16-bit? |
| 366 | if (BIT(m_r[PSW].w, 1)) |
| 367 | { |
| 368 | m_dma_value = m_iop->read_word(m_r[GA + CC_SOURCE].w); |
| 369 | m_r[GA + CC_SOURCE].w += 2; |
| 370 | m_r[BC].w -= 2; |
| 371 | } |
| 372 | // destination is 16-bit, byte count is even |
| 373 | else if (BIT(m_r[PSW].w, 0) && !(m_r[BC].w & 1)) |
| 374 | { |
| 375 | m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].w); |
| 376 | m_r[GA + CC_SOURCE].w++; |
| 377 | m_r[BC].w--; |
| 378 | } |
| 379 | // destination is 16-bit, byte count is odd |
| 380 | else if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) |
| 381 | { |
| 382 | m_dma_value |= m_iop->read_byte(m_r[GA + CC_SOURCE].w) << 8; |
| 383 | m_r[GA + CC_SOURCE].w++; |
| 384 | m_r[BC].w--; |
| 385 | } |
| 386 | // 8-bit transfer |
| 387 | else |
| 388 | { |
| 389 | m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].w); |
| 390 | m_r[GA + CC_SOURCE].w++; |
| 391 | m_r[BC].w--; |
| 392 | } |
| 393 | |
| 394 | if (VERBOSE_DMA) |
| 395 | logerror("[ %04x ]\n", m_dma_value); |
| 396 | |
| 397 | if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) |
| 398 | m_dma_state = DMA_FETCH; |
| 399 | else if (CC_TRANS) |
| 400 | m_dma_state = DMA_TRANSLATE; |
| 401 | else if (CC_SYNC == 0x02) |
| 402 | m_dma_state = DMA_WAIT_FOR_DEST_DRQ; |
| 403 | else |
| 404 | m_dma_state = DMA_STORE; |
| 405 | |
| 406 | break; |
| 407 | |
| 408 | case DMA_TRANSLATE: |
| 409 | fatalerror("%s('%s'): dma translate requested\n", shortname(), tag()); |
| 410 | break; |
| 411 | |
| 412 | case DMA_WAIT_FOR_DEST_DRQ: |
| 413 | fatalerror("%s('%s'): wait for destination drq not supported\n", shortname(), tag()); |
| 414 | break; |
| 415 | |
| 416 | case DMA_STORE: |
| 417 | if (VERBOSE_DMA) |
| 418 | logerror("%s('%s'): entering state: DMA_STORE", shortname(), tag()); |
| 419 | |
| 420 | // destination is 16-bit? |
| 421 | if (BIT(m_r[PSW].w, 0)) |
| 422 | { |
| 423 | m_iop->write_word(m_r[GB - CC_SOURCE].w, m_dma_value); |
| 424 | m_r[GB - CC_SOURCE].w += 2; |
| 425 | |
| 426 | if (VERBOSE_DMA) |
| 427 | logerror("[ %04x ]\n", m_dma_value); |
| 428 | } |
| 429 | // destination is 8-bit |
| 430 | else |
| 431 | { |
| 432 | m_iop->write_byte(m_r[GB - CC_SOURCE].w, m_dma_value & 0xff); |
| 433 | m_r[GB - CC_SOURCE].w++; |
| 434 | |
| 435 | if (VERBOSE_DMA) |
| 436 | logerror("[ %02x ]\n", m_dma_value & 0xff); |
| 437 | } |
| 438 | |
| 439 | if (CC_TMC & 0x03) |
| 440 | m_dma_state = DMA_COMPARE; |
| 441 | else |
| 442 | m_dma_state = DMA_TERMINATE; |
| 443 | |
| 444 | break; |
| 445 | |
| 446 | case DMA_COMPARE: |
| 447 | fatalerror("%s('%s'): dma compare requested\n", shortname(), tag()); |
| 448 | break; |
| 449 | |
| 450 | case DMA_TERMINATE: |
| 451 | if (VERBOSE_DMA) |
| 452 | logerror("%s('%s'): entering state: DMA_TERMINATE\n", shortname(), tag()); |
| 453 | |
| 454 | // terminate on masked compare? |
| 455 | if (CC_TMC & 0x03) |
| 456 | fatalerror("%s('%s'): terminate on masked compare not supported\n", shortname(), tag()); |
| 457 | |
| 458 | // terminate on byte count? |
| 459 | else if (CC_TBC && m_r[BC].w == 0) |
| 460 | terminate_dma((CC_TBC - 1) * 4); |
| 461 | |
| 462 | // terminate on external signal |
| 463 | else if (CC_TX) |
| 464 | fatalerror("%s('%s'): terminate on external signal not supported\n", shortname(), tag()); |
| 465 | |
| 466 | // terminate on single transfer |
| 467 | else if (CC_TS) |
| 468 | fatalerror("%s('%s'): terminate on single transfer not supported\n", shortname(), tag()); |
| 469 | |
| 470 | // not terminated, continue transfer |
| 471 | else |
| 472 | // do we need to read another byte? |
| 473 | if (BIT(m_r[PSW].w, 1) && !BIT(m_r[PSW].w, 0)) |
| 474 | if (CC_SYNC == 0x02) |
| 475 | m_dma_state = DMA_WAIT_FOR_DEST_DRQ; |
| 476 | else |
| 477 | m_dma_state = DMA_STORE_BYTE_HIGH; |
| 478 | |
| 479 | // transfer done |
| 480 | else |
| 481 | m_dma_state = DMA_IDLE; |
| 482 | |
| 483 | break; |
| 484 | |
| 485 | case DMA_STORE_BYTE_HIGH: |
| 486 | if (VERBOSE_DMA) |
| 487 | logerror("%s('%s'): entering state: DMA_STORE_BYTE_HIGH[ %02x ]\n", shortname(), tag(), (m_dma_value >> 8) & 0xff); |
| 488 | |
| 489 | m_iop->write_byte(m_r[GB - CC_SOURCE].w, (m_dma_value >> 8) & 0xff); |
| 490 | m_r[GB - CC_SOURCE].w++; |
| 491 | m_dma_state = DMA_TERMINATE; |
| 492 | |
| 493 | break; |
| 494 | } |
| 495 | |
| 496 | m_icount--; |
| 273 | 497 | } |
| 274 | 498 | |
| 275 | 499 | // executing task block instructions? |
| 276 | 500 | else if (BIT(m_r[PSW].w, 2)) |
| 277 | 501 | { |
| 502 | // dma transfer pending? |
| 503 | if (m_xfer_pending) |
| 504 | m_r[PSW].w |= 1 << 6; |
| 505 | |
| 278 | 506 | // fetch first two instruction bytes |
| 279 | 507 | UINT16 op = m_iop->read_word(m_r[TP].w); |
| 280 | 508 | m_r[TP].w += 2; |
| r24864 | r24865 | |
| 296 | 524 | UINT8 o; |
| 297 | 525 | UINT16 off, seg; |
| 298 | 526 | |
| 527 | logerror("%s('%s'): executing %x %x %x %x %02x %x\n", shortname(), tag(), brp, wb, aa, w, opc, mm); |
| 528 | |
| 299 | 529 | switch (opc) |
| 300 | 530 | { |
| 301 | 531 | case 0x00: // control |
| r24864 | r24865 | |
| 305 | 535 | case 1: invalid(opc); break; |
| 306 | 536 | case 2: sintr(); break; |
| 307 | 537 | case 3: xfer(); break; |
| 308 | | default: |
| 309 | | if (BIT(brp, 2)) |
| 310 | | wid(BIT(brp, 1), BIT(brp, 0)); |
| 538 | default: wid(BIT(brp, 1), BIT(brp, 0)); |
| 311 | 539 | } |
| 312 | 540 | break; |
| 313 | 541 | |
| r24864 | r24865 | |
| 659 | 887 | void i8089_channel::movb_rm(int r, int m, int o) |
| 660 | 888 | { |
| 661 | 889 | UINT8 byte = m_iop->read_byte(m_r[m].w + o); |
| 662 | | m_r[r].w = (BIT(byte, 7) ? 0xffff0 : 0x00000) | byte; |
| 890 | m_r[r].w = (BIT(byte, 7) ? 0xfff00 : 0x00000) | byte; |
| 663 | 891 | m_r[r].t = 1; |
| 664 | 892 | } |
| 665 | 893 | |
| r24864 | r24865 | |
| 673 | 901 | // move immediate byte to register |
| 674 | 902 | void i8089_channel::movbi_ri(int r, int i) |
| 675 | 903 | { |
| 676 | | m_r[r].w = (BIT(i, 7) ? 0xffff0 : 0x00000) | (i & 0xff); |
| 904 | m_r[r].w = (BIT(i, 7) ? 0xfff00 : 0x00000) | (i & 0xff); |
| 677 | 905 | m_r[r].t = 1; |
| 678 | 906 | } |
| 679 | 907 | |
| r24864 | r24865 | |
| 686 | 914 | // move immediate word to register |
| 687 | 915 | void i8089_channel::movi_ri(int r, int i) |
| 688 | 916 | { |
| 689 | | m_r[r].w = (BIT(i, 15) ? 0xffff0 : 0x00000) | (i & 0xffff); |
| 917 | m_r[r].w = (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff); |
| 690 | 918 | m_r[r].t = 1; |
| 691 | 919 | } |
| 692 | 920 | |
| 693 | 921 | // move immediate word to memory word |
| 694 | 922 | void i8089_channel::movi_mi(int m, int i, int o) |
| 695 | 923 | { |
| 696 | | m_iop->write_word(m_r[m].w + o, (BIT(i, 15) ? 0xffff0 : 0x00000) | (i & 0xffff)); |
| 924 | m_iop->write_word(m_r[m].w + o, (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff)); |
| 697 | 925 | } |
| 698 | 926 | |
| 699 | 927 | // move pointer to memory (store) |
| r24864 | r24865 | |
| 753 | 981 | m_r[PSW].w |= s << 1; |
| 754 | 982 | } |
| 755 | 983 | |
| 756 | | void i8089_channel::xfer() { UNIMPLEMENTED } |
| 984 | // enter dma transfer mode after next instruction |
| 985 | void i8089_channel::xfer() |
| 986 | { |
| 987 | m_xfer_pending = true; |
| 988 | } |
| 757 | 989 | |
| 758 | 990 | void i8089_channel::invalid(int opc) |
| 759 | 991 | { |