trunk/src/emu/machine/hdc9234.c
r32473 | r32474 | |
34 | 34 | #define TRACE_SETREG 0 |
35 | 35 | #define TRACE_SETPTR 0 |
36 | 36 | #define TRACE_FORMAT 0 |
| 37 | #define TRACE_READTRACK 0 |
37 | 38 | |
38 | 39 | // Common states |
39 | 40 | #define TRACE_READID 0 |
r32473 | r32474 | |
59 | 60 | |
60 | 61 | #define UNRELIABLE_MEDIA 0 |
61 | 62 | |
62 | | // Not implemented: |
63 | | // Poll drives |
64 | | // Seek/Read ID |
65 | | // Read track |
66 | | // Write long (variant of the write operation, selectable by MODE register) |
67 | | // Tape operations |
| 63 | /* |
| 64 | === Not implemented === |
| 65 | ECC |
| 66 | Write long (see MODE register; only useful with ECC) |
| 67 | Tape operations |
| 68 | Hard disk operation |
68 | 69 | |
69 | | // Untested: |
70 | | // Multi-sector read/write |
71 | | // Seek complete |
72 | | // Read/write sectors physical |
| 70 | === Implemented but untested === |
| 71 | Burst mode |
| 72 | Restore |
| 73 | Poll drives |
| 74 | Seek/Read ID |
| 75 | Multi-sector read/write |
| 76 | Usage of seek complete |
| 77 | Read/write sectors physical |
| 78 | Read track |
| 79 | */ |
73 | 80 | |
74 | | // TDF |
75 | | |
76 | 81 | /* |
77 | | Register names of the HDC. The left part is the set of write registers, |
78 | | while the right part are the read registers. |
| 82 | Some registers of the HDC. |
79 | 83 | |
80 | 84 | +------+------+------+------+------+------+------+------+ |
81 | 85 | DHEAD: | 0 | Sector size | 0 | Desired head (OUTPUT2) | AT mode |
r32473 | r32474 | |
299 | 303 | |
300 | 304 | STEP_ON, |
301 | 305 | STEP_OFF, |
302 | | RESTORE_CHECK1, |
303 | | RESTORE_CHECK2, |
| 306 | RESTORE_CHECK, |
| 307 | WAIT_SEEK_COMPLETE, |
304 | 308 | SEEK_COMPLETE, |
305 | 309 | HEAD_DELAY, |
306 | 310 | WAITINDEX0, |
307 | 311 | WAITINDEX1, |
308 | 312 | TRACKSTART, |
309 | 313 | TRACKDONE, |
| 314 | POLL1, |
| 315 | POLL2, |
| 316 | POLL3, |
310 | 317 | |
311 | 318 | READ_ID = 0x40, |
312 | 319 | READ_ID1, |
313 | 320 | READ_ID_STEPON, |
314 | 321 | READ_ID_STEPOFF, |
| 322 | READ_ID_SEEK_COMPLETE, |
315 | 323 | |
316 | 324 | VERIFY = 0x50, |
317 | 325 | VERIFY1, |
r32473 | r32474 | |
367 | 375 | WRITE_DONE, |
368 | 376 | WRITE_HEADER_CRC, |
369 | 377 | |
| 378 | READ_TRACK, |
| 379 | READ_TRACK_ID, |
| 380 | READ_TRACK_ID_DONE, |
| 381 | |
370 | 382 | NO_DMA_ACK |
371 | 383 | }; |
372 | 384 | |
r32473 | r32474 | |
476 | 488 | |
477 | 489 | int hdc9234_device::current_cylinder() |
478 | 490 | { |
| 491 | int abc = 0; |
479 | 492 | return (m_register_r[CURRENT_CYLINDER] & 0xff) | (m_register_r[CURRENT_HEAD] & 0x70); |
480 | 493 | } |
481 | 494 | |
r32473 | r32474 | |
489 | 502 | return m_register_w[COMMAND]; |
490 | 503 | } |
491 | 504 | |
| 505 | bool hdc9234_device::using_floppy() |
| 506 | { |
| 507 | return (m_selected_drive_type == TYPE_FLOPPY5 || m_selected_drive_type == TYPE_FLOPPY8); |
| 508 | } |
| 509 | |
492 | 510 | /* |
493 | | Set/clear INT |
494 | | |
495 | | Interupts are generated in the following occasions: |
496 | | - when the DONE bit is set to 1 in the ISR and ST_DONE is set to 1 |
497 | | - when the READY_CHANGE bit is set to 1 in the ISR and ST_RDYCHNG is set to 1 |
498 | | (ready change: 1->0 or 0->1) |
| 511 | Delivers the step time (in microseconds) minus the pulse width |
499 | 512 | */ |
500 | | void hdc9234_device::set_interrupt(line_state intr) |
| 513 | int hdc9234_device::step_time() |
501 | 514 | { |
502 | | if (intr == ASSERT_LINE) |
503 | | { |
504 | | // Only if there is not already a pending interrupt |
505 | | if ((m_register_r[INT_STATUS] & ST_INTPEND) == 0) |
506 | | { |
507 | | m_register_r[INT_STATUS] |= ST_INTPEND; |
508 | | m_out_intrq(intr); |
509 | | } |
510 | | } |
| 515 | int time = 0; |
| 516 | int index = m_register_w[MODE] & MO_STEPRATE; |
| 517 | // Get seek time. |
| 518 | if (m_selected_drive_type == TYPE_FLOPPY8) |
| 519 | time = step_flop8[index] - pulse_flop8; |
| 520 | |
| 521 | else if (m_selected_drive_type == TYPE_FLOPPY5) |
| 522 | time = step_flop5[index] - pulse_flop5; |
511 | 523 | else |
512 | | { |
513 | | // if there is a pending interrupt |
514 | | if ((m_register_r[INT_STATUS] & ST_INTPEND) != 0) |
515 | | m_out_intrq(intr); |
516 | | } |
| 524 | time = step_hd[index] - pulse_hd; |
| 525 | |
| 526 | if (fm_mode()) time = time * 2; |
| 527 | return time; |
517 | 528 | } |
518 | 529 | |
519 | 530 | /* |
520 | | Assert Command Done status bit, triggering interrupts as needed |
| 531 | Delivers the pulse width time (in microseconds) |
521 | 532 | */ |
522 | | void hdc9234_device::set_command_done(int flags) |
| 533 | int hdc9234_device::pulse_width() |
523 | 534 | { |
524 | | set_bits(m_register_r[INT_STATUS], ST_DONE, true); |
| 535 | int time = 0; |
| 536 | // Get seek time. |
| 537 | if (m_selected_drive_type == TYPE_FLOPPY8) |
| 538 | time = pulse_flop8; |
525 | 539 | |
526 | | if (flags != -1) |
527 | | { |
528 | | set_bits(m_register_r[INT_STATUS], ST_TERMCOD, false); // clear the previously set flags |
529 | | m_register_r[INT_STATUS] |= flags; |
530 | | if (TRACE_DONE) logerror("%s: command %02x done, flags=%02x\n", tag(), current_command(), flags); |
531 | | } |
| 540 | else if (m_selected_drive_type == TYPE_FLOPPY5) |
| 541 | time = pulse_flop5; |
532 | 542 | else |
533 | | { |
534 | | if (TRACE_DONE) logerror("%s: command %02x done\n", tag(), current_command()); |
535 | | } |
| 543 | time = pulse_hd; |
536 | 544 | |
537 | | // [1], p. 6 |
538 | | if (TRACE_INT) logerror("%s: Raise interrupt DONE\n", tag()); |
539 | | set_interrupt(ASSERT_LINE); |
| 545 | if (fm_mode()) time = time * 2; |
| 546 | return time; |
| 547 | } |
540 | 548 | |
541 | | m_substate = UNDEF; |
542 | | m_executing = false; |
| 549 | bool hdc9234_device::rapid_steps() |
| 550 | { |
| 551 | return (m_register_w[MODE] & MO_STEPRATE) == 0; |
543 | 552 | } |
544 | 553 | |
545 | 554 | /* |
546 | | Preserve previously set termination code |
| 555 | Delivers the sector size |
547 | 556 | */ |
548 | | void hdc9234_device::set_command_done() |
| 557 | int hdc9234_device::calc_sector_size() |
549 | 558 | { |
550 | | set_command_done(-1); |
| 559 | return 128 << (m_register_r[CURRENT_SIZE] & 3); |
551 | 560 | } |
552 | 561 | |
| 562 | // =========================================================================== |
| 563 | // Wait handling |
| 564 | // We can wait for a given time period or for a line to be set or cleared |
| 565 | // =========================================================================== |
| 566 | |
553 | 567 | void hdc9234_device::wait_time(emu_timer *tm, int microsec, int next_substate) |
554 | 568 | { |
555 | 569 | if (TRACE_DELAY) logerror("%s: Delay by %d microsec\n", tag(), microsec); |
r32473 | r32474 | |
564 | 578 | m_substate = param; |
565 | 579 | } |
566 | 580 | |
| 581 | /* |
| 582 | Set the hook for line level handling |
| 583 | */ |
| 584 | void hdc9234_device::wait_line(int line, line_state level, int substate, bool stopwrite) |
| 585 | { |
| 586 | m_event_line = line; |
| 587 | m_line_level = level; |
| 588 | m_state_after_line = substate; |
| 589 | m_stopwrite = stopwrite; |
| 590 | } |
| 591 | |
567 | 592 | // ================================================================== |
568 | 593 | // Common subroutines READ ID, VERIFY, DATA TRANSFER |
569 | 594 | // called by all sector access commands |
r32473 | r32474 | |
578 | 603 | (must have saved that value before!) |
579 | 604 | - steps to that location during OUTPUT2 times |
580 | 605 | */ |
581 | | void hdc9234_device::read_id(int& cont, bool implied_seek) |
| 606 | void hdc9234_device::read_id(int& cont, bool implied_seek, bool wait_seek_complete) |
582 | 607 | { |
583 | 608 | cont = CONTINUE; |
584 | 609 | |
r32473 | r32474 | |
590 | 615 | // Implied seek: Enter the READ_ID subprogram. |
591 | 616 | if (TRACE_READID && TRACE_SUBSTATES) logerror("%s: substate READ_ID\n", tag()); |
592 | 617 | |
593 | | m_substate = implied_seek? READ_ID1 : VERIFY; |
594 | | |
595 | 618 | // First step: Search the next IDAM, and if found, read the |
596 | 619 | // ID values into the registers |
597 | | // Depending on the implied seek flag, continue with the read_id, |
| 620 | |
| 621 | // Depending on the implied seek flag, continue with read_id, |
598 | 622 | // else switch to verify. |
| 623 | m_substate = implied_seek? READ_ID1 : VERIFY; |
| 624 | |
599 | 625 | m_live_state.bit_count_total = 0; |
600 | 626 | live_start(SEARCH_IDAM); |
601 | 627 | cont = WAIT; |
r32473 | r32474 | |
638 | 664 | // Any more steps left? |
639 | 665 | if (m_track_delta == 0) |
640 | 666 | { |
641 | | m_substate = VERIFY; |
642 | | cont = NEXT; |
| 667 | if (wait_seek_complete) |
| 668 | { |
| 669 | // We have to wait for SEEK COMPLETE |
| 670 | wait_line(SEEKCOMP_LINE, ASSERT_LINE, READ_ID_SEEK_COMPLETE, false); |
| 671 | cont = WAIT; |
| 672 | } |
| 673 | else |
| 674 | { |
| 675 | // We do not wait for SEEK COMPLETE |
| 676 | m_substate = VERIFY; |
| 677 | cont = NEXT; |
| 678 | } |
643 | 679 | break; |
644 | 680 | } |
645 | 681 | |
r32473 | r32474 | |
647 | 683 | // STEPDIR = 0 -> towards TRK00 |
648 | 684 | set_bits(m_output2, OUT2_STEPDIR, (m_track_delta>0)); |
649 | 685 | set_bits(m_output2, OUT2_STEPPULSE, true); |
650 | | auxbus_out(); |
651 | 686 | wait_time(m_timer, pulse_width(), READ_ID_STEPOFF); |
652 | 687 | cont = WAIT; |
653 | 688 | break; |
r32473 | r32474 | |
655 | 690 | case READ_ID_STEPOFF: |
656 | 691 | if (TRACE_READID && TRACE_SUBSTATES) logerror("%s: substate STEP_OFF\n", tag()); |
657 | 692 | set_bits(m_output2, OUT2_STEPPULSE, false); |
658 | | auxbus_out(); |
659 | 693 | m_track_delta += (m_track_delta<0)? 1 : -1; |
660 | 694 | // Return to STEP_ON, check whether there are more steps |
661 | 695 | wait_time(m_timer, step_time(), READ_ID_STEPON); |
662 | 696 | cont = WAIT; |
663 | 697 | break; |
664 | 698 | |
| 699 | case READ_ID_SEEK_COMPLETE: |
| 700 | m_substate = VERIFY; |
| 701 | cont = NEXT; |
| 702 | break; |
| 703 | |
665 | 704 | default: |
666 | 705 | logerror("%s: unknown substate %d in read_id\n", tag(), m_substate); |
667 | 706 | cont = ERROR; |
r32473 | r32474 | |
958 | 997 | |
959 | 998 | /* |
960 | 999 | RESET |
| 1000 | Reset the controller. This has the same effect as asserting the RST* input line. |
| 1001 | |
| 1002 | Command word |
| 1003 | |
| 1004 | 7 6 5 4 3 2 1 0 |
| 1005 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1006 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
| 1007 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1008 | |
961 | 1009 | */ |
962 | 1010 | void hdc9234_device::reset_controller() |
963 | 1011 | { |
964 | 1012 | logerror("%s: RESET command\n", tag()); |
965 | 1013 | device_reset(); |
966 | 1014 | } |
| 1015 | |
967 | 1016 | /* |
968 | 1017 | DESELECT DRIVE |
| 1018 | Deselect all drives. |
| 1019 | |
| 1020 | Command word |
| 1021 | |
| 1022 | 7 6 5 4 3 2 1 0 |
| 1023 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1024 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |
| 1025 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
969 | 1026 | */ |
970 | 1027 | void hdc9234_device::drive_deselect() |
971 | 1028 | { |
972 | 1029 | if (TRACE_SELECT) logerror("%s: DESELECT command\n", tag()); |
973 | 1030 | m_selected_drive_number = NODRIVE; |
974 | | auxbus_out(); |
975 | 1031 | set_command_done(TC_SUCCESS); |
976 | 1032 | } |
977 | 1033 | |
978 | 1034 | /* |
979 | | // RESTORE DRIVE |
980 | | // bit 0: |
981 | | // 0 -> command ends after last seek pulse, |
982 | | // 1 -> command ends when the drive asserts the seek complete pin |
| 1035 | RESTORE DRIVE |
| 1036 | Moves the heads to cylinder 0. If skcom is set, the command terminates |
| 1037 | after the SEEK COMPLETE line is set. |
| 1038 | |
| 1039 | Command word |
| 1040 | |
| 1041 | 7 6 5 4 3 2 1 0 |
| 1042 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1043 | | 0 | 0 | 0 | 0 | 0 | 0 | 1 |skcom| |
| 1044 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
983 | 1045 | */ |
984 | 1046 | void hdc9234_device::restore_drive() |
985 | 1047 | { |
986 | 1048 | int cont = CONTINUE; |
| 1049 | bool buffered_step = current_command() & 1; |
987 | 1050 | |
988 | 1051 | // The substate is set to UNDEF when the command is started; |
989 | | // when we return here after a pause, the substate is set to some other value |
| 1052 | // when we reenter the command processing after a pause, the substate is set to some other value |
990 | 1053 | // In wd_fdc this is solved using two methods <command>_start and <command>_continue |
| 1054 | |
991 | 1055 | if (m_substate == UNDEF) |
992 | 1056 | { |
993 | 1057 | if (TRACE_RESTORE) logerror("%s: RESTORE command %02x\n", tag(), current_command()); |
994 | 1058 | m_seek_count = 0; |
995 | | m_substate = RESTORE_CHECK1; |
| 1059 | m_substate = RESTORE_CHECK; |
996 | 1060 | } |
997 | 1061 | |
998 | 1062 | while (cont==CONTINUE) |
999 | 1063 | { |
1000 | 1064 | switch (m_substate) |
1001 | 1065 | { |
1002 | | case RESTORE_CHECK1: |
1003 | | if (TRACE_RESTORE && TRACE_SUBSTATES) logerror("%s: substate RESTORE_CHECK; seek count = %d\n", tag(), m_seek_count); |
1004 | | // If the drive is on track 0 or not ready (no drive), terminate the command |
1005 | | if (on_track00()) |
| 1066 | case RESTORE_CHECK: |
| 1067 | // Track 0 has not been reached yet |
| 1068 | if ((m_register_r[DRIVE_STATUS] & HDC_DS_READY)==0) |
1006 | 1069 | { |
1007 | | if (TRACE_RESTORE) logerror("%s: restore command TRK00 reached\n", tag()); |
1008 | | if (current_command() & 1) |
| 1070 | if (TRACE_RESTORE) logerror("%s: restore command: drive not ready\n", tag()); |
| 1071 | // Does not look like a success, but this takes into account |
| 1072 | // that if a drive is not connected we do not want an error message |
| 1073 | cont = SUCCESS; |
| 1074 | break; |
| 1075 | } |
| 1076 | |
| 1077 | // Are we done? |
| 1078 | if (m_seek_count>=4096 || on_track00()) |
| 1079 | { |
| 1080 | if (buffered_step) |
1009 | 1081 | { |
1010 | | // Buffered seek; wait for SEEK_COMPLETE |
| 1082 | // When we have buffered steps, the seek limit will be reached |
| 1083 | // before TRK00 is asserted. In that case we have to wait for |
| 1084 | // SEEK_COMPLETE. We also wait as soon as TRK00 is asserted. |
1011 | 1085 | wait_line(SEEKCOMP_LINE, ASSERT_LINE, SEEK_COMPLETE, false); |
1012 | 1086 | cont = WAIT; |
1013 | 1087 | } |
1014 | 1088 | else |
1015 | 1089 | { |
1016 | | cont = SUCCESS; |
| 1090 | // No buffered seek. If the seek limit has been reached |
| 1091 | // and TRK00 is not true, we failed. This will be decided below. |
| 1092 | m_substate = SEEK_COMPLETE; |
1017 | 1093 | } |
1018 | | break; |
1019 | 1094 | } |
1020 | | m_substate = RESTORE_CHECK2; |
| 1095 | else m_substate = STEP_ON; |
1021 | 1096 | break; |
1022 | 1097 | |
1023 | | case RESTORE_CHECK2: |
1024 | | // Track 0 has not been reached yet |
1025 | | if ((m_register_r[DRIVE_STATUS] & HDC_DS_READY)==0) |
1026 | | { |
1027 | | if (TRACE_RESTORE) logerror("%s: restore command: drive not ready\n", tag()); |
1028 | | // Does not look like a success, but this takes into account |
1029 | | // that if a drive is not connected we do not want an error message |
1030 | | cont = SUCCESS; |
1031 | | break; |
1032 | | } |
| 1098 | case STEP_ON: |
| 1099 | if (TRACE_RESTORE && TRACE_SUBSTATES) logerror("%s: substate STEP_ON\n", tag()); |
1033 | 1100 | |
1034 | 1101 | // Increase step count |
1035 | 1102 | m_seek_count++; |
1036 | | if (m_seek_count>=4096) |
1037 | | { |
1038 | | if (TRACE_FAIL) logerror("%s: restore command: failed to reach track 00\n", tag()); |
1039 | | set_command_done(TC_VRFYERR); |
1040 | | cont = ERROR; |
1041 | | break; |
1042 | | } |
1043 | 1103 | |
1044 | | step_on(true, STEP_OFF); |
| 1104 | // STEPDIR = 0 -> towards TRK00 |
| 1105 | set_bits(m_output2, OUT2_STEPDIR, false); |
| 1106 | |
| 1107 | // Raising edge (note that all signals must be inverted before leading them to the drive) |
| 1108 | set_bits(m_output2, OUT2_STEPPULSE, true); |
| 1109 | wait_time(m_timer, pulse_width(), STEP_OFF); |
1045 | 1110 | cont = WAIT; |
1046 | 1111 | break; |
1047 | 1112 | |
1048 | 1113 | case STEP_OFF: |
1049 | | step_off(RESTORE_CHECK1); |
| 1114 | if (TRACE_RESTORE && TRACE_SUBSTATES) logerror("%s: substate STEP_OFF\n", tag()); |
| 1115 | set_bits(m_output2, OUT2_STEPPULSE, false); |
| 1116 | wait_time(m_timer, step_time(), RESTORE_CHECK); |
1050 | 1117 | cont = WAIT; |
1051 | 1118 | break; |
1052 | 1119 | |
1053 | 1120 | case SEEK_COMPLETE: |
1054 | | cont = SUCCESS; |
| 1121 | // If TRK00 is not set, the drive failed to reach it. |
| 1122 | if (!on_track00()) |
| 1123 | { |
| 1124 | if (TRACE_FAIL) logerror("%s: restore command: failed to reach track 00\n", tag()); |
| 1125 | set_command_done(TC_VRFYERR); |
| 1126 | cont = ERROR; |
| 1127 | } |
| 1128 | else |
| 1129 | cont = SUCCESS; |
1055 | 1130 | break; |
1056 | 1131 | } |
1057 | 1132 | } |
r32473 | r32474 | |
1060 | 1135 | |
1061 | 1136 | /* |
1062 | 1137 | STEP IN / OUT 1 CYLINDER |
| 1138 | Move the heads 1 step towards the center (in) or towards the outermost |
| 1139 | track (out). |
| 1140 | |
| 1141 | Command word |
| 1142 | |
| 1143 | 7 6 5 4 3 2 1 0 |
| 1144 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1145 | | 0 | 0 | 0 | 0 | 0 | 1 | out |skcom| |
| 1146 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1147 | |
1063 | 1148 | */ |
1064 | 1149 | void hdc9234_device::step_drive() |
1065 | 1150 | { |
r32473 | r32474 | |
1076 | 1161 | switch (m_substate) |
1077 | 1162 | { |
1078 | 1163 | case STEP_ON: |
1079 | | step_on((current_command() & 0x02)!=0, STEP_OFF); |
| 1164 | if (TRACE_STEP && TRACE_SUBSTATES) logerror("%s: substate STEP_ON\n", tag()); |
| 1165 | |
| 1166 | // STEPDIR = 0 -> towards TRK00 |
| 1167 | set_bits(m_output2, OUT2_STEPDIR, (current_command() & 0x02)==0); |
| 1168 | |
| 1169 | // Raising edge (note that all signals must be inverted before leading them to the drive) |
| 1170 | set_bits(m_output2, OUT2_STEPPULSE, true); |
| 1171 | wait_time(m_timer, pulse_width(), STEP_OFF); |
1080 | 1172 | cont = WAIT; |
1081 | 1173 | break; |
| 1174 | |
1082 | 1175 | case STEP_OFF: |
1083 | | step_off(DONE); |
| 1176 | if (TRACE_STEP && TRACE_SUBSTATES) logerror("%s: substate STEP_OFF\n", tag()); |
| 1177 | set_bits(m_output2, OUT2_STEPPULSE, false); |
| 1178 | wait_time(m_timer, step_time(), ((current_command() & 0x01)!=0)? WAIT_SEEK_COMPLETE : DONE); |
1084 | 1179 | cont = WAIT; |
1085 | 1180 | break; |
| 1181 | |
| 1182 | case WAIT_SEEK_COMPLETE: |
| 1183 | wait_line(SEEKCOMP_LINE, ASSERT_LINE, DONE, false); |
| 1184 | cont = WAIT; |
| 1185 | break; |
| 1186 | |
1086 | 1187 | case DONE: |
1087 | 1188 | cont = SUCCESS; |
1088 | 1189 | break; |
r32473 | r32474 | |
1103 | 1204 | |
1104 | 1205 | /* |
1105 | 1206 | POLL DRIVES |
1106 | | Not implemented |
| 1207 | Repeat |
| 1208 | - i = i+1 % 4 |
| 1209 | - select drive if its bit is set in the command word |
| 1210 | until seek_complete is true. |
| 1211 | |
| 1212 | Command word |
| 1213 | |
| 1214 | 7 6 5 4 3 2 1 0 |
| 1215 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1216 | | 0 | 0 | 0 | 1 | Drv3| Drv2| Drv1| Drv0| |
| 1217 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1218 | |
| 1219 | This command only sets the select lines but does not process parameters |
| 1220 | like head load times or drive types. |
1107 | 1221 | */ |
1108 | 1222 | void hdc9234_device::poll_drives() |
1109 | 1223 | { |
1110 | | logerror("%s: POLL DRIVES command %02x not implemented\n", tag(), current_command()); |
1111 | | set_command_done(TC_SUCCESS); |
| 1224 | UINT8 drivebit = 0; |
| 1225 | if (m_substate == UNDEF) |
| 1226 | { |
| 1227 | logerror("%s: POLL DRIVES command %02x\n", tag(), current_command()); |
| 1228 | m_substate = POLL1; |
| 1229 | m_selected_drive_number = 0; |
| 1230 | // If there is no selection, do not enter the loop |
| 1231 | if ((current_command() & 0x0f)==0) m_substate = DONE; |
| 1232 | } |
| 1233 | |
| 1234 | int cont = CONTINUE; |
| 1235 | |
| 1236 | while (cont==CONTINUE) |
| 1237 | { |
| 1238 | switch (m_substate) |
| 1239 | { |
| 1240 | case POLL1: |
| 1241 | drivebit = (1 << m_selected_drive_number) & 0x0f; |
| 1242 | |
| 1243 | if ((current_command() & drivebit) != 0) |
| 1244 | { |
| 1245 | // Test this drive |
| 1246 | m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | m_selected_drive_number; |
| 1247 | |
| 1248 | m_output1 = (drivebit << 4) | (m_register_w[RETRY_COUNT]&0x0f); |
| 1249 | if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT1 to %02x\n", tag(), m_output1); |
| 1250 | wait_time(m_timer, 1, POLL2); // Wait for 1 usec |
| 1251 | cont = WAIT; |
| 1252 | } |
| 1253 | else |
| 1254 | m_substate = POLL3; |
| 1255 | |
| 1256 | break; |
| 1257 | |
| 1258 | case POLL2: |
| 1259 | if ((m_register_r[DRIVE_STATUS] & HDC_DS_SKCOM)!=0) |
| 1260 | { |
| 1261 | // Seek complete has been set |
| 1262 | m_substate = DONE; |
| 1263 | // Selected drive is still found in the chip status register |
| 1264 | } |
| 1265 | else m_substate = POLL3; |
| 1266 | break; |
| 1267 | |
| 1268 | case POLL3: |
| 1269 | m_selected_drive_number = (m_selected_drive_number + 1) & 0x03; |
| 1270 | m_substate = POLL1; |
| 1271 | break; |
| 1272 | |
| 1273 | case DONE: |
| 1274 | cont = SUCCESS; |
| 1275 | break; |
| 1276 | } |
| 1277 | } |
| 1278 | |
| 1279 | if (cont==SUCCESS) set_command_done(TC_SUCCESS); |
1112 | 1280 | } |
1113 | 1281 | |
1114 | 1282 | /* |
1115 | 1283 | DRIVE SELECT |
| 1284 | Selects a drive. With this command, parameters for the drive are also |
| 1285 | defined, like the type of drive (Floppy 8" or 5", AT Hard disk, or generic |
| 1286 | Hard disk), the drive number, and the head load delay. |
1116 | 1287 | |
1117 | | Command word |
| 1288 | On the next OUTPUT1 time, the number of the drive (one of four lines) |
| 1289 | is set on the higher four bits of the auxiliary bus. Also, the lower |
| 1290 | 4 bits of the RETRY COUNT register are put on the lower 4 bits of the bus |
| 1291 | (user-programmable output, [1] p. 5). |
1118 | 1292 | |
| 1293 | The HFDC controller board uses the user-programmable output to |
| 1294 | select one of four floppy disk drives with Drive set to 00. |
| 1295 | Drive codes 01, 10, and 11 remain for three hard disk drives. |
| 1296 | |
| 1297 | Command word |
| 1298 | |
1119 | 1299 | 7 6 5 4 3 2 1 0 |
1120 | 1300 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
1121 | 1301 | | 0 | 0 | 1 |Delay| Type | Drive | |
1122 | 1302 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
1123 | | |
1124 | | [1] p.5: lower 4 bits of RETRY COUNT register (user programmable output) is put on OUTPUT1 |
1125 | | |
1126 | | The HFDC controller board uses the user programmable output to |
1127 | | select one of four floppy disk drives with Drive set to 00. |
1128 | | Drive codes 01, 10, and 11 remain for three hard disk drives. |
1129 | 1303 | */ |
1130 | 1304 | |
1131 | 1305 | void hdc9234_device::drive_select() |
r32473 | r32474 | |
1162 | 1336 | m_output1 = (m_selected_drive_number != NODRIVE)? (0x10 << m_selected_drive_number) : 0; |
1163 | 1337 | m_output1 |= (m_register_w[RETRY_COUNT]&0x0f); |
1164 | 1338 | if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT1 to %02x\n", tag(), m_output1); |
1165 | | |
1166 | | auxbus_out(); |
1167 | | |
1168 | 1339 | m_substate = (head_load_delay>0)? HEAD_DELAY : DONE; |
1169 | 1340 | } |
1170 | 1341 | |
r32473 | r32474 | |
1208 | 1379 | |
1209 | 1380 | /* |
1210 | 1381 | SEEK / READ ID |
1211 | | Not implemented |
| 1382 | This command is used to move the head to the desired cylinder. |
| 1383 | Depending on the Verify setting, the target sector is sought on the |
| 1384 | track, else the command terminates after the step pulses have been issued. |
| 1385 | |
| 1386 | Command word |
| 1387 | |
| 1388 | 7 6 5 4 3 2 1 0 |
| 1389 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1390 | | 0 | 1 | 0 | 1 | 0 | Step| Seek| Verf| |
| 1391 | +-----+-----+-----+-----+-----+-----+-----+-----+ |
| 1392 | |
| 1393 | All combinations of flags are legal ([1], p.12). |
1212 | 1394 | */ |
1213 | 1395 | void hdc9234_device::seek_read_id() |
1214 | 1396 | { |
1215 | | logerror("%s: SEEK / READ ID command %02x not implemented\n", tag(), current_command()); |
1216 | | set_command_done(TC_SUCCESS); |
| 1397 | if (m_substate == UNDEF) |
| 1398 | { |
| 1399 | // Command init |
| 1400 | if (TRACE_READ) logerror("%s: SEEK / READ ID command %02x, CHS=(%d,%d,%d)\n", tag(), current_command(), desired_cylinder(), desired_head(), desired_sector()); |
| 1401 | m_substate = READ_ID; |
| 1402 | } |
| 1403 | |
| 1404 | int cont = NEXT; |
| 1405 | bool step_enable = (current_command() & 0x04)==1; |
| 1406 | bool wait_seek_comp = ((current_command() & 0x02)==1) || rapid_steps(); |
| 1407 | bool do_verify = (current_command() & 0x01)==1; |
| 1408 | |
| 1409 | while (cont == NEXT) |
| 1410 | { |
| 1411 | switch (m_substate & 0xf0) |
| 1412 | { |
| 1413 | case READ_ID: |
| 1414 | read_id(cont, step_enable, wait_seek_comp); |
| 1415 | break; |
| 1416 | case VERIFY: |
| 1417 | if (!do_verify) |
| 1418 | cont = SUCCESS; |
| 1419 | else |
| 1420 | verify(cont, true); |
| 1421 | break; |
| 1422 | case DATA_TRANSFER: |
| 1423 | // No data transfer here. Just exit. |
| 1424 | cont = SUCCESS; |
| 1425 | break; |
| 1426 | default: |
| 1427 | logerror("%s: unknown substate %d in seek_read_id\n", tag(), m_substate); |
| 1428 | cont = ERROR; |
| 1429 | } |
| 1430 | } |
| 1431 | |
| 1432 | if (cont==SUCCESS) set_command_done(TC_SUCCESS); |
1217 | 1433 | } |
1218 | 1434 | |
1219 | 1435 | /* |
r32473 | r32474 | |
1229 | 1445 | Logical: |
1230 | 1446 | For multiple sectors, read the sectors in ascending order of their sector field (sector n, n+1, n+2 ...). |
1231 | 1447 | |
1232 | | Command flags |
1233 | | [ 0 ] [ 1 ] [ 0 ] [ 1 ] [ 1 ] [ Logical ] [ NoImplSeek ] [ Transfer ] |
| 1448 | Command word |
| 1449 | |
| 1450 | 7 6 5 4 3 2 1 0 |
| 1451 | +-----+-----+-----+-----+-----+--------+------+------+ |
| 1452 | | 0 | 1 | 0 | 1 | 1 | Logical|NoSeek| Trans| |
| 1453 | +-----+-----+-----+-----+-----+--------+------+------+ |
| 1454 | |
1234 | 1455 | */ |
1235 | 1456 | void hdc9234_device::read_sectors() |
1236 | 1457 | { |
r32473 | r32474 | |
1255 | 1476 | switch (m_substate & 0xf0) |
1256 | 1477 | { |
1257 | 1478 | case READ_ID: |
1258 | | read_id(cont, implied_seek); |
| 1479 | read_id(cont, implied_seek, rapid_steps()); |
1259 | 1480 | break; |
1260 | 1481 | case VERIFY: |
1261 | 1482 | verify(cont, logical); // for physical, only verify the first sector |
r32473 | r32474 | |
1272 | 1493 | |
1273 | 1494 | /* |
1274 | 1495 | READ TRACK |
1275 | | Not implemented |
| 1496 | Read all ID and data fields as they appear on the track. Command 5A only |
| 1497 | transmits the ID fields via DMA, which 5B transmits all ID and data fields. |
| 1498 | Note that the specifications do not mention any gaps to be transmitted as |
| 1499 | well. |
| 1500 | |
| 1501 | Command word |
| 1502 | |
| 1503 | 7 6 5 4 3 2 1 0 |
| 1504 | +-----+-----+-----+-----+-----+-----+-----+------+ |
| 1505 | | 0 | 1 | 0 | 1 | 1 | 0 | 1 | All | |
| 1506 | +-----+-----+-----+-----+-----+-----+-----+------+ |
| 1507 | |
1276 | 1508 | */ |
1277 | 1509 | void hdc9234_device::read_track() |
1278 | 1510 | { |
1279 | | logerror("%s: READ TRACK command %02x not implemented\n", tag(), current_command()); |
1280 | | set_command_done(TC_SUCCESS); |
| 1511 | if (m_substate == UNDEF) |
| 1512 | { |
| 1513 | if (TRACE_READTRACK) logerror("%s: READ TRACK command %02x, head = %d\n", tag(), current_command(), desired_head()); |
| 1514 | dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]); |
| 1515 | m_transfer_enabled = (current_command() & 1)!=0; |
| 1516 | } |
| 1517 | |
| 1518 | int cont = NEXT; |
| 1519 | while (cont == NEXT) |
| 1520 | { |
| 1521 | switch (m_substate) |
| 1522 | { |
| 1523 | case WAITINDEX0: |
| 1524 | // Do we happen to have an index hole right now? |
| 1525 | if ((m_register_r[DRIVE_STATUS] & HDC_DS_INDEX)==0) |
| 1526 | { |
| 1527 | m_substate = WAITINDEX1; |
| 1528 | } |
| 1529 | else |
| 1530 | { |
| 1531 | // Waiting for the index line going down |
| 1532 | wait_line(INDEX_LINE, ASSERT_LINE, WAITINDEX1, false); |
| 1533 | cont = WAIT; |
| 1534 | } |
| 1535 | break; |
| 1536 | case WAITINDEX1: |
| 1537 | // Waiting for the next rising edge |
| 1538 | wait_line(INDEX_LINE, ASSERT_LINE, TRACKSTART, false); |
| 1539 | cont = WAIT; |
| 1540 | break; |
| 1541 | case TRACKSTART: |
| 1542 | live_start(READ_TRACK); |
| 1543 | wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true); |
| 1544 | cont = WAIT; |
| 1545 | break; |
| 1546 | case TRACKDONE: |
| 1547 | if (TRACE_READTRACK && TRACE_SUBSTATES) logerror("%s: Track reading done\n", tag()); |
| 1548 | cont = SUCCESS; |
| 1549 | break; |
| 1550 | } |
| 1551 | } |
| 1552 | |
| 1553 | if (cont==SUCCESS) set_command_done(TC_SUCCESS); |
1281 | 1554 | } |
1282 | 1555 | |
1283 | 1556 | /* |
r32473 | r32474 | |
1330 | 1603 | 7 and 8 must be repeated. If the DESIRED_HEAD register must be updated, |
1331 | 1604 | the complete setup process must be done. |
1332 | 1605 | |
1333 | | Command flags |
1334 | | [ 0 ] [ 1 ] [ 1 ] [ NormalData ] [ ReducedWC ] [ PreC2, PreC1, PreC0 ] |
| 1606 | Command word |
| 1607 | |
| 1608 | 7 6 5 4 3 2 1 0 |
| 1609 | +-----+-----+-----+------+-----+-----+-----+------+ |
| 1610 | | 0 | 1 | 1 |Normal|RedWC| Precompensation | |
| 1611 | +-----+-----+-----+------+-----+-----+-----+------+ |
1335 | 1612 | */ |
1336 | 1613 | void hdc9234_device::format_track() |
1337 | 1614 | { |
r32473 | r32474 | |
1419 | 1696 | For multiple sectors, write the sectors in ascending order of their |
1420 | 1697 | sector field (sector n, n+1, n+2 ...). |
1421 | 1698 | |
1422 | | Command flags |
1423 | | [ 1 ] [ NoImplSeek ] [ Logical ] [ NormalData ] [ ReducedWC ] [ PreC2, PreC1, PreC0 ] |
| 1699 | Command word |
1424 | 1700 | |
| 1701 | 7 6 5 4 3 2 1 0 |
| 1702 | +-----+------+-------+------+-----+-----+-----+------+ |
| 1703 | | 1 |NoSeek|Logical|Normal|RedWC| Precompensation | |
| 1704 | +-----+------+-------+------+-----+-----+-----+------+ |
| 1705 | |
1425 | 1706 | */ |
1426 | 1707 | void hdc9234_device::write_sectors() |
1427 | 1708 | { |
r32473 | r32474 | |
1452 | 1733 | switch (m_substate & 0xf0) |
1453 | 1734 | { |
1454 | 1735 | case READ_ID: |
1455 | | read_id(cont, implied_seek); |
| 1736 | read_id(cont, implied_seek, rapid_steps()); |
1456 | 1737 | break; |
1457 | 1738 | case VERIFY: |
1458 | 1739 | verify(cont, logical); |
r32473 | r32474 | |
1468 | 1749 | } |
1469 | 1750 | } |
1470 | 1751 | |
1471 | | void hdc9234_device::reenter_command_processing() |
1472 | | { |
1473 | | // Do we have a live run on the track? |
1474 | | if (m_live_state.state != IDLE) |
1475 | | { |
1476 | | // Continue with it |
1477 | | live_run(); |
1478 | | if (m_live_state.state != IDLE) return; |
1479 | | } |
1480 | | |
1481 | | // We're here when there is no live_run anymore |
1482 | | // Where were we last time? |
1483 | | // Take care not to restart commands because of the index callback |
1484 | | if (m_executing && m_substate != UNDEF) (this->*m_command)(); |
1485 | | } |
1486 | | |
1487 | | // =========================================================================== |
1488 | | |
1489 | 1752 | /* |
1490 | | Step on / off; used by RESTORE and STEP IN/OUT |
1491 | | */ |
1492 | | void hdc9234_device::step_on(bool towards00, int next) |
1493 | | { |
1494 | | if ((TRACE_RESTORE | TRACE_STEP) && TRACE_SUBSTATES) logerror("%s: substate STEP_ON\n", tag()); |
1495 | | |
1496 | | // STEPDIR = 0 -> towards TRK00 |
1497 | | set_bits(m_output2, OUT2_STEPDIR, !towards00); |
1498 | | |
1499 | | // Raising edge (note that all signals must be inverted before leading them to the drive) |
1500 | | set_bits(m_output2, OUT2_STEPPULSE, true); |
1501 | | auxbus_out(); |
1502 | | wait_time(m_timer, pulse_width(), next); |
1503 | | } |
1504 | | |
1505 | | void hdc9234_device::step_off(int next) |
1506 | | { |
1507 | | if ((TRACE_RESTORE | TRACE_STEP) && TRACE_SUBSTATES) logerror("%s: substate STEP_OFF\n", tag()); |
1508 | | set_bits(m_output2, OUT2_STEPPULSE, false); |
1509 | | auxbus_out(); |
1510 | | wait_time(m_timer, step_time(), next); |
1511 | | } |
1512 | | |
1513 | | /* |
1514 | | Delivers the step time (in microseconds) minus the pulse width |
1515 | | */ |
1516 | | int hdc9234_device::step_time() |
1517 | | { |
1518 | | int time = 0; |
1519 | | int index = m_register_w[MODE] & MO_STEPRATE; |
1520 | | // Get seek time. |
1521 | | if (m_selected_drive_type == TYPE_FLOPPY8) |
1522 | | time = step_flop8[index] - pulse_flop8; |
1523 | | |
1524 | | else if (m_selected_drive_type == TYPE_FLOPPY5) |
1525 | | time = step_flop5[index] - pulse_flop5; |
1526 | | else |
1527 | | time = step_hd[index] - pulse_hd; |
1528 | | |
1529 | | if (fm_mode()) time = time * 2; |
1530 | | return time; |
1531 | | } |
1532 | | |
1533 | | /* |
1534 | | Delivers the pulse width time (in microseconds) |
1535 | | */ |
1536 | | int hdc9234_device::pulse_width() |
1537 | | { |
1538 | | int time = 0; |
1539 | | // Get seek time. |
1540 | | if (m_selected_drive_type == TYPE_FLOPPY8) |
1541 | | time = pulse_flop8; |
1542 | | |
1543 | | else if (m_selected_drive_type == TYPE_FLOPPY5) |
1544 | | time = pulse_flop5; |
1545 | | else |
1546 | | time = pulse_hd; |
1547 | | |
1548 | | if (fm_mode()) time = time * 2; |
1549 | | return time; |
1550 | | } |
1551 | | |
1552 | | /* |
1553 | | Delivers the sector size |
1554 | | */ |
1555 | | int hdc9234_device::calc_sector_size() |
1556 | | { |
1557 | | return 128 << (m_register_r[CURRENT_SIZE] & 3); |
1558 | | } |
1559 | | |
1560 | | /* |
1561 | 1753 | =========================================================================== |
1562 | 1754 | |
1563 | 1755 | Live state machine |
r32473 | r32474 | |
1667 | 1859 | // We're doing this complicated logerror check to avoid |
1668 | 1860 | // repeated logging in the same state. This can be found for the |
1669 | 1861 | // other live states as well. m_last_live_state is only used to |
1670 | | // control this loggind. |
| 1862 | // control this logging. |
1671 | 1863 | |
1672 | 1864 | if (TRACE_LIVE && m_last_live_state != SEARCH_IDAM) |
1673 | 1865 | { |
r32473 | r32474 | |
1807 | 1999 | if(slot > 4) |
1808 | 2000 | { |
1809 | 2001 | // We successfully read the ID fields; let's wait for the machine time to catch up. |
1810 | | // Live run is done here; it is the main state machine's turn again. |
1811 | 2002 | m_live_state.bit_count_total = 0; |
1812 | | wait_for_realtime(IDLE); |
| 2003 | |
| 2004 | if ((current_command() & 0xfe) == 0x5a) |
| 2005 | // Continue if we're reading a complete track |
| 2006 | wait_for_realtime(READ_TRACK_ID_DONE); |
| 2007 | else |
| 2008 | // Live run is done here; it is the main state machine's turn again. |
| 2009 | wait_for_realtime(IDLE); |
1813 | 2010 | return; |
1814 | 2011 | } |
1815 | 2012 | break; |
r32473 | r32474 | |
1949 | 2146 | { |
1950 | 2147 | if ((m_live_state.bit_counter & 15)== 1) |
1951 | 2148 | { |
1952 | | set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); |
1953 | | m_out_dmarq(ASSERT_LINE); |
| 2149 | // For floppies, request DMA for each byte. For hard disk, get it |
| 2150 | // only for the first byte and then keep the bus until the last byte. |
| 2151 | if (using_floppy() || m_live_state.bit_counter < 16) |
| 2152 | { |
| 2153 | set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); |
| 2154 | m_out_dmarq(ASSERT_LINE); |
| 2155 | } |
1954 | 2156 | } |
1955 | 2157 | } |
1956 | 2158 | |
r32473 | r32474 | |
1971 | 2173 | // CRC |
1972 | 2174 | if (slot == calc_sector_size()+1) |
1973 | 2175 | { |
1974 | | if (TRACE_LIVE) logerror("%s: [%s] Sector read completed\n", tag(),tts(m_live_state.time).cstr()); |
1975 | | wait_for_realtime(IDLE); |
| 2176 | if ((current_command() & 0xfe)==0x5a) |
| 2177 | { |
| 2178 | // Reading a track? Continue with next ID. |
| 2179 | wait_for_realtime(READ_TRACK_ID); |
| 2180 | } |
| 2181 | else |
| 2182 | { |
| 2183 | if (TRACE_LIVE) logerror("%s: [%s] Sector read completed\n", tag(),tts(m_live_state.time).cstr()); |
| 2184 | wait_for_realtime(IDLE); |
| 2185 | } |
1976 | 2186 | return; |
1977 | 2187 | } |
1978 | 2188 | } |
r32473 | r32474 | |
1998 | 2208 | if (m_transfer_enabled) |
1999 | 2209 | { |
2000 | 2210 | m_register_r[DATA] = m_register_w[DATA] = m_live_state.data_reg; |
2001 | | m_out_dip(ASSERT_LINE); |
| 2211 | // See above: For floppy, do it for each byte; for hard disk, only for the first byte, |
| 2212 | if (using_floppy() || m_live_state.bit_counter == 16) |
| 2213 | m_out_dip(ASSERT_LINE); |
| 2214 | |
2002 | 2215 | m_out_dma(0, m_register_r[DATA], 0xff); |
2003 | | m_out_dip(CLEAR_LINE); |
2004 | 2216 | |
2005 | | m_out_dmarq(CLEAR_LINE); |
| 2217 | // And again, for floppies, clear line after writing each byte, for hard disk, only after the last byte |
| 2218 | if (using_floppy() || (m_live_state.bit_counter >> 4)==calc_sector_size()-1) |
| 2219 | { |
| 2220 | m_out_dip(CLEAR_LINE); |
| 2221 | m_out_dmarq(CLEAR_LINE); |
| 2222 | } |
2006 | 2223 | } |
2007 | 2224 | |
2008 | 2225 | m_live_state.state = READ_SECTOR_DATA; |
r32473 | r32474 | |
2078 | 2295 | } |
2079 | 2296 | else |
2080 | 2297 | { |
2081 | | m_out_dip(ASSERT_LINE); |
| 2298 | // For floppies, set this for each byte; for hard disk, set it only at the beginning |
| 2299 | if (using_floppy() || m_live_state.byte_counter == calc_sector_size()) |
| 2300 | m_out_dip(ASSERT_LINE); |
| 2301 | |
2082 | 2302 | m_register_r[DATA] = m_register_w[DATA] = m_in_dma(0, 0xff); |
2083 | | m_out_dip(CLEAR_LINE); |
2084 | | m_out_dmarq(CLEAR_LINE); |
2085 | 2303 | |
| 2304 | if (using_floppy() || m_live_state.byte_counter == 0) |
| 2305 | { |
| 2306 | m_out_dip(CLEAR_LINE); |
| 2307 | m_out_dmarq(CLEAR_LINE); |
| 2308 | } |
| 2309 | |
2086 | 2310 | if (m_live_state.byte_counter > 0) |
2087 | 2311 | { |
2088 | 2312 | m_live_state.byte_counter--; |
2089 | 2313 | write_on_track(encode(m_register_r[DATA]), 1, WRITE_SECDATA); |
2090 | | m_out_dmarq(ASSERT_LINE); |
| 2314 | if (using_floppy()) m_out_dmarq(ASSERT_LINE); |
2091 | 2315 | } |
2092 | 2316 | else |
2093 | 2317 | { |
r32473 | r32474 | |
2231 | 2455 | m_out_dip(ASSERT_LINE); |
2232 | 2456 | m_live_state.byte_counter--; |
2233 | 2457 | UINT8 headbyte = m_in_dma(0, 0xff); |
| 2458 | |
2234 | 2459 | write_on_track(encode(headbyte), 1, (m_live_state.byte_counter>0)? WRITE_HEADER : WRITE_HEADER_CRC); |
2235 | | m_out_dip(CLEAR_LINE); |
2236 | | m_out_dmarq(CLEAR_LINE); |
| 2460 | |
| 2461 | if (using_floppy() || m_live_state.byte_counter==0) |
| 2462 | { |
| 2463 | m_out_dip(CLEAR_LINE); |
| 2464 | m_out_dmarq(CLEAR_LINE); |
| 2465 | } |
2237 | 2466 | // Writing will occur after the break; set the DMARQ again |
2238 | 2467 | if (m_live_state.byte_counter>0) |
2239 | 2468 | m_out_dmarq(ASSERT_LINE); |
r32473 | r32474 | |
2277 | 2506 | // Write a single byte; when the index hole shows up, the live run will be aborted |
2278 | 2507 | write_on_track(encode(fm_mode()? 0xff : 0x4e), 1, WRITE_GAP4); |
2279 | 2508 | break; |
| 2509 | // -------------------------------------------------------- |
2280 | 2510 | |
| 2511 | // ================================================== |
| 2512 | // Live states for track reading |
| 2513 | // ================================================== |
| 2514 | |
| 2515 | // Quite simple. Read the next ID fields, then the sector contents. |
| 2516 | // Continue until the next index hole shows up (live_abort). |
| 2517 | case READ_TRACK: |
| 2518 | if (TRACE_LIVE) logerror("%s: READ_TRACK\n", tag()); |
| 2519 | m_live_state.state = READ_TRACK_ID; |
| 2520 | break; |
| 2521 | |
| 2522 | case READ_TRACK_ID: |
| 2523 | m_live_state.state = SEARCH_IDAM; |
| 2524 | // Ask for access to bus |
| 2525 | set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); |
| 2526 | m_out_dmarq(ASSERT_LINE); |
| 2527 | break; |
| 2528 | |
| 2529 | case READ_TRACK_ID_DONE: |
| 2530 | if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) |
| 2531 | { |
| 2532 | if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer overrun\n", tag()); |
| 2533 | set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); |
| 2534 | m_live_state.state = IDLE; |
| 2535 | return; |
| 2536 | } |
| 2537 | if (TRACE_LIVE) logerror("%s: READ_TRACK1\n", tag()); |
| 2538 | |
| 2539 | m_out_dip(ASSERT_LINE); |
| 2540 | |
| 2541 | // Write the header via DMA |
| 2542 | for (int slot = 0; slot < 6; slot++) |
| 2543 | m_out_dma(0, m_register_r[id_field[slot]], 0xff); |
| 2544 | |
| 2545 | m_out_dip(CLEAR_LINE); |
| 2546 | m_out_dmarq(CLEAR_LINE); |
| 2547 | |
| 2548 | // Continue with reading the sector data |
| 2549 | m_live_state.state = SEARCH_DAM; |
| 2550 | break; |
| 2551 | |
2281 | 2552 | // ================================================================= |
2282 | 2553 | |
2283 | 2554 | case READ_TRACK_BYTE: |
r32473 | r32474 | |
2640 | 2911 | // =========================================================================== |
2641 | 2912 | |
2642 | 2913 | /* |
2643 | | This is pretty simple here, compared to wd17xx, because index and ready |
2644 | | callbacks have to be tied to the controller board outside the chip. |
2645 | | */ |
2646 | | void hdc9234_device::connect_floppy_drive(floppy_image_device* floppy) |
2647 | | { |
2648 | | m_floppy = floppy; |
2649 | | } |
2650 | | |
2651 | | /* |
2652 | 2914 | Read a byte of data from the controller |
2653 | 2915 | The address (offset) encodes the C/D* line (command and /data) |
2654 | 2916 | */ |
r32473 | r32474 | |
2727 | 2989 | } |
2728 | 2990 | m_register_w[m_register_pointer] = m_regvalue; |
2729 | 2991 | |
2730 | | // Changes to these registers must be output via the auxbus |
2731 | | if (m_register_pointer == DESIRED_HEAD || m_register_pointer == RETRY_COUNT) |
2732 | | auxbus_out(); |
2733 | | |
2734 | 2992 | // The DMA registers and the sector register for read and |
2735 | 2993 | // write are identical, so in that case we copy the contents |
2736 | 2994 | if (m_register_pointer < DESIRED_HEAD) m_register_r[m_register_pointer] = m_regvalue; |
r32473 | r32474 | |
2773 | 3031 | logerror("%s: Command %02x not defined\n", tag(), m_register_w[COMMAND]); |
2774 | 3032 | } |
2775 | 3033 | } |
| 3034 | auxbus_out(); |
2776 | 3035 | } |
2777 | 3036 | |
| 3037 | void hdc9234_device::reenter_command_processing() |
| 3038 | { |
| 3039 | // Do we have a live run on the track? |
| 3040 | if (m_live_state.state != IDLE) |
| 3041 | { |
| 3042 | // Continue with it |
| 3043 | live_run(); |
| 3044 | if (m_live_state.state != IDLE) return; |
| 3045 | } |
| 3046 | |
| 3047 | // We're here when there is no live_run anymore |
| 3048 | // Where were we last time? |
| 3049 | // Take care not to restart commands because of the index callback |
| 3050 | if (m_executing && m_substate != UNDEF) (this->*m_command)(); |
| 3051 | auxbus_out(); |
| 3052 | } |
| 3053 | |
2778 | 3054 | /* |
| 3055 | Assert Command Done status bit, triggering interrupts as needed |
| 3056 | */ |
| 3057 | void hdc9234_device::set_command_done(int flags) |
| 3058 | { |
| 3059 | // Do another output, then set the flag |
| 3060 | auxbus_out(); |
| 3061 | |
| 3062 | set_bits(m_register_r[INT_STATUS], ST_DONE, true); |
| 3063 | |
| 3064 | if (flags != -1) |
| 3065 | { |
| 3066 | set_bits(m_register_r[INT_STATUS], ST_TERMCOD, false); // clear the previously set flags |
| 3067 | m_register_r[INT_STATUS] |= flags; |
| 3068 | if (TRACE_DONE) logerror("%s: command %02x done, flags=%02x\n", tag(), current_command(), flags); |
| 3069 | } |
| 3070 | else |
| 3071 | { |
| 3072 | if (TRACE_DONE) logerror("%s: command %02x done\n", tag(), current_command()); |
| 3073 | } |
| 3074 | |
| 3075 | // [1], p. 6 |
| 3076 | if (TRACE_INT) logerror("%s: Raise interrupt DONE\n", tag()); |
| 3077 | set_interrupt(ASSERT_LINE); |
| 3078 | |
| 3079 | m_substate = UNDEF; |
| 3080 | m_executing = false; |
| 3081 | } |
| 3082 | |
| 3083 | /* |
| 3084 | Preserve previously set termination code |
| 3085 | */ |
| 3086 | void hdc9234_device::set_command_done() |
| 3087 | { |
| 3088 | set_command_done(-1); |
| 3089 | } |
| 3090 | |
| 3091 | /* |
2779 | 3092 | Auxiliary bus operation. |
2780 | 3093 | |
2781 | 3094 | The auxbus of the HDC9234 is used to poll the drive status of the cur- |
r32473 | r32474 | |
2924 | 3237 | } |
2925 | 3238 | |
2926 | 3239 | /* |
2927 | | Set the hook for line level handling |
2928 | | */ |
2929 | | void hdc9234_device::wait_line(int line, line_state level, int substate, bool stopwrite) |
2930 | | { |
2931 | | m_event_line = line; |
2932 | | m_line_level = level; |
2933 | | m_state_after_line = substate; |
2934 | | m_stopwrite = stopwrite; |
2935 | | } |
2936 | | |
2937 | | /* |
2938 | 3240 | Push the output registers over the auxiliary bus. It is expected that |
2939 | 3241 | the PCB contains latches to store the values. |
2940 | 3242 | |
r32473 | r32474 | |
2962 | 3264 | */ |
2963 | 3265 | void hdc9234_device::auxbus_out() |
2964 | 3266 | { |
2965 | | m_out_auxbus((offs_t)HDC_OUTPUT_1, m_output1); |
2966 | | |
2967 | 3267 | // prepare output2 |
2968 | 3268 | set_bits(m_output2, OUT2_DRVSEL3I, (m_output1 & OUT1_DRVSEL3)==0); |
2969 | 3269 | |
r32473 | r32474 | |
2971 | 3271 | if (m_reduced_write_current) m_output2 |= OUT2_REDWRT; |
2972 | 3272 | |
2973 | 3273 | if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT2 to %02x\n", tag(), m_output2); |
2974 | | m_out_auxbus((offs_t)HDC_OUTPUT_2, m_output2); |
| 3274 | |
| 3275 | if (m_output1 != m_output1_old || m_output2 != m_output2_old) |
| 3276 | { |
| 3277 | // Only propagate changes |
| 3278 | m_out_auxbus((offs_t)HDC_OUTPUT_1, m_output1); |
| 3279 | m_out_auxbus((offs_t)HDC_OUTPUT_2, m_output2); |
| 3280 | m_output1_old = m_output1; |
| 3281 | m_output2_old = m_output2; |
| 3282 | } |
2975 | 3283 | } |
2976 | 3284 | |
2977 | 3285 | void hdc9234_device::dma_address_out(UINT8 addrub, UINT8 addrhb, UINT8 addrlb) |
r32473 | r32474 | |
2983 | 3291 | } |
2984 | 3292 | |
2985 | 3293 | /* |
2986 | | This is reached when a timer has expired |
| 3294 | Set/clear INT |
| 3295 | |
| 3296 | Interupts are generated in the following occasions: |
| 3297 | - when the DONE bit is set to 1 in the ISR and ST_DONE is set to 1 |
| 3298 | - when the READY_CHANGE bit is set to 1 in the ISR and ST_RDYCHNG is set to 1 |
| 3299 | (ready change: 1->0 or 0->1) |
2987 | 3300 | */ |
2988 | | void hdc9234_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 3301 | void hdc9234_device::set_interrupt(line_state intr) |
2989 | 3302 | { |
2990 | | live_sync(); |
2991 | | |
2992 | | switch (id) |
| 3303 | if (intr == ASSERT_LINE) |
2993 | 3304 | { |
2994 | | case GEN_TIMER: |
2995 | | reenter_command_processing(); |
2996 | | break; |
2997 | | case COM_TIMER: |
2998 | | process_command(); |
2999 | | break; |
3000 | | case LIVE_TIMER: |
3001 | | live_run(); |
3002 | | break; |
| 3305 | // Only if there is not already a pending interrupt |
| 3306 | if ((m_register_r[INT_STATUS] & ST_INTPEND) == 0) |
| 3307 | { |
| 3308 | m_register_r[INT_STATUS] |= ST_INTPEND; |
| 3309 | m_out_intrq(intr); |
| 3310 | } |
3003 | 3311 | } |
| 3312 | else |
| 3313 | { |
| 3314 | // if there is a pending interrupt |
| 3315 | if ((m_register_r[INT_STATUS] & ST_INTPEND) != 0) |
| 3316 | m_out_intrq(intr); |
| 3317 | } |
3004 | 3318 | } |
3005 | 3319 | |
3006 | 3320 | /* |
r32473 | r32474 | |
3016 | 3330 | } |
3017 | 3331 | |
3018 | 3332 | /* |
| 3333 | This is pretty simple here, compared to wd17xx, because index and ready |
| 3334 | callbacks have to be tied to the controller board outside the chip. |
| 3335 | */ |
| 3336 | void hdc9234_device::connect_floppy_drive(floppy_image_device* floppy) |
| 3337 | { |
| 3338 | m_floppy = floppy; |
| 3339 | } |
| 3340 | |
| 3341 | /* |
3019 | 3342 | Clock divider. This input line actually belongs to the data separator which |
3020 | 3343 | is a separate circuit. Maybe we will take it out of this implementation |
3021 | 3344 | at some time and make it a device of its own. |
r32473 | r32474 | |
3027 | 3350 | } |
3028 | 3351 | |
3029 | 3352 | /* |
| 3353 | This is reached when a timer has expired |
| 3354 | */ |
| 3355 | void hdc9234_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 3356 | { |
| 3357 | live_sync(); |
| 3358 | |
| 3359 | switch (id) |
| 3360 | { |
| 3361 | case GEN_TIMER: |
| 3362 | reenter_command_processing(); |
| 3363 | break; |
| 3364 | case COM_TIMER: |
| 3365 | process_command(); |
| 3366 | break; |
| 3367 | case LIVE_TIMER: |
| 3368 | live_run(); |
| 3369 | break; |
| 3370 | } |
| 3371 | } |
| 3372 | |
| 3373 | /* |
3030 | 3374 | Reset the controller. Negative logic, but we use ASSERT_LINE. |
3031 | 3375 | */ |
3032 | 3376 | WRITE_LINE_MEMBER( hdc9234_device::reset ) |
r32473 | r32474 | |
3068 | 3412 | m_multi_sector = false; |
3069 | 3413 | m_output1 = 0; |
3070 | 3414 | m_output2 = 0x80; |
| 3415 | m_output1_old = 1; // force an initial output |
| 3416 | m_output2_old = 0x81; |
3071 | 3417 | m_precompensation = 0; |
3072 | 3418 | m_reduced_write_current = false; |
3073 | 3419 | m_regvalue = 0; |