branches/alto2/src/emu/machine/diablo_hd.c
| r26227 | r26228 | |
| 63 | 63 | diablo_hd_device::diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 64 | 64 | device_t(mconfig, DIABLO_HD, "Diablo Disk", tag, owner, clock, "diablo_hd", __FILE__), |
| 65 | 65 | #if DIABLO_DEBUG |
| 66 | | m_log_level(6), |
| 66 | m_log_level(9), |
| 67 | 67 | #endif |
| 68 | 68 | m_diablo31(true), |
| 69 | 69 | m_unit(0), |
| r26227 | r26228 | |
| 141 | 141 | { |
| 142 | 142 | if (m_sector_callback_cookie == cookie && m_sector_callback == callback) |
| 143 | 143 | return; |
| 144 | | LOG_DRIVE((0,"[DHD] %s cookie=%p callback=%p\n", __FUNCTION__, cookie, callback)); |
| 144 | LOG_DRIVE((0,"[DHD%u] cookie=%p callback=%p\n", m_unit, cookie, callback)); |
| 145 | 145 | m_sector_callback_cookie = cookie; |
| 146 | 146 | m_sector_callback = callback; |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | | #define DIABLO31_ROTATION_TIME attotime::from_msec(39.9999) //!< DIABLO 31 rotation time is approx. 40ms |
| 150 | | #define DIABLO31_SECTOR_TIME attotime::from_msec(39.9999/12) //!< DIABLO 31 sector time |
| 149 | #define DIABLO31_ROTATION_TIME attotime::from_usec(40000) //!< DIABLO 31 rotation time is approx. 40ms |
| 150 | #define DIABLO31_SECTOR_TIME attotime::from_usec(40000/12) //!< DIABLO 31 sector time |
| 151 | 151 | /** |
| 152 | 152 | * @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit |
| 153 | 153 | * ~= 133333 bits/track (?) |
| r26227 | r26228 | |
| 155 | 155 | * ~= 347 words/sector |
| 156 | 156 | */ |
| 157 | 157 | #define DIABLO31_BIT_TIME(bits) attotime::from_nsec(300*(bits)) |
| 158 | #define DIABLO31_SECTOR_BITS 11111 |
| 158 | 159 | #define DIABLO31_SECTOR_WORDS 347 //!< DIABLO 31 possible sector words |
| 159 | 160 | #define DIABLO31_SECTOR_MARK_PULSE_PRE DIABLO31_BIT_TIME(16) //!< pulse width of sector mark before the next sector begins |
| 160 | 161 | #define DIABLO31_SECTOR_MARK_PULSE_POST DIABLO31_BIT_TIME(16) //!< pulse width of sector mark after the next sector began |
| 161 | 162 | |
| 162 | | #define DIABLO44_ROTATION_TIME attotime::from_msec(25) //!< DIABLO 44 rotation time is approx. 25ms |
| 163 | | #define DIABLO44_SECTOR_TIME attotime::from_msec(25/12) //!< DIABLO 44 sector time |
| 163 | #define DIABLO44_ROTATION_TIME attotime::from_usec(25000) //!< DIABLO 44 rotation time is approx. 25ms |
| 164 | #define DIABLO44_SECTOR_TIME attotime::from_usec(25000/12) //!< DIABLO 44 sector time |
| 164 | 165 | /** |
| 165 | 166 | * @brief DIABLO 44 bit clock is 5000kHz ~= 200ns per bit |
| 166 | 167 | * ~= 125184 bits/track (?) |
| r26227 | r26228 | |
| 168 | 169 | * ~= 325 words/sector |
| 169 | 170 | */ |
| 170 | 171 | #define DIABLO44_BIT_TIME(bits) attotime::from_nsec(200*(bits)) |
| 172 | #define DIABLO44_SECTOR_BITS 10432 |
| 171 | 173 | #define DIABLO44_SECTOR_WORDS 325 //!< DIABLO 44 possible sector words |
| 172 | 174 | #define DIABLO44_SECTOR_MARK_PULSE_PRE DIABLO44_BIT_TIME(16) //!< pulse width of sector mark before the next sector begins |
| 173 | 175 | #define DIABLO44_SECTOR_MARK_PULSE_POST DIABLO44_BIT_TIME(16) //!< pulse width of sector mark after the next sector began |
| r26227 | r26228 | |
| 292 | 294 | { |
| 293 | 295 | /* If there's no drive, just reset the page number */ |
| 294 | 296 | if (!m_image) { |
| 295 | | LOG_DRIVE((0,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => no image\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 297 | LOG_DRIVE((0,"[DHD%u] C/H/S:%d/%d/%d => no image\n", m_unit, m_cylinder, m_head, m_sector)); |
| 296 | 298 | m_page = -1; |
| 297 | 299 | return; |
| 298 | 300 | } |
| 299 | 301 | if (m_cylinder < 0 || m_cylinder >= DIABLO_CYLINDERS) { |
| 300 | | LOG_DRIVE((0,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => invalid cylinder\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 302 | LOG_DRIVE((0,"[DHD%u] C/H/S:%d/%d/%d => invalid cylinder\n", m_unit, m_cylinder, m_head, m_sector)); |
| 301 | 303 | m_page = -1; |
| 302 | 304 | return; |
| 303 | 305 | } |
| 304 | 306 | if (m_head < 0 || m_head >= DIABLO_HEADS) { |
| 305 | | LOG_DRIVE((0,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => invalid head\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 307 | LOG_DRIVE((0,"[DHD%u] C/H/S:%d/%d/%d => invalid head\n", m_unit, m_cylinder, m_head, m_sector)); |
| 306 | 308 | m_page = -1; |
| 307 | 309 | return; |
| 308 | 310 | } |
| 309 | 311 | if (m_sector < 0 || m_sector >= DIABLO_SPT) { |
| 310 | | LOG_DRIVE((0,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => invalid sector\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 312 | LOG_DRIVE((0,"[DHD%u] C/H/S:%d/%d/%d => invalid sector\n", m_unit, m_cylinder, m_head, m_sector)); |
| 311 | 313 | m_page = -1; |
| 312 | 314 | return; |
| 313 | 315 | } |
| r26227 | r26228 | |
| 316 | 318 | |
| 317 | 319 | // already have the sector image? |
| 318 | 320 | if (m_cache[m_page]) { |
| 319 | | LOG_DRIVE((6,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => page:%d is cached\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 321 | LOG_DRIVE((6,"[DHD%u] C/H/S:%d/%d/%d => page:%d is cached\n", m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 320 | 322 | return; |
| 321 | 323 | } |
| 322 | 324 | |
| r26227 | r26228 | |
| 324 | 326 | m_cache[m_page] = global_alloc_array(UINT8, sizeof(diablo_sector_t)); |
| 325 | 327 | /* and read the page from the hard_disk image */ |
| 326 | 328 | if (hard_disk_read(m_disk, m_page, m_cache[m_page])) { |
| 327 | | LOG_DRIVE((2,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => page:%d loaded\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 329 | LOG_DRIVE((2,"[DHD%u] C/H/S:%d/%d/%d => page:%d loaded\n", m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 328 | 330 | } else { |
| 329 | | LOG_DRIVE((0,"[DHD] %s: unit #%d C/H/S:%d/%d/%d => page:%d read failed\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 331 | LOG_DRIVE((0,"[DHD%u] C/H/S:%d/%d/%d => page:%d read failed\n", m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 330 | 332 | global_free(m_cache[m_page]); |
| 331 | 333 | m_cache[m_page] = 0; |
| 332 | 334 | } |
| r26227 | r26228 | |
| 445 | 447 | |
| 446 | 448 | /* allocate a sector buffer */ |
| 447 | 449 | if (!m_cache[m_page]) { |
| 448 | | LOG_DRIVE((0,"[DHD] %s: no image for #%d page #%d\n", __FUNCTION__, m_unit, m_page)); |
| 450 | LOG_DRIVE((0,"[DHD%u] no image for page #%d\n", m_unit, m_page)); |
| 449 | 451 | return NULL; |
| 450 | 452 | } |
| 451 | 453 | diablo_sector_t *s = reinterpret_cast<diablo_sector_t *>(m_cache[m_page]); |
| r26227 | r26228 | |
| 492 | 494 | } |
| 493 | 495 | m_bits[m_page] = bits; |
| 494 | 496 | |
| 495 | | LOG_DRIVE((0,"[DHD] %s: BITS #%d: %03d/%d/%02d #%-5d bits (@%03d.%02d)\n", |
| 496 | | __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, dst, dst / 32, dst % 32)); |
| 497 | | |
| 497 | LOG_DRIVE((0,"[DHD%u] C/H/S:%03d/%d/%02d #%5d bits\n", m_unit, m_cylinder, m_head, m_sector, dst)); |
| 498 | #if DIABLO_DEBUG |
| 499 | dump_record(s->pageno, 0, sizeof(s->pageno), "pageno", 0); |
| 500 | dump_record(s->header, 0, sizeof(s->header), "header", 0); |
| 501 | dump_record(s->label, 0, sizeof(s->label), "label", 0); |
| 502 | dump_record(s->data, 0, sizeof(s->data), "data", 1); |
| 503 | #endif |
| 498 | 504 | return bits; |
| 499 | 505 | } |
| 500 | 506 | |
| r26227 | r26228 | |
| 576 | 582 | } |
| 577 | 583 | } |
| 578 | 584 | /* return if no sync found within size*32 clock and data bits */ |
| 579 | | LOG_DRIVE((0,"[DHD] %s: no sync within %d words\n", __FUNCTION__, size)); |
| 585 | LOG_DRIVE((0,"[DHD%u] no sync within %d words\n", m_unit, size)); |
| 580 | 586 | return src; |
| 581 | 587 | } |
| 582 | 588 | |
| r26227 | r26228 | |
| 611 | 617 | } |
| 612 | 618 | } |
| 613 | 619 | /* return if no sync found within size*32 clock and data bits */ |
| 614 | | LOG_DRIVE((0,"[DHD] %s: no unsync within %d words\n", __FUNCTION__, size)); |
| 620 | LOG_DRIVE((0,"[DHD%u] no unsync within %d words\n", m_unit, size)); |
| 615 | 621 | return src; |
| 616 | 622 | } |
| 617 | 623 | |
| r26227 | r26228 | |
| 684 | 690 | int cksum_header, cksum_label, cksum_data; |
| 685 | 691 | |
| 686 | 692 | if (m_rdfirst >= 0) { |
| 687 | | LOG_DRIVE((0, "[DHD] %s: RD #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n", |
| 688 | | __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, |
| 689 | | m_rdfirst, m_rdfirst / 32, m_rdfirst % 32, |
| 690 | | m_rdlast, m_rdlast / 32, m_rdlast % 32)); |
| 693 | LOG_DRIVE((0, "[DHD%u] RD CHS:%03d/%d/%02d bit#%-5d ... bit#%-5d\n", |
| 694 | m_cylinder, m_head, m_sector, m_rdfirst, m_rdlast)); |
| 691 | 695 | } |
| 692 | 696 | m_rdfirst = -1; |
| 693 | 697 | m_rdlast = -1; |
| r26227 | r26228 | |
| 707 | 711 | } |
| 708 | 712 | |
| 709 | 713 | if (m_wrfirst >= 0) { |
| 710 | | LOG_DRIVE((0, "[DHD] %s: WR #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n", |
| 711 | | __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, |
| 712 | | m_wrfirst, m_wrfirst / 32, m_wrfirst % 32, |
| 713 | | m_wrlast, m_wrlast / 32, m_wrlast % 32)); |
| 714 | LOG_DRIVE((0, "[DHD%u] WR C/H/S:%03d/%d/%02d bit#%-5d ... bit#%-5d\n", |
| 715 | m_unit, m_cylinder, m_head, m_sector, m_wrfirst, m_wrlast)); |
| 714 | 716 | } |
| 715 | 717 | m_wrfirst = -1; |
| 716 | 718 | m_wrlast = -1; |
| 717 | 719 | |
| 718 | 720 | if (m_page < 0 || m_page >= DIABLO_PAGES) { |
| 719 | | LOG_DRIVE((0,"[DHD] %s: no sector for #%d: %d/%d/%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 721 | LOG_DRIVE((0,"[DHD%u] page not set\n", m_unit)); |
| 720 | 722 | return; |
| 721 | 723 | } |
| 722 | 724 | |
| 723 | 725 | if (!m_cache[m_page]) { |
| 724 | | LOG_DRIVE((0,"[DHD] %s: no image for #%d: %d/%d/%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 726 | LOG_DRIVE((0,"[DHD%u] no image\n", m_unit)); |
| 725 | 727 | return; |
| 726 | 728 | } |
| 727 | 729 | |
| 728 | 730 | /* no bits to write? */ |
| 729 | 731 | if (!m_bits[m_page]) { |
| 730 | | LOG_DRIVE((0,"[DHD] %s: no bits for #%d: %d/%d/%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 732 | LOG_DRIVE((0,"[DHD%u] no bits\n", m_unit)); |
| 731 | 733 | return; |
| 732 | 734 | } |
| 733 | 735 | UINT32 *bits = m_bits[m_page]; |
| r26227 | r26228 | |
| 743 | 745 | src = squeeze_unsync(bits, src, 40); |
| 744 | 746 | /* sync on header preamble */ |
| 745 | 747 | src = squeeze_sync(bits, src, 40); |
| 746 | | LOG_DRIVE((0,"[DHD] %s: header sync bit #%d (@%03d.%02d)\n", __FUNCTION__, src, src / 32, src % 32)); |
| 748 | LOG_DRIVE((0,"[DHD%u] header sync bit #%5d\n", m_unit, src)); |
| 747 | 749 | src = squeeze_record(bits, src, s->header, sizeof(s->header)); |
| 748 | 750 | src = squeeze_cksum(bits, src, &cksum_header); |
| 749 | 751 | #if DIABLO_DEBUG |
| r26227 | r26228 | |
| 754 | 756 | src = squeeze_unsync(bits, src, 40); |
| 755 | 757 | /* sync on label preamble */ |
| 756 | 758 | src = squeeze_sync(bits, src, 40); |
| 757 | | LOG_DRIVE((0,"[DHD] %s: label sync bit #%d (@%03d.%02d)\n", __FUNCTION__, src, src / 32, src % 32)); |
| 759 | LOG_DRIVE((0,"[DHD%u] label sync bit #%5d\n", m_unit, src)); |
| 758 | 760 | src = squeeze_record(bits, src, s->label, sizeof(s->label)); |
| 759 | 761 | src = squeeze_cksum(bits, src, &cksum_label); |
| 760 | 762 | #if DIABLO_DEBUG |
| r26227 | r26228 | |
| 765 | 767 | src = squeeze_unsync(bits, src, 40); |
| 766 | 768 | /* sync on data preamble */ |
| 767 | 769 | src = squeeze_sync(bits, src, 40); |
| 768 | | LOG_DRIVE((0,"[DHD] %s: data sync bit #%d (@%03d.%02d)\n", __FUNCTION__, src, src / 32, src % 32)); |
| 770 | LOG_DRIVE((0,"[DHD%u] data sync bit #%5d\n", m_unit, src)); |
| 769 | 771 | src = squeeze_record(bits, src, s->data, sizeof(s->data)); |
| 770 | 772 | src = squeeze_cksum(bits, src, &cksum_data); |
| 771 | 773 | #if DIABLO_DEBUG |
| r26227 | r26228 | |
| 779 | 781 | |
| 780 | 782 | if (cksum_header || cksum_label || cksum_data) { |
| 781 | 783 | #if DIABLO_DEBUG |
| 782 | | LOG_DRIVE((0,"[DHD] %s: cksum check - header:%06o label:%06o data:%06o\n", __FUNCTION__, cksum_header, cksum_label, cksum_data)); |
| 784 | LOG_DRIVE((0,"[DHD%u] cksum check - header:%06o label:%06o data:%06o\n", m_unit, cksum_header, cksum_label, cksum_data)); |
| 783 | 785 | #endif |
| 784 | 786 | } |
| 785 | 787 | global_free(m_bits[m_page]); |
| 786 | 788 | m_bits[m_page] = 0; |
| 787 | 789 | |
| 788 | 790 | if (!hard_disk_write(m_disk, m_page, m_cache[m_page])) { |
| 789 | | LOG_DRIVE((0,"[DHD] %s: write failed for #%d page #%d\n", __FUNCTION__, m_unit, m_page)); |
| 791 | LOG_DRIVE((0,"[DHD%u] write failed for page #%d\n", m_unit, m_page)); |
| 790 | 792 | } |
| 791 | 793 | } |
| 792 | 794 | |
| 793 | 795 | /** |
| 794 | | * @brief return number of bitclk edges for a sector |
| 796 | * @brief return number of bit clocks for a sector (clock and data) |
| 795 | 797 | * @return number of bitclks for a sector |
| 796 | 798 | */ |
| 797 | 799 | int diablo_hd_device::bits_per_sector() const |
| 798 | 800 | { |
| 799 | | return m_diablo31 ? DIABLO31_SECTOR_WORDS * 32 : DIABLO44_SECTOR_WORDS * 32; |
| 801 | return m_diablo31 ? DIABLO31_SECTOR_BITS : DIABLO44_SECTOR_BITS; |
| 800 | 802 | } |
| 801 | 803 | |
| 802 | 804 | /** |
| r26227 | r26228 | |
| 805 | 807 | */ |
| 806 | 808 | const char* diablo_hd_device::description() const |
| 807 | 809 | { |
| 808 | | return m_description; |
| 810 | return m_description; |
| 809 | 811 | } |
| 810 | 812 | |
| 811 | 813 | /** |
| r26227 | r26228 | |
| 814 | 816 | */ |
| 815 | 817 | int diablo_hd_device::unit() const |
| 816 | 818 | { |
| 817 | | return m_unit; |
| 819 | return m_unit; |
| 818 | 820 | } |
| 819 | 821 | |
| 820 | 822 | /** |
| r26227 | r26228 | |
| 823 | 825 | */ |
| 824 | 826 | attotime diablo_hd_device::rotation_time() const |
| 825 | 827 | { |
| 826 | | return m_rotation_time; |
| 828 | return m_rotation_time; |
| 827 | 829 | } |
| 828 | 830 | |
| 829 | 831 | /** |
| r26227 | r26228 | |
| 832 | 834 | */ |
| 833 | 835 | attotime diablo_hd_device::sector_time() const |
| 834 | 836 | { |
| 835 | | return m_sector_time; |
| 837 | return m_sector_time; |
| 836 | 838 | } |
| 837 | 839 | |
| 838 | 840 | /** |
| r26227 | r26228 | |
| 841 | 843 | */ |
| 842 | 844 | attotime diablo_hd_device::bit_time() const |
| 843 | 845 | { |
| 844 | | return m_bit_time; |
| 846 | return m_bit_time; |
| 845 | 847 | } |
| 846 | 848 | |
| 847 | 849 | /** |
| r26227 | r26228 | |
| 850 | 852 | */ |
| 851 | 853 | int diablo_hd_device::get_seek_read_write_0() const |
| 852 | 854 | { |
| 853 | | return m_s_r_w_0; |
| 855 | return m_s_r_w_0; |
| 854 | 856 | } |
| 855 | 857 | |
| 856 | 858 | /** |
| r26227 | r26228 | |
| 859 | 861 | */ |
| 860 | 862 | int diablo_hd_device::get_ready_0() const |
| 861 | 863 | { |
| 862 | | return m_ready_0; |
| 864 | return m_ready_0; |
| 863 | 865 | } |
| 864 | 866 | |
| 865 | 867 | /** |
| r26227 | r26228 | |
| 887 | 889 | */ |
| 888 | 890 | int diablo_hd_device::get_addx_acknowledge_0() const |
| 889 | 891 | { |
| 890 | | return m_addx_acknowledge_0; |
| 892 | return m_addx_acknowledge_0; |
| 891 | 893 | } |
| 892 | 894 | |
| 893 | 895 | /** |
| r26227 | r26228 | |
| 896 | 898 | */ |
| 897 | 899 | int diablo_hd_device::get_log_addx_interlock_0() const |
| 898 | 900 | { |
| 899 | | return m_log_addx_interlock_0; |
| 901 | return m_log_addx_interlock_0; |
| 900 | 902 | } |
| 901 | 903 | |
| 902 | 904 | /** |
| r26227 | r26228 | |
| 905 | 907 | */ |
| 906 | 908 | int diablo_hd_device::get_seek_incomplete_0() const |
| 907 | 909 | { |
| 908 | | return m_seek_incomplete_0; |
| 910 | return m_seek_incomplete_0; |
| 909 | 911 | } |
| 910 | 912 | |
| 911 | 913 | /** |
| r26227 | r26228 | |
| 919 | 921 | */ |
| 920 | 922 | int diablo_hd_device::get_cylinder() const |
| 921 | 923 | { |
| 922 | | return m_cylinder; |
| 924 | return m_cylinder; |
| 923 | 925 | } |
| 924 | 926 | |
| 925 | 927 | /** |
| r26227 | r26228 | |
| 933 | 935 | */ |
| 934 | 936 | int diablo_hd_device::get_head() const |
| 935 | 937 | { |
| 936 | | return m_head; |
| 938 | return m_head; |
| 937 | 939 | } |
| 938 | 940 | |
| 939 | 941 | /** |
| r26227 | r26228 | |
| 951 | 953 | */ |
| 952 | 954 | int diablo_hd_device::get_sector() const |
| 953 | 955 | { |
| 954 | | return m_sector; |
| 956 | return m_sector; |
| 955 | 957 | } |
| 956 | 958 | |
| 957 | 959 | /** |
| r26227 | r26228 | |
| 965 | 967 | */ |
| 966 | 968 | int diablo_hd_device::get_page() const |
| 967 | 969 | { |
| 968 | | return m_page; |
| 970 | return m_page; |
| 969 | 971 | } |
| 970 | 972 | |
| 971 | 973 | /** |
| r26227 | r26228 | |
| 980 | 982 | /* this drive is selected */ |
| 981 | 983 | if ((head & DIABLO_HEAD_MASK) != m_head) { |
| 982 | 984 | m_head = head & DIABLO_HEAD_MASK; |
| 983 | | LOG_DRIVE((0,"[DHD] %s: unit:%d head:%d\n", __FUNCTION__, unit, head)); |
| 985 | LOG_DRIVE((0,"[DHD%u] select unit:%d head:%d\n", m_unit, unit, head)); |
| 984 | 986 | } |
| 985 | 987 | |
| 986 | 988 | if (m_image) { |
| r26227 | r26228 | |
| 988 | 990 | m_s_r_w_0 = 0; // and can take seek/read/write commands |
| 989 | 991 | m_addx_acknowledge_0 = 0; // assert address acknowledge (?) |
| 990 | 992 | m_log_addx_interlock_0 = 1; // deassert log address interlock (?) |
| 991 | | LOG_DRIVE((1,"[DHD] %s: UNIT select %d ready\n", __FUNCTION__, unit)); |
| 993 | LOG_DRIVE((1,"[DHD%u] select unit:%d ready\n", m_unit, unit)); |
| 992 | 994 | } else { |
| 993 | 995 | m_ready_0 = 1; // it is not ready (?) |
| 994 | 996 | m_s_r_w_0 = 1; // can't take seek/read/write commands (?) |
| 995 | 997 | m_addx_acknowledge_0 = 0; // assert address acknowledge (?) |
| 996 | 998 | m_log_addx_interlock_0 = 1; // deassert log address interlock (?) |
| 997 | | LOG_DRIVE((1,"[DHD] %s: UNIT select %d not ready (no image)\n", __FUNCTION__, unit)); |
| 999 | LOG_DRIVE((1,"[DHD%u] select unit:%d not ready (no image)\n", m_unit, unit)); |
| 998 | 1000 | } |
| 999 | 1001 | read_sector(); |
| 1000 | 1002 | } |
| r26227 | r26228 | |
| 1013 | 1015 | { |
| 1014 | 1016 | int seekto = restore ? 0 : cylinder; |
| 1015 | 1017 | if (strobe) { |
| 1016 | | LOG_DRIVE((1,"[DHD] %s: STROBE end of interlock\n", __FUNCTION__, seekto)); |
| 1018 | LOG_DRIVE((1,"[DHD%u] STROBE end of interlock\n", m_unit)); |
| 1017 | 1019 | // deassert the log address interlock |
| 1018 | 1020 | m_log_addx_interlock_0 = 1; |
| 1019 | 1021 | return; |
| r26227 | r26228 | |
| 1023 | 1025 | m_log_addx_interlock_0 = 0; |
| 1024 | 1026 | |
| 1025 | 1027 | if (seekto == m_cylinder) { |
| 1026 | | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d acknowledge\n", __FUNCTION__, seekto)); |
| 1028 | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d acknowledge\n", m_unit, seekto)); |
| 1027 | 1029 | m_addx_acknowledge_0 = 0; // address acknowledge, if cylinder is reached |
| 1028 | 1030 | m_seek_incomplete_0 = 1; // reset seek incomplete |
| 1029 | 1031 | return; |
| r26227 | r26228 | |
| 1038 | 1040 | m_log_addx_interlock_0 = 1; // deassert the log address interlock signal |
| 1039 | 1041 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1040 | 1042 | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1041 | | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d incomplete\n", __FUNCTION__, seekto)); |
| 1043 | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d incomplete\n", m_unit, seekto)); |
| 1042 | 1044 | return; |
| 1043 | 1045 | } |
| 1044 | 1046 | } |
| r26227 | r26228 | |
| 1050 | 1052 | m_log_addx_interlock_0 = 1; // deassert the log address interlock signal |
| 1051 | 1053 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1052 | 1054 | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1053 | | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d incomplete\n", __FUNCTION__, seekto)); |
| 1055 | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d incomplete\n", m_unit, seekto)); |
| 1054 | 1056 | return; |
| 1055 | 1057 | } |
| 1056 | 1058 | } |
| 1057 | | LOG_DRIVE((1,"[DHD] %s: STROBE to cylinder %d (now %d) - interlock\n", __FUNCTION__, seekto, m_cylinder)); |
| 1059 | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d (now %d) - interlock\n", m_unit, seekto, m_cylinder)); |
| 1058 | 1060 | |
| 1059 | 1061 | m_addx_acknowledge_0 = 1; // deassert address acknowledge signal |
| 1060 | 1062 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| r26227 | r26228 | |
| 1067 | 1069 | */ |
| 1068 | 1070 | void diablo_hd_device::set_egate(int gate) |
| 1069 | 1071 | { |
| 1070 | | m_egate_0 = gate & 1; |
| 1072 | m_egate_0 = gate & 1; |
| 1071 | 1073 | } |
| 1072 | 1074 | |
| 1073 | 1075 | /** |
| r26227 | r26228 | |
| 1076 | 1078 | */ |
| 1077 | 1079 | void diablo_hd_device::set_wrgate(int gate) |
| 1078 | 1080 | { |
| 1079 | | m_wrgate_0 = gate & 1; |
| 1081 | m_wrgate_0 = gate & 1; |
| 1080 | 1082 | } |
| 1081 | 1083 | |
| 1082 | 1084 | /** |
| r26227 | r26228 | |
| 1085 | 1087 | */ |
| 1086 | 1088 | void diablo_hd_device::set_rdgate(int gate) |
| 1087 | 1089 | { |
| 1088 | | m_rdgate_0 = gate & 1; |
| 1090 | m_rdgate_0 = gate & 1; |
| 1089 | 1091 | } |
| 1090 | 1092 | |
| 1091 | 1093 | /** |
| r26227 | r26228 | |
| 1108 | 1110 | void diablo_hd_device::wr_data(int index, int wrdata) |
| 1109 | 1111 | { |
| 1110 | 1112 | if (m_wrgate_0) { |
| 1111 | | LOG_DRIVE((0,"[DHD] %s: unit #%d wrgate not asserted\n", __FUNCTION__, m_unit)); |
| 1113 | LOG_DRIVE((0,"[DHD%u] wrgate not asserted\n", m_unit)); |
| 1112 | 1114 | return; // write gate is not asserted (active 0) |
| 1113 | 1115 | } |
| 1114 | 1116 | |
| 1115 | 1117 | if (index < 0 || index >= bits_per_sector()) { |
| 1116 | | LOG_DRIVE((0,"[DHD] %s: unit #%d index out of range (%d)\n", __FUNCTION__, m_unit, index)); |
| 1118 | LOG_DRIVE((0,"[DHD%u] index out of range (%d)\n", m_unit, index)); |
| 1117 | 1119 | return; // don't write before or beyond the sector |
| 1118 | 1120 | } |
| 1119 | 1121 | |
| 1120 | 1122 | if (-1 == m_page) { |
| 1121 | | LOG_DRIVE((0,"[DHD] %s: unit #%d invalid page\n", __FUNCTION__, m_unit)); |
| 1123 | LOG_DRIVE((0,"[DHD%u] invalid page\n", m_unit)); |
| 1122 | 1124 | return; // invalid page |
| 1123 | 1125 | } |
| 1124 | 1126 | |
| r26227 | r26228 | |
| 1126 | 1128 | if (-1 == m_wrfirst) |
| 1127 | 1129 | m_wrfirst = index; |
| 1128 | 1130 | |
| 1129 | | LOG_DRIVE((7,"[DHD] %s: unit #%d %d/%d/%d bit #%d bit:%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, index, wrdata)); |
| 1131 | LOG_DRIVE((7,"[DHD%u] C/H/S:%d/%d/%d index #%d bit:%d\n", m_unit, m_cylinder, m_head, m_sector, index, wrdata)); |
| 1130 | 1132 | |
| 1131 | 1133 | if (index < GUARD_ZONE_BITS) { |
| 1132 | 1134 | /* don't write in the guard zone (?) */ |
| r26227 | r26228 | |
| 1150 | 1152 | int bit = 0; |
| 1151 | 1153 | |
| 1152 | 1154 | if (m_rdgate_0) { |
| 1153 | | LOG_DRIVE((8,"[DHD] %s: unit #%d rdgate not asserted\n", __FUNCTION__, m_unit)); |
| 1154 | | return 0; // read gate is not asserted (active 0) |
| 1155 | LOG_DRIVE((8,"[DHD%u] rdgate not asserted\n", m_unit)); |
| 1156 | return 1; // read gate is not asserted (active 0) |
| 1155 | 1157 | } |
| 1156 | 1158 | |
| 1157 | 1159 | if (index < 0 || index >= bits_per_sector()) { |
| 1158 | | LOG_DRIVE((0,"[DHD] %s: unit #%d index out of range (%d)\n", __FUNCTION__, m_unit, index)); |
| 1160 | LOG_DRIVE((0,"[DHD%u] index out of range (%d)\n", m_unit, index)); |
| 1159 | 1161 | return 1; // don't read before or beyond the sector |
| 1160 | 1162 | } |
| 1161 | 1163 | |
| 1162 | 1164 | if (0 == m_sector_mark_0) { |
| 1163 | | LOG_DRIVE((0,"[DHD] %s: unit #%d read while sector mark is asserted\n", __FUNCTION__, m_unit)); |
| 1165 | LOG_DRIVE((0,"[DHD%u] read while sector mark is asserted\n", m_unit)); |
| 1164 | 1166 | return 1; // no data while sector mark is asserted |
| 1165 | 1167 | } |
| 1166 | 1168 | |
| 1167 | 1169 | if (-1 == m_page) { |
| 1168 | | LOG_DRIVE((0,"[DHD] %s: unit #%d invalid page\n", __FUNCTION__, m_unit)); |
| 1170 | LOG_DRIVE((0,"[DHD%u] invalid page\n", m_unit)); |
| 1169 | 1171 | return 1; // invalid page |
| 1170 | 1172 | } |
| 1171 | 1173 | |
| r26227 | r26228 | |
| 1174 | 1176 | m_rdfirst = index; |
| 1175 | 1177 | |
| 1176 | 1178 | RDBIT(bits,index,bit); |
| 1177 | | LOG_DRIVE((7,"[DHD] %s: read #%d %d/%d/%d bit #%d:%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, index, bit)); |
| 1179 | LOG_DRIVE((7,"[DHD%u] C/H/S:%d/%d/%d index #%d bit:%d\n", m_unit, m_cylinder, m_head, m_sector, index, bit)); |
| 1178 | 1180 | m_rdlast = index; |
| 1179 | 1181 | return bit; |
| 1180 | 1182 | } |
| r26227 | r26228 | |
| 1193 | 1195 | int clk = 0; |
| 1194 | 1196 | |
| 1195 | 1197 | if (index < 0 || index >= bits_per_sector()) { |
| 1196 | | LOG_DRIVE((0,"[DHD] %s: unit #%d index out of range (%d)\n", __FUNCTION__, m_unit, index)); |
| 1198 | LOG_DRIVE((0,"[DHD%u] index out of range (%d)\n", m_unit, index)); |
| 1197 | 1199 | return 1; // don't read before or beyond the sector |
| 1198 | 1200 | } |
| 1199 | 1201 | |
| 1200 | 1202 | if (0 == m_sector_mark_0) { |
| 1201 | | LOG_DRIVE((0,"[DHD] %s: unit #%d read while sector mark is asserted\n", __FUNCTION__, m_unit)); |
| 1203 | LOG_DRIVE((0,"[DHD%u] read while sector mark is asserted\n", m_unit)); |
| 1202 | 1204 | return 1; // no clock while sector mark is low (?) |
| 1203 | 1205 | } |
| 1204 | 1206 | |
| 1205 | 1207 | if (-1 == m_page) { |
| 1206 | | LOG_DRIVE((0,"[DHD] %s: unit #%d invalid page\n", __FUNCTION__, m_unit)); |
| 1208 | LOG_DRIVE((0,"[DHD%u] invalid page\n", m_unit)); |
| 1207 | 1209 | return 1; // invalid page |
| 1208 | 1210 | } |
| 1209 | 1211 | |
| r26227 | r26228 | |
| 1219 | 1221 | } else { |
| 1220 | 1222 | clk = 0; |
| 1221 | 1223 | } |
| 1222 | | LOG_DRIVE((7,"[DHD] %s: read #%d %d/%d/%d clk #%d:%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector, index, clk)); |
| 1224 | LOG_DRIVE((7,"[DHD%u] C/H/S:%d/%d/%d index #%d clk:%d\n", m_unit, m_cylinder, m_head, m_sector, index, clk)); |
| 1223 | 1225 | m_rdlast = index; |
| 1224 | 1226 | return clk ^ 1; |
| 1225 | 1227 | } |
| r26227 | r26228 | |
| 1230 | 1232 | */ |
| 1231 | 1233 | void diablo_hd_device::sector_mark_1() |
| 1232 | 1234 | { |
| 1233 | | LOG_DRIVE((9,"[DHD] %s: unit #%d C/H/S:%d/%d/%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 1234 | | /* set sector mark to 1 */ |
| 1235 | | m_sector_mark_0 = 1; |
| 1235 | LOG_DRIVE((9,"[DHD%u] C/H/S:%d/%d/%d sector_mark_0=1\n", m_unit, m_cylinder, m_head, m_sector)); |
| 1236 | m_sector_mark_0 = 1; // deassert sector mark (set to 1) |
| 1236 | 1237 | } |
| 1237 | 1238 | |
| 1238 | 1239 | /** |
| r26227 | r26228 | |
| 1245 | 1246 | */ |
| 1246 | 1247 | void diablo_hd_device::sector_mark_0() |
| 1247 | 1248 | { |
| 1248 | | LOG_DRIVE((9,"[DHD] %s: unit #%d C/H/S:%d/%d/%d\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector)); |
| 1249 | LOG_DRIVE((9,"[DHD%u] C/H/S:%d/%d/%d sector_mark_0=0\n", m_unit, m_cylinder, m_head, m_sector)); |
| 1249 | 1250 | |
| 1250 | | // squeeze previous sector bits, if it was written to |
| 1251 | | squeeze_sector(); |
| 1252 | | |
| 1253 | | m_sector_mark_0 = 0; |
| 1254 | | |
| 1251 | squeeze_sector(); // squeeze previous sector bits, if it was written to |
| 1252 | m_sector_mark_0 = 0; // assert sector mark (set to 0) |
| 1255 | 1253 | // reset read and write bit locations |
| 1256 | 1254 | m_rdfirst = -1; |
| 1257 | 1255 | m_rdlast = -1; |
| r26227 | r26228 | |
| 1268 | 1266 | m_image = static_cast<diablo_image_device *>(subdevice("drive")); |
| 1269 | 1267 | |
| 1270 | 1268 | m_packs = 1; // FIXME: get from configuration? |
| 1269 | m_unit = strstr(m_image->tag(), "diablo0") ? 0 : 1; |
| 1271 | 1270 | |
| 1272 | 1271 | m_cache = global_alloc_array(UINT8*, DIABLO_PAGES); |
| 1273 | 1272 | memset(m_cache, 0, sizeof(UINT8*) * DIABLO_PAGES); |
| r26227 | r26228 | |
| 1297 | 1296 | m_sector_mark_1_time = DIABLO44_SECTOR_MARK_PULSE_PRE; |
| 1298 | 1297 | m_bit_time = DIABLO44_BIT_TIME(1); |
| 1299 | 1298 | } |
| 1300 | | LOG_DRIVE((0,"[DHD] %s: rotation time : %.0fns\n", __FUNCTION__, 1e9 * m_rotation_time.as_double())); |
| 1301 | | LOG_DRIVE((0,"[DHD] %s: sector time : %.0fns\n", __FUNCTION__, 1e9 * m_sector_time.as_double())); |
| 1302 | | LOG_DRIVE((0,"[DHD] %s: sector mark 0 time : %.0fns\n", __FUNCTION__, 1e9 * m_sector_mark_0_time.as_double())); |
| 1303 | | LOG_DRIVE((0,"[DHD] %s: sector mark 1 time : %.0fns\n", __FUNCTION__, 1e9 * m_sector_mark_1_time.as_double())); |
| 1304 | | LOG_DRIVE((0,"[DHD] %s: bit time : %.0fns\n", __FUNCTION__, 1e9 * m_bit_time.as_double())); |
| 1299 | LOG_DRIVE((0,"[DHD%u] rotation time : %.0fns\n", m_unit, m_rotation_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1300 | LOG_DRIVE((0,"[DHD%u] sector time : %.0fns\n", m_unit, m_sector_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1301 | LOG_DRIVE((0,"[DHD%u] sector mark 0 time : %.0fns\n", m_unit, m_sector_mark_0_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1302 | LOG_DRIVE((0,"[DHD%u] sector mark 1 time : %.0fns\n", m_unit, m_sector_mark_1_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1303 | LOG_DRIVE((0,"[DHD%u] bit time : %.0fns\n", m_unit, m_bit_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1305 | 1304 | |
| 1306 | 1305 | m_s_r_w_0 = 1; // deassert seek/read/write ready |
| 1307 | 1306 | m_ready_0 = 1; // deassert drive ready |
| r26227 | r26228 | |
| 1313 | 1312 | // reset the disk drive's address |
| 1314 | 1313 | m_cylinder = 0; |
| 1315 | 1314 | m_head = 0; |
| 1316 | | m_sector = 0; |
| 1317 | | m_page = 0; |
| 1315 | m_sector = 10; |
| 1316 | m_page = 10; |
| 1318 | 1317 | |
| 1319 | 1318 | // disable the erase, write and read gates |
| 1320 | 1319 | m_egate_0 = 1; |
| r26227 | r26228 | |
| 1338 | 1337 | * @brief timer callback that is called thrice per sector in the rotation |
| 1339 | 1338 | * |
| 1340 | 1339 | * The timer is called three times at the events: |
| 1341 | | * 0: sector mark goes inactive |
| 1342 | | * 1: sector mark goes active |
| 1340 | * 0: sector mark goes active |
| 1341 | * 1: sector mark goes inactive |
| 1343 | 1342 | * 2: in the middle of the active phase |
| 1344 | 1343 | * |
| 1345 | 1344 | * @param id timer id |
| r26227 | r26228 | |
| 1347 | 1346 | */ |
| 1348 | 1347 | void diablo_hd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 1349 | 1348 | { |
| 1350 | | LOG_DRIVE((6,"[DHD] %s: id=%d param=%d ptr=%p @%lldns\n", __FUNCTION__, id, param, ptr, (long long int)(timer.elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND))); |
| 1349 | LOG_DRIVE((6,"[DHD%u] TIMER id=%d param=%d ptr=%p @%.0fns\n", m_unit, id, param, ptr, timer.elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1351 | 1350 | |
| 1352 | 1351 | switch (param) { |
| 1353 | 1352 | case 0: |
| 1353 | // assert sector mark |
| 1354 | sector_mark_0(); |
| 1355 | // next sector timer event is in the middle between sector_mark going 0 and back to 1 |
| 1354 | 1356 | timer.adjust(m_sector_mark_0_time, 1); |
| 1355 | | /* assert sector mark */ |
| 1356 | | sector_mark_0(); |
| 1357 | 1357 | break; |
| 1358 | 1358 | case 1: |
| 1359 | | /* next sector starting soon now */ |
| 1360 | | timer.adjust(m_sector_mark_1_time, 2); |
| 1361 | 1359 | /* call the sector_callback, if any */ |
| 1362 | 1360 | if (m_sector_callback) |
| 1363 | 1361 | (void)(*m_sector_callback)(m_sector_callback_cookie, m_unit); |
| 1362 | // next sector timer event is deassert of sector_mark_0 (set to 1) |
| 1363 | timer.adjust(m_sector_mark_1_time, 2); |
| 1364 | 1364 | break; |
| 1365 | 1365 | case 2: |
| 1366 | // deassert sector mark |
| 1367 | sector_mark_1(); |
| 1368 | // next sector timer event is sector_mark_0 for next sector |
| 1366 | 1369 | timer.adjust(m_sector_time - m_sector_mark_0_time, 0); |
| 1367 | | /* deassert sector mark */ |
| 1368 | | sector_mark_1(); |
| 1369 | 1370 | break; |
| 1370 | 1371 | } |
| 1371 | 1372 | } |