branches/alto2/src/emu/machine/diablo_hd.c
| r26330 | r26331 | |
| 5 | 5 | * |
| 6 | 6 | * Licenses: MAME, GPLv2 |
| 7 | 7 | **********************************************************/ |
| 8 | | |
| 9 | 8 | #include "diablo_hd.h" |
| 10 | 9 | |
| 11 | 10 | /** |
| r26330 | r26331 | |
| 83 | 82 | m_egate_0(1), |
| 84 | 83 | m_wrgate_0(1), |
| 85 | 84 | m_rdgate_0(1), |
| 85 | m_cylinders(DIABLO_CYLINDERS), |
| 86 | m_pages(DIABLO_PAGES), |
| 86 | 87 | m_cylinder(-1), |
| 87 | 88 | m_head(-1), |
| 88 | 89 | m_sector(-1), |
| 89 | 90 | m_page(-1), |
| 90 | | m_pages(DIABLO_PAGES), |
| 91 | 91 | m_cache(0), |
| 92 | 92 | m_bits(0), |
| 93 | 93 | m_rdfirst(-1), |
| r26330 | r26331 | |
| 132 | 132 | m_sector_callback = callback; |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | | #define DIABLO31_ROTATION_TIME attotime::from_usec(40000) //!< DIABLO 31 rotation time is approx. 40ms |
| 136 | | #define DIABLO31_SECTOR_TIME attotime::from_usec(40000/12) //!< DIABLO 31 sector time |
| 135 | #define DIABLO31_ROTATION_TIME attotime::from_usec(39900) //!< DIABLO 31 rotation time is approx. 40ms |
| 136 | #define DIABLO31_SECTOR_TIME attotime::from_usec(39900/12) //!< DIABLO 31 sector time |
| 137 | 137 | /** |
| 138 | 138 | * @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit |
| 139 | 139 | * ~= 133333 bits/track (?) |
| r26330 | r26331 | |
| 141 | 141 | * ~= 347 words/sector |
| 142 | 142 | */ |
| 143 | 143 | #define DIABLO31_BIT_TIME(bits) attotime::from_nsec(300*(bits)) |
| 144 | | #define DIABLO31_SECTOR_BITS 11111 |
| 145 | | #define DIABLO31_SECTOR_WORDS 347 //!< DIABLO 31 possible sector words |
| 144 | #define DIABLO31_SECTOR_BITS 10432 |
| 145 | #define DIABLO31_SECTOR_WORDS 347 //!< DIABLO 31 possible sector words |
| 146 | 146 | #define DIABLO31_SECTOR_MARK_PULSE_PRE DIABLO31_BIT_TIME(16) //!< pulse width of sector mark before the next sector begins |
| 147 | 147 | #define DIABLO31_SECTOR_MARK_PULSE_POST DIABLO31_BIT_TIME(16) //!< pulse width of sector mark after the next sector began |
| 148 | 148 | |
| r26330 | r26331 | |
| 155 | 155 | * ~= 325 words/sector |
| 156 | 156 | */ |
| 157 | 157 | #define DIABLO44_BIT_TIME(bits) attotime::from_nsec(200*(bits)) |
| 158 | | #define DIABLO44_SECTOR_BITS 10432 |
| 158 | #define DIABLO44_SECTOR_BITS 10432 |
| 159 | 159 | #define DIABLO44_SECTOR_WORDS 325 //!< DIABLO 44 possible sector words |
| 160 | 160 | #define DIABLO44_SECTOR_MARK_PULSE_PRE DIABLO44_BIT_TIME(16) //!< pulse width of sector mark before the next sector begins |
| 161 | 161 | #define DIABLO44_SECTOR_MARK_PULSE_POST DIABLO44_BIT_TIME(16) //!< pulse width of sector mark after the next sector began |
| r26330 | r26331 | |
| 284 | 284 | m_page = -1; |
| 285 | 285 | return; |
| 286 | 286 | } |
| 287 | | if (m_cylinder < 0 || m_cylinder >= DIABLO_CYLINDERS) { |
| 287 | if (m_cylinder < 0 || m_cylinder >= m_cylinders) { |
| 288 | 288 | LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d => invalid cylinder\n", m_unit, m_cylinder, m_head, m_sector)); |
| 289 | 289 | m_page = -1; |
| 290 | 290 | return; |
| r26330 | r26331 | |
| 304 | 304 | |
| 305 | 305 | // already have the sector image? |
| 306 | 306 | if (m_cache[m_page]) { |
| 307 | | LOG_DRIVE((6,"[DHD%u] CHS:%03d/%d/%02d => page:%d is cached\n", m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 307 | LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d => page:%d is cached\n", m_unit, m_cylinder, m_head, m_sector, m_page)); |
| 308 | 308 | return; |
| 309 | 309 | } |
| 310 | 310 | |
| r26330 | r26331 | |
| 735 | 735 | src = squeeze_sync(bits, src, 40); // sync on header preamble |
| 736 | 736 | LOG_DRIVE((0,"[DHD%u] header sync bit #%5d\n", m_unit, src)); |
| 737 | 737 | src = squeeze_record(bits, src, s->header, sizeof(s->header)); |
| 738 | LOG_DRIVE((0,"[DHD%u] header CRC bit #%5d\n", m_unit, src)); |
| 738 | 739 | src = squeeze_cksum(bits, src, &cksum_header); |
| 739 | 740 | #if DIABLO_DEBUG |
| 740 | 741 | dump_record(s->header, 0, sizeof(s->header), "header", 0); |
| r26330 | r26331 | |
| 744 | 745 | src = squeeze_sync(bits, src, 40); // sync on label preamble |
| 745 | 746 | LOG_DRIVE((0,"[DHD%u] label sync bit #%5d\n", m_unit, src)); |
| 746 | 747 | src = squeeze_record(bits, src, s->label, sizeof(s->label)); |
| 748 | LOG_DRIVE((0,"[DHD%u] label CRC bit #%5d\n", m_unit, src)); |
| 747 | 749 | src = squeeze_cksum(bits, src, &cksum_label); |
| 748 | 750 | #if DIABLO_DEBUG |
| 749 | 751 | dump_record(s->label, 0, sizeof(s->label), "label", 0); |
| r26330 | r26331 | |
| 753 | 755 | src = squeeze_sync(bits, src, 40); // sync on data preamble |
| 754 | 756 | LOG_DRIVE((0,"[DHD%u] data sync bit #%5d\n", m_unit, src)); |
| 755 | 757 | src = squeeze_record(bits, src, s->data, sizeof(s->data)); |
| 758 | LOG_DRIVE((0,"[DHD%u] data CRC bit #%5d\n", m_unit, src)); |
| 756 | 759 | src = squeeze_cksum(bits, src, &cksum_data); |
| 757 | 760 | #if DIABLO_DEBUG |
| 758 | 761 | dump_record(s->data, 0, sizeof(s->data), "data", 1); |
| 759 | 762 | #endif |
| 763 | LOG_DRIVE((0,"[DHD%u] postamble bit #%5d\n", m_unit, src)); |
| 760 | 764 | |
| 761 | 765 | /* The checksum start value always seems to be 0521 */ |
| 762 | 766 | cksum_header ^= cksum(s->header, sizeof(s->header), 0521); |
| r26330 | r26331 | |
| 786 | 790 | */ |
| 787 | 791 | int diablo_hd_device::bits_per_sector() const |
| 788 | 792 | { |
| 789 | | return m_diablo31 ? DIABLO31_SECTOR_BITS : DIABLO44_SECTOR_BITS; |
| 793 | return m_diablo31 ? DIABLO31_SECTOR_BITS : DIABLO44_SECTOR_BITS; |
| 790 | 794 | } |
| 791 | 795 | |
| 792 | 796 | /** |
| r26330 | r26331 | |
| 795 | 799 | */ |
| 796 | 800 | const char* diablo_hd_device::description() const |
| 797 | 801 | { |
| 798 | | return m_description; |
| 802 | return m_description; |
| 799 | 803 | } |
| 800 | 804 | |
| 801 | 805 | /** |
| r26330 | r26331 | |
| 804 | 808 | */ |
| 805 | 809 | int diablo_hd_device::unit() const |
| 806 | 810 | { |
| 807 | | return m_unit; |
| 811 | return m_unit; |
| 808 | 812 | } |
| 809 | 813 | |
| 810 | 814 | /** |
| r26330 | r26331 | |
| 813 | 817 | */ |
| 814 | 818 | attotime diablo_hd_device::rotation_time() const |
| 815 | 819 | { |
| 816 | | return m_rotation_time; |
| 820 | return m_rotation_time; |
| 817 | 821 | } |
| 818 | 822 | |
| 819 | 823 | /** |
| r26330 | r26331 | |
| 822 | 826 | */ |
| 823 | 827 | attotime diablo_hd_device::sector_time() const |
| 824 | 828 | { |
| 825 | | return m_sector_time; |
| 829 | return m_sector_time; |
| 826 | 830 | } |
| 827 | 831 | |
| 828 | 832 | /** |
| r26330 | r26331 | |
| 831 | 835 | */ |
| 832 | 836 | attotime diablo_hd_device::bit_time() const |
| 833 | 837 | { |
| 834 | | return m_bit_time; |
| 838 | return m_bit_time; |
| 835 | 839 | } |
| 836 | 840 | |
| 837 | 841 | /** |
| r26330 | r26331 | |
| 840 | 844 | */ |
| 841 | 845 | int diablo_hd_device::get_seek_read_write_0() const |
| 842 | 846 | { |
| 843 | | return m_s_r_w_0; |
| 847 | return m_s_r_w_0; |
| 844 | 848 | } |
| 845 | 849 | |
| 846 | 850 | /** |
| r26330 | r26331 | |
| 849 | 853 | */ |
| 850 | 854 | int diablo_hd_device::get_ready_0() const |
| 851 | 855 | { |
| 852 | | return m_ready_0; |
| 856 | return m_ready_0; |
| 853 | 857 | } |
| 854 | 858 | |
| 855 | 859 | /** |
| r26330 | r26331 | |
| 877 | 881 | */ |
| 878 | 882 | int diablo_hd_device::get_addx_acknowledge_0() const |
| 879 | 883 | { |
| 880 | | return m_addx_acknowledge_0; |
| 884 | return m_addx_acknowledge_0; |
| 881 | 885 | } |
| 882 | 886 | |
| 883 | 887 | /** |
| r26330 | r26331 | |
| 886 | 890 | */ |
| 887 | 891 | int diablo_hd_device::get_log_addx_interlock_0() const |
| 888 | 892 | { |
| 889 | | return m_log_addx_interlock_0; |
| 893 | return m_log_addx_interlock_0; |
| 890 | 894 | } |
| 891 | 895 | |
| 892 | 896 | /** |
| r26330 | r26331 | |
| 895 | 899 | */ |
| 896 | 900 | int diablo_hd_device::get_seek_incomplete_0() const |
| 897 | 901 | { |
| 898 | | return m_seek_incomplete_0; |
| 902 | return m_seek_incomplete_0; |
| 899 | 903 | } |
| 900 | 904 | |
| 901 | 905 | /** |
| r26330 | r26331 | |
| 909 | 913 | */ |
| 910 | 914 | int diablo_hd_device::get_cylinder() const |
| 911 | 915 | { |
| 912 | | return m_cylinder; |
| 916 | return m_cylinder; |
| 913 | 917 | } |
| 914 | 918 | |
| 915 | 919 | /** |
| r26330 | r26331 | |
| 923 | 927 | */ |
| 924 | 928 | int diablo_hd_device::get_head() const |
| 925 | 929 | { |
| 926 | | return m_head; |
| 930 | return m_head; |
| 927 | 931 | } |
| 928 | 932 | |
| 929 | 933 | /** |
| r26330 | r26331 | |
| 941 | 945 | */ |
| 942 | 946 | int diablo_hd_device::get_sector() const |
| 943 | 947 | { |
| 944 | | return m_sector; |
| 948 | return m_sector; |
| 945 | 949 | } |
| 946 | 950 | |
| 947 | 951 | /** |
| r26330 | r26331 | |
| 955 | 959 | */ |
| 956 | 960 | int diablo_hd_device::get_page() const |
| 957 | 961 | { |
| 958 | | return m_page; |
| 962 | return m_page; |
| 959 | 963 | } |
| 960 | 964 | |
| 961 | 965 | /** |
| r26330 | r26331 | |
| 1021 | 1025 | // assert the seek-read-write signal |
| 1022 | 1026 | m_s_r_w_0 = 0; |
| 1023 | 1027 | |
| 1028 | bool complete = true; |
| 1024 | 1029 | if (seekto < m_cylinder) { |
| 1025 | 1030 | m_cylinder--; // previous cylinder |
| 1026 | 1031 | if (m_cylinder < 0) { |
| 1027 | 1032 | m_cylinder = 0; |
| 1028 | | m_log_addx_interlock_0 = 1; // deassert the log address interlock signal |
| 1029 | | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1030 | | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1031 | | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d incomplete\n", m_unit, seekto)); |
| 1032 | | return; |
| 1033 | complete = false; |
| 1033 | 1034 | } |
| 1034 | 1035 | } |
| 1035 | 1036 | if (seekto > m_cylinder) { |
| 1036 | 1037 | /* increment cylinder */ |
| 1037 | 1038 | m_cylinder++; |
| 1038 | | if (m_cylinder >= DIABLO_CYLINDERS) { |
| 1039 | | m_cylinder = DIABLO_CYLINDERS - 1; |
| 1040 | | m_log_addx_interlock_0 = 1; // deassert the log address interlock signal |
| 1041 | | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1042 | | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1043 | | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d incomplete\n", m_unit, seekto)); |
| 1044 | | return; |
| 1039 | if (m_cylinder >= m_cylinders) { |
| 1040 | m_cylinder = m_cylinders - 1; |
| 1041 | complete = false; |
| 1045 | 1042 | } |
| 1046 | 1043 | } |
| 1047 | | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d (now %d) - interlock\n", m_unit, seekto, m_cylinder)); |
| 1048 | | |
| 1049 | | m_addx_acknowledge_0 = 1; // deassert address acknowledge signal |
| 1050 | | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1051 | | read_sector(); |
| 1044 | if (complete) { |
| 1045 | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d (now %d) - interlock\n", m_unit, seekto, m_cylinder)); |
| 1046 | m_addx_acknowledge_0 = 1; // deassert address acknowledge signal |
| 1047 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1048 | read_sector(); |
| 1049 | } else { |
| 1050 | m_log_addx_interlock_0 = 0; // deassert the log address interlock signal |
| 1051 | m_seek_incomplete_0 = 1; // deassert seek incomplete signal |
| 1052 | m_addx_acknowledge_0 = 0; // assert address acknowledge signal |
| 1053 | LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d incomplete\n", m_unit, seekto)); |
| 1054 | } |
| 1052 | 1055 | } |
| 1053 | 1056 | |
| 1054 | 1057 | /** |
| r26330 | r26331 | |
| 1057 | 1060 | */ |
| 1058 | 1061 | void diablo_hd_device::set_egate(int gate) |
| 1059 | 1062 | { |
| 1060 | | m_egate_0 = gate & 1; |
| 1063 | m_egate_0 = gate & 1; |
| 1061 | 1064 | } |
| 1062 | 1065 | |
| 1063 | 1066 | /** |
| r26330 | r26331 | |
| 1066 | 1069 | */ |
| 1067 | 1070 | void diablo_hd_device::set_wrgate(int gate) |
| 1068 | 1071 | { |
| 1069 | | m_wrgate_0 = gate & 1; |
| 1072 | m_wrgate_0 = gate & 1; |
| 1070 | 1073 | } |
| 1071 | 1074 | |
| 1072 | 1075 | /** |
| r26330 | r26331 | |
| 1075 | 1078 | */ |
| 1076 | 1079 | void diablo_hd_device::set_rdgate(int gate) |
| 1077 | 1080 | { |
| 1078 | | m_rdgate_0 = gate & 1; |
| 1081 | m_rdgate_0 = gate & 1; |
| 1079 | 1082 | } |
| 1080 | 1083 | |
| 1081 | 1084 | /** |
| r26330 | r26331 | |
| 1098 | 1101 | void diablo_hd_device::wr_data(int index, int wrdata) |
| 1099 | 1102 | { |
| 1100 | 1103 | if (m_wrgate_0) { |
| 1101 | | LOG_DRIVE((0,"[DHD%u] wrgate not asserted\n", m_unit)); |
| 1104 | LOG_DRIVE((0,"[DHD%u] index=%d wrgate not asserted\n", m_unit, index)); |
| 1102 | 1105 | return; // write gate is not asserted (active 0) |
| 1103 | 1106 | } |
| 1104 | 1107 | |
| 1105 | 1108 | if (index < 0 || index >= bits_per_sector()) { |
| 1106 | | LOG_DRIVE((0,"[DHD%u] index out of range (%d)\n", m_unit, index)); |
| 1109 | LOG_DRIVE((0,"[DHD%u] index=%d out of range\n", m_unit, index)); |
| 1107 | 1110 | return; // don't write before or beyond the sector |
| 1108 | 1111 | } |
| 1109 | 1112 | |
| r26330 | r26331 | |
| 1140 | 1143 | int bit = 0; |
| 1141 | 1144 | |
| 1142 | 1145 | if (m_rdgate_0) { |
| 1143 | | LOG_DRIVE((1,"[DHD%u] rdgate not asserted\n", m_unit)); |
| 1146 | LOG_DRIVE((1,"[DHD%u] index=%d rdgate not asserted\n", m_unit, index)); |
| 1144 | 1147 | return 0; // read gate is not asserted (active 0) |
| 1145 | 1148 | } |
| 1146 | 1149 | |
| 1147 | 1150 | if (index < 0 || index >= bits_per_sector()) { |
| 1148 | | LOG_DRIVE((0,"[DHD%u] index out of range (%d)\n", m_unit, index)); |
| 1151 | LOG_DRIVE((0,"[DHD%u] index=%d out of range\n", m_unit, index)); |
| 1149 | 1152 | return 1; // don't read before or beyond the sector |
| 1150 | 1153 | } |
| 1151 | 1154 | |
| r26330 | r26331 | |
| 1236 | 1239 | { |
| 1237 | 1240 | LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d sector_mark_0=0\n", m_unit, m_cylinder, m_head, m_sector)); |
| 1238 | 1241 | |
| 1242 | // HACK: deassert wrgate |
| 1243 | m_wrgate_0 = 1; |
| 1244 | |
| 1239 | 1245 | squeeze_sector(); // squeeze previous sector bits, if it was written to |
| 1240 | 1246 | m_sector_mark_0 = 0; // assert sector mark (set to 0) |
| 1241 | 1247 | // reset read and write bit locations |
| r26330 | r26331 | |
| 1287 | 1293 | m_sector_mark_0_time = DIABLO31_SECTOR_MARK_PULSE_PRE; |
| 1288 | 1294 | m_sector_mark_1_time = DIABLO31_SECTOR_MARK_PULSE_PRE; |
| 1289 | 1295 | m_bit_time = DIABLO31_BIT_TIME(1); |
| 1296 | m_cylinders = DIABLO_CYLINDERS; |
| 1290 | 1297 | m_pages = DIABLO_PAGES; |
| 1291 | 1298 | } else { |
| 1292 | 1299 | snprintf(m_description, sizeof(m_description), "DIABLO44"); |
| r26330 | r26331 | |
| 1295 | 1302 | m_sector_mark_0_time = DIABLO44_SECTOR_MARK_PULSE_PRE; |
| 1296 | 1303 | m_sector_mark_1_time = DIABLO44_SECTOR_MARK_PULSE_PRE; |
| 1297 | 1304 | m_bit_time = DIABLO44_BIT_TIME(1); |
| 1305 | m_cylinders = 2 * DIABLO_CYLINDERS; |
| 1298 | 1306 | m_pages = 2 * DIABLO_PAGES; |
| 1299 | 1307 | } |
| 1300 | 1308 | LOG_DRIVE((0,"[DHD%u] rotation time : %.0fns\n", m_unit, m_rotation_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| r26330 | r26331 | |
| 1349 | 1357 | */ |
| 1350 | 1358 | void diablo_hd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 1351 | 1359 | { |
| 1352 | | 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)); |
| 1360 | LOG_DRIVE((9,"[DHD%u] TIMER id=%d param=%d ptr=%p @%.0fns\n", m_unit, id, param, ptr, timer.elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND)); |
| 1353 | 1361 | |
| 1354 | 1362 | switch (param) { |
| 1355 | 1363 | case 0: |