trunk/src/emu/machine/hdc9234.c
| r32111 | r32112 | |
| 4 | 4 | Standard Microsystems Corporation (SMC) |
| 5 | 5 | |
| 6 | 6 | This controller handles MFM and FM encoded floppy disks and hard disks. |
| 7 | | A variant, the SMC9224, is used in some DEC systems. |
| 7 | A variant, the HDC9224, is used in some DEC systems. |
| 8 | 8 | |
| 9 | 9 | The HDC9234 is used in the Myarc HFDC card for the TI99/4A. |
| 10 | 10 | |
| r32111 | r32112 | |
| 14 | 14 | The HDC9234 controller is also referred to as the "Universal Disk Controller" (UDC) |
| 15 | 15 | by the data book |
| 16 | 16 | |
| 17 | | Michael Zapf, June 2014 |
| 17 | Michael Zapf, September 2014 |
| 18 | 18 | |
| 19 | 19 | ***************************************************************************/ |
| 20 | 20 | |
| r32111 | r32112 | |
| 25 | 25 | #define TRACE_ACT 0 |
| 26 | 26 | #define TRACE_SHIFT 0 |
| 27 | 27 | #define TRACE_LIVE 0 |
| 28 | | #define TRACE_SYNC 0 |
| 28 | #define TRACE_RWSEC 0 |
| 29 | #define TRACE_LINES 0 |
| 30 | #define TRACE_AUXBUS 0 |
| 31 | #define TRACE_COMMAND 0 |
| 32 | #define TRACE_DELAY 0 |
| 33 | #define TRACE_WRITE 0 |
| 34 | #define TRACE_INDEX 0 |
| 35 | #define TRACE_INT 0 |
| 36 | #define TRACE_SETREG 0 |
| 37 | #define TRACE_DONE 0 |
| 38 | #define TRACE_VERIFY 0 |
| 29 | 39 | |
| 30 | 40 | #define UNRELIABLE_MEDIA 0 |
| 31 | 41 | |
| 32 | | // Seek complete? |
| 33 | | |
| 34 | 42 | // Untested: |
| 35 | 43 | // Multi-sector read |
| 36 | 44 | // Seek complete |
| 37 | 45 | // read sectors physical |
| 38 | | // |
| 39 | 46 | |
| 40 | 47 | /* |
| 41 | 48 | Register names of the HDC. The left part is the set of write registers, |
| r32111 | r32112 | |
| 180 | 187 | OUT2_REDWRT = 0x40, |
| 181 | 188 | OUT2_STEPDIR = 0x20, |
| 182 | 189 | OUT2_STEPPULSE = 0x10, |
| 183 | | OUT2_HEADSEL3 = 0x08, |
| 184 | | OUT2_HEADSEL2 = 0x04, |
| 185 | | OUT2_HEADSEL1 = 0x02, |
| 186 | | OUT2_HEADSEL0 = 0x01 |
| 190 | OUT2_HEADSEL = 0x0f |
| 187 | 191 | }; |
| 188 | 192 | |
| 189 | 193 | enum |
| r32111 | r32112 | |
| 191 | 195 | TYPE_AT = 0x00, |
| 192 | 196 | TYPE_HD = 0x01, |
| 193 | 197 | TYPE_FLOPPY8 = 0x02, |
| 194 | | TYPE_FLOPPY5 = 0x03 |
| 198 | TYPE_FLOPPY5 = 0x03, |
| 199 | DRIVE_TYPE = 0x03 |
| 195 | 200 | }; |
| 196 | 201 | |
| 197 | | #define DRIVE_TYPE 0x03 |
| 198 | | |
| 199 | 202 | /* |
| 200 | 203 | Timers |
| 201 | 204 | */ |
| r32111 | r32112 | |
| 231 | 234 | static const int id_field[] = { CURRENT_CYLINDER, CURRENT_HEAD, CURRENT_SECTOR, CURRENT_SIZE, CURRENT_CRC1, CURRENT_CRC2 }; |
| 232 | 235 | |
| 233 | 236 | /* |
| 234 | | Pulse widths for stepping in ??s |
| 237 | Pulse widths for stepping in usec |
| 235 | 238 | */ |
| 236 | 239 | enum |
| 237 | 240 | { |
| r32111 | r32112 | |
| 251 | 254 | |
| 252 | 255 | enum |
| 253 | 256 | { |
| 254 | | UNDEF, |
| 257 | UNDEF = 0x00, |
| 255 | 258 | IDLE, |
| 256 | 259 | DONE, |
| 260 | COMMAND_INIT, |
| 261 | REGISTER_ACCESS, |
| 262 | |
| 257 | 263 | STEP_ON, |
| 258 | 264 | STEP_OFF, |
| 259 | 265 | RESTORE_CHECK1, |
| 260 | 266 | RESTORE_CHECK2, |
| 261 | 267 | SEEK_COMPLETE, |
| 262 | 268 | |
| 263 | | READ_ID, |
| 269 | READ_ID = 0x40, |
| 264 | 270 | READ_ID1, |
| 271 | READ_ID_STEPON, |
| 272 | READ_ID_STEPOFF, |
| 265 | 273 | |
| 266 | | VERIFY, |
| 274 | VERIFY = 0x50, |
| 267 | 275 | VERIFY1, |
| 268 | 276 | VERIFY2, |
| 269 | 277 | VERIFY3, |
| 270 | 278 | |
| 271 | | DATA_TRANSFER, |
| 272 | | DATA_TRANSFER1, |
| 279 | DATA_TRANSFER = 0x60, |
| 280 | DATA_TRANSFER_READ, |
| 281 | DATA_TRANSFER_WRITE, |
| 273 | 282 | |
| 274 | 283 | // Live states |
| 284 | LIVE_STATES = 0x80, |
| 275 | 285 | SEARCH_IDAM, |
| 276 | 286 | SEARCH_IDAM_FAILED, |
| 277 | 287 | READ_TWO_MORE_A1_IDAM, |
| r32111 | r32112 | |
| 280 | 290 | READ_TWO_MORE_A1_DAM, |
| 281 | 291 | SEARCH_DAM_FAILED, |
| 282 | 292 | READ_SECTOR_DATA, |
| 283 | | READ_SECTOR_DATA1 |
| 293 | READ_SECTOR_DATA1, |
| 294 | WRITE_DAM_AND_SECTOR, |
| 295 | WRITE_SEC_SKIP_GAP2, |
| 296 | WRITE_SEC_SKIP_GAP2_LOOP, |
| 297 | WRITE_SEC_BYTE, |
| 298 | WRITE_SEC_NEXT_BYTE |
| 284 | 299 | }; |
| 285 | 300 | |
| 301 | /* |
| 302 | State machine metastates. |
| 303 | */ |
| 286 | 304 | enum |
| 287 | 305 | { |
| 288 | | NOCMD, |
| 289 | | RESET, |
| 290 | | DESELECT, |
| 291 | | RESTORE, |
| 292 | | STEP, |
| 293 | | SELECT, |
| 294 | | SETREG, |
| 295 | | READSECL, |
| 296 | | READSECP |
| 306 | CONTINUE = 0, |
| 307 | WAIT, |
| 308 | NEXT, |
| 309 | ERROR, |
| 310 | SUCCESS |
| 297 | 311 | }; |
| 298 | 312 | |
| 299 | 313 | const hdc9234_device::cmddef hdc9234_device::s_command[] = |
| 300 | 314 | { |
| 301 | | { 0x00, 0xff, RESET, &hdc9234_device::device_reset }, |
| 302 | | { 0x01, 0xff, DESELECT, &hdc9234_device::drive_deselect }, |
| 303 | | { 0x02, 0xfe, RESTORE, &hdc9234_device::restore_drive }, |
| 304 | | { 0x04, 0xfc, STEP, &hdc9234_device::step_drive }, |
| 305 | | { 0x20, 0xe0, SELECT, &hdc9234_device::drive_select }, |
| 306 | | { 0x40, 0xf0, SETREG, &hdc9234_device::set_register_pointer }, |
| 307 | | { 0x58, 0xfe, READSECP, &hdc9234_device::read_sector_physical }, |
| 308 | | { 0x5c, 0xfc, READSECL, &hdc9234_device::read_sector_logical }, |
| 309 | | { 0, 0, 0, 0 } |
| 315 | { 0x00, 0xff, &hdc9234_device::device_reset }, |
| 316 | { 0x01, 0xff, &hdc9234_device::drive_deselect }, |
| 317 | { 0x02, 0xfe, &hdc9234_device::restore_drive }, |
| 318 | { 0x04, 0xfc, &hdc9234_device::step_drive }, |
| 319 | { 0x20, 0xe0, &hdc9234_device::drive_select }, |
| 320 | { 0x40, 0xf0, &hdc9234_device::set_register_pointer }, |
| 321 | { 0x58, 0xfe, &hdc9234_device::read_sectors }, |
| 322 | { 0x5c, 0xfc, &hdc9234_device::read_sectors }, |
| 323 | { 0xa0, 0xa0, &hdc9234_device::write_sector_logical }, |
| 324 | { 0, 0, 0 } |
| 310 | 325 | }; |
| 311 | 326 | |
| 312 | 327 | /* |
| r32111 | r32112 | |
| 342 | 357 | } |
| 343 | 358 | |
| 344 | 359 | /* |
| 360 | Accessor functions for specific parameters. |
| 361 | */ |
| 362 | int hdc9234_device::desired_head() |
| 363 | { |
| 364 | return m_register_w[DESIRED_HEAD] & 0x0f; |
| 365 | } |
| 366 | |
| 367 | int hdc9234_device::desired_cylinder() |
| 368 | { |
| 369 | return (m_register_w[DESIRED_CYLINDER] & 0xff) | (m_register_w[DESIRED_HEAD] & 0x70); |
| 370 | } |
| 371 | |
| 372 | int hdc9234_device::desired_sector() |
| 373 | { |
| 374 | return m_register_w[DESIRED_SECTOR] & 0xff; |
| 375 | } |
| 376 | |
| 377 | int hdc9234_device::current_head() |
| 378 | { |
| 379 | return m_register_r[CURRENT_HEAD] & 0x0f; |
| 380 | } |
| 381 | |
| 382 | int hdc9234_device::current_cylinder() |
| 383 | { |
| 384 | return (m_register_r[CURRENT_CYLINDER] & 0xff) | (m_register_r[CURRENT_HEAD] & 0x70); |
| 385 | } |
| 386 | |
| 387 | int hdc9234_device::current_sector() |
| 388 | { |
| 389 | return m_register_r[CURRENT_SECTOR] & 0xff; |
| 390 | } |
| 391 | |
| 392 | UINT8 hdc9234_device::current_command() |
| 393 | { |
| 394 | return m_register_w[COMMAND]; |
| 395 | } |
| 396 | |
| 397 | /* |
| 345 | 398 | Set/clear INT |
| 346 | 399 | |
| 347 | 400 | Interupts are generated in the following occasions: |
| r32111 | r32112 | |
| 379 | 432 | { |
| 380 | 433 | set_bits(m_register_r[INT_STATUS], ST_TERMCOD, false); // clear the previously set flags |
| 381 | 434 | m_register_r[INT_STATUS] |= flags; |
| 382 | | if (TRACE_ACT) logerror("%s: command %02x done, flags=%02x\n", tag(), m_command, flags); |
| 435 | if (TRACE_DONE) logerror("%s: command %02x done, flags=%02x\n", tag(), current_command(), flags); |
| 383 | 436 | } |
| 384 | 437 | else |
| 385 | 438 | { |
| 386 | | if (TRACE_ACT) logerror("%s: command %02x done\n", tag(), m_command); |
| 439 | if (TRACE_DONE) logerror("%s: command %02x done\n", tag(), current_command()); |
| 387 | 440 | } |
| 388 | 441 | |
| 389 | 442 | // [1], p. 6 |
| 390 | | if (TRACE_ACT) logerror("%s: Raise interrupt DONE\n", tag()); |
| 443 | if (TRACE_INT) logerror("%s: Raise interrupt DONE\n", tag()); |
| 391 | 444 | set_interrupt(ASSERT_LINE); |
| 392 | 445 | |
| 393 | | m_substate = IDLE; |
| 394 | | m_main_state = IDLE; |
| 395 | | m_command = NOCMD; |
| 446 | m_substate = UNDEF; |
| 447 | m_executing = false; |
| 396 | 448 | } |
| 397 | 449 | |
| 398 | 450 | /* |
| r32111 | r32112 | |
| 405 | 457 | |
| 406 | 458 | void hdc9234_device::wait_time(emu_timer *tm, int microsec, int next_substate) |
| 407 | 459 | { |
| 408 | | if (TRACE_ACT) logerror("%s: Delay by %d microsec\n", tag(), microsec); |
| 460 | if (TRACE_DELAY) logerror("%s: Delay by %d microsec\n", tag(), microsec); |
| 409 | 461 | tm->adjust(attotime::from_usec(microsec)); |
| 410 | 462 | m_substate = next_substate; |
| 411 | 463 | } |
| 412 | 464 | |
| 413 | 465 | void hdc9234_device::wait_time(emu_timer *tm, attotime delay, int param) |
| 414 | 466 | { |
| 415 | | if (TRACE_ACT) logerror("%s: [%s] Delaying by %4.2f microsecs\n", tag(), ttsn().cstr(), delay.as_double()*1000000); |
| 467 | if (TRACE_DELAY) logerror("%s: [%s] Delaying by %4.2f microsecs\n", tag(), ttsn().cstr(), delay.as_double()*1000000); |
| 416 | 468 | tm->adjust(delay); |
| 417 | 469 | m_substate = param; |
| 418 | 470 | } |
| 419 | 471 | |
| 420 | | // =========================================================================== |
| 421 | | // States |
| 422 | | // =========================================================================== |
| 423 | | |
| 472 | // ================================================================== |
| 473 | // Common subroutines READ ID, VERIFY, DATA TRANSFER |
| 474 | // called by all sector access commands |
| 475 | // ================================================================== |
| 424 | 476 | /* |
| 425 | | DESELECT DRIVE |
| 426 | | done when no drive is in use |
| 477 | READ ID FIELD ([1] p. 9) |
| 478 | The controller |
| 479 | - scans for the next IDAM |
| 480 | - reads the ID field values into the CURRENT_HEAD/CYLINDER/SECTOR registers |
| 481 | - checks the CRC |
| 482 | - calculates the number of steps and the direction towards DESIRED_CYLINDER |
| 483 | (must have saved that value before!) |
| 484 | - steps to that location during OUTPUT2 times |
| 427 | 485 | */ |
| 428 | | void hdc9234_device::drive_deselect() |
| 486 | void hdc9234_device::read_id(int& cont, bool implied_seek) |
| 429 | 487 | { |
| 430 | | if (TRACE_ACT) logerror("%s: deselect command\n", tag()); |
| 431 | | set_bits(m_output1, OUT1_DRVSEL3|OUT1_DRVSEL2|OUT1_DRVSEL1|OUT1_DRVSEL0, false); |
| 432 | | sync_latches_out(); |
| 433 | | set_command_done(TC_SUCCESS); |
| 434 | | } |
| 488 | cont = CONTINUE; |
| 435 | 489 | |
| 436 | | /* |
| 437 | | "Restore" command |
| 438 | | // RESTORE DRIVE |
| 439 | | // bit 0: |
| 440 | | // 0 -> command ends after last seek pulse, |
| 441 | | // 1 -> command ends when the drive asserts the seek complete pin |
| 442 | | */ |
| 443 | | void hdc9234_device::restore_drive() |
| 444 | | { |
| 445 | | if (TRACE_ACT) logerror("%s: restore command %02x\n", tag(), m_command); |
| 446 | | |
| 447 | | m_seek_count = 0; |
| 448 | | m_substate = RESTORE_CHECK1; |
| 449 | | step_drive_continue(); |
| 450 | | } |
| 451 | | |
| 452 | | /* |
| 453 | | STEP IN / OUT 1 CYLINDER |
| 454 | | */ |
| 455 | | void hdc9234_device::step_drive() |
| 456 | | { |
| 457 | | if (TRACE_ACT) logerror("%s: step in/out command %02x\n", tag(), m_command); |
| 458 | | m_substate = STEP_ON; |
| 459 | | step_drive_continue(); |
| 460 | | } |
| 461 | | |
| 462 | | void hdc9234_device::step_drive_continue() |
| 463 | | { |
| 464 | | while (true) |
| 490 | while (cont==CONTINUE) |
| 465 | 491 | { |
| 466 | 492 | switch (m_substate) |
| 467 | 493 | { |
| 468 | | case DONE: |
| 469 | | set_command_done(TC_SUCCESS); |
| 470 | | return; |
| 471 | | |
| 472 | | case STEP_ON: |
| 473 | | if (TRACE_ACT) logerror("%s: substate STEP_ON\n", tag()); |
| 474 | | // STEPDIR = 0 -> towards TRK00 |
| 475 | | set_bits(m_output2, OUT2_STEPDIR, (m_command & 0x02)==0); |
| 476 | | // Raising edge (note that all signals must be inverted before leading them to the drive) |
| 477 | | set_bits(m_output2, OUT2_STEPPULSE, true); |
| 478 | | sync_latches_out(); |
| 479 | | wait_time(m_timer, pulse_width(), STEP_OFF); |
| 480 | | return; |
| 481 | | |
| 482 | | case STEP_OFF: |
| 483 | | if (TRACE_ACT) logerror("%s: substate STEP_OFF\n", tag()); |
| 484 | | set_bits(m_output2, OUT2_STEPPULSE, false); |
| 485 | | sync_latches_out(); |
| 486 | | if (m_main_state==RESTORE) |
| 487 | | { |
| 488 | | wait_time(m_timer, get_step_time(), RESTORE_CHECK1); |
| 489 | | } |
| 490 | | else |
| 491 | | { |
| 492 | | wait_time(m_timer, get_step_time(), DONE); |
| 493 | | } |
| 494 | | return; |
| 495 | | |
| 496 | | case RESTORE_CHECK1: |
| 497 | | if (TRACE_ACT) logerror("%s: substate RESTORE_CHECK; seek count = %d\n", tag(), m_seek_count); |
| 498 | | // If the drive is on track 0 or not ready (no drive), terminate the command |
| 499 | | if (on_track00()) |
| 500 | | { |
| 501 | | if (TRACE_ACT) logerror("%s: restore command TRK00 reached\n", tag()); |
| 502 | | if (m_command & 1) |
| 503 | | { |
| 504 | | // Buffered seek; wait for SEEK_COMPLETE |
| 505 | | wait_line(SEEK_COMPLETE); |
| 506 | | return; |
| 507 | | } |
| 508 | | else |
| 509 | | { |
| 510 | | m_substate = DONE; |
| 511 | | break; |
| 512 | | } |
| 513 | | } |
| 514 | | m_substate = RESTORE_CHECK2; |
| 515 | | break; |
| 516 | | |
| 517 | | case RESTORE_CHECK2: |
| 518 | | // Track 0 has not been reached yet |
| 519 | | if ((m_register_r[DRIVE_STATUS] & HDC_DS_READY)==0) |
| 520 | | { |
| 521 | | if (TRACE_ACT) logerror("%s: restore command: drive not ready\n", tag()); |
| 522 | | m_substate = DONE; |
| 523 | | break; |
| 524 | | } |
| 525 | | |
| 526 | | // Increase step count |
| 527 | | m_seek_count++; |
| 528 | | if (m_seek_count>=4096) |
| 529 | | { |
| 530 | | if (TRACE_ACT) logerror("%s: restore command: giving up\n", tag()); |
| 531 | | set_command_done(TC_VRFYERR); |
| 532 | | return; |
| 533 | | } |
| 534 | | |
| 535 | | m_substate = STEP_ON; |
| 536 | | break; |
| 537 | | |
| 538 | | case SEEK_COMPLETE: |
| 539 | | m_substate = RESTORE_CHECK2; |
| 540 | | break; |
| 541 | | } |
| 542 | | } |
| 543 | | } |
| 544 | | |
| 545 | | void hdc9234_device::drive_select() |
| 546 | | { |
| 547 | | int driveparm = m_command & 0x1f; |
| 548 | | |
| 549 | | // Command word |
| 550 | | // |
| 551 | | // 7 6 5 4 3 2 1 0 |
| 552 | | // +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 553 | | // | 0 | 0 | 1 |Delay| Type | Drive | |
| 554 | | // +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 555 | | // |
| 556 | | // [1] p.5: lower 4 bits of retry count register is put on OUTPUT1 |
| 557 | | |
| 558 | | m_output1 = (0x10 << (driveparm & 0x03)) | (m_register_w[RETRY_COUNT]&0x0f); |
| 559 | | // Bit 7 of OUTPUT2 is complement of Bit 7 of OUTPUT1 |
| 560 | | |
| 561 | | // The drive type is used to configure DMA burst mode ([1], p.12) |
| 562 | | // and to select the timing parameters |
| 563 | | m_selected_drive_type = (driveparm>>2) & 0x03; |
| 564 | | m_head_load_delay_enable = (driveparm>>4)&0x01; |
| 565 | | |
| 566 | | if (TRACE_ACT) logerror("%s: drive select command (%02x): head load delay=%d, type=%d, drive=%d\n", tag(), m_command, m_head_load_delay_enable, m_selected_drive_type, driveparm&3); |
| 567 | | |
| 568 | | // We need to store the type of the drive for the poll_drives command |
| 569 | | // to be able to correctly select the device (floppy or hard disk). |
| 570 | | // m_types[driveparm&0x03] = m_selected_drive_type; |
| 571 | | |
| 572 | | // Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER, |
| 573 | | // and CURRENT_IDENT. This is required during formatting ([1], p. 14) |
| 574 | | // as the format command reuses the registers for formatting parameters. |
| 575 | | m_register_r[CURRENT_HEAD] = m_register_r[DMA7_0]; |
| 576 | | m_register_r[CURRENT_CYLINDER] = m_register_r[DMA15_8]; |
| 577 | | m_register_r[CURRENT_IDENT] = m_register_r[DMA23_16]; |
| 578 | | |
| 579 | | // Copy the selected drive number to the chip status register |
| 580 | | m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | (driveparm & 0x03); |
| 581 | | |
| 582 | | sync_latches_out(); |
| 583 | | set_command_done(TC_SUCCESS); |
| 584 | | } |
| 585 | | |
| 586 | | void hdc9234_device::set_register_pointer() |
| 587 | | { |
| 588 | | m_register_pointer = m_command & 0xf; |
| 589 | | if (TRACE_ACT) logerror("%s: setregptr command; start reg=%d\n", tag(), m_register_pointer); |
| 590 | | // Spec does not say anything about the effect of setting an |
| 591 | | // invalid value (only "care should be taken") |
| 592 | | if (m_register_pointer > 10) |
| 593 | | { |
| 594 | | logerror("%s: set register pointer: Invalid register number: %d. Setting to 10.\n", tag(), m_register_pointer); |
| 595 | | m_register_pointer = 10; |
| 596 | | } |
| 597 | | set_command_done(TC_SUCCESS); |
| 598 | | } |
| 599 | | |
| 600 | | /* |
| 601 | | Read the desired sector. For multiple sectors, read the sectors in |
| 602 | | the order as they appear on the track. The command terminates with the |
| 603 | | next index pulse or when all sectors have been read before. |
| 604 | | Opcodes: |
| 605 | | 58 = transfer disabled |
| 606 | | 59 = transfer enabled |
| 607 | | */ |
| 608 | | void hdc9234_device::read_sector_physical() |
| 609 | | { |
| 610 | | if (TRACE_ACT) logerror("%s: read sectors physical command %02x\n", tag(), m_command); |
| 611 | | if (TRACE_ACT) logerror("%s: sector: C=%d H=%d S=%d\n", tag(), m_register_w[DESIRED_CYLINDER], m_register_w[DESIRED_HEAD],m_register_w[DESIRED_SECTOR]); |
| 612 | | |
| 613 | | m_retry_save = m_register_w[RETRY_COUNT]; |
| 614 | | m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); |
| 615 | | |
| 616 | | m_substate = READ_ID; |
| 617 | | read_sector_continue(); |
| 618 | | } |
| 619 | | |
| 620 | | /* |
| 621 | | Read the desired sector. For multiple sectors, read the sectors in |
| 622 | | ascending order (sector n, n+1, n+2 ...). |
| 623 | | Opcodes: |
| 624 | | 5c = implied seek / transfer disabled |
| 625 | | 5d = implied seek / transfer enabled |
| 626 | | 5e = no implied seek / transfer disabled |
| 627 | | 5f = no implied seek / transfer enabled |
| 628 | | */ |
| 629 | | void hdc9234_device::read_sector_logical() |
| 630 | | { |
| 631 | | if (TRACE_ACT) logerror("%s: read sectors logical command %02x\n", tag(), m_command); |
| 632 | | if (TRACE_ACT) logerror("%s: sector: C=%d H=%d S=%d\n", tag(), m_register_w[DESIRED_CYLINDER], m_register_w[DESIRED_HEAD],m_register_w[DESIRED_SECTOR]); |
| 633 | | |
| 634 | | m_retry_save = m_register_w[RETRY_COUNT]; |
| 635 | | m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); |
| 636 | | |
| 637 | | m_substate = READ_ID; |
| 638 | | read_sector_continue(); |
| 639 | | } |
| 640 | | |
| 641 | | void hdc9234_device::read_sector_continue() |
| 642 | | { |
| 643 | | while (true) |
| 644 | | { |
| 645 | | switch (m_substate) |
| 646 | | { |
| 647 | | /* |
| 648 | | READ ID FIELD ([1] p. 9) |
| 649 | | The controller |
| 650 | | - scans for the next IDAM |
| 651 | | - reads the ID field values into the CURRENT_HEAD/CYLINDER/SECTOR registers |
| 652 | | - checks the CRC |
| 653 | | - calculates the number of steps and the direction towards DESIRED_CYLINDER |
| 654 | | (must have saved that value before!) |
| 655 | | - steps to that location during OUTPUT2 times |
| 656 | | |
| 657 | | When an error occurs, the COMMAND_TERMINATION bits are set to 01 |
| 658 | | */ |
| 659 | 494 | case READ_ID: |
| 660 | 495 | // Implied seek: Enter the READ_ID subprogram. |
| 661 | 496 | if (TRACE_ACT) logerror("%s: substate READ_ID\n", tag()); |
| 662 | 497 | |
| 663 | | // Bit 1 = 0: enable implied seek (i.e. the controller will seek the desired track) |
| 664 | | // Bit 1 = 1: disable implied seek (controller will stay on the current track) |
| 665 | | // Also, do implied seek for read physical |
| 666 | | if ((m_command & 0x0e)==0x0e) |
| 667 | | m_substate = VERIFY; |
| 668 | | else |
| 669 | | m_substate = READ_ID1; |
| 498 | m_substate = implied_seek? READ_ID1 : VERIFY; |
| 670 | 499 | |
| 671 | 500 | // First step: Search the next IDAM, and if found, read the |
| 672 | 501 | // ID values into the registers |
| 502 | // Depending on the implied seek flag, continue with the read_id, |
| 503 | // else switch to verify. |
| 673 | 504 | m_live_state.bit_count_total = 0; |
| 674 | 505 | live_start(SEARCH_IDAM); |
| 675 | | return; |
| 506 | cont = WAIT; |
| 507 | break; |
| 676 | 508 | |
| 677 | 509 | case READ_ID1: |
| 678 | 510 | // If an error occured (no IDAM found), terminate the command |
| 679 | 511 | if ((m_register_r[CHIP_STATUS] & CS_SYNCERR) != 0) |
| 680 | 512 | { |
| 681 | | if (TRACE_ACT) logerror("%s: READ_ID: No IDAM found\n", tag()); |
| 682 | | set_command_done(TC_RDIDERR); |
| 683 | | return; |
| 513 | logerror("%s: READ_ID failed to find an IDAM\n", tag()); |
| 514 | cont = ERROR; |
| 515 | break; |
| 684 | 516 | } |
| 685 | 517 | |
| 686 | 518 | if (TRACE_ACT) |
| 687 | 519 | { |
| 688 | 520 | logerror("%s: substate READ_ID1\n", tag()); |
| 689 | | logerror("%s: DESIRED_CYL = %d; CURRENT_CYL = %d\n", tag(), m_register_w[DESIRED_CYLINDER], m_register_r[CURRENT_CYLINDER]); |
| 521 | logerror("%s: DESIRED_CYL = %d; CURRENT_CYL = %d\n", tag(), desired_cylinder(), current_cylinder()); |
| 690 | 522 | } |
| 691 | 523 | |
| 692 | 524 | // The CRC has been updated automatically with each read_one_bit during the live_run. |
| r32111 | r32112 | |
| 695 | 527 | { |
| 696 | 528 | logerror("%s: CRC error in sector header\n", tag()); |
| 697 | 529 | set_bits(m_register_r[CHIP_STATUS], CS_CRCERR, true); |
| 698 | | set_command_done(TC_RDIDERR); |
| 699 | | return; |
| 530 | cont = ERROR; |
| 531 | break; |
| 700 | 532 | } |
| 701 | 533 | |
| 702 | 534 | // Calculate the direction and number of step pulses |
| 703 | 535 | // positive -> towards inner cylinders |
| 704 | 536 | // negative -> towards outer cylinders |
| 705 | 537 | // zero -> we're already there |
| 706 | | m_track_delta = m_register_w[DESIRED_CYLINDER] - m_register_r[CURRENT_CYLINDER]; |
| 707 | | m_substate = STEP_ON; |
| 538 | m_track_delta = desired_cylinder() - current_cylinder(); |
| 539 | m_substate = READ_ID_STEPON; |
| 708 | 540 | break; |
| 709 | 541 | |
| 710 | | case STEP_ON: |
| 542 | case READ_ID_STEPON: |
| 711 | 543 | // Any more steps left? |
| 712 | 544 | if (m_track_delta == 0) |
| 713 | 545 | { |
| 714 | 546 | m_substate = VERIFY; |
| 547 | cont = NEXT; |
| 715 | 548 | break; |
| 716 | 549 | } |
| 717 | 550 | |
| r32111 | r32112 | |
| 719 | 552 | // STEPDIR = 0 -> towards TRK00 |
| 720 | 553 | set_bits(m_output2, OUT2_STEPDIR, (m_track_delta>0)); |
| 721 | 554 | set_bits(m_output2, OUT2_STEPPULSE, true); |
| 722 | | sync_latches_out(); |
| 723 | | wait_time(m_timer, pulse_width(), STEP_OFF); |
| 724 | | return; |
| 555 | auxbus_out(); |
| 556 | wait_time(m_timer, pulse_width(), READ_ID_STEPOFF); |
| 557 | cont = WAIT; |
| 558 | break; |
| 725 | 559 | |
| 726 | | case STEP_OFF: |
| 560 | case READ_ID_STEPOFF: |
| 727 | 561 | if (TRACE_ACT) logerror("%s: substate STEP_OFF\n", tag()); |
| 728 | 562 | set_bits(m_output2, OUT2_STEPPULSE, false); |
| 729 | | sync_latches_out(); |
| 563 | auxbus_out(); |
| 730 | 564 | m_track_delta += (m_track_delta<0)? 1 : -1; |
| 731 | 565 | // Return to STEP_ON, check whether there are more steps |
| 732 | | wait_time(m_timer, get_step_time(), STEP_ON); |
| 733 | | return; |
| 566 | wait_time(m_timer, step_time(), READ_ID_STEPON); |
| 567 | cont = WAIT; |
| 568 | break; |
| 734 | 569 | |
| 570 | default: |
| 571 | if (TRACE_ACT) logerror("%s: unknown substate %d in read_id\n", tag(), m_substate); |
| 572 | cont = ERROR; |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | // When an error occurs, the COMMAND_TERMINATION bits are set to 01 |
| 577 | if (cont == ERROR) set_command_done(TC_RDIDERR); |
| 578 | } |
| 579 | |
| 580 | /* |
| 581 | VERIFY ([1] p. 10) |
| 582 | The controller |
| 583 | - continues to read the next ID field until the current values match the |
| 584 | contents of the DESIRED_HEAD/CYLINDER/SECTOR registers |
| 585 | - checks the CRC |
| 586 | */ |
| 587 | void hdc9234_device::verify(int& cont, bool verify_all) |
| 588 | { |
| 589 | cont = CONTINUE; |
| 590 | |
| 591 | while (cont==CONTINUE) |
| 592 | { |
| 593 | switch (m_substate) |
| 594 | { |
| 735 | 595 | case VERIFY: |
| 736 | | /* |
| 737 | | VERIFY ([1] p. 10) |
| 738 | | The controller |
| 739 | | - continues to read the next ID field until the current values match the |
| 740 | | contents of the DESIRED_HEAD/CYLINDER/SECTOR registers |
| 741 | | - checks the CRC |
| 742 | | |
| 743 | | When an error occurs, the COMMAND_TERMINATION bits are set to 10 |
| 744 | | */ |
| 745 | 596 | // After seeking (or immediately when implied seek has been disabled), |
| 746 | 597 | // find the desired sector. |
| 747 | 598 | |
| r32111 | r32112 | |
| 751 | 602 | // (This test is only relevant when we did not have a seek phase before) |
| 752 | 603 | if ((m_register_r[CHIP_STATUS] & CS_SYNCERR) != 0) |
| 753 | 604 | { |
| 754 | | if (TRACE_ACT) logerror("%s: READ_ID: No IDAM found\n", tag()); |
| 755 | | set_command_done(TC_VRFYERR); |
| 756 | | return; |
| 605 | logerror("%s: VERIFY failed to find an IDAM\n", tag()); |
| 606 | cont = ERROR; |
| 607 | break; |
| 757 | 608 | } |
| 758 | 609 | |
| 759 | 610 | // Count from 0 again |
| r32111 | r32112 | |
| 763 | 614 | |
| 764 | 615 | case VERIFY1: |
| 765 | 616 | // Check whether we are already there |
| 766 | | if ((m_register_w[DESIRED_CYLINDER] == m_register_r[CURRENT_CYLINDER]) |
| 767 | | && (m_register_w[DESIRED_HEAD] == m_register_r[CURRENT_HEAD]) |
| 768 | | && (m_register_w[DESIRED_SECTOR] == m_register_r[CURRENT_SECTOR])) |
| 617 | if (desired_cylinder() == current_cylinder() |
| 618 | && desired_head() == current_head() |
| 619 | && desired_sector() == current_sector()) |
| 769 | 620 | { |
| 770 | | if (TRACE_ACT) logerror("%s: Found the desired sector\n", tag()); |
| 621 | if (TRACE_ACT) logerror("%s: Found the desired sector CHS=(%d,%d,%d)\n", tag(), |
| 622 | desired_cylinder(), |
| 623 | desired_head(), |
| 624 | desired_sector()); |
| 771 | 625 | m_substate = DATA_TRANSFER; |
| 626 | cont = NEXT; |
| 772 | 627 | } |
| 773 | 628 | else |
| 774 | 629 | { |
| 775 | | if (TRACE_ACT) logerror("%s: Current CHS=(%d,%d,%d), desired CHS=(%d,%d,%d).\n", tag(), |
| 776 | | m_register_r[CURRENT_CYLINDER] & 0xff, |
| 777 | | m_register_r[CURRENT_HEAD] & 0xff, |
| 778 | | m_register_r[CURRENT_SECTOR] & 0xff, |
| 779 | | m_register_w[DESIRED_CYLINDER] & 0xff, |
| 780 | | m_register_w[DESIRED_HEAD] & 0xff, |
| 781 | | m_register_w[DESIRED_SECTOR] & 0xff); |
| 630 | if (TRACE_VERIFY) logerror("%s: Current CHS=(%d,%d,%d), desired CHS=(%d,%d,%d).\n", tag(), |
| 631 | current_cylinder(), |
| 632 | current_head(), |
| 633 | current_sector(), |
| 634 | desired_cylinder(), |
| 635 | desired_head(), |
| 636 | desired_sector()); |
| 782 | 637 | m_substate = VERIFY2; |
| 783 | 638 | } |
| 784 | 639 | break; |
| r32111 | r32112 | |
| 787 | 642 | // Search the next ID |
| 788 | 643 | m_substate = VERIFY3; |
| 789 | 644 | live_start(SEARCH_IDAM); |
| 790 | | return; |
| 645 | cont = WAIT; |
| 646 | break; |
| 791 | 647 | |
| 792 | 648 | case VERIFY3: |
| 793 | 649 | if ((m_register_r[CHIP_STATUS] & CS_SYNCERR) != 0) |
| 794 | 650 | { |
| 795 | | if (TRACE_ACT) logerror("%s: VERIFY: Desired sector not found\n", tag()); |
| 651 | logerror("%s: VERIFY failed to find sector CHS=(%d,%d,%d)\n", tag(), |
| 652 | desired_cylinder(), |
| 653 | desired_head(), |
| 654 | desired_sector()); |
| 796 | 655 | // live_run has set the sync error; clear it |
| 797 | 656 | set_bits(m_register_r[CHIP_STATUS], CS_SYNCERR, false); |
| 798 | 657 | // and set the compare error bit instead |
| 799 | 658 | set_bits(m_register_r[CHIP_STATUS], CS_COMPERR, true); |
| 800 | | set_command_done(TC_VRFYERR); |
| 801 | | return; |
| 659 | cont = ERROR; |
| 660 | break; |
| 802 | 661 | } |
| 803 | 662 | |
| 804 | 663 | // Continue with the loop |
| 805 | | if ((m_command & 0x0c)==0x0c) |
| 664 | if (verify_all) |
| 806 | 665 | { |
| 807 | 666 | // this is for the logical sector reading |
| 808 | 667 | m_substate = VERIFY1; |
| r32111 | r32112 | |
| 813 | 672 | // do not verify the next ID field |
| 814 | 673 | m_substate = DATA_TRANSFER; |
| 815 | 674 | m_wait_for_index = true; |
| 675 | cont = NEXT; |
| 816 | 676 | } |
| 817 | 677 | break; |
| 818 | 678 | |
| 679 | default: |
| 680 | logerror("%s: unknown substate %d in verify\n", tag(), m_substate); |
| 681 | cont = ERROR; |
| 682 | } |
| 683 | } |
| 684 | |
| 685 | // When an error occurs, the COMMAND_TERMINATION bits are set to 10 |
| 686 | if (cont == ERROR) set_command_done(TC_VRFYERR); |
| 687 | } |
| 688 | |
| 689 | /* |
| 690 | DATA TRANSFER ([1], p. 10) |
| 691 | only during READ/WRITE PHYSICAL/LOGICAL |
| 692 | The controller |
| 693 | - scans for the next DAM |
| 694 | - initiates a DMA request and waits for ACK from the system processor |
| 695 | - transfers the contents of the current sector into memory via DMA (read) or |
| 696 | via DMA to the sector (write) |
| 697 | */ |
| 698 | void hdc9234_device::data_transfer(int& cont) |
| 699 | { |
| 700 | cont = CONTINUE; |
| 701 | |
| 702 | while (cont==CONTINUE) |
| 703 | { |
| 704 | switch (m_substate) |
| 705 | { |
| 819 | 706 | case DATA_TRANSFER: |
| 820 | | /* |
| 821 | | DATA TRANSFER ([1], p. 10) |
| 822 | | only during READ PHYSICAL/LOGICAL |
| 823 | | The controller |
| 824 | | - scans for the next DAM |
| 825 | | - initiates a DMA request and waits for ACK from the system processor |
| 826 | | - transfers the contents of the current sector into memory via DMA |
| 827 | | |
| 828 | | When an error occurs, the COMMAND_TERMINATION bits are set to 11 |
| 829 | | */ |
| 830 | 707 | if (TRACE_ACT) logerror("%s: substate DATA_TRANSFER\n", tag()); |
| 831 | 708 | |
| 832 | | // Search the DAM and transfer the contents via DMA |
| 833 | | m_substate = DATA_TRANSFER1; |
| 834 | | |
| 835 | 709 | // Count from 0 again |
| 836 | 710 | m_live_state.bit_count_total = 0; |
| 837 | 711 | |
| 838 | | dma_address_out(); |
| 839 | | live_start(SEARCH_DAM); |
| 840 | | return; |
| 712 | if (m_transfer_enabled) dma_address_out(); |
| 841 | 713 | |
| 842 | | case DATA_TRANSFER1: |
| 714 | if (TRACE_RWSEC) logerror("%s: %s sector CHS=(%d,%d,%d)\n", tag(), m_write? "write" : "read", |
| 715 | desired_cylinder(), |
| 716 | desired_head(), |
| 717 | desired_sector()); |
| 718 | |
| 719 | if (m_write) |
| 720 | { |
| 721 | m_substate = DATA_TRANSFER_WRITE; |
| 722 | live_start(WRITE_DAM_AND_SECTOR); |
| 723 | } |
| 724 | else |
| 725 | { |
| 726 | m_substate = DATA_TRANSFER_READ; |
| 727 | live_start(SEARCH_DAM); |
| 728 | } |
| 729 | |
| 730 | cont = WAIT; |
| 731 | break; |
| 732 | |
| 733 | case DATA_TRANSFER_READ: |
| 843 | 734 | // OK, sector has been read. |
| 844 | 735 | // Check CRC |
| 845 | 736 | if (m_live_state.crc != 0) |
| 846 | 737 | { |
| 847 | | if (TRACE_ACT) logerror("%s: CRC error in sector data\n", tag()); |
| 848 | 738 | // Set Retry Required flag |
| 849 | 739 | set_bits(m_register_r[CHIP_STATUS], CS_RETREQ, true); |
| 850 | 740 | |
| 851 | 741 | // Decrement the retry register (one's complemented value; 0000 = 15) |
| 852 | 742 | int retry = 15-((m_register_w[RETRY_COUNT] >> 4)&0x0f); |
| 853 | | if (TRACE_ACT) logerror("%s: CRC error; retries = %d\n", tag(), retry); |
| 743 | |
| 744 | logerror("%s: DATA TRANSFER got CRC error in sector data, retries = %d\n", tag(), retry); |
| 854 | 745 | m_register_w[RETRY_COUNT] = (m_register_w[RETRY_COUNT] & 0x0f) | ((15-(retry-1))<<4); |
| 855 | 746 | |
| 856 | 747 | if (retry == 0) |
| 857 | 748 | { |
| 858 | 749 | if (TRACE_ACT) logerror("%s: CRC error; no retries left\n", tag()); |
| 859 | 750 | set_bits(m_register_r[CHIP_STATUS], CS_CRCERR, true); |
| 860 | | set_command_done(TC_DATAERR); |
| 861 | | return; |
| 751 | cont = ERROR; |
| 862 | 752 | } |
| 863 | 753 | else |
| 864 | 754 | { |
| r32111 | r32112 | |
| 869 | 759 | // We'll rely on the properly written software as well. |
| 870 | 760 | m_live_state.bit_count_total = 0; |
| 871 | 761 | m_substate = VERIFY2; |
| 762 | cont = NEXT; |
| 872 | 763 | } |
| 873 | 764 | } |
| 874 | 765 | else |
| r32111 | r32112 | |
| 882 | 773 | (m_register_w[DMA15_8] & 0xff) << 8 | |
| 883 | 774 | (m_register_w[DMA7_0] & 0xff); |
| 884 | 775 | |
| 885 | | dma_address = (dma_address + get_sector_size()) & 0xffffff; |
| 776 | dma_address = (dma_address + calc_sector_size()) & 0xffffff; |
| 886 | 777 | |
| 887 | 778 | m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16; |
| 888 | 779 | m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 16; |
| r32111 | r32112 | |
| 904 | 795 | // What happens when we exceed the highest sector number |
| 905 | 796 | // in the track? We have to assume that this is possible |
| 906 | 797 | // and that in this case the VERIFY routine fails. |
| 907 | | m_register_w[DESIRED_SECTOR] = (m_register_w[DESIRED_SECTOR] + 1) & 0xff; |
| 798 | m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff; |
| 908 | 799 | m_substate = VERIFY1; |
| 800 | cont = NEXT; |
| 909 | 801 | m_live_state.bit_count_total = 0; |
| 910 | 802 | } |
| 911 | 803 | else |
| 804 | cont = SUCCESS; |
| 805 | } |
| 806 | break; |
| 807 | |
| 808 | case DATA_TRANSFER_WRITE: |
| 809 | if (TRACE_ACT) logerror("%s: Sector successfully written\n", tag()); |
| 810 | |
| 811 | // Update the DMA registers for multi-sector operations |
| 812 | if (m_multi_sector) |
| 813 | { |
| 814 | int dma_address = (m_register_w[DMA23_16] & 0xff) << 16 | |
| 815 | (m_register_w[DMA15_8] & 0xff) << 8 | |
| 816 | (m_register_w[DMA7_0] & 0xff); |
| 817 | |
| 818 | dma_address = (dma_address + calc_sector_size()) & 0xffffff; |
| 819 | |
| 820 | m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16; |
| 821 | m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 16; |
| 822 | m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff) >> 16; |
| 823 | } |
| 824 | |
| 825 | // Decrement the count |
| 826 | m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1) & 0xff; |
| 827 | if (m_register_w[SECTOR_COUNT] != 0 && !m_stop_after_index) |
| 828 | { |
| 829 | m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff; |
| 830 | m_substate = VERIFY1; |
| 831 | cont = NEXT; |
| 832 | m_live_state.bit_count_total = 0; |
| 833 | } |
| 834 | else |
| 835 | cont = SUCCESS; |
| 836 | |
| 837 | break; |
| 838 | |
| 839 | default: |
| 840 | logerror("%s: unknown substate %d in data_transfer\n", tag(), m_substate); |
| 841 | cont = ERROR; |
| 842 | } |
| 843 | } |
| 844 | |
| 845 | if (cont==SUCCESS) set_command_done(TC_SUCCESS); |
| 846 | |
| 847 | // When an error occurs, the COMMAND_TERMINATION bits are set to 11 |
| 848 | if (cont==ERROR) set_command_done(TC_DATAERR); |
| 849 | } |
| 850 | |
| 851 | // =========================================================================== |
| 852 | // Commands |
| 853 | // =========================================================================== |
| 854 | |
| 855 | /* |
| 856 | DESELECT DRIVE |
| 857 | done when no drive is in use |
| 858 | */ |
| 859 | void hdc9234_device::drive_deselect() |
| 860 | { |
| 861 | if (TRACE_COMMAND) logerror("%s: DESELECT command\n", tag()); |
| 862 | set_bits(m_output1, OUT1_DRVSEL3|OUT1_DRVSEL2|OUT1_DRVSEL1|OUT1_DRVSEL0, false); |
| 863 | auxbus_out(); |
| 864 | set_command_done(TC_SUCCESS); |
| 865 | } |
| 866 | |
| 867 | /* |
| 868 | Step on / off; used by RESTORE and STEP IN/OUT |
| 869 | */ |
| 870 | void hdc9234_device::step_on(bool towards00, int next) |
| 871 | { |
| 872 | if (TRACE_ACT) logerror("%s: substate STEP_ON\n", tag()); |
| 873 | |
| 874 | // STEPDIR = 0 -> towards TRK00 |
| 875 | set_bits(m_output2, OUT2_STEPDIR, !towards00); |
| 876 | |
| 877 | // Raising edge (note that all signals must be inverted before leading them to the drive) |
| 878 | set_bits(m_output2, OUT2_STEPPULSE, true); |
| 879 | auxbus_out(); |
| 880 | wait_time(m_timer, pulse_width(), next); |
| 881 | } |
| 882 | |
| 883 | void hdc9234_device::step_off(int next) |
| 884 | { |
| 885 | if (TRACE_ACT) logerror("%s: substate STEP_OFF\n", tag()); |
| 886 | set_bits(m_output2, OUT2_STEPPULSE, false); |
| 887 | auxbus_out(); |
| 888 | wait_time(m_timer, step_time(), next); |
| 889 | } |
| 890 | |
| 891 | /* |
| 892 | // RESTORE DRIVE |
| 893 | // bit 0: |
| 894 | // 0 -> command ends after last seek pulse, |
| 895 | // 1 -> command ends when the drive asserts the seek complete pin |
| 896 | */ |
| 897 | void hdc9234_device::restore_drive() |
| 898 | { |
| 899 | int cont = CONTINUE; |
| 900 | |
| 901 | // The substate is set to UNDEF when the command is started; |
| 902 | // when we return here after a pause, the substate is set to some other value |
| 903 | // In wd_fdc this is solved using two methods <command>_start and <command>_continue |
| 904 | if (m_substate == UNDEF) |
| 905 | { |
| 906 | if (TRACE_COMMAND) logerror("%s: RESTORE command %02x\n", tag(), current_command()); |
| 907 | m_seek_count = 0; |
| 908 | m_substate = RESTORE_CHECK1; |
| 909 | } |
| 910 | |
| 911 | while (cont==CONTINUE) |
| 912 | { |
| 913 | switch (m_substate) |
| 914 | { |
| 915 | case RESTORE_CHECK1: |
| 916 | if (TRACE_ACT) logerror("%s: substate RESTORE_CHECK; seek count = %d\n", tag(), m_seek_count); |
| 917 | // If the drive is on track 0 or not ready (no drive), terminate the command |
| 918 | if (on_track00()) |
| 919 | { |
| 920 | if (TRACE_ACT) logerror("%s: restore command TRK00 reached\n", tag()); |
| 921 | if (current_command() & 1) |
| 912 | 922 | { |
| 913 | | set_command_done(TC_SUCCESS); |
| 914 | | return; |
| 923 | // Buffered seek; wait for SEEK_COMPLETE |
| 924 | wait_line(SEEK_COMPLETE); |
| 925 | cont = WAIT; |
| 915 | 926 | } |
| 927 | else |
| 928 | { |
| 929 | cont = SUCCESS; |
| 930 | } |
| 931 | break; |
| 916 | 932 | } |
| 933 | m_substate = RESTORE_CHECK2; |
| 917 | 934 | break; |
| 918 | 935 | |
| 936 | case RESTORE_CHECK2: |
| 937 | // Track 0 has not been reached yet |
| 938 | if ((m_register_r[DRIVE_STATUS] & HDC_DS_READY)==0) |
| 939 | { |
| 940 | if (TRACE_COMMAND) logerror("%s: restore command: drive not ready\n", tag()); |
| 941 | // Does not look like a success, but this takes into account |
| 942 | // that if a drive is not connected we do not want an error message |
| 943 | cont = SUCCESS; |
| 944 | break; |
| 945 | } |
| 946 | |
| 947 | // Increase step count |
| 948 | m_seek_count++; |
| 949 | if (m_seek_count>=4096) |
| 950 | { |
| 951 | logerror("%s: restore command: failed to reach track 00\n", tag()); |
| 952 | set_command_done(TC_VRFYERR); |
| 953 | cont = ERROR; |
| 954 | break; |
| 955 | } |
| 956 | |
| 957 | step_on(true, STEP_OFF); |
| 958 | cont = WAIT; |
| 959 | break; |
| 960 | |
| 961 | case STEP_OFF: |
| 962 | step_off(RESTORE_CHECK1); |
| 963 | cont = WAIT; |
| 964 | break; |
| 965 | |
| 966 | case SEEK_COMPLETE: |
| 967 | cont = SUCCESS; |
| 968 | break; |
| 969 | } |
| 970 | } |
| 971 | if (cont==SUCCESS) set_command_done(TC_SUCCESS); |
| 972 | } |
| 973 | |
| 974 | /* |
| 975 | STEP IN / OUT 1 CYLINDER |
| 976 | */ |
| 977 | void hdc9234_device::step_drive() |
| 978 | { |
| 979 | int cont = CONTINUE; |
| 980 | |
| 981 | if (m_substate == UNDEF) |
| 982 | { |
| 983 | if (TRACE_COMMAND) logerror("%s: STEP IN/OUT command %02x\n", tag(), current_command()); |
| 984 | m_substate = STEP_ON; |
| 985 | } |
| 986 | |
| 987 | while (cont==CONTINUE) |
| 988 | { |
| 989 | switch (m_substate) |
| 990 | { |
| 991 | case STEP_ON: |
| 992 | step_on((current_command() & 0x02)!=0, STEP_OFF); |
| 993 | cont = WAIT; |
| 994 | break; |
| 995 | case STEP_OFF: |
| 996 | step_off(DONE); |
| 997 | cont = WAIT; |
| 998 | break; |
| 999 | case DONE: |
| 1000 | cont = SUCCESS; |
| 1001 | break; |
| 1002 | } |
| 1003 | } |
| 1004 | if (cont==SUCCESS) set_command_done(TC_SUCCESS); |
| 1005 | } |
| 1006 | |
| 1007 | /* |
| 1008 | DRIVE SELECT |
| 1009 | |
| 1010 | Command word |
| 1011 | |
| 1012 | 7 6 5 4 3 2 1 0 |
| 1013 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1014 | | 0 | 0 | 1 |Delay| Type | Drive | |
| 1015 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1016 | |
| 1017 | [1] p.5: lower 4 bits of RETRY COUNT register (user programmable output) is put on OUTPUT1 |
| 1018 | |
| 1019 | The HFDC controller board uses the user programmable output to |
| 1020 | select one of four floppy disk drives with Drive set to 00. |
| 1021 | Drive codes 01, 10, and 11 remain for three hard disk drives. |
| 1022 | */ |
| 1023 | |
| 1024 | void hdc9234_device::drive_select() |
| 1025 | { |
| 1026 | int driveparm = current_command() & 0x1f; |
| 1027 | |
| 1028 | m_output1 = (0x10 << (driveparm & 0x03)) | (m_register_w[RETRY_COUNT]&0x0f); |
| 1029 | |
| 1030 | // The drive type is used to configure DMA burst mode ([1], p.12) |
| 1031 | // and to select the timing parameters |
| 1032 | m_selected_drive_type = (driveparm>>2) & 0x03; |
| 1033 | m_head_load_delay_enable = (driveparm>>4)&0x01; |
| 1034 | |
| 1035 | if (TRACE_COMMAND) logerror("%s: DRIVE SELECT command (%02x): head load delay=%d, type=%d, drive=%d, pout=%02x\n", tag(), current_command(), m_head_load_delay_enable, m_selected_drive_type, driveparm&3, m_register_w[RETRY_COUNT]&0x0f); |
| 1036 | |
| 1037 | if (m_substate != UNDEF) |
| 1038 | { |
| 1039 | logerror("%s: substate = %d\n", tag(), m_substate); |
| 1040 | } |
| 1041 | |
| 1042 | // Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER, |
| 1043 | // and CURRENT_IDENT. This is required during formatting ([1], p. 14) |
| 1044 | // as the format command reuses the registers for formatting parameters. |
| 1045 | m_register_r[CURRENT_HEAD] = m_register_r[DMA7_0]; |
| 1046 | m_register_r[CURRENT_CYLINDER] = m_register_r[DMA15_8]; |
| 1047 | m_register_r[CURRENT_IDENT] = m_register_r[DMA23_16]; |
| 1048 | |
| 1049 | // Copy the selected drive number to the chip status register |
| 1050 | m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | (driveparm & 0x03); |
| 1051 | |
| 1052 | auxbus_out(); |
| 1053 | set_command_done(TC_SUCCESS); |
| 1054 | } |
| 1055 | |
| 1056 | /* |
| 1057 | SET REGISTER POINTER |
| 1058 | |
| 1059 | Sets the pointer to the read and write registers. On read or write accesses, |
| 1060 | the pointer is increased until it reaches the DATA register. |
| 1061 | */ |
| 1062 | void hdc9234_device::set_register_pointer() |
| 1063 | { |
| 1064 | m_register_pointer = current_command() & 0xf; |
| 1065 | if (TRACE_SETREG) logerror("%s: SET REGISTER POINTER command; start reg=%d\n", tag(), m_register_pointer); |
| 1066 | // The specification does not say anything about the effect of setting an |
| 1067 | // invalid value (only "care should be taken") |
| 1068 | if (m_register_pointer > 10) |
| 1069 | { |
| 1070 | logerror("%s: set register pointer: Invalid register number: %d. Setting to 10.\n", tag(), m_register_pointer); |
| 1071 | m_register_pointer = 10; |
| 1072 | } |
| 1073 | set_command_done(TC_SUCCESS); |
| 1074 | } |
| 1075 | |
| 1076 | /* |
| 1077 | READ SECTORS PHYSICAL / LOGICAL |
| 1078 | Read the desired sectors, maximum count being specified in SECTOR_COUNT |
| 1079 | |
| 1080 | Physical: |
| 1081 | For multiple sectors, read the sectors in the order as they appear on the track. |
| 1082 | The command terminates with the next index pulse or when all sectors have been read before. |
| 1083 | Implied seek (locate the correct track) is always true. |
| 1084 | Opcodes: |
| 1085 | 58 = transfer disabled |
| 1086 | 59 = transfer enabled |
| 1087 | |
| 1088 | Logical: |
| 1089 | For multiple sectors, read the sectors in ascending order of their sector field (sector n, n+1, n+2 ...). |
| 1090 | Opcodes: |
| 1091 | 5c = implied seek / transfer disabled |
| 1092 | 5d = implied seek / transfer enabled |
| 1093 | 5e = no implied seek / transfer disabled |
| 1094 | 5f = no implied seek / transfer enabled |
| 1095 | */ |
| 1096 | void hdc9234_device::read_sectors() |
| 1097 | { |
| 1098 | bool logical = (current_command() & 0xfc)==0x5c; |
| 1099 | |
| 1100 | if (m_substate == UNDEF) |
| 1101 | { |
| 1102 | // Command init |
| 1103 | if (TRACE_COMMAND) logerror("%s: READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); |
| 1104 | m_retry_save = m_register_w[RETRY_COUNT]; |
| 1105 | m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); |
| 1106 | |
| 1107 | m_substate = READ_ID; |
| 1108 | } |
| 1109 | |
| 1110 | int cont = NEXT; |
| 1111 | bool implied_seek = !logical || (current_command() & 0x02)==0; |
| 1112 | m_transfer_enabled = (current_command()&0x01)!=0; |
| 1113 | |
| 1114 | while (cont == NEXT) |
| 1115 | { |
| 1116 | switch (m_substate & 0xf0) |
| 1117 | { |
| 1118 | case READ_ID: |
| 1119 | read_id(cont, implied_seek); |
| 1120 | break; |
| 1121 | case VERIFY: |
| 1122 | verify(cont, logical); // for physical, only verify the first sector |
| 1123 | break; |
| 1124 | case DATA_TRANSFER: |
| 1125 | m_write = false; |
| 1126 | data_transfer(cont); |
| 1127 | break; |
| 919 | 1128 | default: |
| 920 | | if (TRACE_ACT) logerror("%s: unknown substate %d in read_sector\n", tag(), m_substate); |
| 1129 | logerror("%s: unknown substate %d in read_sectors\n", tag(), m_substate); |
| 1130 | cont = ERROR; |
| 921 | 1131 | } |
| 922 | 1132 | } |
| 923 | 1133 | } |
| 924 | 1134 | |
| 925 | | void hdc9234_device::general_continue() |
| 1135 | /* |
| 1136 | Write the desired sector. For multiple sectors, write the sectors in |
| 1137 | ascending order (sector n, n+1, n+2 ...). |
| 1138 | Opcodes: A0 - BF, E0 - FF |
| 1139 | |
| 1140 | [ 1 ] [ ImplSeek ] [ 1 ] [ NormalData ] [ ReducedWC ] [ PreC2 ] [ PreC1 ] [ PreC0 ] |
| 1141 | */ |
| 1142 | void hdc9234_device::write_sector_logical() |
| 926 | 1143 | { |
| 1144 | if (m_substate == UNDEF) |
| 1145 | { |
| 1146 | if (TRACE_COMMAND) logerror("%s: write sectors logical command %02x, CHS=(%d,%d,%d)\n", tag(), current_command(), desired_cylinder(), desired_head(), desired_sector()); |
| 1147 | m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); |
| 1148 | m_substate = READ_ID; |
| 1149 | } |
| 1150 | |
| 1151 | int cont = NEXT; |
| 1152 | |
| 1153 | m_write = true; |
| 1154 | m_transfer_enabled = true; |
| 1155 | |
| 1156 | m_deleted = (current_command() & 0x10)==0; |
| 1157 | m_precompensation = (current_command() & 0x07); |
| 1158 | m_reduced_write_current = (current_command() & 0x08)!=0; |
| 1159 | |
| 1160 | while (cont == NEXT) |
| 1161 | { |
| 1162 | // We're dispatching by substate value range |
| 1163 | switch (m_substate & 0xf0) |
| 1164 | { |
| 1165 | case READ_ID: |
| 1166 | read_id(cont, (current_command() & 0x02)==0); |
| 1167 | break; |
| 1168 | case VERIFY: |
| 1169 | verify(cont, true); |
| 1170 | break; |
| 1171 | case DATA_TRANSFER: |
| 1172 | data_transfer(cont); |
| 1173 | break; |
| 1174 | default: |
| 1175 | logerror("%s: unknown substate %d in write_sector_logical\n", tag(), m_substate); |
| 1176 | cont = ERROR; |
| 1177 | } |
| 1178 | } |
| 1179 | } |
| 1180 | |
| 1181 | void hdc9234_device::reenter_command_processing() |
| 1182 | { |
| 927 | 1183 | // Do we have a live run on the track? |
| 928 | 1184 | if (m_live_state.state != IDLE) |
| 929 | 1185 | { |
| r32111 | r32112 | |
| 934 | 1190 | |
| 935 | 1191 | // We're here when there is no live_run anymore |
| 936 | 1192 | // Where were we last time? |
| 937 | | switch (m_main_state) |
| 938 | | { |
| 939 | | case IDLE: |
| 940 | | break; |
| 941 | | case RESTORE: |
| 942 | | case STEP: |
| 943 | | step_drive_continue(); |
| 944 | | break; |
| 945 | | case SELECT: |
| 946 | | // During drive_select there is no need to continue |
| 947 | | break; |
| 948 | | case READSECL: |
| 949 | | read_sector_continue(); |
| 950 | | break; |
| 951 | | default: |
| 952 | | logerror("%s: [%s] general_continue on unknown main_state %d\n", tag(), ttsn().cstr(), m_main_state); |
| 953 | | break; |
| 954 | | } |
| 1193 | // Take care not to restart commands because of the index callback |
| 1194 | if (m_executing && m_substate != UNDEF) (this->*m_command)(); |
| 955 | 1195 | } |
| 956 | 1196 | |
| 957 | 1197 | // =========================================================================== |
| r32111 | r32112 | |
| 959 | 1199 | /* |
| 960 | 1200 | Delivers the step time (in microseconds) minus the pulse width |
| 961 | 1201 | */ |
| 962 | | int hdc9234_device::get_step_time() |
| 1202 | int hdc9234_device::step_time() |
| 963 | 1203 | { |
| 964 | 1204 | int time = 0; |
| 965 | 1205 | int index = m_register_w[MODE] & MO_STEPRATE; |
| r32111 | r32112 | |
| 998 | 1238 | /* |
| 999 | 1239 | Delivers the sector size |
| 1000 | 1240 | */ |
| 1001 | | int hdc9234_device::get_sector_size() |
| 1241 | int hdc9234_device::calc_sector_size() |
| 1002 | 1242 | { |
| 1003 | 1243 | return 128 << (m_register_r[CURRENT_SIZE] & 3); |
| 1004 | 1244 | } |
| r32111 | r32112 | |
| 1047 | 1287 | m_live_state.shift_reg = 0; |
| 1048 | 1288 | m_live_state.crc = 0xffff; |
| 1049 | 1289 | m_live_state.bit_counter = 0; |
| 1290 | m_live_state.byte_counter = 0; |
| 1050 | 1291 | m_live_state.data_separator_phase = false; |
| 1051 | 1292 | m_live_state.data_reg = 0; |
| 1052 | 1293 | |
| r32111 | r32112 | |
| 1200 | 1441 | } |
| 1201 | 1442 | |
| 1202 | 1443 | // Repeat until we have collected 16 bits |
| 1203 | | if(m_live_state.bit_counter & 15) break; |
| 1444 | if (m_live_state.bit_counter & 15) break; |
| 1204 | 1445 | |
| 1205 | 1446 | // So we now got 16 bits. Fill this value into the next slot. We expect two more A1 values. |
| 1206 | 1447 | slot = m_live_state.bit_counter >> 4; |
| r32111 | r32112 | |
| 1218 | 1459 | } |
| 1219 | 1460 | |
| 1220 | 1461 | if (TRACE_LIVE) logerror("%s: [%s] Found data value %02X\n", tag(),tts(m_live_state.time).cstr(), m_live_state.data_reg); |
| 1221 | | if (m_live_state.data_reg != 0xfe) |
| 1462 | |
| 1463 | // Check for ident field (fe, ff, fd, fc) |
| 1464 | if ((m_live_state.data_reg & 0xfc) != 0xfc) |
| 1222 | 1465 | { |
| 1223 | 1466 | // This may happen when we accidentally locked onto the DAM. Look for the next IDAM. |
| 1224 | | if (TRACE_LIVE) logerror("%s: Missing FE data after A1A1A1\n", tag()); |
| 1467 | if (TRACE_LIVE) logerror("%s: Missing ident data after A1A1A1\n", tag()); |
| 1225 | 1468 | m_live_state.state = SEARCH_IDAM; |
| 1226 | 1469 | break; |
| 1227 | 1470 | } |
| 1228 | 1471 | |
| 1472 | m_register_r[CURRENT_IDENT] = m_live_state.data_reg; |
| 1473 | |
| 1229 | 1474 | // We're here after we got the three A1 and FE |
| 1230 | 1475 | m_live_state.bit_counter = 0; |
| 1231 | 1476 | m_live_state.state = READ_ID_FIELDS_INTO_REGS; |
| r32111 | r32112 | |
| 1261 | 1506 | } |
| 1262 | 1507 | break; |
| 1263 | 1508 | |
| 1509 | // ================================================== |
| 1510 | // Live states for sector read operations |
| 1511 | // ================================================== |
| 1512 | |
| 1264 | 1513 | case SEARCH_DAM: |
| 1265 | 1514 | if (TRACE_LIVE && m_last_live_state != SEARCH_DAM) |
| 1266 | 1515 | logerror("%s: [%s] SEARCH_DAM\n", tag(),tts(m_live_state.time).cstr()); |
| r32111 | r32112 | |
| 1384 | 1633 | break; |
| 1385 | 1634 | } |
| 1386 | 1635 | case SEARCH_DAM_FAILED: |
| 1387 | | if (TRACE_LIVE) logerror("%s: SEARCH_DAM failed\n", tag()); |
| 1636 | logerror("%s: SEARCH_DAM failed\n", tag()); |
| 1388 | 1637 | m_live_state.state = IDLE; |
| 1389 | 1638 | return; |
| 1390 | 1639 | |
| r32111 | r32112 | |
| 1398 | 1647 | return; |
| 1399 | 1648 | |
| 1400 | 1649 | // Request bus release at the first bit of each byte (floppy; [1], fig 5 and 6) |
| 1401 | | if ((m_command & 0x01)!=0) // transfer enabled |
| 1650 | if (m_transfer_enabled) |
| 1402 | 1651 | { |
| 1403 | 1652 | if ((m_live_state.bit_counter & 15)== 1) |
| 1404 | 1653 | { |
| r32111 | r32112 | |
| 1413 | 1662 | if (TRACE_LIVE) logerror("%s: [%s] Found data value %02X, CRC=%04x\n", tag(),tts(m_live_state.time).cstr(), m_live_state.data_reg, m_live_state.crc); |
| 1414 | 1663 | int slot = (m_live_state.bit_counter >> 4)-1; |
| 1415 | 1664 | |
| 1416 | | if (slot < get_sector_size()) |
| 1665 | if (slot < calc_sector_size()) |
| 1417 | 1666 | { |
| 1418 | 1667 | // Sector data |
| 1419 | 1668 | wait_for_realtime(READ_SECTOR_DATA1); |
| 1420 | 1669 | return; |
| 1421 | 1670 | } |
| 1422 | | else if (slot < get_sector_size()+2) |
| 1671 | else if (slot < calc_sector_size()+2) |
| 1423 | 1672 | { |
| 1424 | 1673 | // CRC |
| 1425 | | if (slot == get_sector_size()+1) |
| 1674 | if (slot == calc_sector_size()+1) |
| 1426 | 1675 | { |
| 1427 | 1676 | if (TRACE_LIVE) logerror("%s: [%s] Sector read completed\n", tag(),tts(m_live_state.time).cstr()); |
| 1428 | 1677 | wait_for_realtime(IDLE); |
| r32111 | r32112 | |
| 1446 | 1695 | return; |
| 1447 | 1696 | } |
| 1448 | 1697 | |
| 1449 | | if ((m_command & 0x01)!=0) // transfer enabled |
| 1698 | if (m_transfer_enabled) |
| 1450 | 1699 | { |
| 1451 | 1700 | m_out_dip(ASSERT_LINE); |
| 1452 | 1701 | m_out_dma(0, m_live_state.data_reg, 0xff); |
| r32111 | r32112 | |
| 1459 | 1708 | checkpoint(); |
| 1460 | 1709 | break; |
| 1461 | 1710 | |
| 1711 | // ================================================== |
| 1712 | // Live states for sector write operations |
| 1713 | // ================================================== |
| 1714 | |
| 1715 | case WRITE_DAM_AND_SECTOR: |
| 1716 | // 1. Wait for 22*16 cells (MFM) or 11*16 cells (FM) [704 usec, Gap 2] |
| 1717 | // 2. Write 12 (MFM) or 6 (FM) zeros |
| 1718 | // 3. Write 3*A1 sync plus the ident byte (MFM) or FB (FM) or F8 (deleted) |
| 1719 | // 4. Write the sector content and calculate the CRC on the fly |
| 1720 | // 5. Write the CRC bytes |
| 1721 | |
| 1722 | if (TRACE_LIVE && m_last_live_state != WRITE_DAM_AND_SECTOR) |
| 1723 | logerror("%s: [%s] WRITE_DAM_AND_SECTOR\n", tag(), tts(m_live_state.time).cstr()); |
| 1724 | m_last_live_state = m_live_state.state; |
| 1725 | m_live_state.state = WRITE_SEC_SKIP_GAP2; |
| 1726 | break; |
| 1727 | |
| 1728 | case WRITE_SEC_SKIP_GAP2: |
| 1729 | // The pause is implemented by doing dummy reads on the floppy |
| 1730 | if (read_one_bit(limit)) |
| 1731 | return; |
| 1732 | |
| 1733 | // Repeat until we have collected 16 bits |
| 1734 | if (m_live_state.bit_counter & 15) break; |
| 1735 | |
| 1736 | wait_for_realtime(WRITE_SEC_SKIP_GAP2_LOOP); |
| 1737 | return; |
| 1738 | |
| 1739 | case WRITE_SEC_SKIP_GAP2_LOOP: |
| 1740 | m_live_state.state = WRITE_SEC_SKIP_GAP2; |
| 1741 | m_live_state.byte_counter++; |
| 1742 | m_live_state.bit_counter = 0; |
| 1743 | if (TRACE_LIVE) logerror("%s: [%s] %d bytes skipped\n", tag(), tts(m_live_state.time).cstr(), m_live_state.byte_counter); |
| 1744 | |
| 1745 | if (m_live_state.byte_counter == (fm_mode()? 11 : 22)) |
| 1746 | { |
| 1747 | if (TRACE_LIVE) logerror("%s: [%s] Skipped over gap2\n", tag(), tts(m_live_state.time).cstr()); |
| 1748 | if (TRACE_WRITE) logerror("%s: [%s] Write 00\n", tag(), tts(m_live_state.time).cstr()); |
| 1749 | // Start writing 0x00 |
| 1750 | m_live_state.state = WRITE_SEC_BYTE; |
| 1751 | m_live_state.bit_counter = 16; |
| 1752 | m_live_state.byte_counter = 0; |
| 1753 | // The bit context is actually not used in FM |
| 1754 | m_live_state.last_data_bit = m_live_state.data_reg & 1; |
| 1755 | m_pll.start_writing(m_live_state.time); |
| 1756 | encode_byte(0x00); |
| 1757 | |
| 1758 | // Clear the overrun/underrun flag |
| 1759 | set_bits(m_register_r[INT_STATUS], ST_OVRUN, false); |
| 1760 | } |
| 1761 | break; |
| 1762 | |
| 1763 | case WRITE_SEC_BYTE: |
| 1764 | if (write_one_bit(limit)) |
| 1765 | return; |
| 1766 | |
| 1767 | if (m_live_state.bit_counter == 0) |
| 1768 | { |
| 1769 | // All bits written; get the next byte into the shift register |
| 1770 | wait_for_realtime(WRITE_SEC_NEXT_BYTE); |
| 1771 | return; |
| 1772 | } |
| 1773 | break; |
| 1774 | |
| 1775 | case WRITE_SEC_NEXT_BYTE: |
| 1776 | { |
| 1777 | if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) |
| 1778 | { |
| 1779 | if (TRACE_LIVE) logerror("%s: No DMA ACK - buffer underrun\n", tag()); |
| 1780 | set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); |
| 1781 | m_pll.stop_writing(m_floppy, m_live_state.time); |
| 1782 | m_live_state.state = IDLE; |
| 1783 | return; |
| 1784 | } |
| 1785 | |
| 1786 | int sector_start = fm_mode()? 7 : 16; |
| 1787 | int sync0_length = fm_mode()? 6 : 12; |
| 1788 | int sector_end = sector_start + calc_sector_size(); |
| 1789 | |
| 1790 | m_live_state.state = WRITE_SEC_BYTE; |
| 1791 | m_live_state.bit_counter = 16; |
| 1792 | m_live_state.byte_counter++; |
| 1793 | |
| 1794 | // Write all sync zeros |
| 1795 | if (m_live_state.byte_counter < sync0_length) |
| 1796 | { |
| 1797 | if (TRACE_WRITE) logerror("%s: [%s] Write 00\n", tag(), tts(m_live_state.time).cstr()); |
| 1798 | encode_byte(0x00); |
| 1799 | checkpoint(); |
| 1800 | break; |
| 1801 | } |
| 1802 | |
| 1803 | // Write the DAM (MFM) |
| 1804 | if (m_live_state.byte_counter >= sync0_length && m_live_state.byte_counter < sector_start-1) |
| 1805 | { |
| 1806 | if (TRACE_WRITE) logerror("%s: [%s] Write A1\n", tag(), tts(m_live_state.time).cstr()); |
| 1807 | // only applies for MFM since sector_start-1 = 6 = sync0_length |
| 1808 | encode_raw(0x4489); |
| 1809 | checkpoint(); |
| 1810 | break; |
| 1811 | } |
| 1812 | |
| 1813 | // Ident byte (and DAM for FM) |
| 1814 | if (m_live_state.byte_counter == sector_start-1) |
| 1815 | { |
| 1816 | if (TRACE_WRITE) logerror("%s: [%s] Write ident\n", tag(), tts(m_live_state.time).cstr()); |
| 1817 | if (fm_mode()) |
| 1818 | { |
| 1819 | // Init the CRC for the DAM and sector |
| 1820 | m_live_state.crc = 0xffff; |
| 1821 | |
| 1822 | // 1111 0101 0110 1010 = F8 deleted |
| 1823 | // 1111 0101 0110 1111 = FB normal |
| 1824 | encode_raw(m_deleted? 0xf56a : 0xf56f); |
| 1825 | } |
| 1826 | else |
| 1827 | { |
| 1828 | // Init the CRC for the ident byte and sector |
| 1829 | m_live_state.crc = 0xcdb4; // value for 3*A1 |
| 1830 | encode_byte(m_deleted? 0xf8 : 0xfb); |
| 1831 | } |
| 1832 | |
| 1833 | // Set the over/underrun flag and hope that it will be cleared before we return here |
| 1834 | set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); |
| 1835 | m_out_dmarq(ASSERT_LINE); |
| 1836 | |
| 1837 | checkpoint(); |
| 1838 | break; |
| 1839 | } |
| 1840 | |
| 1841 | // Write the sector contents |
| 1842 | if (m_live_state.byte_counter >= sector_start && m_live_state.byte_counter < sector_end) |
| 1843 | { |
| 1844 | // Read byte via DMA |
| 1845 | m_out_dip(ASSERT_LINE); |
| 1846 | UINT8 data = m_in_dma(0, 0xff); |
| 1847 | if (TRACE_WRITE) logerror("%s: [%s] Write %02x\n", tag(), tts(m_live_state.time).cstr(), data); |
| 1848 | encode_byte(data); |
| 1849 | m_out_dip(CLEAR_LINE); |
| 1850 | m_out_dmarq(CLEAR_LINE); |
| 1851 | |
| 1852 | if (m_live_state.byte_counter < sector_end - 1) |
| 1853 | { |
| 1854 | // Set the underrun flag and hope that it will be cleared before we return here |
| 1855 | set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); |
| 1856 | m_out_dmarq(ASSERT_LINE); |
| 1857 | } |
| 1858 | checkpoint(); |
| 1859 | break; |
| 1860 | } |
| 1861 | |
| 1862 | // CRC (two passes) |
| 1863 | // N.B.: when we write the first CRC byte, the value of the CRC will |
| 1864 | // change to the previous second byte, so we can write the first |
| 1865 | // byte in two iterations to get both |
| 1866 | if (m_live_state.byte_counter >= sector_end && m_live_state.byte_counter < sector_end + 2) |
| 1867 | { |
| 1868 | if (TRACE_WRITE) logerror("%s: [%s] Write CRC\n", tag(), tts(m_live_state.time).cstr()); |
| 1869 | encode_byte(m_live_state.crc >> 8); |
| 1870 | checkpoint(); |
| 1871 | break; |
| 1872 | } |
| 1873 | |
| 1874 | // Write a FF behind |
| 1875 | if (m_live_state.byte_counter == sector_end + 2) |
| 1876 | { |
| 1877 | encode_byte(0xff); |
| 1878 | checkpoint(); |
| 1879 | break; |
| 1880 | } |
| 1881 | |
| 1882 | // Done |
| 1883 | if (m_live_state.byte_counter > sector_end + 2) |
| 1884 | { |
| 1885 | if (TRACE_LIVE) logerror("%s: [%s] Write sector complete\n", tag(), tts(m_live_state.time).cstr()); |
| 1886 | m_pll.stop_writing(m_floppy, m_live_state.time); |
| 1887 | m_live_state.state = IDLE; |
| 1888 | return; |
| 1889 | } |
| 1890 | } |
| 1891 | |
| 1462 | 1892 | default: |
| 1463 | 1893 | logerror("%s: Unknown live state: %02x\n", tag(), m_live_state.state); |
| 1464 | 1894 | m_last_live_state = m_live_state.state; |
| r32111 | r32112 | |
| 1482 | 1912 | if(m_live_state.time > machine().time()) |
| 1483 | 1913 | { |
| 1484 | 1914 | // If so, we must roll back to the last checkpoint |
| 1485 | | if (TRACE_SYNC) logerror("%s: [%s] Rolling back and replaying (%s)\n", tag(), ttsn().cstr(), tts(m_live_state.time).cstr()); |
| 1915 | if (TRACE_LIVE) logerror("%s: [%s] Rolling back and replaying (%s)\n", tag(), ttsn().cstr(), tts(m_live_state.time).cstr()); |
| 1486 | 1916 | rollback(); |
| 1487 | 1917 | // and replay until we reach the machine time |
| 1488 | 1918 | live_run_until(machine().time()); |
| r32111 | r32112 | |
| 1493 | 1923 | { |
| 1494 | 1924 | // We are behind machine time, so we will never get back to that |
| 1495 | 1925 | // time, thus we can commit that position |
| 1496 | | if (TRACE_SYNC) logerror("%s: [%s] Committing (%s)\n", tag(), ttsn().cstr(), tts(m_live_state.time).cstr()); |
| 1926 | if (TRACE_LIVE) logerror("%s: [%s] Committing (%s)\n", tag(), ttsn().cstr(), tts(m_live_state.time).cstr()); |
| 1497 | 1927 | m_pll.commit(m_floppy, m_live_state.time); |
| 1498 | 1928 | |
| 1499 | 1929 | if (m_live_state.next_state != -1) |
| r32111 | r32112 | |
| 1576 | 2006 | return false; |
| 1577 | 2007 | } |
| 1578 | 2008 | |
| 2009 | bool hdc9234_device::write_one_bit(const attotime &limit) |
| 2010 | { |
| 2011 | bool bit = (m_live_state.shift_reg & 0x8000)!=0; |
| 2012 | |
| 2013 | bool over_limit = m_pll.write_next_bit(bit, m_live_state.time, m_floppy, limit); |
| 2014 | if (over_limit) return true; |
| 2015 | |
| 2016 | // Calculate the CRC from the data bits on the odd positions |
| 2017 | if (m_live_state.bit_counter & 1) |
| 2018 | { |
| 2019 | if ((m_live_state.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) |
| 2020 | m_live_state.crc = (m_live_state.crc << 1) ^ 0x1021; |
| 2021 | else |
| 2022 | m_live_state.crc = m_live_state.crc << 1; |
| 2023 | } |
| 2024 | m_live_state.shift_reg = m_live_state.shift_reg << 1; |
| 2025 | m_live_state.bit_counter--; |
| 2026 | return false; |
| 2027 | } |
| 2028 | |
| 2029 | /* |
| 2030 | Encode a byte for FM or MFM recording. Result is returned in the |
| 2031 | shift register of m_live_state. |
| 2032 | */ |
| 2033 | void hdc9234_device::encode_byte(UINT8 byte) |
| 2034 | { |
| 2035 | UINT16 raw; |
| 2036 | UINT8 check_pos; |
| 2037 | bool last_bit_set; |
| 2038 | check_pos = 0x80; |
| 2039 | |
| 2040 | if (fm_mode()) |
| 2041 | { |
| 2042 | // Set all clock bits |
| 2043 | raw = 0xaaaa; |
| 2044 | |
| 2045 | // FM: data bit = 1 -> encode as 11 |
| 2046 | // data bit = 0 -> encode as 10 |
| 2047 | for (int i=0; i<8; i++) |
| 2048 | { |
| 2049 | if (byte & check_pos) raw |= 0x4000 >> (2*i); |
| 2050 | check_pos >>= 1; |
| 2051 | } |
| 2052 | last_bit_set = ((byte & 1)!=0); |
| 2053 | } |
| 2054 | else |
| 2055 | { |
| 2056 | last_bit_set = m_live_state.last_data_bit; |
| 2057 | raw = 0; |
| 2058 | for (int i=0; i<8; i++) |
| 2059 | { |
| 2060 | bool bit_set = ((byte & check_pos)!=0); |
| 2061 | |
| 2062 | // MFM: data bit = 1 -> encode as 01 |
| 2063 | // data bit = 0 -> encode as x0 (x = !last_bit) |
| 2064 | if (bit_set) |
| 2065 | raw |= 0x4000 >> (2*i); |
| 2066 | else |
| 2067 | raw |= (last_bit_set? 0x0000 : 0x8000) >> (2*i); |
| 2068 | |
| 2069 | last_bit_set = bit_set; |
| 2070 | check_pos >>= 1; |
| 2071 | } |
| 2072 | } |
| 2073 | m_live_state.last_data_bit = last_bit_set; |
| 2074 | m_live_state.shift_reg = raw; |
| 2075 | m_live_state.data_reg = byte; |
| 2076 | } |
| 2077 | |
| 2078 | void hdc9234_device::encode_raw(UINT16 raw) |
| 2079 | { |
| 2080 | m_live_state.shift_reg = raw; |
| 2081 | m_live_state.last_data_bit = raw & 1; |
| 2082 | } |
| 2083 | |
| 1579 | 2084 | void hdc9234_device::pll_reset(const attotime &when) |
| 1580 | 2085 | { |
| 1581 | 2086 | m_pll.reset(when); |
| 1582 | | // In FM mode, cells are 4 ??s long; in MFM they are 2 ??s long. |
| 2087 | // In FM mode, cells are 4 usec long; in MFM they are 2 usec long. |
| 1583 | 2088 | m_pll.set_clock(attotime::from_usec(fm_mode()? 4 : 2)); |
| 1584 | 2089 | } |
| 1585 | 2090 | |
| r32111 | r32112 | |
| 1647 | 2152 | |
| 1648 | 2153 | if ((offset & 1) == 0) |
| 1649 | 2154 | { |
| 1650 | | wait_time(m_cmd_timer, attotime::from_nsec(REGISTER_COMMIT), 0); |
| 2155 | wait_time(m_cmd_timer, attotime::from_nsec(REGISTER_COMMIT), REGISTER_ACCESS); |
| 1651 | 2156 | } |
| 1652 | 2157 | else |
| 1653 | 2158 | { |
| 1654 | | if (m_command != NOCMD) |
| 2159 | if (m_executing) |
| 1655 | 2160 | { |
| 1656 | | logerror("%s: [%s] Error - previous command %02x not completed; new command %02x ignored\n", tag(), ttsn().cstr(), m_command, m_data); |
| 2161 | logerror("%s: [%s] Error - previous command %02x not completed; new command %02x ignored\n", tag(), ttsn().cstr(), current_command(), m_data); |
| 1657 | 2162 | } |
| 1658 | 2163 | else |
| 1659 | 2164 | { |
| 1660 | | wait_time(m_cmd_timer, attotime::from_nsec(COMMAND_COMMIT), 1); |
| 2165 | wait_time(m_cmd_timer, attotime::from_nsec(COMMAND_COMMIT), COMMAND_INIT); |
| 1661 | 2166 | } |
| 1662 | 2167 | } |
| 1663 | 2168 | } |
| 1664 | 2169 | |
| 1665 | 2170 | /* |
| 1666 | | When the commit period has passed, process the command. |
| 2171 | When the commit period has passed, process the command or register access |
| 1667 | 2172 | */ |
| 1668 | | void hdc9234_device::command_continue() |
| 2173 | void hdc9234_device::process_command() |
| 1669 | 2174 | { |
| 1670 | | // Reset DONE and BAD_SECTOR [1], p.7 |
| 1671 | | set_bits(m_register_r[INT_STATUS], ST_DONE | ST_BADSECT, false); |
| 2175 | if (m_substate == REGISTER_ACCESS) |
| 2176 | { |
| 2177 | // Writing data to registers |
| 2178 | // Data register |
| 2179 | if (TRACE_REG) |
| 2180 | { |
| 2181 | if (m_register_pointer == INT_COMM_TERM) |
| 2182 | logerror("%s: Setting interrupt trigger DONE=%d READY=%d\n", tag(), (m_data & TC_INTDONE)? 1:0, (m_data & TC_INTRDCH)? 1:0); |
| 2183 | else |
| 2184 | logerror("%s: register[%d] <- %02x\n", tag(), m_register_pointer, m_data); |
| 2185 | } |
| 2186 | m_register_w[m_register_pointer] = m_data; |
| 1672 | 2187 | |
| 1673 | | // Reset interrupt line (not explicitly mentioned in spec, but seems reasonable |
| 1674 | | set_interrupt(CLEAR_LINE); |
| 2188 | // Changes to these registers must be output via the auxbus |
| 2189 | if (m_register_pointer == DESIRED_HEAD || m_register_pointer == RETRY_COUNT) |
| 2190 | auxbus_out(); |
| 1675 | 2191 | |
| 1676 | | // Clear Interrupt Pending and Ready Change |
| 1677 | | set_bits(m_register_r[INT_STATUS], ST_INTPEND | ST_RDYCHNG, false); |
| 2192 | // The DMA registers and the sector register for read and |
| 2193 | // write are identical, so in that case we copy the contents |
| 2194 | if (m_register_pointer < DESIRED_HEAD) m_register_r[m_register_pointer] = m_data; |
| 1678 | 2195 | |
| 1679 | | m_command = m_data; |
| 1680 | | m_stop_after_index = false; |
| 1681 | | m_wait_for_index = false; |
| 1682 | | |
| 1683 | | int index = 0; |
| 1684 | | m_main_state = UNDEF; |
| 1685 | | while (s_command[index].mask!=0 && m_main_state == UNDEF) |
| 1686 | | { |
| 1687 | | if ((m_command & s_command[index].mask) == s_command[index].baseval) |
| 1688 | | { |
| 1689 | | // Invoke command |
| 1690 | | m_main_state = s_command[index].state; |
| 1691 | | (this->*s_command[index].command)(); |
| 1692 | | } |
| 1693 | | index++; |
| 2196 | // Autoincrement until DATA is reached. |
| 2197 | if (m_register_pointer < DATA) m_register_pointer++; |
| 1694 | 2198 | } |
| 1695 | | if (m_main_state==UNDEF) |
| 2199 | else |
| 1696 | 2200 | { |
| 1697 | | logerror("%s: Command %02x not defined\n", tag(), m_command); |
| 1698 | | } |
| 1699 | | } |
| 2201 | // Reset DONE and BAD_SECTOR [1], p.7 |
| 2202 | set_bits(m_register_r[INT_STATUS], ST_DONE | ST_BADSECT, false); |
| 1700 | 2203 | |
| 1701 | | /* |
| 1702 | | When the commit period has passed, process the register write operation. |
| 1703 | | */ |
| 1704 | | void hdc9234_device::register_write_continue() |
| 1705 | | { |
| 1706 | | // Writing data to registers |
| 1707 | | // Data register |
| 1708 | | if (TRACE_REG) |
| 1709 | | { |
| 1710 | | if (m_register_pointer == INT_COMM_TERM) |
| 1711 | | logerror("%s: Setting interrupt trigger DONE=%d READY=%d\n", tag(), (m_data & TC_INTDONE)? 1:0, (m_data & TC_INTRDCH)? 1:0); |
| 1712 | | else |
| 1713 | | logerror("%s: register[%d] <- %02x\n", tag(), m_register_pointer, m_data); |
| 1714 | | } |
| 1715 | | m_register_w[m_register_pointer] = m_data; |
| 2204 | // Reset interrupt line (not explicitly mentioned in spec, but seems reasonable |
| 2205 | set_interrupt(CLEAR_LINE); |
| 1716 | 2206 | |
| 1717 | | // The DMA registers and the sector register for read and |
| 1718 | | // write are identical, so in that case we copy the contents |
| 1719 | | if (m_register_pointer < DESIRED_HEAD) m_register_r[m_register_pointer] = m_data; |
| 2207 | // Clear Interrupt Pending and Ready Change |
| 2208 | set_bits(m_register_r[INT_STATUS], ST_INTPEND | ST_RDYCHNG, false); |
| 1720 | 2209 | |
| 1721 | | // Autoincrement until DATA is reached. |
| 1722 | | if (m_register_pointer < DATA) m_register_pointer++; |
| 2210 | // Store command |
| 2211 | UINT8 command = m_data; |
| 2212 | m_register_w[COMMAND] = command; |
| 2213 | m_stop_after_index = false; |
| 2214 | m_wait_for_index = false; |
| 2215 | |
| 2216 | int index = 0; |
| 2217 | bool found = false; |
| 2218 | |
| 2219 | while (s_command[index].mask!=0 && !found) |
| 2220 | { |
| 2221 | if ((command & s_command[index].mask) == s_command[index].baseval) |
| 2222 | { |
| 2223 | // Invoke command |
| 2224 | m_substate = UNDEF; |
| 2225 | found = true; |
| 2226 | m_executing = true; |
| 2227 | m_command = s_command[index].command; |
| 2228 | (this->*m_command)(); |
| 2229 | } |
| 2230 | else index++; |
| 2231 | } |
| 2232 | if (!found) |
| 2233 | { |
| 2234 | logerror("%s: Command %02x not defined\n", tag(), command); |
| 2235 | } |
| 2236 | } |
| 1723 | 2237 | } |
| 1724 | 2238 | |
| 1725 | 2239 | /* |
| r32111 | r32112 | |
| 1762 | 2276 | +------+------+------+------+------+------+------+------+ |
| 1763 | 2277 | | ECC |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault | |
| 1764 | 2278 | +------+------+------+------+------+------+------+------+ |
| 1765 | | |
| 1766 | | |
| 1767 | | OUTPUT1 register contents |
| 1768 | | S0 = 0, S1 = 1 |
| 1769 | | +------+------+------+------+------+------+------+------+ |
| 1770 | | | Drv3 | Drv2 | Drv1 | Drv0 | PO3 | PO2 | PO1 | PO0 | |
| 1771 | | +------+------+------+------+------+------+------+------+ |
| 1772 | | |
| 1773 | | DrvX = select Drive X (only one bit allowed) |
| 1774 | | POX = Programmable output X (contents from low 4 bits of register RETRY_COUNT) |
| 1775 | | |
| 1776 | | |
| 1777 | | OUTPUT2 register contents |
| 1778 | | S0 = 1, S1 = 1 |
| 1779 | | +------+------+------+------+------+------+------+------+ |
| 1780 | | | Drv3*| WCur | Dir | Step | Head | |
| 1781 | | +------+------+------+------+------+------+------+------+ |
| 1782 | | |
| 1783 | | Drv3* = inverted Drv3 signal of OUTPUT1 |
| 1784 | | WCur = Reduced write current |
| 1785 | | Dir = Step direction (0 = towards track 0) |
| 1786 | | Step = Step pulse |
| 1787 | | Head = desired head |
| 1788 | 2279 | */ |
| 1789 | 2280 | |
| 1790 | 2281 | /* |
| r32111 | r32112 | |
| 1797 | 2288 | if (!m_initialized) |
| 1798 | 2289 | return; |
| 1799 | 2290 | |
| 1800 | | if (TRACE_ACT) logerror("%s: Got value %02x via auxbus: ecc=%d index=%d seek_comp=%d tr00=%d user=%d writeprot=%d ready=%d fault=%d\n", |
| 2291 | if (TRACE_AUXBUS) logerror("%s: Got value %02x via auxbus: ecc=%d index=%d seek_comp=%d tr00=%d user=%d writeprot=%d ready=%d fault=%d\n", |
| 1801 | 2292 | tag(), data, |
| 1802 | 2293 | (data&HDC_DS_ECCERR)? 1:0, (data&HDC_DS_INDEX)? 1:0, |
| 1803 | 2294 | (data&HDC_DS_SKCOM)? 1:0, (data&HDC_DS_TRK00)? 1:0, |
| r32111 | r32112 | |
| 1827 | 2318 | |
| 1828 | 2319 | void hdc9234_device::index_callback(int level) |
| 1829 | 2320 | { |
| 1830 | | if (TRACE_ACT) logerror("%s: [%s] Index callback level=%d\n", tag(), ttsn().cstr(), level); |
| 2321 | if (TRACE_LINES) logerror("%s: [%s] Index callback level=%d\n", tag(), ttsn().cstr(), level); |
| 1831 | 2322 | |
| 1832 | 2323 | // Synchronize our position on the track |
| 1833 | 2324 | live_sync(); |
| 1834 | 2325 | |
| 1835 | | if (level==CLEAR_LINE) { |
| 1836 | | general_continue(); |
| 1837 | | return; |
| 1838 | | } |
| 1839 | | else |
| 2326 | if (level==ASSERT_LINE) |
| 1840 | 2327 | { |
| 1841 | | // ... |
| 2328 | if (TRACE_INDEX) logerror("%s: Index pulse\n", tag()); |
| 1842 | 2329 | if (m_wait_for_index) m_stop_after_index = true; |
| 1843 | | general_continue(); |
| 1844 | 2330 | } |
| 2331 | |
| 2332 | reenter_command_processing(); |
| 1845 | 2333 | } |
| 1846 | 2334 | |
| 1847 | 2335 | void hdc9234_device::ready_callback(int level) |
| 1848 | 2336 | { |
| 1849 | | if (TRACE_ACT) logerror("%s: [%s] Ready callback level=%d\n", tag(), ttsn().cstr(), level); |
| 2337 | if (TRACE_LINES) logerror("%s: [%s] Ready callback level=%d\n", tag(), ttsn().cstr(), level); |
| 1850 | 2338 | |
| 1851 | 2339 | // Set the interrupt status flag |
| 1852 | 2340 | set_bits(m_register_r[INT_STATUS], ST_RDYCHNG, true); |
| r32111 | r32112 | |
| 1857 | 2345 | // Raise an interrupt if desired |
| 1858 | 2346 | if (m_register_w[INT_COMM_TERM] & TC_INTRDCH) |
| 1859 | 2347 | { |
| 1860 | | if (TRACE_ACT) logerror("%s: Raise interrupt READY change\n", tag()); |
| 2348 | if (TRACE_INT) logerror("%s: Raise interrupt READY change\n", tag()); |
| 1861 | 2349 | set_interrupt(ASSERT_LINE); |
| 1862 | 2350 | } |
| 2351 | |
| 2352 | // reenter_command_processing(); |
| 1863 | 2353 | } |
| 1864 | 2354 | |
| 1865 | 2355 | void hdc9234_device::seek_complete_callback(int level) |
| 1866 | 2356 | { |
| 1867 | | if (TRACE_ACT) logerror("%s: [%s] Seek complete callback level=%d\n", tag(), ttsn().cstr(), level); |
| 2357 | if (TRACE_LINES) logerror("%s: [%s] Seek complete callback level=%d\n", tag(), ttsn().cstr(), level); |
| 1868 | 2358 | |
| 1869 | 2359 | // Synchronize our position on the track |
| 1870 | 2360 | live_sync(); |
| 1871 | 2361 | |
| 1872 | | if (level==ASSERT_LINE && m_next_state != UNDEF) |
| 2362 | if (level==ASSERT_LINE && m_state_after_line != UNDEF) |
| 1873 | 2363 | { |
| 1874 | | m_substate = m_next_state; |
| 1875 | | general_continue(); |
| 2364 | m_substate = m_state_after_line; |
| 2365 | m_state_after_line = UNDEF; |
| 2366 | reenter_command_processing(); |
| 1876 | 2367 | } |
| 1877 | 2368 | } |
| 1878 | 2369 | |
| 1879 | 2370 | void hdc9234_device::wait_line(int substate) |
| 1880 | 2371 | { |
| 1881 | | m_next_state = substate; |
| 2372 | m_state_after_line = substate; |
| 1882 | 2373 | } |
| 1883 | 2374 | |
| 1884 | 2375 | bool hdc9234_device::on_track00() |
| r32111 | r32112 | |
| 1889 | 2380 | /* |
| 1890 | 2381 | Push the output registers over the auxiliary bus. It is expected that |
| 1891 | 2382 | the PCB contains latches to store the values. |
| 2383 | |
| 2384 | OUTPUT1 register contents |
| 2385 | S0 = 0, S1 = 1 |
| 2386 | +------+------+------+------+------+------+------+------+ |
| 2387 | | Drv3 | Drv2 | Drv1 | Drv0 | PO3 | PO2 | PO1 | PO0 | |
| 2388 | +------+------+------+------+------+------+------+------+ |
| 2389 | |
| 2390 | DrvX = select Drive X (only one bit allowed) |
| 2391 | POX = Programmable output X (contents from low 4 bits of register RETRY_COUNT) |
| 2392 | |
| 2393 | |
| 2394 | OUTPUT2 register contents |
| 2395 | S0 = 1, S1 = 1 |
| 2396 | +------+------+------+------+------+------+------+------+ |
| 2397 | | Drv3*| WCur | Dir | Step | Head | |
| 2398 | +------+------+------+------+------+------+------+------+ |
| 2399 | |
| 2400 | Drv3* = inverted Drv3 signal of OUTPUT1 |
| 2401 | WCur = Reduced write current |
| 2402 | Dir = Step direction (0 = towards track 0) |
| 2403 | Step = Step pulse |
| 2404 | Head = desired head |
| 1892 | 2405 | */ |
| 1893 | | void hdc9234_device::sync_latches_out() |
| 2406 | void hdc9234_device::auxbus_out() |
| 1894 | 2407 | { |
| 1895 | | if (TRACE_ACT) logerror("%s: Setting OUTPUT1 to %02x\n", tag(), m_output1); |
| 2408 | if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT1 to %02x\n", tag(), m_output1); |
| 1896 | 2409 | m_out_auxbus((offs_t)HDC_OUTPUT_1, m_output1); |
| 1897 | | set_bits(m_output2, OUT2_DRVSEL3I, (m_output1 & 0x80)==0); |
| 1898 | | if (TRACE_ACT) logerror("%s: Setting OUTPUT2 to %02x\n", tag(), m_output2); |
| 2410 | |
| 2411 | // prepare output2 |
| 2412 | set_bits(m_output2, OUT2_DRVSEL3I, (m_output1 & OUT1_DRVSEL3)==0); |
| 2413 | |
| 2414 | m_output2 = (m_output2 & 0xb0) | desired_head(); |
| 2415 | if (m_reduced_write_current) m_output2 |= OUT2_REDWRT; |
| 2416 | |
| 2417 | if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT2 to %02x\n", tag(), m_output2); |
| 1899 | 2418 | m_out_auxbus((offs_t)HDC_OUTPUT_2, m_output2); |
| 1900 | 2419 | } |
| 1901 | 2420 | |
| r32111 | r32112 | |
| 1912 | 2431 | */ |
| 1913 | 2432 | void hdc9234_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 1914 | 2433 | { |
| 1915 | | if (TRACE_ACT) logerror("%s: [%s] Timer id=%d expired\n", tag(), ttsn().cstr(), id); |
| 1916 | 2434 | live_sync(); |
| 1917 | 2435 | |
| 1918 | 2436 | switch (id) |
| 1919 | 2437 | { |
| 1920 | 2438 | case GEN_TIMER: |
| 1921 | | general_continue(); |
| 2439 | reenter_command_processing(); |
| 1922 | 2440 | break; |
| 1923 | 2441 | case COM_TIMER: |
| 1924 | | if (m_substate==1) command_continue(); |
| 1925 | | else register_write_continue(); |
| 2442 | process_command(); |
| 1926 | 2443 | break; |
| 1927 | 2444 | case LIVE_TIMER: |
| 1928 | 2445 | live_run(); |
| r32111 | r32112 | |
| 1937 | 2454 | { |
| 1938 | 2455 | if (state==ASSERT_LINE) |
| 1939 | 2456 | { |
| 1940 | | if (TRACE_ACT) logerror("%s: [%s] DMA acknowledged\n", tag(), ttsn().cstr()); |
| 2457 | if (TRACE_LINES) logerror("%s: [%s] DMA acknowledged\n", tag(), ttsn().cstr()); |
| 1941 | 2458 | set_bits(m_register_r[INT_STATUS], ST_OVRUN, false); |
| 1942 | 2459 | } |
| 1943 | 2460 | } |
| r32111 | r32112 | |
| 1978 | 2495 | |
| 1979 | 2496 | m_selected_drive_type = 0; |
| 1980 | 2497 | m_head_load_delay_enable = false; |
| 2498 | |
| 1981 | 2499 | m_register_pointer = 0; |
| 2500 | |
| 1982 | 2501 | m_output1 = 0; |
| 1983 | 2502 | m_output2 = 0x80; |
| 1984 | 2503 | |
| r32111 | r32112 | |
| 1989 | 2508 | for (int i=0; i<=11; i++) |
| 1990 | 2509 | m_register_r[i] = m_register_w[i] = 0; |
| 1991 | 2510 | |
| 1992 | | m_step_direction = 0; |
| 1993 | | |
| 1994 | | m_next_state = IDLE; |
| 2511 | m_state_after_line = UNDEF; |
| 1995 | 2512 | m_seek_count = 0; |
| 1996 | 2513 | |
| 1997 | 2514 | m_live_state.time = attotime::never; |
| 1998 | 2515 | m_live_state.state = IDLE; |
| 1999 | | m_initialized = true; |
| 2000 | 2516 | |
| 2001 | 2517 | m_track_delta = 0; |
| 2002 | 2518 | |
| 2003 | 2519 | m_multi_sector = false; |
| 2004 | 2520 | m_retry_save = 0; |
| 2005 | 2521 | |
| 2006 | | m_substate = IDLE; |
| 2007 | | m_main_state = IDLE; |
| 2008 | | m_command = NOCMD; |
| 2522 | m_substate = UNDEF; |
| 2009 | 2523 | |
| 2524 | m_executing = false; |
| 2525 | |
| 2010 | 2526 | m_stop_after_index = false; |
| 2011 | 2527 | m_wait_for_index = false; |
| 2012 | 2528 | |
| 2529 | m_transfer_enabled = true; |
| 2530 | m_write = false; |
| 2531 | m_deleted = false; |
| 2532 | |
| 2013 | 2533 | m_data = 0; |
| 2534 | m_precompensation = 0; |
| 2535 | m_reduced_write_current = false; |
| 2536 | |
| 2537 | m_initialized = true; |
| 2014 | 2538 | } |
| 2015 | 2539 | |
| 2016 | 2540 | const device_type HDC9234 = &device_creator<hdc9234_device>; |