src/mess/machine/99_dsk.c
| r8042 | r8043 | |
| 36 | 36 | #include "99_dsk.h" |
| 37 | 37 | #include "mm58274c.h" |
| 38 | 38 | #include "devices/flopdrv.h" |
| 39 | #include "devices/harddriv.h" |
| 40 | #include "devices/ti99_hd.h" |
| 41 | #include "harddisk.h" |
| 42 | #include "formats/ti99_dsk.h" |
| 39 | 43 | |
| 40 | | |
| 41 | 44 | #define MAX_FLOPPIES 4 |
| 42 | 45 | |
| 43 | | static int use_80_track_drives; |
| 44 | | |
| 45 | 46 | /* defines for DRQ_IRQ_status */ |
| 46 | 47 | enum |
| 47 | 48 | { |
| r8042 | r8043 | |
| 89 | 90 | } |
| 90 | 91 | |
| 91 | 92 | /* |
| 92 | | Callback for the ti99_dsk format. Required for the image format handler |
| 93 | | to find out whether we have a 40-track disk in an 80-track drive. |
| 94 | | */ |
| 95 | | int ti99_image_in_80_track_drive() |
| 96 | | { |
| 97 | | return use_80_track_drives; |
| 98 | | } |
| 99 | | |
| 100 | | /* |
| 101 | 93 | call this when the state of DSKhold or DRQ/IRQ or DVENA change |
| 102 | 94 | |
| 103 | 95 | Emulation is faulty because the CPU is actually stopped in the midst of |
| r8042 | r8043 | |
| 120 | 112 | fdc_handle_hold(machine); |
| 121 | 113 | } |
| 122 | 114 | |
| 123 | | static void hfdc_int_callback(int which, int state); |
| 124 | | static int hfdc_select_callback(int which, select_mode_t select_mode, int select_line, int gpos); |
| 125 | | static UINT8 hfdc_dma_read_callback(int which, offs_t offset); |
| 126 | | static void hfdc_dma_write_callback(int which, offs_t offset, UINT8 data); |
| 127 | | |
| 128 | | static const smc92x4_intf hfdc_intf = |
| 129 | | { |
| 130 | | hfdc_select_callback, |
| 131 | | hfdc_dma_read_callback, |
| 132 | | hfdc_dma_write_callback, |
| 133 | | hfdc_int_callback |
| 134 | | }; |
| 135 | | |
| 136 | 115 | /* |
| 137 | 116 | callback called whenever DRQ/IRQ state change |
| 138 | 117 | */ |
| r8042 | r8043 | |
| 170 | 149 | {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3} |
| 171 | 150 | }; |
| 172 | 151 | |
| 173 | | |
| 174 | 152 | /* |
| 175 | 153 | Initializes all available controllers. This routine is only used in the |
| 176 | 154 | init state of the emulator. During the normal operation, only the |
| 177 | 155 | reset routines are used. |
| 178 | 156 | */ |
| 157 | // TODO: Check that: floppy_mon_w(w->drive, CLEAR_LINE); |
| 158 | |
| 179 | 159 | void ti99_floppy_controllers_init_all(running_machine *machine) |
| 180 | 160 | { |
| 181 | | /* initialize the controller chip for HFDC */ |
| 182 | | smc92x4_init(0, & hfdc_intf); |
| 183 | | |
| 184 | 161 | motor_on_timer = timer_alloc(machine, motor_on_timer_callback, NULL); |
| 185 | 162 | } |
| 186 | 163 | |
| r8042 | r8043 | |
| 221 | 198 | DVENA = 0; |
| 222 | 199 | motor_on = 0; |
| 223 | 200 | |
| 201 | ti99_set_80_track_drives(FALSE); |
| 202 | |
| 224 | 203 | set_all_geometries(machine, FLOPPY_DRIVE_DS_40); |
| 225 | | use_80_track_drives = FALSE; |
| 226 | | |
| 204 | |
| 227 | 205 | ti99_peb_set_card_handlers(0x1100, & fdc_handlers); |
| 228 | 206 | if (fdc) { |
| 229 | 207 | wd17xx_reset(fdc); /* resets the fdc */ |
| r8042 | r8043 | |
| 414 | 392 | DVENA = 0; |
| 415 | 393 | motor_on = 0; |
| 416 | 394 | |
| 395 | ti99_set_80_track_drives(FALSE); |
| 396 | |
| 417 | 397 | set_all_geometries(machine, FLOPPY_DRIVE_DS_40); |
| 418 | | use_80_track_drives = FALSE; |
| 419 | 398 | |
| 420 | 399 | ti99_peb_set_card_handlers(0x1100, & ccfdc_handlers); |
| 421 | 400 | |
| r8042 | r8043 | |
| 635 | 614 | DVENA = 0; |
| 636 | 615 | motor_on = 0; |
| 637 | 616 | |
| 617 | ti99_set_80_track_drives(FALSE); |
| 618 | |
| 638 | 619 | set_all_geometries(machine, FLOPPY_DRIVE_DS_40); |
| 639 | | use_80_track_drives = FALSE; |
| 640 | 620 | |
| 641 | 621 | ti99_peb_set_card_handlers(0x1100, & bwg_handlers); |
| 642 | 622 | |
| r8042 | r8043 | |
| 894 | 874 | Reference: |
| 895 | 875 | * hfdc manual |
| 896 | 876 | <ftp://ftp.whtech.com//datasheets & manuals/Hardware manuals/hfdc manual.max> |
| 877 | |
| 878 | For smc92x4 (HFDC-internal DSR) |
| 879 | FM: gap0=3, gap1=26, gap2=11, gap3=27, gap4=42, sync=6, count=9, size=2, fm=16, gap_byte=ff |
| 880 | MFM: gap0=2, gap1=30, gap2=22, gap3=20, gap4=42, sync=12, count=18, size=2, fm=0, gap_byte=4e |
| 897 | 881 | */ |
| 898 | 882 | |
| 899 | 883 | /* prototypes */ |
| r8042 | r8043 | |
| 910 | 894 | hfdc_mem_w |
| 911 | 895 | }; |
| 912 | 896 | |
| 897 | #define HFDC_MAX_FLOPPY 4 |
| 898 | #define HFDC_MAX_HARD 4 |
| 899 | |
| 913 | 900 | static int hfdc_rtc_enable; |
| 914 | 901 | static int hfdc_ram_offset[3]; |
| 915 | 902 | static int hfdc_rom_offset; |
| 916 | 903 | static int cru_sel; |
| 917 | 904 | static UINT8 *hfdc_ram; |
| 905 | |
| 918 | 906 | static int hfdc_irq_state; |
| 907 | static int hfdc_dip_state; |
| 919 | 908 | |
| 909 | static running_device *floppy_unit[4]; |
| 910 | static running_device *harddisk_unit[4]; |
| 911 | |
| 912 | static UINT8 output1_latch; |
| 913 | static UINT8 output2_latch; |
| 914 | |
| 915 | static int dma_address; |
| 916 | |
| 917 | static int line_to_index(UINT8 line, int max) |
| 918 | { |
| 919 | int index = 0; |
| 920 | while (index < max) |
| 921 | { |
| 922 | if ((line & 0x01)!=0) |
| 923 | break; |
| 924 | else |
| 925 | { |
| 926 | line = line >> 1; |
| 927 | index++; |
| 928 | } |
| 929 | } |
| 930 | if (index==max) return -1; |
| 931 | return index; |
| 932 | } |
| 933 | |
| 920 | 934 | /* |
| 921 | | Select the correct HFDC disk units. |
| 922 | | floppy disks are selected by the 4 gpos instead of the select lines. |
| 935 | Select the HFDC hard disk unit |
| 936 | This function implements the selection logic on the PCB (outside the |
| 937 | controller chip) |
| 938 | The HDC9234 allows up to four drives to be selected by the select lines. |
| 939 | This is not enough for controlling four floppy drives and three hard |
| 940 | drives, so the user programmable outputs are used to select the floppy |
| 941 | drives. This selection happens completely outside of the controller, |
| 942 | so we must implement it here. |
| 923 | 943 | */ |
| 924 | | static int hfdc_select_callback(int which, select_mode_t select_mode, int select_line, int gpos) |
| 944 | |
| 945 | static running_device *hfdc_current_harddisk(void) |
| 925 | 946 | { |
| 926 | | int disk_unit; |
| 947 | int disk_unit = -1; |
| 948 | disk_unit = line_to_index((output1_latch>>4)&0x0f, HFDC_MAX_HARD); |
| 927 | 949 | |
| 928 | | (void) which; |
| 950 | /* The HFDC does not use disk_unit=0. The first HD has index 1. */ |
| 951 | /* if (disk_unit>=0) printf("Select hard disk %d\n", disk_unit); |
| 952 | else printf("No hard disk selected\n"); |
| 953 | */ |
| 954 | return harddisk_unit[disk_unit]; |
| 955 | } |
| 929 | 956 | |
| 930 | | switch (select_mode) |
| 957 | /* |
| 958 | Select the HFDC floppy disk unit |
| 959 | This function implements the selection logic on the PCB (outside the |
| 960 | controller chip) |
| 961 | */ |
| 962 | |
| 963 | static running_device *hfdc_current_floppy(void) |
| 964 | { |
| 965 | int disk_unit = -1; |
| 966 | disk_unit = line_to_index(output1_latch & 0x0f, HFDC_MAX_FLOPPY); |
| 967 | |
| 968 | if (disk_unit<0) |
| 931 | 969 | { |
| 932 | | /*case sm_at_harddisk:*/ |
| 933 | | case sm_harddisk: |
| 934 | | /* hard disk */ |
| 935 | | disk_unit = select_line - 1; |
| 936 | | break; |
| 970 | // printf("No unit selected\n"); |
| 971 | return NULL; |
| 972 | } |
| 937 | 973 | |
| 938 | | case sm_floppy_slow: |
| 939 | | case sm_floppy_fast: |
| 940 | | /* floppy disk */ |
| 941 | | /* We use the 4 general purpose output as select lines in order to |
| 942 | | support 4 drives. */ |
| 943 | | switch (gpos & 0xf) |
| 944 | | { |
| 945 | | case 1: |
| 946 | | disk_unit = 0; |
| 947 | | break; |
| 948 | | case 2: |
| 949 | | disk_unit = 1; |
| 950 | | break; |
| 951 | | case 4: |
| 952 | | disk_unit = 2; |
| 953 | | break; |
| 954 | | case 8: |
| 955 | | disk_unit = 3; |
| 956 | | break; |
| 957 | | default: |
| 958 | | disk_unit = -1; |
| 959 | | break; |
| 960 | | } |
| 961 | | break; |
| 974 | // printf("Select floppy disk %d (output1=%02x)\n", index, output1_latch); |
| 975 | return floppy_unit[disk_unit]; |
| 976 | } |
| 962 | 977 | |
| 963 | | default: |
| 964 | | disk_unit = -1; |
| 978 | /* |
| 979 | Called whenever the state of the sms9234 interrupt pin changes. |
| 980 | */ |
| 981 | static WRITE_LINE_DEVICE_HANDLER( ti99_hfdc_intrq_w ) |
| 982 | { |
| 983 | hfdc_irq_state = state; |
| 984 | |
| 985 | /* Set INTA */ |
| 986 | if (state) |
| 987 | { |
| 988 | ti99_peb_set_ila_bit(device->machine, intb_fdc_bit, 1); |
| 989 | } |
| 990 | else |
| 991 | { |
| 992 | ti99_peb_set_ila_bit(device->machine, intb_fdc_bit, 0); |
| 993 | } |
| 994 | |
| 995 | /* TODO: Check */ |
| 996 | fdc_handle_hold(device->machine); |
| 997 | } |
| 998 | |
| 999 | /* |
| 1000 | Called whenever the state of the sms9234 DMA in progress changes. |
| 1001 | */ |
| 1002 | static WRITE_LINE_DEVICE_HANDLER( ti99_hfdc_dip_w ) |
| 1003 | { |
| 1004 | hfdc_dip_state = state; |
| 1005 | } |
| 1006 | |
| 1007 | static WRITE8_DEVICE_HANDLER( ti99_hfdc_auxbus_out ) |
| 1008 | { |
| 1009 | switch (offset) |
| 1010 | { |
| 1011 | case INPUT_STATUS: |
| 1012 | logerror("99_dsk: Invalid operation: S0=S1=0, but tried to write (expected: read drive status)\n"); |
| 1013 | return; |
| 1014 | case OUTPUT_DMA_ADDR: |
| 1015 | /* Value is dma address byte. Shift previous contents to the left. */ |
| 1016 | dma_address = ((dma_address << 8) + (data&0xff))&0xffffff; |
| 965 | 1017 | break; |
| 1018 | case OUTPUT_OUTPUT1: |
| 1019 | /* value is output1 */ |
| 1020 | output1_latch = data; |
| 1021 | break; |
| 1022 | case OUTPUT_OUTPUT2: |
| 1023 | /* value is output2 */ |
| 1024 | output2_latch = data; |
| 1025 | break; |
| 966 | 1026 | } |
| 1027 | } |
| 967 | 1028 | |
| 968 | | return disk_unit; |
| 1029 | static READ_LINE_DEVICE_HANDLER( ti99_hfdc_auxbus_in ) |
| 1030 | { |
| 1031 | running_device *drive; |
| 1032 | UINT8 reply = 0; |
| 1033 | |
| 1034 | if (output1_latch==0) |
| 1035 | { |
| 1036 | // printf("Neither floppy nor hard disk selected.\n"); |
| 1037 | return 0; /* is that the correct default value? */ |
| 1038 | } |
| 1039 | |
| 1040 | /* If a floppy is selected, we have one line set among the four programmable outputs. */ |
| 1041 | if ((output1_latch & 0x0f)!=0) |
| 1042 | { |
| 1043 | drive = hfdc_current_floppy(); |
| 1044 | |
| 1045 | /* Get floppy status. */ |
| 1046 | if (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_INDEX) == FLOPPY_DRIVE_INDEX) |
| 1047 | reply |= DS_INDEX; |
| 1048 | if (floppy_tk00_r(drive) == CLEAR_LINE) |
| 1049 | reply |= DS_TRK00; |
| 1050 | if (floppy_wpt_r(drive) == CLEAR_LINE) |
| 1051 | reply |= DS_WRPROT; |
| 1052 | |
| 1053 | /* if (image_exists(disk_img)) */ |
| 1054 | |
| 1055 | reply |= DS_READY; /* Floppies don't have a READY line; line is pulled up */ |
| 1056 | reply |= DS_SKCOM; /* Same here. */ |
| 1057 | } |
| 1058 | else /* one of the first four lines must be selected */ |
| 1059 | { |
| 1060 | UINT8 state; |
| 1061 | drive = hfdc_current_harddisk(); |
| 1062 | state = ti99_mfm_harddisk_status(drive); |
| 1063 | if (state & MFMHD_TRACK00) |
| 1064 | reply |= DS_TRK00; |
| 1065 | if (state & MFMHD_SEEKCOMP) |
| 1066 | reply |= DS_SKCOM; |
| 1067 | if (state & MFMHD_WRFAULT) |
| 1068 | reply |= DS_WRFAULT; |
| 1069 | if (state & MFMHD_INDEX) |
| 1070 | reply |= DS_INDEX; |
| 1071 | if (state & MFMHD_READY) |
| 1072 | reply |= DS_READY; |
| 1073 | } |
| 1074 | return reply; |
| 969 | 1075 | } |
| 970 | 1076 | |
| 971 | 1077 | /* |
| 972 | 1078 | Read a byte from buffer in DMA mode |
| 973 | 1079 | */ |
| 974 | | static UINT8 hfdc_dma_read_callback(int which, offs_t offset) |
| 1080 | static UINT8 hfdc_dma_read_callback(void) |
| 975 | 1081 | { |
| 976 | | (void) which; |
| 977 | | return hfdc_ram[offset & 0x7fff]; |
| 1082 | UINT8 value = hfdc_ram[dma_address & 0x7fff]; |
| 1083 | dma_address++; |
| 1084 | return value; |
| 978 | 1085 | } |
| 979 | 1086 | |
| 980 | 1087 | /* |
| 981 | 1088 | Write a byte to buffer in DMA mode |
| 982 | 1089 | */ |
| 983 | | static void hfdc_dma_write_callback(int which, offs_t offset, UINT8 data) |
| 1090 | static void hfdc_dma_write_callback(UINT8 data) |
| 984 | 1091 | { |
| 985 | | (void) which; |
| 986 | | hfdc_ram[offset & 0x7fff] = data; |
| 1092 | hfdc_ram[dma_address & 0x7fff] = data; |
| 1093 | dma_address++; |
| 987 | 1094 | } |
| 988 | 1095 | |
| 989 | | /* |
| 990 | | Called whenever the state of the sms9234 interrupt pin changes. |
| 1096 | /* |
| 1097 | Preliminary MFM harddisk interface. |
| 991 | 1098 | */ |
| 992 | | static void hfdc_int_callback(int which, int state) |
| 1099 | static void hfdc_harddisk_get_next_id(int head, chrn_id_hd *id) |
| 993 | 1100 | { |
| 994 | | assert(which == 0); |
| 1101 | running_device *harddisk = hfdc_current_harddisk(); |
| 1102 | ti99_mfm_harddisk_get_next_id(harddisk, head, id); |
| 1103 | } |
| 995 | 1104 | |
| 996 | | hfdc_irq_state = state; |
| 1105 | static void hfdc_harddisk_seek(int direction) |
| 1106 | { |
| 1107 | running_device *harddisk = hfdc_current_harddisk(); |
| 1108 | ti99_mfm_harddisk_seek(harddisk, direction); |
| 997 | 1109 | } |
| 998 | 1110 | |
| 1111 | static void hfdc_harddisk_read_sector(int cylinder, int head, int sector, UINT8 **buf, int *sector_length) |
| 1112 | { |
| 1113 | running_device *harddisk = hfdc_current_harddisk(); |
| 1114 | if (harddisk != NULL) |
| 1115 | ti99_mfm_harddisk_read_sector(harddisk, cylinder, head, sector, buf, sector_length); |
| 1116 | } |
| 1117 | |
| 1118 | static void hfdc_harddisk_write_sector(int cylinder, int head, int sector, UINT8 *buf, int sector_length) |
| 1119 | { |
| 1120 | running_device *harddisk = hfdc_current_harddisk(); |
| 1121 | if (harddisk != NULL) |
| 1122 | ti99_mfm_harddisk_write_sector(harddisk, cylinder, head, sector, buf, sector_length); |
| 1123 | } |
| 1124 | |
| 1125 | static void hfdc_harddisk_read_track(int head, UINT8 **buffer, int *data_count) |
| 1126 | { |
| 1127 | running_device *harddisk = hfdc_current_harddisk(); |
| 1128 | if (harddisk != NULL) |
| 1129 | ti99_mfm_harddisk_read_track(harddisk, head, buffer, data_count); |
| 1130 | } |
| 1131 | |
| 1132 | static void hfdc_harddisk_write_track(int head, UINT8 *buffer, int data_count) |
| 1133 | { |
| 1134 | running_device *harddisk = hfdc_current_harddisk(); |
| 1135 | if (harddisk != NULL) |
| 1136 | ti99_mfm_harddisk_write_track(harddisk, head, buffer, data_count); |
| 1137 | } |
| 1138 | |
| 999 | 1139 | /* |
| 1000 | 1140 | Reset fdc card, set up handlers |
| 1001 | 1141 | */ |
| 1002 | 1142 | void ti99_hfdc_reset(running_machine *machine) |
| 1003 | 1143 | { |
| 1144 | running_device *device = devtag_get_device(machine, "smc92x4"); |
| 1145 | const char *flopname[] = {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}; |
| 1146 | const char *hardname[] = {MFMHD_0, MFMHD_1, MFMHD_2}; |
| 1147 | |
| 1148 | int i; |
| 1149 | |
| 1004 | 1150 | ti99_disk_DSR = memory_region(machine, region_dsr) + offset_hfdc_dsr; |
| 1005 | 1151 | hfdc_ram = memory_region(machine, region_dsr) + offset_hfdc_ram; |
| 1006 | 1152 | hfdc_ram_offset[0] = hfdc_ram_offset[1] = hfdc_ram_offset[2] = 0; |
| r8042 | r8043 | |
| 1016 | 1162 | |
| 1017 | 1163 | ti99_peb_set_card_handlers(0x1100, & hfdc_handlers); |
| 1018 | 1164 | |
| 1165 | if ((input_port_read(machine, "DISKCTRL") & DISK_HFDC) |
| 1166 | && (input_port_read(machine, "HFDCDIP")&0x55)) |
| 1167 | ti99_set_80_track_drives(TRUE); |
| 1168 | else |
| 1169 | ti99_set_80_track_drives(FALSE); |
| 1170 | |
| 1171 | smc92x4_set_timing(device, input_port_read(machine, "DRVSPD")); |
| 1172 | |
| 1019 | 1173 | set_all_geometries(machine, FLOPPY_DRIVE_DS_80); |
| 1020 | | use_80_track_drives = TRUE; |
| 1021 | 1174 | |
| 1022 | | smc92x4_reset(0); |
| 1175 | /* Connect floppy drives to controller. Note that *this* is the |
| 1176 | controller, not the controller chip. The pcb contains a select |
| 1177 | logic. |
| 1178 | TODO: Turn this implementation into a device so that this is |
| 1179 | correctly modelled. |
| 1180 | */ |
| 1181 | for (i = 0; i < 4; i++) |
| 1182 | { |
| 1183 | if (device->owner != NULL) |
| 1184 | { |
| 1185 | floppy_unit[i] = device->owner->subdevice(flopname[i]); |
| 1186 | if (floppy_unit[i]==NULL) |
| 1187 | { |
| 1188 | floppy_unit[i] = devtag_get_device(device->machine, flopname[i]); |
| 1189 | } |
| 1190 | } |
| 1191 | else |
| 1192 | { |
| 1193 | floppy_unit[i] = devtag_get_device(device->machine, flopname[i]); |
| 1194 | } |
| 1195 | |
| 1196 | if (floppy_unit[i]!=NULL) |
| 1197 | { |
| 1198 | floppy_drive_set_controller(floppy_unit[i], device); |
| 1199 | // floppy_drive_set_index_pulse_callback(floppy_unit[i], smc92x4_index_pulse_callback); |
| 1200 | floppy_drive_set_rpm(floppy_unit[i], 300.); |
| 1201 | } |
| 1202 | else |
| 1203 | { |
| 1204 | logerror("99_dsk: Image %s is null\n", flopname[i]); |
| 1205 | } |
| 1206 | } |
| 1207 | |
| 1208 | /* In the HFDC ROM, WDSx selects drive x; drive 0 is not used */ |
| 1209 | for (i = 1; i < 4; i++) |
| 1210 | { |
| 1211 | harddisk_unit[i] = devtag_get_device(device->machine, hardname[i-1]); |
| 1212 | } |
| 1213 | harddisk_unit[0] = NULL; |
| 1214 | |
| 1215 | if (device) { |
| 1216 | smc92x4_reset(device); |
| 1217 | } |
| 1023 | 1218 | } |
| 1024 | 1219 | |
| 1220 | const smc92x4_interface ti99_smc92x4_interface = |
| 1221 | { |
| 1222 | FALSE, /* do not use the full track layout */ |
| 1223 | DEVCB_LINE(ti99_hfdc_intrq_w), |
| 1224 | DEVCB_LINE(ti99_hfdc_dip_w), |
| 1225 | DEVCB_HANDLER(ti99_hfdc_auxbus_out), |
| 1226 | DEVCB_LINE(ti99_hfdc_auxbus_in), |
| 1227 | |
| 1228 | hfdc_current_floppy, |
| 1229 | hfdc_dma_read_callback, |
| 1230 | hfdc_dma_write_callback, |
| 1025 | 1231 | |
| 1232 | /* Preliminary MFM harddisk interface. */ |
| 1233 | hfdc_harddisk_get_next_id, |
| 1234 | hfdc_harddisk_seek, |
| 1235 | hfdc_harddisk_read_sector, |
| 1236 | hfdc_harddisk_write_sector, |
| 1237 | hfdc_harddisk_read_track, |
| 1238 | hfdc_harddisk_write_track |
| 1239 | }; |
| 1240 | |
| 1241 | int mycheck = 0; |
| 1242 | |
| 1026 | 1243 | /* |
| 1027 | | Read disk CRU interface |
| 1244 | Read disk CRU interface |
| 1245 | HFDC manual p. 44 |
| 1246 | |
| 1247 | CRU Select=0 |
| 1248 | CRU rel. address Definition |
| 1249 | 00 Disk controller interrupt |
| 1250 | 02 Motor status |
| 1251 | 04 DMA in progress |
| 1252 | |
| 1253 | Note that the cru line settings on the board do not match the |
| 1254 | description. 02 and 04 switch positions. Similarly, the dip switches |
| 1255 | for the drive configurations are not correctly enumerated in the manual. |
| 1256 | |
| 1257 | CRU Select=1 |
| 1258 | CRU rel. address Definition |
| 1259 | 00 Switch 4 status \_ drive 2 config |
| 1260 | 02 Switch 3 status / |
| 1261 | 04 Switch 2 status \_ drive 1 config |
| 1262 | 06 Switch 1 status / |
| 1263 | 08 Switch 8 status \_ drive 4 config |
| 1264 | 0A Switch 7 status / |
| 1265 | 0C Switch 6 status \_ drive 3 config |
| 1266 | 0E Switch 5 status / |
| 1267 | |
| 1268 | config: 00 = 9/16/18 sectors, 40 tracks, 16 msec |
| 1269 | 10 = 9/16/18 sectors, 40 tracks, 8 msec |
| 1270 | 01 = 9/16/18 sectors, 80 tracks, 2 msec |
| 1271 | 11 = 36 sectors, 80 tracks, 2 msec |
| 1028 | 1272 | */ |
| 1029 | 1273 | static int hfdc_cru_r(running_machine *machine, int offset) |
| 1030 | 1274 | { |
| 1031 | 1275 | int reply; |
| 1032 | | switch (offset) |
| 1276 | if (offset==0) /* CRU bits 0-7 */ |
| 1033 | 1277 | { |
| 1034 | | case 0: |
| 1035 | 1278 | /* CRU bits */ |
| 1036 | 1279 | if (cru_sel) |
| 1280 | { |
| 1037 | 1281 | /* DIP switches. Logic levels are inverted (on->0, off->1). CRU |
| 1038 | | bit order is the reverse of DIP-switch order, too (dip 1 -> bit 7, |
| 1039 | | dip 8 -> bit 0). Return value examples: |
| 1040 | | ff -> 4 slow 40-track DD drives |
| 1041 | | 55 -> 4 fast 40-track DD drives |
| 1042 | | aa -> 4 80-track DD drives |
| 1043 | | 00 -> 4 80-track HD drives */ |
| 1044 | | reply = use_80_track_drives ? 0x00 : 0x55; |
| 1282 | bit order is the reverse of DIP-switch order, too (dip 1 -> bit 7, |
| 1283 | dip 8 -> bit 0). |
| 1284 | |
| 1285 | MZ: 00 should not be used since there is a bug in the |
| 1286 | DSR of the HFDC which causes problems with SD disks |
| 1287 | (controller tries DD and then fails to fall back to SD) */ |
| 1288 | |
| 1289 | reply = ~(input_port_read(machine, "HFDCDIP")); |
| 1290 | // printf("hfdc cru read 7-0 = %02x\n", reply); |
| 1291 | } |
| 1045 | 1292 | else |
| 1046 | 1293 | { |
| 1047 | 1294 | reply = 0; |
| 1048 | | if (hfdc_irq_state) |
| 1295 | /* if (hfdc_irq_state) |
| 1049 | 1296 | reply |= 1; |
| 1050 | 1297 | if (motor_on) |
| 1051 | 1298 | reply |= 2; |
| 1052 | | /*if (hfdc_dma_in_progress) |
| 1053 | | reply |= 4;*/ |
| 1299 | if (hfdc_dma_in_progress) |
| 1300 | reply |= 4;*/ |
| 1301 | |
| 1302 | if (hfdc_irq_state) |
| 1303 | reply |= 0x01; |
| 1304 | if (hfdc_dip_state) |
| 1305 | reply |= 0x02; |
| 1306 | if (motor_on) |
| 1307 | reply |= 0x04; |
| 1308 | // printf("hfdc cru read 7-0 = %02x\n", reply); |
| 1309 | |
| 1054 | 1310 | } |
| 1055 | | break; |
| 1056 | | |
| 1057 | | default: |
| 1311 | } |
| 1312 | else /* CRU bits 8+ */ |
| 1058 | 1313 | reply = 0; |
| 1059 | | break; |
| 1060 | | } |
| 1314 | // printf("hfdc cru read %d = %d\n", offset, reply); |
| 1061 | 1315 | |
| 1062 | 1316 | return reply; |
| 1063 | 1317 | } |
| 1064 | 1318 | |
| 1065 | 1319 | |
| 1066 | 1320 | /* |
| 1067 | | Write disk CRU interface |
| 1321 | Write disk CRU interface |
| 1322 | HFDC manual p. 43 |
| 1323 | |
| 1324 | CRU rel. address Definition Active |
| 1325 | 00 Device Service Routine Select HIGH |
| 1326 | 02 Reset to controller chip LOW |
| 1327 | 04 Floppy Motor on / CD0 HIGH |
| 1328 | 06 ROM page select 0 / CD1 |
| 1329 | 08 ROM page select 1 / CRU input select |
| 1330 | 12/4/6/8/A RAM page select at 0x5400 |
| 1331 | 1C/E/0/2/4 RAM page select at 0x5800 |
| 1332 | 26/8/A/C/E RAM page select at 0x5C00 |
| 1333 | |
| 1334 | CD0 and CD1 are Clock Divider selections for the Floppy Data Separator (FDC9216) |
| 1068 | 1335 | */ |
| 1069 | 1336 | static void hfdc_cru_w(running_machine *machine, int offset, int data) |
| 1070 | | { |
| 1337 | { |
| 1071 | 1338 | switch (offset) |
| 1072 | 1339 | { |
| 1073 | 1340 | case 0: |
| r8042 | r8043 | |
| 1077 | 1344 | |
| 1078 | 1345 | case 1: |
| 1079 | 1346 | /* reset fdc (active low) */ |
| 1080 | | if (data) |
| 1347 | if (!data) |
| 1081 | 1348 | { |
| 1082 | | smc92x4_reset(0); |
| 1083 | | logerror("CRU sel %d\n", cru_sel); |
| 1349 | running_device *device = devtag_get_device(machine, "smc92x4"); |
| 1350 | smc92x4_reset(device); |
| 1084 | 1351 | } |
| 1085 | 1352 | break; |
| 1086 | 1353 | |
| 1087 | 1354 | case 2: |
| 1088 | | /* Strobe motor + density ("CD0 OF 9216 CHIP") */ |
| 1355 | /* Strobe motor and Clock Divider Bit 0 (CD0) */ |
| 1089 | 1356 | if (data && !motor_on) |
| 1090 | 1357 | { |
| 1091 | 1358 | DVENA = 1; |
| r8042 | r8043 | |
| 1093 | 1360 | timer_adjust_oneshot(motor_on_timer, ATTOTIME_IN_MSEC(4230), 0); |
| 1094 | 1361 | } |
| 1095 | 1362 | motor_on = data; |
| 1363 | //printf("99dsk set motor on / clock divider 0 to %d\n", data); |
| 1096 | 1364 | break; |
| 1097 | 1365 | |
| 1098 | 1366 | case 3: |
| 1099 | | /* rom page select 0 + density ("CD1 OF 9216 CHIP") */ |
| 1367 | /* rom page select 0 and Clock Divider Bit 1 (CD1) */ |
| 1100 | 1368 | if (data) |
| 1101 | 1369 | hfdc_rom_offset |= 0x2000; |
| 1102 | 1370 | else |
| 1103 | 1371 | hfdc_rom_offset &= ~0x2000; |
| 1372 | //printf("99dsk set rom page 0 / clock divider 1 to %d\n", data); |
| 1104 | 1373 | break; |
| 1105 | 1374 | |
| 1106 | 1375 | case 4: |
| r8042 | r8043 | |
| 1110 | 1379 | else |
| 1111 | 1380 | hfdc_rom_offset &= ~0x1000; |
| 1112 | 1381 | cru_sel = data; |
| 1113 | | logerror("CRU sel %d\n", cru_sel); |
| 1114 | 1382 | break; |
| 1115 | 1383 | |
| 1116 | 1384 | case 9: |
| r8042 | r8043 | |
| 1135 | 1403 | hfdc_ram_offset[(offset-9)/5] &= ~(0x400 << ((offset-9)%5)); |
| 1136 | 1404 | break; |
| 1137 | 1405 | } |
| 1406 | // printf("hfdc cru write bit %d = %d\n", offset, data); |
| 1138 | 1407 | } |
| 1139 | 1408 | |
| 1140 | 1409 | |
| 1141 | 1410 | /* |
| 1142 | | read a byte in disk DSR space |
| 1411 | read a byte in disk DSR space |
| 1412 | HFDC manual, p. 44 |
| 1413 | Memory map as seen by the 99/4A PEB |
| 1414 | |
| 1415 | 0x4000 - 0x4fbf one of four possible ROM pages |
| 1416 | 0x4fc0 - 0x4fcf tape select |
| 1417 | 0x4fd0 - 0x4fdf disk controller select |
| 1418 | 0x4fe0 - 0x4fff time chip select |
| 1419 | |
| 1420 | 0x5000 - 0x53ff static RAM page 0x10 |
| 1421 | 0x5400 - 0x57ff static RAM page any of 32 pages |
| 1422 | 0x5800 - 0x5bff static RAM page any of 32 pages |
| 1423 | 0x5c00 - 0x5fff static RAM page any of 32 pages |
| 1143 | 1424 | */ |
| 1144 | 1425 | static READ8_HANDLER(hfdc_mem_r) |
| 1145 | 1426 | { |
| 1146 | | int reply = 0; |
| 1427 | running_device *device = devtag_get_device(space->machine, "smc92x4"); |
| 1147 | 1428 | |
| 1148 | | if (offset < 0x0fc0) |
| 1429 | if (offset >= 0x0000 && offset <= 0x0fbf) |
| 1149 | 1430 | { |
| 1150 | 1431 | /* dsr ROM */ |
| 1151 | | reply = ti99_disk_DSR[hfdc_rom_offset+offset]; |
| 1432 | return ti99_disk_DSR[hfdc_rom_offset+offset]; |
| 1152 | 1433 | } |
| 1153 | | else if (offset < 0x0fd0) |
| 1434 | |
| 1435 | if (offset >= 0xfc0 && offset <= 0x0fcf) |
| 1154 | 1436 | { |
| 1155 | 1437 | /* tape controller */ |
| 1438 | logerror("99_dsk: Tape support not available (access to offset %04x)\n", offset); |
| 1439 | return 0; |
| 1156 | 1440 | } |
| 1157 | | else if (offset < 0x0fe0) |
| 1441 | |
| 1442 | if (offset >= 0xfd0 && offset <= 0x0fdf) |
| 1443 | { |
| 1444 | /* Disk controller. Note that the odd addresses are ignored and |
| 1445 | the addresses used for the write ports are also masked away |
| 1446 | since the write operations in the ti99 system are always |
| 1447 | accompanied by read operations before. |
| 1448 | */ |
| 1449 | if ((offset & 3) == 0x00) |
| 1450 | { |
| 1451 | return smc92x4_r(device, (offset>>2)&1); |
| 1452 | } |
| 1453 | else return 0; |
| 1454 | } |
| 1455 | if (offset >= 0x0fe0 && offset <= 0x0fff) |
| 1158 | 1456 | { |
| 1159 | | /* disk controller */ |
| 1160 | | switch (offset) |
| 1457 | /* Real-time clock. Again, ignore odd addresses. */ |
| 1458 | if ((offset & 1) == 0) |
| 1161 | 1459 | { |
| 1162 | | case 0x0fd0: |
| 1163 | | reply = smc92x4_r(space->machine,0, 0); |
| 1164 | | //logerror("hfdc9234 data read\n"); |
| 1165 | | break; |
| 1166 | | |
| 1167 | | case 0x0fd4: |
| 1168 | | reply = smc92x4_r(space->machine,0, 1); |
| 1169 | | //logerror("hfdc9234 status read\n"); |
| 1170 | | break; |
| 1460 | running_device *clock = devtag_get_device(space->machine, "mm58274c_floppy"); |
| 1461 | return mm58274c_r(clock, (offset - 0x0fe0) >> 1); |
| 1171 | 1462 | } |
| 1172 | | if (offset >= 0x0fd8) |
| 1173 | | logerror("hfdc9234 read %d\n", offset); |
| 1463 | else return 0; |
| 1174 | 1464 | } |
| 1175 | | else if (offset < 0x1000) |
| 1465 | |
| 1466 | if (offset >= 0x1000 && offset <= 0x13ff) |
| 1176 | 1467 | { |
| 1177 | | /* rtc */ |
| 1178 | | if (! (offset & 1)) |
| 1179 | | reply = mm58274c_r(devtag_get_device(space->machine, "mm58274c_floppy"), (offset - 0x1FE0) >> 1); |
| 1180 | | } |
| 1181 | | else if (offset < 0x1400) |
| 1182 | | { |
| 1183 | 1468 | /* ram page >08 (hfdc manual says >10) */ |
| 1184 | | reply = hfdc_ram[0x2000+(offset-0x1000)]; |
| 1469 | return hfdc_ram[0x2000+(offset-0x1000)]; |
| 1185 | 1470 | } |
| 1186 | | else |
| 1187 | | { |
| 1188 | | /* ram with mapper */ |
| 1189 | | reply = hfdc_ram[hfdc_ram_offset[(offset-0x1400) >> 10]+((offset-0x1000) & 0x3ff)]; |
| 1190 | | } |
| 1191 | | return reply; |
| 1471 | |
| 1472 | /* The remaining space is ram with mapper: |
| 1473 | 1400, 1800, 1c00 are the three banks; get the pointer |
| 1474 | plus the offset within the bank |
| 1475 | */ |
| 1476 | return hfdc_ram[hfdc_ram_offset[(offset-0x1400) >> 10] + (offset & 0x3ff)]; |
| 1192 | 1477 | } |
| 1193 | 1478 | |
| 1194 | 1479 | /* |
| r8042 | r8043 | |
| 1196 | 1481 | */ |
| 1197 | 1482 | static WRITE8_HANDLER(hfdc_mem_w) |
| 1198 | 1483 | { |
| 1199 | | if (offset < 0x0fc0) |
| 1484 | running_device *diskcnt = devtag_get_device(space->machine, "smc92x4"); |
| 1485 | |
| 1486 | if (offset >= 0x0000 && offset <= 0x0fbf) |
| 1200 | 1487 | { |
| 1201 | 1488 | /* dsr ROM */ |
| 1489 | logerror("99_dsk: Writing to HFDC ROM ignored (access to offset %04x)\n", offset); |
| 1490 | return; |
| 1202 | 1491 | } |
| 1203 | | else if (offset < 0x0fd0) |
| 1492 | |
| 1493 | if (offset >= 0xfc0 && offset <= 0x0fcf) |
| 1204 | 1494 | { |
| 1205 | 1495 | /* tape controller */ |
| 1496 | logerror("99_dsk: Tape support not available (access to offset %04x)\n", offset); |
| 1497 | return; |
| 1206 | 1498 | } |
| 1207 | | else if (offset < 0x0fe0) |
| 1499 | |
| 1500 | if (offset >= 0xfd0 && offset <= 0x0fdf) |
| 1501 | { |
| 1502 | /* Disk controller. Note that the odd addresses are ignored. */ |
| 1503 | if ((offset & 3) == 0x02) /* 0x0fd2 and 0x0fd6 */ |
| 1504 | { |
| 1505 | smc92x4_w(diskcnt, (offset>>2)&1, data); |
| 1506 | } |
| 1507 | return; |
| 1508 | } |
| 1509 | |
| 1510 | if (offset >= 0x0fe0 && offset <= 0x0fff) |
| 1208 | 1511 | { |
| 1209 | | /* disk controller */ |
| 1210 | | switch (offset) |
| 1512 | /* Real-time clock. Again, ignore odd addresses. */ |
| 1513 | if ((offset & 1) == 0) |
| 1211 | 1514 | { |
| 1212 | | case 0x0fd2: |
| 1213 | | smc92x4_w(space->machine,0, 0, data); |
| 1214 | | //logerror("hfdc9234 data write %d\n", data); |
| 1215 | | break; |
| 1216 | | |
| 1217 | | case 0x0fd6: |
| 1218 | | smc92x4_w(space->machine,0, 1, data); |
| 1219 | | //logerror("hfdc9234 command write %d\n", data); |
| 1220 | | break; |
| 1515 | running_device *clock = devtag_get_device(space->machine, "mm58274c_floppy"); |
| 1516 | mm58274c_w(clock, (offset - 0x0fe0) >> 1, data); |
| 1221 | 1517 | } |
| 1222 | | if (offset >= 0x0fd8) |
| 1223 | | logerror("hfdc9234 write %d %d\n", offset, data); |
| 1518 | return; |
| 1224 | 1519 | } |
| 1225 | | else if (offset < 0x1000) |
| 1520 | |
| 1521 | if (offset >= 0x1000 && offset <= 0x13ff) |
| 1226 | 1522 | { |
| 1227 | | /* rtc */ |
| 1228 | | if (! (offset & 1)) |
| 1229 | | mm58274c_w(devtag_get_device(space->machine, "mm58274c_floppy"), (offset - 0x1FE0) >> 1, data); |
| 1230 | | } |
| 1231 | | else if (offset < 0x1400) |
| 1232 | | { |
| 1233 | 1523 | /* ram page >08 (hfdc manual says >10) */ |
| 1234 | 1524 | hfdc_ram[0x2000+(offset-0x1000)] = data; |
| 1525 | return; |
| 1235 | 1526 | } |
| 1236 | | else |
| 1237 | | { |
| 1238 | | /* ram with mapper */ |
| 1239 | | hfdc_ram[hfdc_ram_offset[(offset-0x1400) >> 10]+((offset-0x1000) & 0x3ff)] = data; |
| 1240 | | } |
| 1527 | |
| 1528 | /* The remaining space is ram with mapper: |
| 1529 | 1400, 1800, 1c00 are the three banks; get the pointer |
| 1530 | plus the offset within the bank |
| 1531 | */ |
| 1532 | // if ((offset&0x0f)==0) printf("\n"); |
| 1533 | // printf("%02x ", data); |
| 1534 | |
| 1535 | hfdc_ram[hfdc_ram_offset[(offset-0x1400) >> 10] + (offset & 0x3ff)] = data; |
| 1241 | 1536 | } |
| 1242 | | |
src/mess/machine/smc92x4.c
| r8042 | r8043 | |
| 1 | 1 | /* |
| 2 | | SMC9224 and SMC9234 Hard and Floppy Disk Controller (HFDC) |
| 2 | HDC9224 and HDC9234 Hard and Floppy Disk Controller (HFDC) |
| 3 | 3 | |
| 4 | | This controller handles MFM and FM encoded floppy disks and hard disks. |
| 5 | | The SMC9224 is used in some DEC systems. The SMC9234 is used in the Myarc |
| 6 | | HFDC card for the TI99/4a. The main difference between the two chips is |
| 7 | | the way the ECC bytes are computed; there are differences in the way seek |
| 8 | | times are computed, too. |
| 4 | This controller handles MFM and FM encoded floppy disks and hard disks. |
| 5 | The SMC9224 is used in some DEC systems. The HDC9234 is used in the |
| 6 | Myarc HFDC card for the TI99/4a. The main difference between the two |
| 7 | chips is the way the ECC bytes are computed; there are differences in |
| 8 | the way seek times are computed, too. |
| 9 | |
| 10 | References: |
| 11 | * SMC HDC9234 preliminary data book (1988) |
| 12 | |
| 13 | Michael Zapf, April 2010 |
| 9 | 14 | |
| 10 | | References: |
| 11 | | * SMC HDC9234 preliminary data book (1988) |
| 12 | | |
| 13 | | Raphael Nabet, 2003 |
| 15 | First version by Raphael Nabet, 2003 |
| 14 | 16 | */ |
| 15 | 17 | |
| 16 | 18 | #include "emu.h" |
| 17 | 19 | #include "devices/flopdrv.h" |
| 20 | #include "devices/harddriv.h" |
| 21 | #include "harddisk.h" |
| 18 | 22 | |
| 19 | 23 | #include "smc92x4.h" |
| 20 | 24 | |
| 21 | | #define MAX_HFDC 1 |
| 22 | | #define MAX_SECTOR_LEN 2048 /* ??? */ |
| 25 | /*************************************************************************** |
| 26 | TYPE DEFINITIONS |
| 27 | ***************************************************************************/ |
| 23 | 28 | |
| 24 | 29 | /* |
| 25 | | hfdc state structure |
| 26 | | */ |
| 27 | | typedef struct hfdc_t |
| 28 | | { |
| 29 | | UINT8 status; /* command status register */ |
| 30 | | UINT8 disk_sel; /* disk selection state */ |
| 31 | | UINT8 regs[10+6]; /* 4th through 10th registers are actually 2 distinct |
| 32 | | registers each (one is r/o and the other w/o). The |
| 33 | | 11th register ("data") is only used for communication |
| 34 | | with the drive in non-DMA modes??? */ |
| 35 | | int reg_ptr; |
| 36 | | int (*select_callback)(int which, select_mode_t select_mode, int select_line, int gpos); |
| 37 | | UINT8 (*dma_read_callback)(int which, offs_t offset); |
| 38 | | void (*dma_write_callback)(int which, offs_t offset, UINT8 data); |
| 39 | | void (*int_callback)(int which, int state); |
| 40 | | } hfdc_t; |
| 41 | | |
| 42 | | enum |
| 43 | | { |
| 44 | | disk_sel_none = (UINT8) -1 |
| 45 | | }; |
| 46 | | |
| 47 | | enum |
| 48 | | { |
| 49 | | hfdc_reg_dma_low = 0, |
| 50 | | hfdc_reg_dma_mid, |
| 51 | | hfdc_reg_dma_high, |
| 52 | | hfdc_reg_des_sector, |
| 53 | | hfdc_reg_des_head, |
| 54 | | hfdc_reg_des_cyl, |
| 55 | | hfdc_reg_sector_count, |
| 56 | | hfdc_reg_retry_count, |
| 57 | | hfdc_reg_mode, |
| 58 | | hfdc_reg_term, |
| 59 | | hfdc_reg_cur_head, |
| 60 | | hfdc_reg_cur_cyl, |
| 61 | | hfdc_reg_read_6, |
| 62 | | hfdc_reg_read_7, |
| 63 | | hfdc_reg_chip_stat, |
| 64 | | hfdc_reg_drive_stat |
| 65 | | }; |
| 66 | | |
| 67 | | /* |
| 68 | 30 | Definition of bits in the status register |
| 69 | 31 | */ |
| 70 | | #define ST_INTPEND (1<<7) /* interrupt pending */ |
| 71 | | #define ST_DMAREQ (1<<6) /* DMA request */ |
| 72 | | #define ST_DONE (1<<5) /* command done */ |
| 73 | | #define ST_TERMCOD (3<<3) /* termination code (see below) */ |
| 74 | | #define ST_RDYCHNG (1<<2) /* ready change */ |
| 75 | | #define ST_OVRUN (1<<1) /* overrun/underrun */ |
| 76 | | #define ST_BADSECT (1<<0) /* bad sector */ |
| 32 | #define ST_INTPEND 0x80 /* interrupt pending */ |
| 33 | #define ST_DMAREQ 0x40 /* DMA request */ |
| 34 | #define ST_DONE 0x20 /* command done */ |
| 35 | #define ST_TERMCOD 0x18 /* termination code (see below) */ |
| 36 | #define ST_RDYCHNG 0x04 /* ready change */ |
| 37 | #define ST_OVRUN 0x02 /* overrun/underrun */ |
| 38 | #define ST_BADSECT 0x01 /* bad sector */ |
| 77 | 39 | |
| 78 | 40 | /* |
| 79 | | Definition of the termination codes |
| 41 | Definition of the termination codes (INT_STATUS) |
| 80 | 42 | */ |
| 81 | | #define ST_TC_SUCCESS (0<<3) /* Successful completion */ |
| 82 | | #define ST_TC_RDIDERR (1<<3) /* Error in READ-ID sequence */ |
| 83 | | #define ST_TC_VRFYERR (2<<3) /* Error in VERIFY sequence */ |
| 84 | | #define ST_TC_DATAERR (3<<3) /* Error in DATA-TRANSFER seq. */ |
| 43 | #define ST_TC_SUCCESS 0x00 /* Successful completion */ |
| 44 | #define ST_TC_RDIDERR 0x08 /* Error in READ-ID sequence */ |
| 45 | #define ST_TC_SEEKERR 0x10 /* Error in SEEK sequence */ |
| 46 | #define ST_TC_DATAERR 0x18 /* Error in DATA-TRANSFER seq. */ |
| 85 | 47 | |
| 86 | 48 | |
| 87 | 49 | /* |
| 88 | 50 | Definition of bits in the Termination-Conditions register |
| 89 | 51 | */ |
| 90 | | #define TC_CRCPRE (1<<7) /* CRC register preset, must be 1 */ |
| 91 | | #define TC_UNUSED (1<<6) /* bit 6 is not used and must be 0 */ |
| 92 | | #define TC_INTDONE (1<<5) /* interrupt on done */ |
| 93 | | #define TC_TDELDAT (1<<4) /* terminate on deleted data */ |
| 94 | | #define TC_TDSTAT3 (1<<3) /* terminate on drive status 3 change */ |
| 95 | | #define TC_TWPROT (1<<2) /* terminate on write-protect (FDD only) */ |
| 96 | | #define TC_INTRDCH (1<<1) /* interrupt on ready change (FDD only) */ |
| 97 | | #define TC_TWRFLT (1<<0) /* interrupt on write-fault (HDD only) */ |
| 52 | #define TC_CRCPRE 0x80 /* CRC register preset, must be 1 */ |
| 53 | #define TC_UNUSED 0x40 /* bit 6 is not used and must be 0 */ |
| 54 | #define TC_INTDONE 0x20 /* interrupt on done */ |
| 55 | #define TC_TDELDAT 0x10 /* terminate on deleted data */ |
| 56 | #define TC_TDSTAT3 0x08 /* terminate on drive status 3 change */ |
| 57 | #define TC_TWPROT 0x04 /* terminate on write-protect (FDD only) */ |
| 58 | #define TC_INTRDCH 0x02 /* interrupt on ready change (FDD only) */ |
| 59 | #define TC_TWRFLT 0x01 /* interrupt on write-fault (HDD only) */ |
| 98 | 60 | |
| 99 | 61 | /* |
| 100 | 62 | Definition of bits in the Chip-Status register |
| 101 | 63 | */ |
| 102 | | #define CS_RETREQ (1<<7) /* retry required */ |
| 103 | | #define CS_ECCATT (1<<6) /* ECC correction attempted */ |
| 104 | | #define CS_ECCERR (1<<5) /* ECC/CRC error */ |
| 105 | | #define CS_DELDATA (1<<4) /* deleted data mark */ |
| 106 | | #define CS_SYNCERR (1<<3) /* synchronization error */ |
| 107 | | #define CS_COMPERR (1<<2) /* compare error */ |
| 108 | | #define CS_PRESDRV (3<<0) /* present drive selected */ |
| 64 | #define CS_RETREQ 0x80 /* retry required */ |
| 65 | #define CS_ECCATT 0x40 /* ECC correction attempted */ |
| 66 | #define CS_CRCERR 0x20 /* ECC/CRC error */ |
| 67 | #define CS_DELDATA 0x10 /* deleted data mark */ |
| 68 | #define CS_SYNCERR 0x08 /* synchronization error */ |
| 69 | #define CS_COMPERR 0x04 /* compare error */ |
| 70 | #define CS_PRESDRV 0x03 /* present drive selected */ |
| 109 | 71 | |
| 110 | 72 | /* |
| 111 | | Definition of bits in the Disk-Status register |
| 73 | Definition of bits in the Mode register |
| 112 | 74 | */ |
| 113 | | #define DS_SELACK (1<<7) /* select acknowledge (harddisk only!) */ |
| 114 | | #define DS_INDEX (1<<6) /* index point */ |
| 115 | | #define DS_SKCOM (1<<5) /* seek complete */ |
| 116 | | #define DS_TRK00 (1<<4) /* track 0 */ |
| 117 | | #define DS_DSTAT3 (1<<3) /* drive status 3 (MBZ) */ |
| 118 | | #define DS_WRPROT (1<<2) /* write protect (floppy only!) */ |
| 119 | | #define DS_READY (1<<1) /* drive ready bit */ |
| 120 | | #define DS_WRFAULT (1<<0) /* write fault */ |
| 75 | #define MO_TYPE 0x80 /* Hard disk (1) or floppy (0) */ |
| 76 | #define MO_CRCECC 0x60 /* Values for CRC/ECC handling */ |
| 77 | #define MO_DENSITY 0x10 /* FM = 1; MFM = 0 */ |
| 78 | #define MO_UNUSED 0x08 /* Unused, 0 */ |
| 79 | #define MO_STEPRATE 0x07 /* Step rates */ |
| 121 | 80 | |
| 122 | | static hfdc_t hfdc[MAX_HFDC]; |
| 123 | | |
| 124 | 81 | /* |
| 125 | | Perform the read id field sequence for a floppy disk (but do not perform |
| 126 | | any implied seek) |
| 82 | hfdc state structure |
| 127 | 83 | |
| 128 | | which: udc controller index |
| 129 | | disk_unit: floppy drive index |
| 130 | | head: selected head |
| 84 | status |
| 85 | ab7 ecc error |
| 86 | ab6 index pulse |
| 87 | ab5 seek complete |
| 88 | ab4 track 0 |
| 89 | ab3 user-defined |
| 90 | ab2 write-protected |
| 91 | ab1 drive ready |
| 92 | ab0 write fault |
| 93 | |
| 94 | output1 |
| 95 | ab7 drive select 3 |
| 96 | ab6 drive select 2 |
| 97 | ab5 drive select 1 |
| 98 | ab4 drive select 0 |
| 99 | ab3 programmable outputs |
| 100 | ab2 programmable outputs |
| 101 | ab1 programmable outputs |
| 102 | ab0 programmable outputs |
| 103 | |
| 104 | output2 |
| 105 | ab7 drive select 3* (active low, used for tape operations) |
| 106 | ab6 reduce write current |
| 107 | ab5 step direction |
| 108 | ab4 step pulse |
| 109 | ab3 desired head 3 |
| 110 | ab2 desired head 2 |
| 111 | ab1 desired head 1 |
| 112 | ab0 desired head 0 |
| 131 | 113 | */ |
| 132 | | static int floppy_read_id(running_machine *machine,int which, int disk_unit, int head) |
| 114 | |
| 115 | #define OUT1_DRVSEL3 0x80 |
| 116 | #define OUT1_DRVSEL2 0x40 |
| 117 | #define OUT1_DRVSEL1 0x20 |
| 118 | #define OUT1_DRVSEL0 0x10 |
| 119 | #define OUT2_DRVSEL3_ 0x80 |
| 120 | #define OUT2_REDWRT 0x40 |
| 121 | #define OUT2_STEPDIR 0x20 |
| 122 | #define OUT2_STEPPULSE 0x10 |
| 123 | #define OUT2_HEADSEL3 0x08 |
| 124 | #define OUT2_HEADSEL2 0x04 |
| 125 | #define OUT2_HEADSEL1 0x02 |
| 126 | #define OUT2_HEADSEL0 0x01 |
| 127 | |
| 128 | #define DRIVE_TYPE 0x03 |
| 129 | #define TYPE_AT 0x00 |
| 130 | #define TYPE_FLOPPY 0x02 /* for testing on any floppy type */ |
| 131 | #define TYPE_FLOPPY8 0x02 |
| 132 | #define TYPE_FLOPPY5 0x03 |
| 133 | |
| 134 | #define MAX_SECTOR_LEN 256 |
| 135 | |
| 136 | #define FORMAT_LONG FALSE |
| 137 | |
| 138 | #define ERROR 0 |
| 139 | #define DONE 1 |
| 140 | #define AGAIN 2 |
| 141 | #define UNDEF 3 |
| 142 | |
| 143 | typedef struct _smc92x4_state |
| 133 | 144 | { |
| 134 | | running_device *disk_img = floppy_get_device(machine, disk_unit); |
| 135 | | UINT8 revolution_count; |
| 136 | | chrn_id id; |
| 145 | devcb_resolved_write_line out_intrq_func; /* INT line */ |
| 146 | devcb_resolved_write_line out_dip_func; /* DMA in progress line */ |
| 147 | devcb_resolved_write8 out_auxbus_func; /* AB0-7 lines (using S0,S1 as address) */ |
| 148 | devcb_resolved_read_line in_auxbus_func; /* AB0-7 lines (only single case) */ |
| 137 | 149 | |
| 138 | | revolution_count = 0; |
| 150 | UINT8 output1; /* UDC-internal register "output1" */ |
| 151 | UINT8 output2; /* UDC-internal register "output2" */ |
| 152 | |
| 153 | int selected_drive_type; |
| 154 | /* We need to store the types, although this is not the case in the |
| 155 | real hardware. The reason is that poll_drives wants to select the drives |
| 156 | without knowing their kinds. In reality this does not matter, since we |
| 157 | only check for the seek_complete line, but in our case, floppy and |
| 158 | harddrive are pretty different, and we need to know which one to check. */ |
| 159 | int types[4]; |
| 160 | int head_load_delay_enable; |
| 161 | int register_pointer; |
| 162 | |
| 163 | UINT8 register_r[12]; |
| 164 | UINT8 register_w[12]; |
| 139 | 165 | |
| 140 | | while (revolution_count < 4) |
| 141 | | { |
| 142 | | if (floppy_drive_get_next_id(disk_img, head, &id)) |
| 143 | | { |
| 144 | | hfdc[which].regs[hfdc_reg_cur_cyl] = id.C; |
| 145 | | hfdc[which].regs[hfdc_reg_cur_head] = id.H; |
| 146 | | hfdc[which].regs[hfdc_reg_read_6] = 0xfe; /* ident byte */ |
| 147 | | if (id.flags & ID_FLAG_DELETED_DATA) |
| 148 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_DELDATA; |
| 149 | | return TRUE; |
| 150 | | } |
| 151 | | } |
| 166 | /* timers to delay execution/completion of commands */ |
| 167 | emu_timer *timer_data, *timer_rs, *timer_ws, *timer_seek, *timer_track; |
| 152 | 168 | |
| 153 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 154 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_SYNCERR; |
| 155 | | return FALSE; |
| 156 | | } |
| 169 | /* Flag which determines whether to use realistic timing. */ |
| 170 | int use_real_timing; |
| 171 | |
| 172 | /* Required to store the current iteration within restore. */ |
| 173 | int seek_count; |
| 174 | |
| 175 | /* Recent command. */ |
| 176 | UINT8 command; |
| 177 | |
| 178 | /* Stores the step direction. */ |
| 179 | int step_direction; |
| 180 | |
| 181 | /* Stores the buffered flag. */ |
| 182 | int buffered; |
| 183 | |
| 184 | /* Stores the recent id field. */ |
| 185 | chrn_id_hd recent_id; |
| 186 | |
| 187 | /* Indicates whether an ID has been found. */ |
| 188 | int found_id; |
| 189 | |
| 190 | /* Indicates whether we are already past the seek_id phase in read/write sector. */ |
| 191 | int after_seek; |
| 192 | |
| 193 | /* Determines whether the command will be continued. */ |
| 194 | int to_be_continued; |
| 195 | |
| 196 | /* Pointer to interface */ |
| 197 | const smc92x4_interface *intf; |
| 198 | |
| 199 | } smc92x4_state; |
| 157 | 200 | |
| 158 | | /* |
| 159 | | Perform the verify sequence for a floppy disk |
| 201 | /* |
| 202 | Step rates in microseconds for MFM. This is set in the mode register, |
| 203 | bits 0-2. Single density doubles all values. |
| 204 | */ |
| 205 | static const int step_hd[] = { 22, 50, 100, 200, 400, 800, 1600, 3200 }; |
| 206 | static const int step_flop8[] = { 218, 500, 1000, 2000, 4000, 8000, 16000, 32000 }; |
| 207 | static const int step_flop5[] = { 436, 1000, 2000, 4000, 8000, 16000, 32000, 64000 }; |
| 160 | 208 | |
| 161 | | which: udc controller index |
| 162 | | disk_unit: floppy drive index |
| 209 | /* |
| 210 | 0.2 seconds for a revolution (300 rpm), +50% average waiting for index |
| 211 | hole. Should be properly done with the index hole detection; we're |
| 212 | simulating this with a timer for now. |
| 163 | 213 | */ |
| 164 | | static int floppy_find_sector(running_machine *machine,int which, int disk_unit, int cylinder, int head, int check_secnum, int sector, int *sector_data_id, int *sector_len) |
| 214 | #define TRACKTIME_FLOPPY 300000 |
| 215 | #define TRACKTIME_HD 1000 |
| 216 | |
| 217 | /* |
| 218 | Register names of the HDC. The left part is the set of write registers, |
| 219 | while the right part are the read registers. |
| 220 | */ |
| 221 | enum |
| 165 | 222 | { |
| 166 | | running_device *disk_img = floppy_get_device(machine, disk_unit); |
| 167 | | UINT8 revolution_count; |
| 168 | | chrn_id id; |
| 223 | DMA7_0=0, |
| 224 | DMA15_8=1, |
| 225 | DMA23_16=2, |
| 226 | DESIRED_SECTOR=3, |
| 227 | DESIRED_HEAD=4, CURRENT_HEAD=4, |
| 228 | DESIRED_CYLINDER=5, CURRENT_CYLINDER=5, |
| 229 | SECTOR_COUNT=6, CURRENT_IDENT=6, |
| 230 | RETRY_COUNT=7, TEMP_STORAGE2=7, |
| 231 | MODE=8, CHIP_STATUS=8, |
| 232 | INT_COMM_TERM=9, DRIVE_STATUS=9, |
| 233 | DATA_DELAY=10, DATA=10, |
| 234 | COMMAND=11, INT_STATUS=11 |
| 235 | }; |
| 169 | 236 | |
| 170 | | revolution_count = 0; |
| 237 | #define TRKSIZE_DD 6144 |
| 238 | #define TRKSIZE_SD 3172 |
| 171 | 239 | |
| 172 | | while (revolution_count < 4) |
| 173 | | { |
| 174 | | if (floppy_drive_get_next_id(disk_img, head, &id)) |
| 175 | | { |
| 176 | | /* compare id values */ |
| 177 | | if ((id.C == cylinder) && (id.H == head) && ((id.R == sector) || ! check_secnum)) |
| 178 | | { |
| 179 | | * sector_data_id = id.data_id; |
| 180 | | * sector_len = 1 << (id.N+7); |
| 181 | | assert((* sector_len) < MAX_SECTOR_LEN); |
| 240 | /*************************************************************************** |
| 241 | PROTOTYPES |
| 242 | ***************************************************************************/ |
| 182 | 243 | |
| 183 | | hfdc[which].regs[hfdc_reg_cur_cyl] = id.C; |
| 184 | | hfdc[which].regs[hfdc_reg_cur_head] = id.H; |
| 185 | | hfdc[which].regs[hfdc_reg_read_6] = 0xfe; /* ident byte (right???) */ |
| 186 | | if (id.flags & ID_FLAG_DELETED_DATA) |
| 187 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_DELDATA; |
| 188 | | else |
| 189 | | hfdc[which].regs[hfdc_reg_chip_stat] &= ~CS_DELDATA; |
| 190 | | return TRUE; |
| 191 | | } |
| 192 | | } |
| 244 | static void smc92x4_process_after_callback(running_device *device); |
| 245 | static void data_transfer_read(running_device *device, chrn_id_hd id, int transfer_enable); |
| 246 | static void data_transfer_write(running_device *device, chrn_id_hd id, int deldata, int redcur, int precomp, int write_long); |
| 193 | 247 | |
| 194 | | /* index set? */ |
| 195 | | if (floppy_drive_get_flag_state(disk_img, FLOPPY_DRIVE_INDEX)) |
| 196 | | { |
| 197 | | /* update revolution count */ |
| 198 | | revolution_count++; |
| 199 | | } |
| 200 | | } |
| 201 | | |
| 202 | | return FALSE; |
| 248 | #if 0 |
| 249 | static void dump_contents(UINT8 *buffer, int length) |
| 250 | { |
| 251 | for (int i=0; i < length; i+=16) |
| 252 | { |
| 253 | for (int j=0; j < 16; j+=2) |
| 254 | { |
| 255 | printf("%02x%02x ", buffer[i+j], buffer[i+j+1]); |
| 256 | } |
| 257 | printf("\n"); |
| 258 | } |
| 203 | 259 | } |
| 260 | #endif |
| 204 | 261 | |
| 205 | | static int smc92x4_floppy_read_sector(running_machine *machine,int which, int disk_unit, int cylinder, int head, int check_secnum, int sector, int *dma_address) |
| 262 | INLINE smc92x4_state *get_safe_token(running_device *device) |
| 206 | 263 | { |
| 207 | | int sector_data_id, sector_len; |
| 208 | | UINT8 buf[MAX_SECTOR_LEN]; |
| 209 | | int i; |
| 210 | | running_device *disk_img = floppy_get_device(machine, disk_unit); |
| 264 | assert(device != NULL); |
| 265 | assert(device->token != NULL); |
| 266 | return (smc92x4_state *)device->token; |
| 267 | } |
| 211 | 268 | |
| 212 | | if (! floppy_find_sector(machine,which, disk_unit, cylinder, head, check_secnum, sector, & sector_data_id, & sector_len)) |
| 213 | | { |
| 214 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 215 | | return FALSE; |
| 216 | | } |
| 217 | 269 | |
| 218 | | floppy_drive_read_sector_data(disk_img, head, sector_data_id, (char *) buf, sector_len); |
| 219 | | for (i=0; i<sector_len; i++) |
| 220 | | { |
| 221 | | (*hfdc[which].dma_write_callback)(which, *dma_address, buf[i]); |
| 222 | | *dma_address = ((*dma_address) + 1) & 0xffffff; |
| 223 | | } |
| 224 | | return TRUE; |
| 270 | static int image_is_single_density(running_device *current_floppy) |
| 271 | { |
| 272 | floppy_image *image = flopimg_get_image(current_floppy); |
| 273 | return (floppy_get_track_size(image, 0, 0)<4000); |
| 225 | 274 | } |
| 226 | 275 | |
| 227 | | static int smc92x4_floppy_write_sector(running_machine *machine,int which, int disk_unit, int cylinder, int head, int check_secnum, int sector, int *dma_address) |
| 276 | static int controller_set_to_single_density(running_device *device) |
| 228 | 277 | { |
| 229 | | int sector_data_id, sector_len; |
| 230 | | UINT8 buf[MAX_SECTOR_LEN]; |
| 231 | | int i; |
| 232 | | running_device *disk_img = floppy_get_device(machine, disk_unit); |
| 278 | smc92x4_state *w = get_safe_token(device); |
| 279 | return ((w->register_w[MODE]&MO_DENSITY)!=0); |
| 280 | } |
| 233 | 281 | |
| 234 | | if (! floppy_find_sector(machine,which, disk_unit, cylinder, head, check_secnum, sector, & sector_data_id, & sector_len)) |
| 235 | | { |
| 236 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 237 | | return FALSE; |
| 238 | | } |
| 282 | static void copyid(chrn_id id1, chrn_id_hd *id2) |
| 283 | { |
| 284 | id2->C = id1.C & 0xff; |
| 285 | id2->H = id1.H; |
| 286 | id2->R = id1.R; |
| 287 | id2->N = id1.N; |
| 288 | id2->data_id = id1.data_id; |
| 289 | id2->flags = id1.flags; |
| 290 | } |
| 239 | 291 | |
| 240 | | for (i=0; i<sector_len; i++) |
| 292 | /* |
| 293 | Set IRQ |
| 294 | */ |
| 295 | static void smc92x4_set_interrupt(running_device *device) |
| 296 | { |
| 297 | smc92x4_state *w = get_safe_token(device); |
| 298 | if ((w->register_r[INT_STATUS] & ST_INTPEND) == 0) |
| 241 | 299 | { |
| 242 | | buf[i] = (*hfdc[which].dma_read_callback)(which, *dma_address); |
| 243 | | *dma_address = ((*dma_address) + 1) & 0xffffff; |
| 300 | w->register_r[INT_STATUS] |= ST_INTPEND; |
| 301 | devcb_call_write_line(&w->out_intrq_func, ASSERT_LINE); |
| 244 | 302 | } |
| 245 | | floppy_drive_write_sector_data(disk_img, head, sector_data_id, (char *) buf, sector_len, FALSE); |
| 246 | | return TRUE; |
| 247 | 303 | } |
| 248 | 304 | |
| 249 | | static void floppy_step(running_machine *machine,int which, int disk_unit, int direction) |
| 305 | /* |
| 306 | Set DMA in progress |
| 307 | */ |
| 308 | static void smc92x4_set_dip(running_device *device, int value) |
| 250 | 309 | { |
| 251 | | running_device *disk_img = floppy_get_device(machine, disk_unit); |
| 252 | | floppy_drive_seek(disk_img, direction); |
| 310 | smc92x4_state *w = get_safe_token(device); |
| 311 | devcb_call_write_line(&w->out_dip_func, value); |
| 253 | 312 | } |
| 254 | 313 | |
| 255 | | static UINT8 floppy_get_disk_status(running_machine *machine,int which, int disk_unit) |
| 314 | /* |
| 315 | Assert Command Done status bit, triggering interrupts as needed |
| 316 | */ |
| 317 | static void set_command_done(running_device *device, int flags) |
| 256 | 318 | { |
| 257 | | running_device *disk_img = floppy_get_device(machine, disk_unit); |
| 258 | | int reply = 0; |
| 319 | //assert(! (w->status & ST_DONE)) |
| 320 | smc92x4_state *w = get_safe_token(device); |
| 321 | //printf("smc92x4 command %02x done, flags=%02x\n", w->command, flags); |
| 322 | |
| 323 | w->register_r[INT_STATUS] |= ST_DONE; |
| 324 | w->register_r[INT_STATUS] &= ~ST_TERMCOD; /* clear the previously set flags */ |
| 325 | w->register_r[INT_STATUS] |= flags; |
| 259 | 326 | |
| 260 | | if (floppy_drive_get_flag_state(disk_img, FLOPPY_DRIVE_INDEX) == FLOPPY_DRIVE_INDEX) |
| 261 | | reply |= DS_INDEX; |
| 262 | | if (floppy_tk00_r(disk_img) == CLEAR_LINE) |
| 263 | | reply |= DS_TRK00; |
| 264 | | if (floppy_wpt_r(disk_img) == CLEAR_LINE) |
| 265 | | reply |= DS_WRPROT; |
| 266 | | if (image_exists(disk_img)) |
| 267 | | reply |= DS_READY; |
| 268 | | |
| 269 | | reply |= DS_SKCOM; |
| 270 | | |
| 271 | | return reply; |
| 327 | /* sm92x4 spec, p. 6 */ |
| 328 | if (w->register_w[INT_COMM_TERM] & TC_INTDONE) |
| 329 | smc92x4_set_interrupt(device); |
| 272 | 330 | } |
| 273 | 331 | |
| 274 | | #include "devices/harddriv.h" |
| 275 | | #include "harddisk.h" |
| 276 | | |
| 277 | | static struct |
| 332 | /* |
| 333 | Preserve previously set termination code |
| 334 | */ |
| 335 | static void set_command_done(running_device *device) |
| 278 | 336 | { |
| 279 | | hard_disk_file *hd_handle; |
| 280 | | unsigned int wp : 1; /* TRUE if disk is write-protected */ |
| 281 | | int current_cylinder; |
| 337 | //assert(! (w->status & ST_DONE)) |
| 338 | smc92x4_state *w = get_safe_token(device); |
| 339 | //printf("smc92x4 command %02x done\n", w->command); |
| 282 | 340 | |
| 283 | | /* disk geometry */ |
| 284 | | unsigned int cylinders, heads, sectors_per_track, bytes_per_sector; |
| 285 | | } hd[10]; |
| 341 | w->register_r[INT_STATUS] |= ST_DONE; |
| 286 | 342 | |
| 287 | | static int get_id_from_device( running_device *device ) |
| 343 | /* sm92x4 spec, p. 6 */ |
| 344 | if (w->register_w[INT_COMM_TERM] & TC_INTDONE) |
| 345 | smc92x4_set_interrupt(device); |
| 346 | } |
| 347 | |
| 348 | /* |
| 349 | Clear IRQ |
| 350 | */ |
| 351 | static void smc92x4_clear_interrupt(running_device *device) |
| 288 | 352 | { |
| 289 | | int id = -1; |
| 290 | | |
| 291 | | if ( ! strcmp( "harddisk1", device->tag() ) ) |
| 353 | smc92x4_state *w = get_safe_token(device); |
| 354 | if ((w->register_r[INT_STATUS] & ST_INTPEND) != 0) |
| 292 | 355 | { |
| 293 | | id = 0; |
| 356 | devcb_call_write_line(&w->out_intrq_func, CLEAR_LINE); |
| 294 | 357 | } |
| 295 | | else if ( ! strcmp( "harddisk2", device->tag() ) ) |
| 296 | | { |
| 297 | | id = 1; |
| 298 | | } |
| 299 | | else if ( ! strcmp( "harddisk3", device->tag() ) ) |
| 300 | | { |
| 301 | | id = 2; |
| 302 | | } |
| 303 | | assert( id >= 0 ); |
| 358 | } |
| 304 | 359 | |
| 305 | | return id; |
| 360 | /* |
| 361 | Sets the DMA address on the external counter. This counter is attached |
| 362 | to the auxiliary bus on the PCB. |
| 363 | */ |
| 364 | static void set_dma_address(running_device *device, int pos2316, int pos1508, int pos0700) |
| 365 | { |
| 366 | smc92x4_state *w = get_safe_token(device); |
| 367 | devcb_call_write8(&w->out_auxbus_func, OUTPUT_DMA_ADDR, w->register_r[pos2316]); |
| 368 | devcb_call_write8(&w->out_auxbus_func, OUTPUT_DMA_ADDR, w->register_r[pos1508]); |
| 369 | devcb_call_write8(&w->out_auxbus_func, OUTPUT_DMA_ADDR, w->register_r[pos0700]); |
| 306 | 370 | } |
| 307 | 371 | |
| 372 | static void dma_add_offset(running_device *device, int offset) |
| 373 | { |
| 374 | smc92x4_state *w = get_safe_token(device); |
| 375 | int dma_address = (w->register_w[DMA23_16]<<16) + (w->register_w[DMA15_8]<<8) + w->register_w[DMA7_0]; |
| 376 | dma_address += offset; |
| 377 | |
| 378 | w->register_w[DMA23_16] = w->register_r[DMA23_16] = (dma_address & 0xff0000)>>16; |
| 379 | w->register_w[DMA15_8] = w->register_r[DMA15_8] = (dma_address & 0x00ff00)>>8; |
| 380 | w->register_w[DMA7_0] = w->register_r[DMA7_0] = (dma_address & 0x0000ff); |
| 381 | } |
| 308 | 382 | |
| 309 | | static DEVICE_IMAGE_LOAD(smc92x4_hd) |
| 383 | /* |
| 384 | Get the state from outside and latch it in the register. |
| 385 | There should be a bus driver on the PCB which provides the signals from |
| 386 | both the hard and floppy drives during S0=S1=0 and STB*=0 times via the |
| 387 | auxiliary bus. |
| 388 | */ |
| 389 | static void sync_status_in(running_device *device) |
| 310 | 390 | { |
| 311 | | const hard_disk_info *info; |
| 391 | UINT8 prev; |
| 392 | smc92x4_state *w = get_safe_token(device); |
| 312 | 393 | |
| 313 | | if ( mess_hd_get_hard_disk_file(image) ) |
| 394 | prev = w->register_r[DRIVE_STATUS]; |
| 395 | w->register_r[DRIVE_STATUS] = devcb_call_read_line(&w->in_auxbus_func); |
| 396 | |
| 397 | /* Raise interrupt if ready changes. TODO: Check this more closely. */ |
| 398 | // printf("disk status = %02x\n", reply); |
| 399 | if (((w->register_r[DRIVE_STATUS] & DS_READY) != (prev & DS_READY)) |
| 400 | & (w->register_r[INT_STATUS] & ST_RDYCHNG)) |
| 314 | 401 | { |
| 315 | | int disk_unit = get_id_from_device( image ); |
| 316 | | |
| 317 | | hd[disk_unit].hd_handle = mess_hd_get_hard_disk_file(image); |
| 318 | | hd[disk_unit].wp = !image_is_writable(image); |
| 319 | | hd[disk_unit].current_cylinder = 0; |
| 320 | | info = hard_disk_get_info(hd[disk_unit].hd_handle); |
| 321 | | hd[disk_unit].cylinders = info->cylinders; |
| 322 | | hd[disk_unit].heads = info->heads; |
| 323 | | hd[disk_unit].sectors_per_track = info->sectors; |
| 324 | | hd[disk_unit].bytes_per_sector = info->sectorbytes; |
| 325 | | |
| 326 | | if ((hd[disk_unit].cylinders > 2048) || (hd[disk_unit].heads > 16) |
| 327 | | || (hd[disk_unit].sectors_per_track > 256) |
| 328 | | || (hd[disk_unit].bytes_per_sector > 2048)) |
| 329 | | { |
| 330 | | hd[disk_unit].hd_handle = NULL; |
| 331 | | return INIT_FAIL; |
| 332 | | } |
| 333 | | if (hd[disk_unit].bytes_per_sector != 256) |
| 334 | | { |
| 335 | | hd[disk_unit].hd_handle = NULL; |
| 336 | | return INIT_FAIL; |
| 337 | | } |
| 338 | | return INIT_PASS; |
| 402 | smc92x4_set_interrupt(device); |
| 339 | 403 | } |
| 340 | | |
| 341 | | return INIT_FAIL; |
| 342 | 404 | } |
| 343 | 405 | |
| 344 | | static DEVICE_IMAGE_UNLOAD(smc92x4_hd) |
| 406 | /* |
| 407 | Push the output registers over the auxiliary bus. It is expected that |
| 408 | the PCB contains latches to store the values. |
| 409 | */ |
| 410 | static void sync_latches_out(running_device *device) |
| 345 | 411 | { |
| 346 | | int disk_unit = get_id_from_device( image ); |
| 412 | smc92x4_state *w = get_safe_token(device); |
| 413 | w->output1 = (w->output1 & 0xf0) | (w->register_w[RETRY_COUNT]&0x0f); |
| 347 | 414 | |
| 348 | | hd[disk_unit].hd_handle = NULL; |
| 415 | devcb_call_write8(&w->out_auxbus_func, OUTPUT_OUTPUT1, w->output1); |
| 416 | devcb_call_write8(&w->out_auxbus_func, OUTPUT_OUTPUT2, w->output2); |
| 349 | 417 | } |
| 350 | 418 | |
| 351 | | static int harddisk_read_id(int which, int disk_unit, int head) |
| 419 | /************************************************************* |
| 420 | Timed requests and callbacks |
| 421 | *************************************************************/ |
| 422 | #if 0 |
| 423 | /* setup a timed data request - data request will be triggered in a few usecs time */ |
| 424 | static void smc92x4_timed_data_request(running_device *device) |
| 352 | 425 | { |
| 353 | | hfdc[which].regs[hfdc_reg_cur_cyl] = hd[disk_unit].current_cylinder & 0xff; |
| 354 | | hfdc[which].regs[hfdc_reg_cur_head] = ((hd[disk_unit].current_cylinder >> 4) & 0x70) | head; |
| 355 | | hfdc[which].regs[hfdc_reg_read_6] = 0xfe; /* ident byte */ |
| 356 | | /*if () |
| 357 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_DELDATA;*/ |
| 358 | | |
| 359 | | return TRUE; |
| 426 | smc92x4_state *w = get_safe_token(device); |
| 427 | int time = controller_set_to_single_density(device)? 128 : 32; |
| 428 | |
| 429 | if (!w->use_real_timing) |
| 430 | time = 1; |
| 431 | |
| 432 | /* set new timer */ |
| 433 | timer_adjust_oneshot(w->timer_data, ATTOTIME_IN_USEC(time, 0)); |
| 360 | 434 | } |
| 435 | #endif |
| 361 | 436 | |
| 362 | | static int harddisk_chs_to_lba(int which, int disk_unit, unsigned int cylinder, unsigned int head, unsigned int sector, UINT32 *lba) |
| 437 | /* setup a timed read sector - read sector will be triggered in a few usecs time */ |
| 438 | static void smc92x4_timed_sector_read_request(running_device *device) |
| 363 | 439 | { |
| 364 | | if (cylinder >= hd[disk_unit].cylinders) |
| 365 | | { |
| 366 | | hd[disk_unit].current_cylinder = hd[disk_unit].cylinders-1; |
| 367 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 368 | | return FALSE; |
| 369 | | } |
| 440 | smc92x4_state *w = get_safe_token(device); |
| 441 | int time=0; |
| 442 | |
| 443 | /* set new timer */ |
| 444 | /* Average time from sector to sector. */ |
| 445 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 446 | time = (controller_set_to_single_density(device))? 30000 : 15000; |
| 370 | 447 | else |
| 371 | | { |
| 372 | | hd[disk_unit].current_cylinder = cylinder; |
| 373 | | } |
| 374 | | if ((head >= hd[disk_unit].heads) || (sector >= hd[disk_unit].sectors_per_track)) |
| 375 | | { |
| 376 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 377 | | return FALSE; |
| 378 | | } |
| 448 | time = 1000; |
| 379 | 449 | |
| 380 | | * lba = (cylinder*hd[disk_unit].heads + head)*hd[disk_unit].sectors_per_track + sector; |
| 450 | if (!w->use_real_timing) |
| 451 | time = 1; |
| 381 | 452 | |
| 382 | | return TRUE; |
| 453 | timer_adjust_oneshot(w->timer_rs, ATTOTIME_IN_USEC(time), 0); |
| 454 | w->to_be_continued = TRUE; |
| 383 | 455 | } |
| 384 | 456 | |
| 385 | | static int harddisk_read_sector(int which, int disk_unit, int cylinder, int head, int sector, int *dma_address) |
| 457 | /* setup a timed write sector - write sector will be triggered in a few usecs time */ |
| 458 | static void smc92x4_timed_sector_write_request(running_device *device) |
| 386 | 459 | { |
| 387 | | UINT32 lba; |
| 388 | | UINT8 buf[MAX_SECTOR_LEN]; |
| 389 | | int i; |
| 460 | smc92x4_state *w = get_safe_token(device); |
| 461 | int time=0; |
| 390 | 462 | |
| 463 | /* Average time from sector to sector. */ |
| 464 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 465 | time = (controller_set_to_single_density(device))? 30000 : 15000; |
| 466 | else |
| 467 | time = 1000; |
| 391 | 468 | |
| 392 | | if (!hd[disk_unit].hd_handle) |
| 393 | | { |
| 394 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 395 | | return FALSE; |
| 396 | | } |
| 469 | if (!w->use_real_timing) |
| 470 | time = 1; |
| 397 | 471 | |
| 398 | | if (! harddisk_chs_to_lba(which, disk_unit, cylinder, head, sector, &lba)) |
| 399 | | return FALSE; |
| 472 | timer_adjust_oneshot(w->timer_ws, ATTOTIME_IN_USEC(time), 0); |
| 473 | w->to_be_continued = TRUE; |
| 474 | } |
| 400 | 475 | |
| 401 | | if (! hard_disk_read(hd[disk_unit].hd_handle, lba, buf)) |
| 402 | | { |
| 403 | | hfdc[which].status |= ST_TC_DATAERR; |
| 404 | | return FALSE; |
| 405 | | } |
| 406 | | for (i=0; i<hd[disk_unit].bytes_per_sector; i++) |
| 407 | | { |
| 408 | | (*hfdc[which].dma_write_callback)(which, *dma_address, buf[i]); |
| 409 | | *dma_address = ((*dma_address) + 1) & 0xffffff; |
| 410 | | } |
| 476 | /* |
| 477 | Set up a timed track read/write |
| 478 | */ |
| 479 | static void smc92x4_timed_track_request(running_device *device) |
| 480 | { |
| 481 | smc92x4_state *w = get_safe_token(device); |
| 482 | int time = 0; |
| 483 | |
| 484 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 485 | time = TRACKTIME_FLOPPY; |
| 486 | else |
| 487 | time = TRACKTIME_HD; |
| 488 | |
| 489 | if (!w->use_real_timing) |
| 490 | time = 1; |
| 411 | 491 | |
| 412 | | return TRUE; |
| 492 | timer_adjust_oneshot(w->timer_track, ATTOTIME_IN_USEC(time), 0); |
| 493 | |
| 494 | w->to_be_continued = TRUE; |
| 413 | 495 | } |
| 414 | 496 | |
| 415 | | static int harddisk_write_sector(int which, int disk_unit, int cylinder, int head, int sector, int *dma_address) |
| 497 | /* |
| 498 | Set up a timed track seek |
| 499 | */ |
| 500 | static void smc92x4_timed_seek_request(running_device *device) |
| 416 | 501 | { |
| 417 | | UINT32 lba; |
| 418 | | UINT8 buf[MAX_SECTOR_LEN]; |
| 419 | | int i; |
| 502 | smc92x4_state *w = get_safe_token(device); |
| 503 | int time = 0; |
| 420 | 504 | |
| 505 | int index = w->register_w[MODE] & MO_STEPRATE; |
| 506 | int fm = controller_set_to_single_density(device); |
| 507 | |
| 508 | /* Get seek time. */ |
| 509 | if ((w->selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY8) |
| 510 | time = step_flop8[index]; |
| 421 | 511 | |
| 422 | | if (!hd[disk_unit].hd_handle) |
| 512 | else if ((w->selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY5) |
| 513 | time = step_flop5[index]; |
| 514 | else |
| 515 | time = step_hd[index]; |
| 516 | |
| 517 | if (fm) |
| 518 | time = time * 2; |
| 519 | |
| 520 | if (!w->use_real_timing) |
| 423 | 521 | { |
| 424 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 425 | | return FALSE; |
| 522 | logerror("smc92x4 info: Disk access without delays\n"); |
| 523 | time = 1; |
| 426 | 524 | } |
| 525 | |
| 526 | timer_adjust_oneshot(w->timer_seek, ATTOTIME_IN_USEC(time), 0); |
| 527 | w->to_be_continued = TRUE; |
| 528 | } |
| 427 | 529 | |
| 428 | | if (! harddisk_chs_to_lba(which, disk_unit, cylinder, head, sector, &lba)) |
| 429 | | return FALSE; |
| 530 | #if 0 |
| 531 | static TIMER_CALLBACK(smc92x4_data_callback) |
| 532 | { |
| 533 | /* running_device *device = (running_device *)ptr; |
| 534 | smc92x4_state *w = get_safe_token(device); */ |
| 535 | } |
| 536 | #endif |
| 430 | 537 | |
| 431 | | for (i=0; i<hd[disk_unit].bytes_per_sector; i++) |
| 432 | | { |
| 433 | | buf[i] = (*hfdc[which].dma_read_callback)(which, *dma_address); |
| 434 | | *dma_address = ((*dma_address) + 1) & 0xffffff; |
| 435 | | } |
| 436 | | if (! hard_disk_write(hd[disk_unit].hd_handle, lba, buf)) |
| 437 | | { |
| 438 | | hfdc[which].status |= ST_TC_DATAERR; |
| 439 | | return FALSE; |
| 440 | | } |
| 538 | static TIMER_CALLBACK(smc92x4_read_sector_callback) |
| 539 | { |
| 540 | running_device *device = (running_device *)ptr; |
| 541 | smc92x4_state *w = get_safe_token(device); |
| 542 | int transfer_enabled = w->command & 0x01; |
| 441 | 543 | |
| 442 | | return TRUE; |
| 544 | /* Now read the sector. */ |
| 545 | data_transfer_read(device, w->recent_id, transfer_enabled); |
| 546 | sync_status_in(device); |
| 547 | smc92x4_process_after_callback(device); |
| 443 | 548 | } |
| 444 | 549 | |
| 445 | | static void harddisk_step(int which, int disk_unit, int direction) |
| 550 | static TIMER_CALLBACK(smc92x4_write_sector_callback) |
| 446 | 551 | { |
| 447 | | hd[disk_unit].current_cylinder += direction; |
| 552 | running_device *device = (running_device *)ptr; |
| 553 | smc92x4_state *w = get_safe_token(device); |
| 554 | int deldata = w->command & 0x10; |
| 555 | int redcur = w->command & 0x08; |
| 556 | int precomp = w->command & 0x07; |
| 557 | int write_long = ((w->register_w[MODE]& MO_CRCECC)==0x40); |
| 448 | 558 | |
| 449 | | if (hd[disk_unit].current_cylinder >= hd[disk_unit].cylinders) |
| 450 | | hd[disk_unit].current_cylinder = hd[disk_unit].cylinders-1; |
| 451 | | if (hd[disk_unit].current_cylinder < 0) |
| 452 | | hd[disk_unit].current_cylinder = 0; |
| 559 | if (deldata) |
| 560 | logerror("smc92x4 warn: Write deleted data mark not supported. Writing normal mark.\n"); |
| 561 | |
| 562 | /* Now write the sector. */ |
| 563 | data_transfer_write(device, w->recent_id, deldata, redcur, precomp, write_long); |
| 564 | sync_status_in(device); |
| 565 | smc92x4_process_after_callback(device); |
| 453 | 566 | } |
| 454 | 567 | |
| 455 | | static UINT8 harddisk_get_disk_status(int which, int disk_unit) |
| 568 | /* |
| 569 | Callback for track access. Nothing interesting here, just used for |
| 570 | delaying. |
| 571 | */ |
| 572 | static TIMER_CALLBACK(smc92x4_track_callback) |
| 456 | 573 | { |
| 457 | | int reply; |
| 574 | running_device *device = (running_device *)ptr; |
| 575 | sync_status_in(device); |
| 576 | smc92x4_process_after_callback(device); |
| 577 | } |
| 458 | 578 | |
| 459 | | reply = 0; |
| 579 | /* |
| 580 | Callback for seek request. |
| 581 | */ |
| 582 | static TIMER_CALLBACK(smc92x4_seek_callback) |
| 583 | { |
| 584 | running_device *device = (running_device *)ptr; |
| 585 | smc92x4_state *w = get_safe_token(device); |
| 586 | running_device *current_floppy = NULL; |
| 587 | /* int buffered = ((w->register_w[MODE] & MO_STEPRATE)==0); */ |
| 588 | /* int buffered = (w->command & 0x01); */ |
| 460 | 589 | |
| 461 | | if (hd[disk_unit].hd_handle) |
| 590 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 462 | 591 | { |
| 463 | | reply |= DS_SELACK; |
| 464 | | /*if () |
| 465 | | reply |= DS_INDEX;*/ |
| 466 | | reply |= DS_SKCOM; |
| 467 | | if (hd[disk_unit].current_cylinder == 0) |
| 468 | | reply |= DS_TRK00; |
| 469 | | if (hd[disk_unit].wp) |
| 470 | | reply |= DS_WRPROT; |
| 471 | | if (hd[disk_unit].hd_handle) |
| 472 | | reply |= DS_READY; |
| 473 | | /*if () |
| 474 | | reply |= DS_WRFAULT;*/ |
| 592 | current_floppy = (*w->intf->current_floppy)(); |
| 593 | if (current_floppy==NULL) |
| 594 | { |
| 595 | logerror("smc92x4 error: seek callback: no floppy\n"); |
| 596 | w->register_r[INT_STATUS] |= ST_TC_SEEKERR; |
| 597 | } |
| 598 | else |
| 599 | { |
| 600 | // printf("smc92x4 step %s direction %d\n", current_floppy->tag(), w->step_direction); |
| 601 | floppy_drive_seek(current_floppy, w->step_direction); |
| 602 | } |
| 475 | 603 | } |
| 604 | else |
| 605 | { |
| 606 | // printf("smc92x4 step harddisk direction %d\n", w->step_direction); |
| 607 | (*w->intf->mfmhd_seek)(w->step_direction); |
| 608 | } |
| 609 | sync_status_in(device); |
| 476 | 610 | |
| 477 | | return reply; |
| 611 | smc92x4_process_after_callback(device); |
| 478 | 612 | } |
| 479 | 613 | |
| 614 | /********************************************************************* |
| 615 | Common functions |
| 616 | *********************************************************************/ |
| 480 | 617 | |
| 618 | /* |
| 619 | Calculate the ident byte from the cylinder. The specification does not |
| 620 | define idents beyond cylinder 1023, but formatting programs seem to |
| 621 | continue with 0xfd for cylinders between 1024 and 2047. |
| 622 | */ |
| 623 | UINT8 cylinder_to_ident(int cylinder) |
| 624 | { |
| 625 | if (cylinder < 256) return 0xfe; |
| 626 | if (cylinder < 512) return 0xff; |
| 627 | if (cylinder < 768) return 0xfc; |
| 628 | if (cylinder < 1024) return 0xfd; |
| 629 | return 0xfd; |
| 630 | } |
| 481 | 631 | |
| 482 | 632 | /* |
| 483 | | Initialize the controller |
| 633 | Calculate the offset from the ident. This is only useful for AT drives; |
| 634 | these drives cannot have more than 1024 cylinders. |
| 484 | 635 | */ |
| 485 | | void smc92x4_init(int which, const smc92x4_intf *intf) |
| 636 | static int ident_to_cylinder(UINT8 ident) |
| 486 | 637 | { |
| 487 | | memset(& hfdc[which], 0, sizeof(hfdc[which])); |
| 488 | | hfdc[which].select_callback = intf->select_callback; |
| 489 | | hfdc[which].dma_read_callback = intf->dma_read_callback; |
| 490 | | hfdc[which].dma_write_callback = intf->dma_write_callback; |
| 491 | | hfdc[which].int_callback = intf->int_callback; |
| 492 | | if (hfdc[which].int_callback) |
| 493 | | (*hfdc[which].int_callback)(which, 0); |
| 638 | switch (ident) |
| 639 | { |
| 640 | case 0xfe: return 0; |
| 641 | case 0xff: return 256; |
| 642 | case 0xfc: return 512; |
| 643 | case 0xfd: return 768; |
| 644 | default: return -1; |
| 645 | } |
| 494 | 646 | } |
| 495 | 647 | |
| 496 | 648 | /* |
| 497 | | Reset the controller |
| 649 | Common function to set the read registers from the recently read id. |
| 498 | 650 | */ |
| 499 | | void smc92x4_reset(int which) |
| 651 | static void update_id_regs(running_device *device, chrn_id_hd id) |
| 500 | 652 | { |
| 501 | | int i; |
| 653 | /* Flags for current head register. Note that the sizes are not in |
| 654 | sequence (128, 256, 512, 1024). This is only interesting for AT |
| 655 | mode. */ |
| 656 | UINT8 sizeflag[] = { 0x60, 0x00, 0x20, 0x40 }; |
| 657 | smc92x4_state *w = get_safe_token(device); |
| 502 | 658 | |
| 503 | | hfdc[which].status = 0; // ??? |
| 504 | | for (i=0; i<10; i++) |
| 505 | | hfdc[which].regs[i] = 0; // ??? |
| 506 | | hfdc[which].reg_ptr = 0; // ??? |
| 507 | | if (hfdc[which].int_callback) |
| 508 | | (*hfdc[which].int_callback)(which, 0); |
| 659 | w->register_r[CURRENT_CYLINDER] = id.C & 0xff; |
| 660 | |
| 661 | w->register_r[CURRENT_HEAD] = id.H & 0x0f; |
| 662 | |
| 663 | if (id.flags & BAD_SECTOR) |
| 664 | w->register_r[CURRENT_HEAD] |= 0x80; |
| 665 | |
| 666 | if ((w->selected_drive_type & DRIVE_TYPE) == TYPE_AT) |
| 667 | w->register_r[CURRENT_HEAD] |= sizeflag[id.N]; |
| 668 | else |
| 669 | w->register_r[CURRENT_HEAD] |= ((id.C & 0x700)>>4); |
| 670 | |
| 671 | w->register_r[CURRENT_IDENT] = cylinder_to_ident(id.C); |
| 509 | 672 | } |
| 510 | 673 | |
| 511 | 674 | /* |
| 512 | | Change the state of IRQ |
| 675 | Common procedure: read_id_field (as described in the specification) |
| 513 | 676 | */ |
| 514 | | static void smc92x4_set_interrupt(int which, int state) |
| 677 | static void read_id_field(running_device *device, int *steps, int *direction, chrn_id_hd *id) |
| 515 | 678 | { |
| 516 | | if ((state != 0) != ((hfdc[which].status & ST_INTPEND) != 0)) |
| 679 | smc92x4_state *w = get_safe_token(device); |
| 680 | int des_cylinder, cur_cylinder; |
| 681 | int found = FALSE; |
| 682 | sync_latches_out(device); |
| 683 | sync_status_in(device); |
| 684 | |
| 685 | /* Set command termination code. The error code is set first, and |
| 686 | on success, it is cleared. */ |
| 687 | w->register_r[INT_STATUS] |= ST_TC_RDIDERR; |
| 688 | |
| 689 | /* Try to find an ID field. */ |
| 690 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 517 | 691 | { |
| 518 | | if (state) |
| 519 | | hfdc[which].status |= ST_INTPEND; |
| 692 | chrn_id idflop; |
| 693 | running_device *disk_img = (*w->intf->current_floppy)(); |
| 694 | if (flopimg_get_image(disk_img) == NULL) |
| 695 | { |
| 696 | logerror("smc92x4 warn: No disk in drive\n"); |
| 697 | w->register_r[CHIP_STATUS] |= CS_SYNCERR; |
| 698 | return; |
| 699 | } |
| 700 | |
| 701 | /* Check whether image and controller are set to the same density. */ |
| 702 | if ((image_is_single_density(disk_img) && controller_set_to_single_density(device)) |
| 703 | || (!image_is_single_density(disk_img) && !controller_set_to_single_density(device)) |
| 704 | ) |
| 705 | { |
| 706 | found = floppy_drive_get_next_id(disk_img, w->register_w[DESIRED_HEAD]&0x0f, &idflop); |
| 707 | copyid(idflop, id); /* Need to use bigger values for HD, but we don't use separate variables here */ |
| 708 | } |
| 520 | 709 | else |
| 521 | | hfdc[which].status &= ~ST_INTPEND; |
| 710 | { |
| 711 | logerror("smc92x4 warn: Controller and medium density do not match.\n"); |
| 712 | } |
| 713 | sync_status_in(device); |
| 522 | 714 | |
| 523 | | if (hfdc[which].int_callback) |
| 524 | | (*hfdc[which].int_callback)(which, state); |
| 715 | if (!found) |
| 716 | { |
| 717 | logerror("smc92x4 error: read_id_field (floppy): sync error\n"); |
| 718 | w->register_r[CHIP_STATUS] |= CS_SYNCERR; |
| 719 | return; |
| 720 | } |
| 525 | 721 | } |
| 722 | else |
| 723 | { |
| 724 | (*w->intf->mfmhd_get_next_id)(w->register_w[DESIRED_HEAD]&0x0f, id); |
| 725 | sync_status_in(device); |
| 726 | if (!(w->register_r[DRIVE_STATUS]& DS_READY)) |
| 727 | { |
| 728 | logerror("smc92x4 error: read_id_field (harddisk): sync error\n"); |
| 729 | w->register_r[CHIP_STATUS] |= CS_SYNCERR; |
| 730 | return; |
| 731 | } |
| 732 | } |
| 733 | |
| 734 | w->register_r[CHIP_STATUS] &= ~CS_SYNCERR; |
| 735 | |
| 736 | /* Update the registers. */ |
| 737 | update_id_regs(device, *id); |
| 738 | |
| 739 | if (id->flags & BAD_CRC) |
| 740 | { |
| 741 | w->register_r[CHIP_STATUS] |= CS_CRCERR; |
| 742 | return; |
| 743 | } |
| 744 | |
| 745 | /* Calculate the steps. */ |
| 746 | if ((w->selected_drive_type & DRIVE_TYPE) == TYPE_AT) |
| 747 | { |
| 748 | /* Note: the spec says CURRENT_REGISTER, but that seems wrong. */ |
| 749 | des_cylinder = ((w->register_r[DATA] & 0x03)<<8) | w->register_w[DESIRED_CYLINDER]; |
| 750 | cur_cylinder = ident_to_cylinder(w->register_r[CURRENT_IDENT]) + w->register_r[CURRENT_CYLINDER]; |
| 751 | } |
| 752 | else |
| 753 | { |
| 754 | des_cylinder = ((w->register_w[DESIRED_HEAD] & 0x70)<<4) | w->register_w[DESIRED_CYLINDER]; |
| 755 | cur_cylinder = ((w->register_r[CURRENT_HEAD] & 0x70)<<4) | w->register_r[CURRENT_CYLINDER]; |
| 756 | } |
| 757 | |
| 758 | if (des_cylinder >= cur_cylinder) |
| 759 | { |
| 760 | *steps = des_cylinder - cur_cylinder; |
| 761 | *direction = +1; |
| 762 | } |
| 763 | else |
| 764 | { |
| 765 | *steps = cur_cylinder - des_cylinder; |
| 766 | *direction = -1; |
| 767 | } |
| 768 | |
| 769 | //printf("smc92x4 seek required: %d steps\n", *steps); |
| 770 | |
| 771 | w->register_r[INT_STATUS] &= ~ST_TC_RDIDERR; |
| 772 | return; |
| 526 | 773 | } |
| 527 | 774 | |
| 528 | 775 | /* |
| 529 | | Select currently selected drive |
| 776 | Common procedure: verify (as described in the specification) |
| 530 | 777 | */ |
| 531 | | static int get_selected_drive(int which, select_mode_t *select_mode, int *disk_unit) |
| 778 | static int verify(running_device *device, chrn_id_hd *id, int check_sector) |
| 532 | 779 | { |
| 533 | | if (hfdc[which].disk_sel == disk_sel_none) |
| 780 | smc92x4_state *w = get_safe_token(device); |
| 781 | int maxtry = 132; /* approx. 33792/(256*32) */ |
| 782 | int pass = 0; |
| 783 | int found = FALSE; |
| 784 | int foundsect = FALSE; |
| 785 | int des_cylinder = 0; |
| 786 | |
| 787 | /* Set command termination code. The error code is set first, and |
| 788 | on success, it is cleared. */ |
| 789 | w->register_r[INT_STATUS] |= ST_TC_SEEKERR; |
| 790 | |
| 791 | while (pass < maxtry && !foundsect) |
| 534 | 792 | { |
| 535 | | * select_mode = sm_undefined; |
| 536 | | * disk_unit = -1; |
| 793 | pass++; |
| 794 | /* Try to find an ID field. */ |
| 795 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 796 | { |
| 797 | chrn_id idflop; |
| 798 | running_device *disk_img = (*w->intf->current_floppy)(); |
| 799 | found = floppy_drive_get_next_id(disk_img, w->register_w[DESIRED_HEAD]&0x0f, &idflop); |
| 800 | copyid(idflop, id); |
| 801 | if (/* pass==1 && */!found) |
| 802 | { |
| 803 | w->register_r[CHIP_STATUS] |= CS_SYNCERR; |
| 804 | logerror("smc92x4 error: verify (floppy): sync error\n"); |
| 805 | return ERROR; |
| 806 | } |
| 807 | } |
| 808 | else |
| 809 | { |
| 810 | (*w->intf->mfmhd_get_next_id)(w->register_w[DESIRED_HEAD]&0x0f, id); |
| 811 | sync_status_in(device); |
| 812 | if (!(w->register_r[DRIVE_STATUS]& DS_READY)) |
| 813 | { |
| 814 | logerror("smc92x4 error: verify (harddisk): sync error\n"); |
| 815 | w->register_r[CHIP_STATUS] |= CS_SYNCERR; |
| 816 | return ERROR; |
| 817 | } |
| 818 | } |
| 819 | |
| 820 | w->register_r[CHIP_STATUS] &= ~CS_SYNCERR; |
| 821 | |
| 822 | /* Compare with the desired sector ID. */ |
| 823 | if ((w->selected_drive_type & DRIVE_TYPE) == TYPE_AT) |
| 824 | { |
| 825 | /* Note: the spec says CURRENT_CYLINDER, but that seems wrong. */ |
| 826 | des_cylinder = ((w->register_r[DATA] & 0x03)<<8) | w->register_w[DESIRED_CYLINDER]; |
| 827 | } |
| 828 | else |
| 829 | { |
| 830 | des_cylinder = ((w->register_w[DESIRED_HEAD] & 0x70)<<4) | w->register_w[DESIRED_CYLINDER]; |
| 831 | } |
| 832 | // printf("smc92x4 check id: current = (%d,%d,%d), required = (%d,%d,%d)\n", id->C, id->H, id->R, des_cylinder, w->register_w[DESIRED_HEAD] & 0x0f, w->register_w[DESIRED_SECTOR]); |
| 833 | if ((des_cylinder == id->C) |
| 834 | && ((w->register_w[DESIRED_HEAD] & 0x0f) == id->H)) |
| 835 | { |
| 836 | if (!check_sector || (w->register_w[DESIRED_SECTOR] == id->R)) |
| 837 | foundsect = TRUE; |
| 838 | } |
| 839 | } |
| 840 | if (!foundsect) |
| 841 | { |
| 842 | w->register_r[CHIP_STATUS] |= CS_COMPERR; |
| 843 | logerror("smc92x4 error: verify: sector not found, seek error (desired cyl=%d/sec=%d, current cyl=%d/sec=%d)\n", des_cylinder, w->register_w[DESIRED_SECTOR], id->C, id->R); |
| 844 | return ERROR; |
| 537 | 845 | } |
| 846 | |
| 847 | w->register_r[INT_STATUS] &= ~ST_TC_SEEKERR; |
| 848 | return DONE; |
| 849 | } |
| 850 | |
| 851 | /* |
| 852 | Common procedure: data_transfer(read) (as described in the specification) |
| 853 | */ |
| 854 | static void data_transfer_read(running_device *device, chrn_id_hd id, int transfer_enable) |
| 855 | { |
| 856 | int i, retry, sector_len; |
| 857 | smc92x4_state *w = get_safe_token(device); |
| 858 | running_device *current_floppy = NULL; |
| 859 | |
| 860 | int sector_data_id; |
| 861 | UINT8 *buf; |
| 862 | |
| 863 | sync_latches_out(device); |
| 864 | sync_status_in(device); |
| 865 | |
| 866 | current_floppy = (*w->intf->current_floppy)(); |
| 867 | |
| 868 | /* Set command termination code. The error code is set first, and |
| 869 | on success, it is cleared. */ |
| 870 | w->register_r[INT_STATUS] |= ST_TC_DATAERR; |
| 871 | |
| 872 | /* Save the value. Note that the retry count is only in the first four |
| 873 | bits, and it is stored in one's complement. In this implementation |
| 874 | we don't work with it. */ |
| 875 | retry = w->register_w[RETRY_COUNT]; |
| 876 | |
| 877 | /* We are already at the correct sector (found by the verify sequence) */ |
| 878 | |
| 879 | /* Find the data sync mark. Easy, we assume it has been found. */ |
| 880 | |
| 881 | if (id.flags & ID_FLAG_DELETED_DATA) |
| 882 | w->register_r[CHIP_STATUS] |= CS_DELDATA; |
| 538 | 883 | else |
| 884 | w->register_r[CHIP_STATUS] &= ~CS_DELDATA; |
| 885 | |
| 886 | /* Found. Now update the current cylinder/head registers. */ |
| 887 | update_id_regs(device, id); |
| 888 | |
| 889 | /* Initiate the DMA. We assume the DMARQ is positive. */ |
| 890 | w->register_r[INT_STATUS] &= ~ST_OVRUN; |
| 891 | |
| 892 | sector_len = 1 << (id.N+7); |
| 893 | sector_data_id = id.data_id; |
| 894 | |
| 895 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 539 | 896 | { |
| 540 | | * select_mode = (select_mode_t) ((hfdc[which].disk_sel >> 2) & 0x3); |
| 541 | | |
| 542 | | switch (* select_mode) |
| 897 | buf = (UINT8 *)malloc(sector_len); |
| 898 | floppy_drive_read_sector_data(current_floppy, id.H, sector_data_id, buf, sector_len); |
| 899 | } |
| 900 | else |
| 901 | { |
| 902 | /* buf is allocated within the function, and sector_len is also set */ |
| 903 | (*w->intf->mfmhd_read_sector)(id.C, id.H, id.R, &buf, §or_len); |
| 904 | } |
| 905 | sync_status_in(device); |
| 906 | |
| 907 | if (transfer_enable) |
| 908 | { |
| 909 | /* Copy via DMA into controller RAM. */ |
| 910 | set_dma_address(device, DMA23_16, DMA15_8, DMA7_0); |
| 911 | |
| 912 | smc92x4_set_dip(device, TRUE); |
| 913 | for (i=0; i < sector_len; i++) |
| 543 | 914 | { |
| 544 | | case sm_at_harddisk: |
| 545 | | case sm_harddisk: |
| 546 | | case sm_floppy_slow: |
| 547 | | case sm_floppy_fast: |
| 548 | | if (hfdc[which].select_callback) |
| 549 | | * disk_unit = (* hfdc[which].select_callback)(which, * select_mode, hfdc[which].disk_sel & 0x3, hfdc[which].regs[hfdc_reg_retry_count] & 0xf); |
| 550 | | else |
| 551 | | * disk_unit = hfdc[which].disk_sel & 0x3; |
| 552 | | |
| 553 | | case sm_undefined: |
| 554 | | break; |
| 915 | (*w->intf->dma_write_callback)(buf[i]); |
| 555 | 916 | } |
| 917 | smc92x4_set_dip(device, FALSE); |
| 556 | 918 | } |
| 919 | free(buf); |
| 557 | 920 | |
| 558 | | return (* disk_unit != -1); |
| 921 | /* Check CRC. We assume everything is OK, no retry required. */ |
| 922 | w->register_r[CHIP_STATUS] &= ~CS_RETREQ; |
| 923 | w->register_r[CHIP_STATUS] &= ~CS_CRCERR; |
| 924 | w->register_r[CHIP_STATUS] &= ~CS_ECCATT; |
| 925 | |
| 926 | /* Update the DMA registers. */ |
| 927 | if (transfer_enable) |
| 928 | dma_add_offset(device, sector_len); |
| 929 | |
| 930 | /* Decrement sector count. */ |
| 931 | w->register_w[SECTOR_COUNT] = (w->register_w[SECTOR_COUNT]-1)&0xff; |
| 932 | |
| 933 | /* Clear the error bits. */ |
| 934 | w->register_r[INT_STATUS] &= ~ST_TC_DATAERR; |
| 935 | |
| 936 | if (w->register_w[SECTOR_COUNT] == 0) |
| 937 | return; |
| 938 | |
| 939 | /* Else this is a multi-sector operation. */ |
| 940 | w->register_w[DESIRED_SECTOR] = |
| 941 | w->register_r[DESIRED_SECTOR] = |
| 942 | (w->register_w[DESIRED_SECTOR]+1) & 0xff; |
| 943 | |
| 944 | /* Reinitialize retry count. */ |
| 945 | w->register_w[RETRY_COUNT] = retry; |
| 559 | 946 | } |
| 560 | 947 | |
| 561 | 948 | /* |
| 562 | | Assert Command Done status bit, triggering interrupts as needed |
| 949 | Common procedure: data_transfer(write) (as described in the specification) |
| 563 | 950 | */ |
| 564 | | INLINE void set_command_done(int which) |
| 951 | static void data_transfer_write(running_device *device, chrn_id_hd id, int deldata, int redcur, int precomp, int write_long) |
| 565 | 952 | { |
| 566 | | //assert(! (hfdc[which].status & ST_DONE)) |
| 567 | | hfdc[which].status |= ST_DONE; |
| 568 | | if (hfdc[which].regs[hfdc_reg_term] & TC_INTDONE) |
| 569 | | smc92x4_set_interrupt(which, 1); |
| 570 | | } |
| 953 | int retry, i, sector_len; |
| 954 | smc92x4_state *w = get_safe_token(device); |
| 955 | running_device *current_floppy = NULL; |
| 956 | UINT8 *buf; |
| 957 | int sector_data_id; |
| 958 | |
| 959 | sync_latches_out(device); |
| 960 | sync_status_in(device); |
| 961 | |
| 962 | current_floppy = (*w->intf->current_floppy)(); |
| 963 | |
| 964 | /* Set command termination code. The error code is set first, and |
| 965 | on success, it is cleared. */ |
| 966 | w->register_r[INT_STATUS] |= ST_TC_DATAERR; |
| 967 | |
| 968 | /* Save the value. Note that the retry count is only in the first four |
| 969 | bits, and it is stored in one's complement. In this implementation |
| 970 | we don't work with it. */ |
| 971 | retry = w->register_w[RETRY_COUNT]; |
| 972 | |
| 973 | /* Initiate the DMA. We assume the DMARQ is positive. */ |
| 974 | w->register_r[INT_STATUS] &= ~ST_OVRUN; |
| 571 | 975 | |
| 572 | | INLINE void step(running_machine *machine,int which, select_mode_t select_mode, int disk_unit, int direction) |
| 573 | | { |
| 574 | | switch (select_mode) |
| 976 | sector_len = 1 << (id.N+7); |
| 977 | sector_data_id = id.data_id; |
| 978 | |
| 979 | buf = (UINT8 *)malloc(sector_len); |
| 980 | |
| 981 | /* Copy via DMA from controller RAM. */ |
| 982 | set_dma_address(device, DMA23_16, DMA15_8, DMA7_0); |
| 983 | |
| 984 | smc92x4_set_dip(device, TRUE); |
| 985 | for (i=0; i<sector_len; i++) |
| 575 | 986 | { |
| 576 | | case sm_undefined: |
| 577 | | default: |
| 578 | | break; |
| 987 | buf[i] = (*w->intf->dma_read_callback)(); |
| 988 | } |
| 989 | smc92x4_set_dip(device, FALSE); |
| 990 | |
| 991 | if (write_long) |
| 992 | { |
| 993 | logerror("smc92x4 write sector: Write_long not supported. Performing a normal write.\n"); |
| 994 | } |
| 995 | |
| 996 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 997 | { |
| 998 | floppy_drive_write_sector_data(current_floppy, id.H, sector_data_id, (char *) buf, sector_len, FALSE); |
| 999 | } |
| 1000 | else |
| 1001 | { |
| 1002 | (*w->intf->mfmhd_write_sector)(id.C, id.H, id.R, buf, sector_len); |
| 1003 | } |
| 1004 | free(buf); |
| 1005 | sync_status_in(device); |
| 1006 | |
| 1007 | w->register_r[CHIP_STATUS] &= ~CS_RETREQ; |
| 1008 | w->register_r[CHIP_STATUS] &= ~CS_CRCERR; |
| 1009 | w->register_r[CHIP_STATUS] &= ~CS_ECCATT; |
| 1010 | |
| 1011 | /* Update the DMA registers. */ |
| 1012 | dma_add_offset(device, sector_len); |
| 579 | 1013 | |
| 580 | | case sm_at_harddisk: |
| 581 | | break; |
| 1014 | /* Decrement sector count. */ |
| 1015 | w->register_w[SECTOR_COUNT] = (w->register_w[SECTOR_COUNT]-1)&0xff; |
| 582 | 1016 | |
| 583 | | case sm_harddisk: |
| 584 | | /* hard disks may ignore programmed seeks */ |
| 585 | | harddisk_step(which, disk_unit, direction); |
| 586 | | break; |
| 587 | | |
| 588 | | case sm_floppy_slow: |
| 589 | | case sm_floppy_fast: |
| 590 | | floppy_step(machine,which, disk_unit, direction); |
| 591 | | break; |
| 592 | | } |
| 1017 | /* Clear the error bits. */ |
| 1018 | w->register_r[INT_STATUS] &= ~ST_TC_DATAERR; |
| 1019 | |
| 1020 | if (w->register_w[SECTOR_COUNT] == 0) |
| 1021 | return; |
| 1022 | |
| 1023 | /* Else this is a multi-sector operation. */ |
| 1024 | w->register_w[DESIRED_SECTOR] = |
| 1025 | w->register_r[DESIRED_SECTOR] = |
| 1026 | (w->register_w[DESIRED_SECTOR]+1) & 0xff; |
| 1027 | |
| 1028 | /* Reinitialize retry count. */ |
| 1029 | w->register_w[RETRY_COUNT] = retry; |
| 593 | 1030 | } |
| 594 | 1031 | |
| 1032 | static void read_sectors_continue(running_device *device); |
| 1033 | static void write_sectors_continue(running_device *device); |
| 1034 | |
| 595 | 1035 | /* |
| 596 | | Perform the read_id phase on a drive |
| 1036 | Read sectors physical / logical. Physical means that the first, the |
| 1037 | second, the third sector appearing under the head will be read. These |
| 1038 | sectors are usually not in logical sequence. The ordering depends on |
| 1039 | the interleave pattern. |
| 597 | 1040 | */ |
| 598 | | INLINE int read_id(running_machine *machine,int which, select_mode_t select_mode, int disk_unit, int head, |
| 599 | | int do_implied_seek, int desired_cylinder) |
| 1041 | static void read_write_sectors(running_device *device) |
| 600 | 1042 | { |
| 601 | | int reply; |
| 1043 | smc92x4_state *w = get_safe_token(device); |
| 602 | 1044 | |
| 603 | | switch (select_mode) |
| 1045 | int logical = w->command & 0x04; |
| 1046 | int implied_seek_disabled = w->command & 0x02; /* for read */ |
| 1047 | int write = (w->command & 0x80); |
| 1048 | |
| 1049 | w->after_seek = FALSE; |
| 1050 | |
| 1051 | w->to_be_continued = FALSE; |
| 1052 | |
| 1053 | if (write) /* write sectors */ |
| 604 | 1054 | { |
| 605 | | case sm_undefined: |
| 606 | | default: |
| 607 | | reply = FALSE; |
| 608 | | break; |
| 1055 | logical = w->command & 0x20; |
| 1056 | implied_seek_disabled = w->command & 0x40; |
| 1057 | } |
| 1058 | |
| 1059 | if (!logical) |
| 1060 | implied_seek_disabled = FALSE; |
| 1061 | |
| 1062 | if (!w->found_id) |
| 1063 | { |
| 1064 | /* First start. */ |
| 1065 | read_id_field(device, &w->seek_count, &w->step_direction, &w->recent_id); |
| 1066 | } |
| 1067 | |
| 1068 | if ((w->register_r[INT_STATUS] & ST_TC_DATAERR) == ST_TC_SUCCESS) |
| 1069 | { |
| 1070 | w->found_id = TRUE; |
| 1071 | /* Perform the seek for the cylinder. */ |
| 1072 | if (!implied_seek_disabled && w->seek_count > 0) |
| 1073 | { |
| 1074 | smc92x4_timed_seek_request(device); |
| 1075 | } |
| 1076 | else |
| 1077 | { |
| 1078 | if (write) |
| 1079 | write_sectors_continue(device); |
| 1080 | else |
| 1081 | read_sectors_continue(device); |
| 1082 | } |
| 1083 | |
| 1084 | } |
| 1085 | else |
| 1086 | { |
| 1087 | set_command_done(device, ST_TC_RDIDERR); |
| 1088 | } |
| 1089 | } |
| 609 | 1090 | |
| 610 | | case sm_at_harddisk: |
| 611 | | reply = FALSE; |
| 612 | | break; |
| 613 | 1091 | |
| 614 | | case sm_harddisk: |
| 615 | | reply = harddisk_read_id(which, disk_unit, head); |
| 616 | | break; |
| 1092 | static void read_sectors_continue(running_device *device) |
| 1093 | { |
| 1094 | smc92x4_state *w = get_safe_token(device); |
| 617 | 1095 | |
| 618 | | case sm_floppy_slow: |
| 619 | | case sm_floppy_fast: |
| 620 | | reply = floppy_read_id(machine,which, disk_unit, head); |
| 621 | | break; |
| 1096 | int check_sector = TRUE; /* always check the first sector */ |
| 1097 | int state = AGAIN; |
| 1098 | int logical = w->command & 0x04; |
| 1099 | |
| 1100 | /* Needed for the two ways of re-entry: during the seek process, and during sector read */ |
| 1101 | if (!w->after_seek) |
| 1102 | { |
| 1103 | // printf("smc92x4 continue with sector read\n"); |
| 1104 | w->seek_count--; |
| 1105 | if (w->seek_count > 0) |
| 1106 | { |
| 1107 | read_write_sectors(device); |
| 1108 | return; |
| 1109 | } |
| 1110 | w->after_seek = TRUE; |
| 622 | 1111 | } |
| 1112 | else |
| 1113 | { |
| 1114 | /* we are here after the sector read. */ |
| 1115 | w->to_be_continued = FALSE; |
| 1116 | if (w->register_r[INT_STATUS] & ST_TERMCOD) |
| 1117 | { |
| 1118 | logerror("smc92x4 error: data error during sector read: INTSTATUS=%02x\n", w->register_r[INT_STATUS]); |
| 1119 | set_command_done(device, ST_TC_DATAERR); |
| 1120 | return; |
| 1121 | } |
| 1122 | } |
| 623 | 1123 | |
| 624 | | if (do_implied_seek && reply) |
| 1124 | w->to_be_continued = FALSE; |
| 1125 | |
| 1126 | /* Wait for SEEK_COMPLETE. We assume the signal has appeared. */ |
| 1127 | |
| 1128 | if (w->register_w[SECTOR_COUNT] > 0 /* && !(w->register_r[DRIVE_STATUS] & DS_INDEX) */) |
| 625 | 1129 | { |
| 626 | | /* perform implied seek */ |
| 627 | | int current_cylinder; |
| 628 | | int step_direction, step_count; |
| 629 | | int i; |
| 1130 | /* Call the verify sequence. */ |
| 1131 | state = verify(device, &w->recent_id, check_sector); |
| 1132 | if (state==ERROR) |
| 1133 | { |
| 1134 | // TODO: set command done? |
| 1135 | logerror("smc92x4 error: verify error during sector read\n"); |
| 1136 | return; |
| 1137 | } |
| 630 | 1138 | |
| 631 | | if (select_mode == sm_at_harddisk) |
| 1139 | /* For read physical, only verify the first sector. */ |
| 1140 | if (!logical) |
| 1141 | check_sector = FALSE; |
| 1142 | |
| 1143 | if (w->recent_id.flags & BAD_SECTOR) |
| 632 | 1144 | { |
| 633 | | switch (hfdc[which].regs[hfdc_reg_read_6]) |
| 634 | | { |
| 635 | | case 0xfe: |
| 636 | | current_cylinder = hfdc[which].regs[hfdc_reg_cur_cyl]; |
| 637 | | break; |
| 638 | | case 0xff: |
| 639 | | current_cylinder = 256 + hfdc[which].regs[hfdc_reg_cur_cyl]; |
| 640 | | break; |
| 641 | | case 0xfc: |
| 642 | | current_cylinder = 512 + hfdc[which].regs[hfdc_reg_cur_cyl]; |
| 643 | | break; |
| 644 | | case 0xfd: |
| 645 | | current_cylinder = 1024 + hfdc[which].regs[hfdc_reg_cur_cyl]; |
| 646 | | break; |
| 647 | | default: |
| 648 | | assert(1); |
| 649 | | current_cylinder = 0; |
| 650 | | break; |
| 651 | | } |
| 1145 | logerror("smc92x4 error: Bad sector, seek error\n"); |
| 1146 | set_command_done(device, ST_TC_SEEKERR); |
| 652 | 1147 | } |
| 653 | | else if (select_mode == sm_harddisk) |
| 654 | | current_cylinder = ((hfdc[which].regs[hfdc_reg_cur_head] & 0x70) << 4) | hfdc[which].regs[hfdc_reg_cur_cyl]; |
| 655 | 1148 | else |
| 656 | | current_cylinder = hfdc[which].regs[hfdc_reg_cur_cyl]; |
| 1149 | { |
| 1150 | /* printf("smc92x4 read sectors CYL=%02x, HEA=%02x, SEC=%02x, MOD=%02x, CNT=%02x, TRY=%02x\n", |
| 1151 | w->register_w[DESIRED_CYLINDER], |
| 1152 | w->register_w[DESIRED_HEAD], |
| 1153 | w->register_w[DESIRED_SECTOR], |
| 1154 | w->register_w[MODE], |
| 1155 | w->register_w[SECTOR_COUNT], |
| 1156 | w->register_w[RETRY_COUNT]); */ |
| 1157 | smc92x4_timed_sector_read_request(device); |
| 1158 | } |
| 1159 | } |
| 1160 | else |
| 1161 | { |
| 1162 | set_command_done(device, ST_TC_SUCCESS); |
| 1163 | //printf("smc92x4 read sector command done\n"); |
| 1164 | } |
| 1165 | } |
| 657 | 1166 | |
| 658 | | if (current_cylinder < desired_cylinder) |
| 1167 | static void write_sectors_continue(running_device *device) |
| 1168 | { |
| 1169 | smc92x4_state *w = get_safe_token(device); |
| 1170 | |
| 1171 | int check_sector = TRUE; /* always check the first sector */ |
| 1172 | int state = AGAIN; |
| 1173 | int logical = w->command & 0x20; |
| 1174 | |
| 1175 | /* Needed for the two ways of re-entry: during the seek process, and during sector write */ |
| 1176 | if (!w->after_seek) |
| 1177 | { |
| 1178 | w->seek_count--; |
| 1179 | if (w->seek_count > 0) |
| 659 | 1180 | { |
| 660 | | step_direction = +1; |
| 661 | | step_count = desired_cylinder - current_cylinder; |
| 1181 | read_write_sectors(device); |
| 1182 | return; |
| 662 | 1183 | } |
| 663 | | else |
| 1184 | w->after_seek = TRUE; |
| 1185 | } |
| 1186 | else |
| 1187 | { |
| 1188 | /* we are here after the sector write. */ |
| 1189 | w->to_be_continued = FALSE; |
| 1190 | if (w->register_r[INT_STATUS] & ST_TERMCOD) |
| 664 | 1191 | { |
| 665 | | step_direction = -1; |
| 666 | | step_count = current_cylinder - desired_cylinder; |
| 1192 | logerror("smc92x4 error: data error during sector write\n"); |
| 1193 | set_command_done(device, ST_TC_DATAERR); |
| 1194 | return; |
| 667 | 1195 | } |
| 1196 | } |
| 1197 | |
| 1198 | w->to_be_continued = FALSE; |
| 668 | 1199 | |
| 669 | | for (i=0; i<step_count; i++) |
| 670 | | step(machine,which, select_mode, disk_unit, step_direction); |
| 1200 | if ((w->register_w[RETRY_COUNT] & 0xf0)!= 0xf0) |
| 1201 | logerror("smc92x4 warn: RETRY_COUNT in write sector should be set to 0. Ignored.\n"); |
| 1202 | |
| 1203 | /* Wait for SEEK_COMPLETE. We assume the signal has appeared. */ |
| 1204 | if (w->register_w[SECTOR_COUNT] > 0) |
| 1205 | { |
| 1206 | /* Call the verify sequence. */ |
| 1207 | state = verify(device, &w->recent_id, check_sector); |
| 1208 | if (state==ERROR) |
| 1209 | { |
| 1210 | logerror("smc92x4 error: verify error during sector write\n"); |
| 1211 | return; |
| 1212 | } |
| 1213 | |
| 1214 | /* For write physical, only verify the first sector. */ |
| 1215 | if (!logical) |
| 1216 | check_sector = FALSE; |
| 1217 | |
| 1218 | /* printf("smc92x4 write sectors CYL=%02x, HEA=%02x, SEC=%02x, MOD=%02x, CNT=%02x, TRY=%02x\n", |
| 1219 | w->register_w[DESIRED_CYLINDER], |
| 1220 | w->register_w[DESIRED_HEAD], |
| 1221 | w->register_w[DESIRED_SECTOR], |
| 1222 | w->register_w[MODE], |
| 1223 | w->register_w[SECTOR_COUNT], |
| 1224 | w->register_w[RETRY_COUNT]); */ |
| 1225 | smc92x4_timed_sector_write_request(device); |
| 671 | 1226 | } |
| 672 | | |
| 673 | | return reply; |
| 1227 | else |
| 1228 | { |
| 1229 | set_command_done(device, ST_TC_SUCCESS); |
| 1230 | // printf("smc92x4 write sector command done\n"); |
| 1231 | } |
| 674 | 1232 | } |
| 675 | 1233 | |
| 1234 | /********************************************************************* |
| 1235 | Command implementations |
| 1236 | *********************************************************************/ |
| 1237 | |
| 676 | 1238 | /* |
| 677 | | Get the status of a drive |
| 1239 | Handle the restore command |
| 678 | 1240 | */ |
| 679 | | INLINE UINT8 get_disk_status(running_machine *machine,int which, select_mode_t select_mode, int disk_unit) |
| 1241 | static void restore_drive(running_device *device) |
| 680 | 1242 | { |
| 681 | | UINT8 reply; |
| 1243 | smc92x4_state *w = get_safe_token(device); |
| 1244 | |
| 1245 | /* TODO: int_after_seek_complete required for buffered seeks */ |
| 1246 | sync_status_in(device); |
| 682 | 1247 | |
| 683 | | switch (select_mode) |
| 1248 | if (w->seek_count>=4096 || !(w->register_r[DRIVE_STATUS] & DS_READY)) |
| 684 | 1249 | { |
| 685 | | case sm_undefined: |
| 686 | | default: |
| 687 | | reply = 0; |
| 688 | | break; |
| 1250 | logerror("smc92x4 error: seek error in restore\n"); |
| 1251 | w->register_r[INT_STATUS] |= ST_TC_SEEKERR; |
| 1252 | return; |
| 1253 | } |
| 1254 | |
| 1255 | if (w->register_r[DRIVE_STATUS] & DS_TRK00) |
| 1256 | { |
| 1257 | w->register_r[INT_STATUS] |= ST_TC_SUCCESS; |
| 1258 | /* Issue interrupt */ |
| 1259 | smc92x4_set_interrupt(device); |
| 1260 | return; |
| 1261 | } |
| 689 | 1262 | |
| 690 | | case sm_at_harddisk: |
| 691 | | reply = 0; |
| 692 | | break; |
| 1263 | w->step_direction = -1; |
| 1264 | smc92x4_timed_seek_request(device); |
| 1265 | } |
| 693 | 1266 | |
| 694 | | case sm_harddisk: |
| 695 | | reply = harddisk_get_disk_status(which, disk_unit); |
| 696 | | break; |
| 1267 | static void restore_continue(running_device *device) |
| 1268 | { |
| 1269 | smc92x4_state *w = get_safe_token(device); |
| 697 | 1270 | |
| 698 | | case sm_floppy_slow: |
| 699 | | case sm_floppy_fast: |
| 700 | | reply = floppy_get_disk_status(machine,which, disk_unit); |
| 701 | | break; |
| 1271 | w->seek_count++; |
| 1272 | |
| 1273 | /* Next iteration */ |
| 1274 | restore_drive(device); |
| 702 | 1275 | |
| 703 | | } |
| 704 | | |
| 705 | | return reply; |
| 1276 | w->to_be_continued = FALSE; |
| 706 | 1277 | } |
| 707 | 1278 | |
| 708 | 1279 | /* |
| 709 | | Handle the step command |
| 1280 | Handle the step command. Note that the CURRENT_CYLINDER register is not |
| 1281 | updated (this would break the format procedure). |
| 710 | 1282 | */ |
| 711 | | static void do_step(running_machine *machine,int which, int mode) |
| 1283 | static void step_in_out(running_device *device) |
| 712 | 1284 | { |
| 713 | | select_mode_t select_mode; |
| 714 | | int disk_unit = 0; |
| 1285 | smc92x4_state *w = get_safe_token(device); |
| 1286 | int direction = (w->command & 0x02)? -1 : +1; |
| 1287 | /* bit 0: 0 -> command ends after last seek pulse, 1 -> command |
| 1288 | ends when the drive asserts the seek complete pin */ |
| 1289 | int buffered = w->command & 0x01; |
| 1290 | |
| 1291 | w->step_direction = direction; |
| 1292 | w->buffered = buffered; |
| 715 | 1293 | |
| 716 | | hfdc[which].status = 0; |
| 1294 | smc92x4_timed_seek_request(device); |
| 1295 | //printf("smc92x4 waiting for drive step\n"); |
| 1296 | } |
| 717 | 1297 | |
| 718 | | /* reset chip status */ |
| 719 | | hfdc[which].regs[hfdc_reg_chip_stat] = hfdc[which].disk_sel & 0x3; |
| 1298 | static void step_continue(running_device *device) |
| 1299 | { |
| 1300 | smc92x4_state *w = get_safe_token(device); |
| 1301 | //printf("smc92x4 step continue\n"); |
| 1302 | w->to_be_continued = FALSE; |
| 1303 | set_command_done(device, ST_TC_SUCCESS); |
| 1304 | } |
| 720 | 1305 | |
| 721 | | if (!get_selected_drive(which, & select_mode, & disk_unit)) |
| 1306 | |
| 1307 | static void drive_select(running_device *device, int drive); |
| 1308 | |
| 1309 | /* |
| 1310 | Poll drives |
| 1311 | This command is used to find out which drive has complete a buffered |
| 1312 | seek (RESTORE, SEEK IN/OUT with BUFFERED set to one) |
| 1313 | */ |
| 1314 | static void poll_drives(running_device *device) |
| 1315 | { |
| 1316 | int mask = 0x08; |
| 1317 | smc92x4_state *w = get_safe_token(device); |
| 1318 | int i; |
| 1319 | int flags = w->command & 0x0f; |
| 1320 | |
| 1321 | /* Spec is unclear: Do we continue to poll the drives after we have checked each |
| 1322 | one for the first time? We are not interested in locking up the emulator, so |
| 1323 | we decide to poll only once. */ |
| 1324 | for (i=3; i>=0; i--) |
| 722 | 1325 | { |
| 723 | | /* no unit has been selected */ |
| 724 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 725 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_SYNCERR; |
| 726 | | goto cleanup; |
| 1326 | if (flags & mask) |
| 1327 | { |
| 1328 | /* Poll drive */ |
| 1329 | drive_select(device, i|((w->types[i])<<2)); |
| 1330 | sync_latches_out(device); |
| 1331 | sync_status_in(device); |
| 1332 | if (w->register_r[DRIVE_STATUS] & DS_SKCOM) return; |
| 1333 | } |
| 1334 | mask = mask>>1; |
| 727 | 1335 | } |
| 1336 | } |
| 728 | 1337 | |
| 729 | | step(machine,which, select_mode, disk_unit, (mode & 2) ? -1 : +1); |
| 1338 | static void drive_select(running_device *device, int driveparm) |
| 1339 | { |
| 1340 | smc92x4_state *w = get_safe_token(device); |
| 730 | 1341 | |
| 731 | | cleanup: |
| 732 | | /* update register state */ |
| 733 | | set_command_done(which); |
| 1342 | w->output1 = (0x10 << (driveparm & 0x03)) | (w->register_w[RETRY_COUNT]&0x0f); |
| 1343 | w->selected_drive_type = (driveparm>>2) & 0x03; |
| 1344 | w->head_load_delay_enable = (driveparm>>4)&0x01; |
| 1345 | |
| 1346 | /* We need to store the type of the drive for the poll_drives command |
| 1347 | to be able to correctly select the device (floppy or hard disk). */ |
| 1348 | w->types[driveparm&0x03] = w->selected_drive_type; |
| 734 | 1349 | |
| 735 | | /* set drive status */ |
| 736 | | hfdc[which].regs[hfdc_reg_drive_stat] = get_disk_status(machine,which, select_mode, disk_unit); |
| 1350 | /* Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER, |
| 1351 | and CURRENT_IDENT. This is required during formatting (p. 14) as the |
| 1352 | format command reuses the registers for formatting parameters. */ |
| 1353 | w->register_r[CURRENT_HEAD] = w->register_r[DMA7_0]; |
| 1354 | w->register_r[CURRENT_CYLINDER] = w->register_r[DMA15_8]; |
| 1355 | w->register_r[CURRENT_IDENT] = w->register_r[DMA23_16]; |
| 1356 | |
| 1357 | sync_latches_out(device); |
| 1358 | sync_status_in(device); |
| 737 | 1359 | } |
| 738 | 1360 | |
| 739 | 1361 | /* |
| 740 | | Handle the restore command |
| 1362 | Command SEEK/READID |
| 741 | 1363 | */ |
| 742 | | static void do_restore(running_machine *machine,int which, int mode) |
| 1364 | static void seek_read_id(running_device *device) |
| 743 | 1365 | { |
| 744 | | select_mode_t select_mode; |
| 745 | | int disk_unit = 0; |
| 746 | | int seek_count; |
| 1366 | smc92x4_state *w = get_safe_token(device); |
| 1367 | int step_enable = (w->command & 0x04); |
| 1368 | int verify_id = (w->command & 0x01); |
| 1369 | int wait = (w->command & 0x02); |
| 747 | 1370 | |
| 748 | | hfdc[which].status = 0; |
| 749 | | |
| 750 | | /* reset chip status */ |
| 751 | | hfdc[which].regs[hfdc_reg_chip_stat] = hfdc[which].disk_sel & 0x3; |
| 752 | | |
| 753 | | if (!get_selected_drive(which, & select_mode, & disk_unit)) |
| 1371 | w->to_be_continued = FALSE; |
| 1372 | |
| 1373 | if (!w->found_id) |
| 754 | 1374 | { |
| 755 | | /* no unit has been selected */ |
| 756 | | /* the drive status will be 0, therefore the SEEK_COMPLETE bit will be |
| 757 | | cleared, which is what we want */ |
| 758 | | goto cleanup; |
| 1375 | /* First start. */ |
| 1376 | read_id_field(device, &w->seek_count, &w->step_direction, &w->recent_id); |
| 1377 | w->found_id = TRUE; |
| 759 | 1378 | } |
| 760 | | |
| 761 | | switch (select_mode) |
| 762 | | { |
| 763 | | case sm_undefined: |
| 764 | | default: |
| 765 | | break; |
| 766 | | |
| 767 | | case sm_at_harddisk: |
| 768 | | break; |
| 769 | | |
| 770 | | case sm_harddisk: |
| 771 | | case sm_floppy_slow: |
| 772 | | case sm_floppy_fast: |
| 773 | | seek_count = 0; |
| 774 | | /* limit iterations to 2048 to prevent an endless loop if the disc is locked */ |
| 775 | | while ((seek_count < 2048) && ! (get_disk_status(machine,which, select_mode, disk_unit) & DS_TRK00)) |
| 1379 | |
| 1380 | if ((w->register_r[INT_STATUS] & ST_TC_DATAERR) == ST_TC_SUCCESS) |
| 1381 | { |
| 1382 | /* Perform the seek for the cylinder. */ |
| 1383 | if (step_enable && w->seek_count > 0) |
| 776 | 1384 | { |
| 777 | | step(machine,which, select_mode, disk_unit, -1); |
| 778 | | seek_count++; |
| 1385 | smc92x4_timed_seek_request(device); |
| 779 | 1386 | } |
| 780 | | break; |
| 1387 | else |
| 1388 | { |
| 1389 | if (wait) |
| 1390 | logerror("smc92x4:seed_read_id: Waiting for seek_complete not implemented.\n"); |
| 1391 | |
| 1392 | if (verify_id) |
| 1393 | { |
| 1394 | verify(device, &w->recent_id, TRUE); |
| 1395 | } |
| 1396 | } |
| 781 | 1397 | } |
| 1398 | else |
| 1399 | { |
| 1400 | set_command_done(device, ST_TC_RDIDERR); |
| 1401 | } |
| 1402 | } |
| 782 | 1403 | |
| 783 | | cleanup: |
| 784 | | /* update register state */ |
| 785 | | set_command_done(which); |
| 786 | | |
| 787 | | /* set drive status */ |
| 788 | | hfdc[which].regs[hfdc_reg_drive_stat] = get_disk_status(machine,which, select_mode, disk_unit); |
| 1404 | static void seek_read_id_continue(running_device *device) |
| 1405 | { |
| 1406 | smc92x4_state *w = get_safe_token(device); |
| 1407 | w->seek_count--; |
| 1408 | seek_read_id(device); |
| 1409 | w->to_be_continued = FALSE; |
| 789 | 1410 | } |
| 790 | 1411 | |
| 791 | 1412 | /* |
| 792 | | Handle the read command |
| 1413 | Formats a track starting from the detection of an index mark until the |
| 1414 | detection of another index mark. |
| 1415 | The formatting is done exclusively by the controller; user programs may |
| 1416 | set parameters for gaps and interleaving. |
| 793 | 1417 | |
| 794 | | which: disk controller selected |
| 795 | | physical_flag: if 1, read consecutive sectors, ignoring sector IDs |
| 796 | | mode: extra flags (ignored) |
| 1418 | 1. Before starting the command, the user program must have set up a |
| 1419 | sector sequence table in the controller RAM (located on the PCB): |
| 1420 | (ident, cylinder, head, sector1, size) (5 bytes) |
| 1421 | (ident, cylinder, head, sector2, size) |
| 1422 | (ident, cylinder, head, sector3, size) |
| 1423 | ... |
| 1424 | ident is not required for floppy FM operation. size is not required |
| 1425 | for IBM AT-compatible hard disks. |
| 1426 | |
| 1427 | 2. The DMA registers must point to the beginning of the table |
| 1428 | |
| 1429 | 3. DRIVE_SELECT must be executed (which moves DMA regs to CUR_HEAD ...) |
| 1430 | |
| 1431 | 4. DESIRED_HEAD register must be loaded |
| 1432 | |
| 1433 | 5. The following setup must be done: |
| 1434 | |
| 1435 | GAP 0 size DMA7_0 (2s comp) |
| 1436 | GAP 1 size DMA15_8 (2s comp) |
| 1437 | GAP 2 size DMA23_16 (2s comp) |
| 1438 | GAP 3 size DESIRED_SECTOR (2s comp) |
| 1439 | Sync size DESIRED_CYLINDER (1s comp) |
| 1440 | Sector count SECTOR_COUNT (1s comp) |
| 1441 | Sector size multiple RETRY_COUNT (1s comp) |
| 1442 | |
| 1443 | GAP4 is variable and fills the rest of the track until the next |
| 1444 | index hole. Usually we have 247 bytes for FM and 598 for MFM. |
| 1445 | |
| 1446 | 6. The step rate and density must be loaded into the MODE register |
| 1447 | |
| 1448 | 7. The drive must be stepped to the desired track. |
| 1449 | |
| 1450 | 8. Now this command may be started. |
| 1451 | |
| 1452 | All data bytes of a sector are filled with 0xe5. The gaps will be filled |
| 1453 | with 0x4e (MFM) or 0xff (FM). |
| 1454 | |
| 1455 | To format another track, the sector id table must be updated, and steps |
| 1456 | 7 and 8 must be repeated. If the DESIRED_HEAD register must be updated, |
| 1457 | the complete setup process must be done. |
| 1458 | |
| 1459 | Options: Command = 011m rppp |
| 1460 | m = set data mark (0 = set deleted) |
| 1461 | r = current (1 = reduced) |
| 1462 | ppp = precompensation (for sector size = (2^ppp) * 128; ppp<4 for floppy ) |
| 1463 | |
| 1464 | =============== |
| 1465 | |
| 1466 | One deviation from the specification: The TI-99 family uses the SDF |
| 1467 | and TDF formats. The TDF formats complies with the formats produced |
| 1468 | by the standard TI disk controller. It does not use index address marks. |
| 1469 | So we could integrate a translation in ti99_dsk when writing to disk, |
| 1470 | but when reading, how can ti99_dsk know whether to blow up the format |
| 1471 | to full length for this controller or keep it as is for the other |
| 1472 | controller? Unless someone comes up with a better idea, we implement |
| 1473 | an "undocumented" option in this controller, allowing to create a |
| 1474 | different track layout. |
| 1475 | |
| 1476 | So there are two layouts for the floppy track: |
| 1477 | |
| 1478 | - full format, including the index address mark, according to the |
| 1479 | specification |
| 1480 | |
| 1481 | - short format without index AM which matches the PC99 format used |
| 1482 | for the TI-99 family. |
| 1483 | |
| 1484 | The formats are determined by setting the flag in the smc92x4 |
| 1485 | interface structure. |
| 797 | 1486 | */ |
| 798 | | static void do_read(running_machine *machine,int which, int physical_flag, int mode) |
| 1487 | static void format_floppy_track(running_device *device, int flags) |
| 799 | 1488 | { |
| 800 | | select_mode_t select_mode; |
| 801 | | int disk_unit = 0; |
| 802 | | int dma_base_address, dma_address; |
| 803 | | int cylinder, head, sector; |
| 1489 | smc92x4_state *w = get_safe_token(device); |
| 1490 | running_device *current_floppy = NULL; |
| 804 | 1491 | |
| 805 | | hfdc[which].status = 0; |
| 1492 | floppy_image *floppy; |
| 1493 | int i,index,j, exp_size; |
| 1494 | int gap0, gap1, gap2, gap3, gap4, sync1, sync2, count, size, fm; |
| 1495 | int gap_byte, pre_gap, crc, mark, inam; |
| 1496 | UINT8 curr_ident, curr_cyl, curr_head, curr_sect, curr_size; |
| 1497 | |
| 1498 | int normal_data_mark = flags & 0x10; |
| 1499 | |
| 1500 | UINT8 *buffer; |
| 806 | 1501 | |
| 807 | | /* reset chip status */ |
| 808 | | hfdc[which].regs[hfdc_reg_chip_stat] = hfdc[which].disk_sel & 0x3; |
| 1502 | /* Determine the track size. We cannot allow different sizes in this |
| 1503 | design. */ |
| 1504 | int data_count = 0; |
| 809 | 1505 | |
| 810 | | dma_base_address = hfdc[which].regs[hfdc_reg_dma_low] |
| 811 | | | (hfdc[which].regs[hfdc_reg_dma_mid] << 8) |
| 812 | | | (hfdc[which].regs[hfdc_reg_dma_high] << 16); |
| 1506 | sync_status_in(device); |
| 1507 | |
| 1508 | current_floppy = (*w->intf->current_floppy)(); |
| 1509 | floppy = flopimg_get_image(current_floppy); |
| 813 | 1510 | |
| 814 | | sector = hfdc[which].regs[hfdc_reg_des_sector]; |
| 815 | | head = hfdc[which].regs[hfdc_reg_des_head] & 0xf; |
| 816 | | cylinder = (((int) hfdc[which].regs[hfdc_reg_des_head] << 4) & 0x700) |
| 817 | | | hfdc[which].regs[hfdc_reg_des_cyl]; |
| 1511 | if (floppy != NULL) |
| 1512 | data_count = floppy_get_track_size(floppy, 0, 0); |
| 1513 | |
| 1514 | if (data_count==0) |
| 1515 | { |
| 1516 | if (controller_set_to_single_density(device)) |
| 1517 | data_count = TRKSIZE_SD; |
| 1518 | else |
| 1519 | data_count = TRKSIZE_DD; |
| 1520 | } |
| 1521 | |
| 1522 | /* Build buffer */ |
| 1523 | buffer = (UINT8*)malloc(data_count); |
| 1524 | |
| 1525 | fm = controller_set_to_single_density(device); |
| 1526 | |
| 1527 | sync2 = (~w->register_w[DESIRED_CYLINDER])&0xff; |
| 1528 | gap2 = (-w->register_w[DMA23_16])&0xff; |
| 1529 | count = (~w->register_w[SECTOR_COUNT])&0xff; |
| 1530 | size = (~w->register_w[RETRY_COUNT])&0xff; |
| 1531 | gap_byte = (fm)? 0xff : 0x4e; |
| 818 | 1532 | |
| 819 | | if (!get_selected_drive(which, & select_mode, & disk_unit)) |
| 820 | | { |
| 821 | | /* no unit has been selected */ |
| 822 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 823 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_SYNCERR; |
| 824 | | goto cleanup; |
| 1533 | if (w->intf->full_track_layout) |
| 1534 | { |
| 1535 | /* Including the index AM. */ |
| 1536 | gap0 = (-w->register_w[DMA7_0])&0xff; |
| 1537 | gap1 = (-w->register_w[DMA15_8])&0xff; |
| 1538 | gap3 = (-w->register_w[DESIRED_SECTOR])&0xff; |
| 1539 | gap4 = (fm)? 247 : 598; |
| 1540 | pre_gap = gap_byte; |
| 1541 | sync1 = sync2; |
| 1542 | inam = sync2 + (fm)? 1 : 4; |
| 825 | 1543 | } |
| 826 | | |
| 827 | | if (! (get_disk_status(machine,which, select_mode, disk_unit) & DS_READY)) |
| 1544 | else |
| 828 | 1545 | { |
| 829 | | /* unit is not ready */ |
| 830 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 831 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_SYNCERR; |
| 832 | | goto cleanup; |
| 1546 | /* Specific overrides for this format. We do not have the index mark. */ |
| 1547 | gap0 = (fm)? 16 : 40; |
| 1548 | gap1 = 0; |
| 1549 | gap3 = (fm)? 45 : 24; |
| 1550 | gap4 = (fm)? 231 : 712; |
| 1551 | pre_gap = (fm)? 0x00 : 0x4e; |
| 1552 | sync1 = (fm)? 6 : 10; |
| 1553 | inam = 0; |
| 833 | 1554 | } |
| 1555 | |
| 1556 | index = 0; |
| 834 | 1557 | |
| 835 | | #if 0 |
| 836 | | /* if we enable write-protect test in read operations, the ti99 HFDC DSR is |
| 837 | | unable to read write-protected floppies! */ |
| 838 | | if ((hfdc[which].regs[hfdc_reg_term] & TC_TWPROT) |
| 839 | | && (get_disk_status(machine,which, select_mode, disk_unit) & DS_WRPROT)) |
| 840 | | { |
| 841 | | /* unit is write protected */ |
| 842 | | hfdc[which].status |= ST_TC_RDIDERR; /* right??? */ |
| 843 | | goto cleanup; |
| 844 | | } |
| 845 | | #endif |
| 1558 | mark = (fm)? 10 : 16; /* ID/DAM + A1 + CRC */ |
| 1559 | |
| 1560 | exp_size = gap0 + inam + gap1 + count*(sync1 + mark + gap2 + sync2 + size*128 + gap3) + gap4; |
| 1561 | |
| 1562 | if (exp_size != data_count) |
| 1563 | logerror("smc92x4 warn: The current track length in the image (%d) does not match the new track length (%d). Keeping the old length. This will break the image (sorry).\n", data_count, exp_size); |
| 1564 | |
| 1565 | /* use the backup registers set up during drive_select */ |
| 1566 | set_dma_address(device, CURRENT_IDENT, CURRENT_CYLINDER, CURRENT_HEAD); |
| 846 | 1567 | |
| 847 | | read_id(machine,which, select_mode, disk_unit, head, ! (mode & 0x02), cylinder); |
| 1568 | memset(&buffer[index], pre_gap, gap0); |
| 1569 | index += gap0; |
| 848 | 1570 | |
| 849 | | while (hfdc[which].regs[hfdc_reg_sector_count]) |
| 1571 | if (w->intf->full_track_layout) |
| 850 | 1572 | { |
| 851 | | /* do read sector */ |
| 852 | | dma_address = dma_base_address; |
| 853 | | switch (select_mode) |
| 1573 | /* Create the Index AM */ |
| 1574 | memset(&buffer[index], 0x00, sync1); |
| 1575 | index += sync1; |
| 1576 | if (!fm) |
| 854 | 1577 | { |
| 855 | | case sm_undefined: |
| 856 | | default: |
| 857 | | break; |
| 1578 | memset(&buffer[index], 0xc2, 3); |
| 1579 | index += 3; |
| 1580 | } |
| 1581 | memset(&buffer[index], gap_byte, gap1); |
| 1582 | index += gap1; |
| 1583 | } |
| 1584 | |
| 1585 | /* for each sector */ |
| 1586 | for (j=0; j < count; j++) |
| 1587 | { |
| 1588 | memset(&buffer[index], 0x00, sync1); |
| 1589 | index += sync1; |
| 858 | 1590 | |
| 859 | | case sm_at_harddisk: |
| 860 | | break; |
| 1591 | if (!fm) |
| 1592 | { |
| 1593 | memset(&buffer[index], 0xa1, 3); |
| 1594 | index += 3; |
| 1595 | } |
| 861 | 1596 | |
| 862 | | case sm_harddisk: |
| 863 | | if (! harddisk_read_sector(which, disk_unit, cylinder, head, sector, &dma_address)) |
| 864 | | goto cleanup; |
| 865 | | break; |
| 1597 | buffer[index++] = 0xfe; |
| 866 | 1598 | |
| 867 | | case sm_floppy_slow: |
| 868 | | case sm_floppy_fast: |
| 869 | | if (! smc92x4_floppy_read_sector(machine,which, disk_unit, cylinder, head, 1, sector, &dma_address)) |
| 870 | | goto cleanup; |
| 871 | | break; |
| 872 | | } |
| 1599 | smc92x4_set_dip(device, TRUE); |
| 1600 | if (!fm) curr_ident = (*w->intf->dma_read_callback)(); |
| 1601 | curr_cyl = (*w->intf->dma_read_callback)(); |
| 1602 | curr_head = (*w->intf->dma_read_callback)(); |
| 1603 | curr_sect = (*w->intf->dma_read_callback)(); |
| 1604 | curr_size = (*w->intf->dma_read_callback)(); |
| 1605 | smc92x4_set_dip(device, FALSE); |
| 873 | 1606 | |
| 874 | | hfdc[which].regs[hfdc_reg_sector_count]--; |
| 875 | | if (hfdc[which].regs[hfdc_reg_sector_count]) |
| 876 | | { |
| 877 | | /* read more sectors */ |
| 1607 | buffer[index++] = curr_cyl; |
| 1608 | buffer[index++] = curr_head; |
| 1609 | buffer[index++] = curr_sect; |
| 1610 | buffer[index++] = curr_size; |
| 878 | 1611 | |
| 879 | | /* increment desired sector */ |
| 880 | | sector++; |
| 1612 | // if (j==0) printf("current_floppy=%s, format track %d, head %d\n", current_floppy->tag(), curr_cyl, curr_head); |
| 881 | 1613 | |
| 882 | | /* update DMA address */ |
| 883 | | dma_base_address = dma_address; |
| 1614 | /* Calculate CRC16 (5 bytes for ID) */ |
| 1615 | crc = ccitt_crc16(0xffff, &buffer[index-5], 5); |
| 1616 | buffer[index++] = (crc>>8)&0xff; |
| 1617 | buffer[index++] = crc & 0xff; |
| 1618 | |
| 1619 | memset(&buffer[index], gap_byte, gap2); |
| 1620 | index += gap2; |
| 1621 | |
| 1622 | memset(&buffer[index], 0x00, sync2); |
| 1623 | index += sync2; |
| 1624 | |
| 1625 | if (!fm) |
| 1626 | { |
| 1627 | memset(&buffer[index], 0xa1, 3); |
| 1628 | index += 3; |
| 884 | 1629 | } |
| 885 | | } |
| 1630 | |
| 1631 | if (normal_data_mark) buffer[index++] = 0xfb; |
| 1632 | else buffer[index++] = 0xf8; |
| 886 | 1633 | |
| 887 | | cleanup: |
| 888 | | /* update register state */ |
| 889 | | set_command_done(which); |
| 1634 | /* Sector data */ |
| 1635 | for (i=0; i < 128*size; i++) buffer[index++] = 0xe5; |
| 890 | 1636 | |
| 891 | | /* update DMA address */ |
| 892 | | hfdc[which].regs[hfdc_reg_dma_low] = dma_base_address & 0xff; |
| 893 | | hfdc[which].regs[hfdc_reg_dma_mid] = (dma_base_address >> 8) & 0xff; |
| 894 | | hfdc[which].regs[hfdc_reg_dma_high] = (dma_base_address >> 16) & 0xff; |
| 1637 | /* Calculate CRC16 (128*size+1 bytes for sector) */ |
| 1638 | crc = ccitt_crc16(0xffff, &buffer[index-128*size-1], 128*size+1); |
| 1639 | buffer[index++] = (crc>>8)&0xff; |
| 1640 | buffer[index++] = crc & 0xff; |
| 895 | 1641 | |
| 896 | | /* update desired sector register */ |
| 897 | | hfdc[which].regs[hfdc_reg_des_sector] = sector; |
| 1642 | memset(&buffer[index], gap_byte, gap3); |
| 1643 | index += gap3; |
| 1644 | } |
| 898 | 1645 | |
| 899 | | /* set drive status */ |
| 900 | | hfdc[which].regs[hfdc_reg_drive_stat] = get_disk_status(machine,which, select_mode, disk_unit); |
| 1646 | memset(&buffer[index], gap_byte, gap4); |
| 1647 | index += gap4; |
| 1648 | |
| 1649 | floppy_drive_write_track_data_info_buffer(current_floppy, w->register_w[DESIRED_HEAD]&0x0f, (char *)buffer, &data_count); |
| 1650 | free(buffer); |
| 1651 | sync_status_in(device); |
| 901 | 1652 | } |
| 902 | 1653 | |
| 903 | 1654 | /* |
| 904 | | Handle the write command |
| 905 | | |
| 906 | | which: disk controller selected |
| 907 | | physical_flag: if 1, ignore CRC/ECC bytes??? (ignored) |
| 908 | | mode: extra flags (ignored) |
| 1655 | Create the track layout of a MFM hard disk. Like floppy disks, |
| 1656 | MFM hard disks are interfaced on a track base, that is, we have to |
| 1657 | create a complete track layout. |
| 1658 | |
| 1659 | For more explanations see the comments to format_floppy_track. |
| 909 | 1660 | */ |
| 910 | | static void do_write(running_machine *machine,int which, int physical_flag, int mode) |
| 1661 | static void format_harddisk_track(running_device *device, int flags) |
| 911 | 1662 | { |
| 912 | | select_mode_t select_mode; |
| 913 | | int disk_unit = 0; |
| 914 | | int dma_base_address, dma_address; |
| 915 | | int cylinder, head, sector; |
| 1663 | smc92x4_state *w = get_safe_token(device); |
| 1664 | int i,index,j; |
| 1665 | int gap0, gap1, gap2, gap3, gap4, sync, count, size, fm, gap_byte, crc; |
| 1666 | UINT8 curr_ident, curr_cyl, curr_head, curr_sect, curr_size; |
| 916 | 1667 | |
| 917 | | hfdc[which].status = 0; |
| 1668 | int normal_data_mark = flags & 0x10; |
| 1669 | int data_count=0; |
| 1670 | |
| 1671 | UINT8 *buffer; |
| 918 | 1672 | |
| 919 | | /* reset chip status */ |
| 920 | | hfdc[which].regs[hfdc_reg_chip_stat] = hfdc[which].disk_sel & 0x3; |
| 1673 | sync_status_in(device); |
| 1674 | |
| 1675 | /* Build buffer */ |
| 1676 | gap0 = (-w->register_w[DMA7_0])&0xff; |
| 1677 | gap1 = (-w->register_w[DMA15_8])&0xff; |
| 1678 | gap2 = (-w->register_w[DMA23_16])&0xff; |
| 1679 | gap3 = (-w->register_w[DESIRED_SECTOR])&0xff; |
| 1680 | gap4 = 340; |
| 921 | 1681 | |
| 922 | | dma_base_address = hfdc[which].regs[hfdc_reg_dma_low] |
| 923 | | | (hfdc[which].regs[hfdc_reg_dma_mid] << 8) |
| 924 | | | (hfdc[which].regs[hfdc_reg_dma_high] << 16); |
| 1682 | sync = (~w->register_w[DESIRED_CYLINDER])&0xff; |
| 1683 | count = (~w->register_w[SECTOR_COUNT])&0xff; |
| 1684 | size = (~w->register_w[RETRY_COUNT])&0xff; |
| 925 | 1685 | |
| 926 | | sector = hfdc[which].regs[hfdc_reg_des_sector]; |
| 927 | | head = hfdc[which].regs[hfdc_reg_des_head] & 0xf; |
| 928 | | cylinder = (((int) hfdc[which].regs[hfdc_reg_des_head] << 4) & 0x700) |
| 929 | | | hfdc[which].regs[hfdc_reg_des_cyl]; |
| 1686 | data_count = gap1 + count*(sync+12+gap2+sync+size*128+gap3)+gap4; |
| 1687 | |
| 1688 | buffer = (UINT8*)malloc(data_count); |
| 1689 | |
| 1690 | index = 0; |
| 1691 | fm = controller_set_to_single_density(device); |
| 1692 | gap_byte = 0x4e; |
| 1693 | |
| 1694 | /* use the backup registers set up during drive_select */ |
| 1695 | set_dma_address(device, CURRENT_IDENT, CURRENT_CYLINDER, CURRENT_HEAD); |
| 930 | 1696 | |
| 931 | | if (!get_selected_drive(which, & select_mode, & disk_unit)) |
| 1697 | for (i=0; i < gap1; i++) buffer[index++] = gap_byte; |
| 1698 | |
| 1699 | /* Now write the sectors. */ |
| 1700 | for (j=0; j < count; j++) |
| 932 | 1701 | { |
| 933 | | /* no unit has been selected */ |
| 934 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 935 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_SYNCERR; |
| 936 | | goto cleanup; |
| 1702 | for (i=0; i < sync; i++) buffer[index++] = 0x00; |
| 1703 | buffer[index++] = 0xa1; |
| 1704 | |
| 1705 | smc92x4_set_dip(device, TRUE); |
| 1706 | curr_ident = (*w->intf->dma_read_callback)(); |
| 1707 | curr_cyl = (*w->intf->dma_read_callback)(); |
| 1708 | curr_head = (*w->intf->dma_read_callback)(); |
| 1709 | curr_sect = (*w->intf->dma_read_callback)(); |
| 1710 | curr_size = (*w->intf->dma_read_callback)(); |
| 1711 | smc92x4_set_dip(device, FALSE); |
| 1712 | |
| 1713 | buffer[index++] = curr_ident; |
| 1714 | buffer[index++] = curr_cyl; |
| 1715 | buffer[index++] = curr_head; |
| 1716 | buffer[index++] = curr_sect; |
| 1717 | buffer[index++] = curr_size; |
| 1718 | |
| 1719 | /* Calculate CRC16 (5 bytes for ID) */ |
| 1720 | crc = ccitt_crc16(0xffff, &buffer[index-5], 5); |
| 1721 | buffer[index++] = (crc>>8)&0xff; |
| 1722 | buffer[index++] = crc & 0xff; |
| 1723 | |
| 1724 | /* GAP 2 */ |
| 1725 | for (i=0; i < gap2; i++) buffer[index++] = gap_byte; |
| 1726 | for (i=0; i < sync; i++) buffer[index++] = 0x00; |
| 1727 | |
| 1728 | buffer[index++] = 0xa1; |
| 1729 | |
| 1730 | if (normal_data_mark) buffer[index++] = 0xfb; |
| 1731 | else buffer[index++] = 0xf8; |
| 1732 | |
| 1733 | /* Sector data */ |
| 1734 | for (i=0; i < 128*size; i++) buffer[index++] = 0xe5; |
| 1735 | |
| 1736 | /* Calculate CRC16 (128*size+1 bytes for sector) */ |
| 1737 | crc = ccitt_crc16(0xffff, &buffer[index-128*size-1], 128*size+1); |
| 1738 | buffer[index++] = (crc>>8)&0xff; |
| 1739 | buffer[index++] = crc & 0xff; |
| 1740 | |
| 1741 | /* GAP 3 */ |
| 1742 | for (i=0; i < 3; i++) buffer[index++] = 0; /* check that, unclear in spec */ |
| 1743 | for (i=0; i < gap3 - 3; i++) buffer[index++] = gap_byte; |
| 937 | 1744 | } |
| 1745 | /* GAP 4 */ |
| 1746 | for (i=0; i < gap4; i++) buffer[index++] = gap_byte; |
| 1747 | |
| 1748 | (*w->intf->mfmhd_write_track)(w->register_w[DESIRED_HEAD]&0x0f, buffer, data_count); |
| 1749 | free(buffer); |
| 1750 | sync_status_in(device); |
| 1751 | } |
| 938 | 1752 | |
| 939 | | if (! (get_disk_status(machine,which, select_mode, disk_unit) & DS_READY)) |
| 1753 | /* |
| 1754 | Read a floppy track. |
| 1755 | A complete track is read at the position of the head. It reads the |
| 1756 | track from one index pulse to the next index pulse. (Note that the |
| 1757 | spec talks about "index mark" and "signal from the drive" which is |
| 1758 | a bit confusing, since the index AM is behind Gap0, the index hole |
| 1759 | is before Gap0. We should check with a real device. Also, it does not |
| 1760 | speak about the head, so we assume the head is set in the DESIRED_HEAD |
| 1761 | register.) |
| 1762 | |
| 1763 | TODO: The TDF format does not support index marks. Need to define TDF |
| 1764 | in a more flexible way. Also consider format variations. |
| 1765 | (Hint: Do a check for the standard "IBM" format. Should probably do |
| 1766 | a translation from IBM to PC99 and back. Requires to parse the track |
| 1767 | image before. Need to decide whether we generally translate to the IBM |
| 1768 | format or generally to the PC99 format between controller and format. |
| 1769 | Format is the image is always PC99.) |
| 1770 | */ |
| 1771 | static void read_floppy_track(running_device *device, int transfer_only_ids) |
| 1772 | { |
| 1773 | smc92x4_state *w = get_safe_token(device); |
| 1774 | running_device *current_floppy = (*w->intf->current_floppy)(); |
| 1775 | |
| 1776 | floppy_image *floppy; |
| 1777 | /* Determine the track size. We cannot allow different sizes in this |
| 1778 | design. */ |
| 1779 | int data_count = 0; |
| 1780 | int i; |
| 1781 | UINT8 *buffer; |
| 1782 | |
| 1783 | sync_latches_out(device); |
| 1784 | |
| 1785 | floppy = flopimg_get_image(current_floppy); |
| 1786 | |
| 1787 | /* Determine the track size. We cannot allow different sizes in this |
| 1788 | design. */ |
| 1789 | if (floppy != NULL) |
| 1790 | data_count = floppy_get_track_size(floppy, 0, 0); |
| 1791 | |
| 1792 | if (data_count==0) |
| 1793 | { |
| 1794 | if (controller_set_to_single_density(device)) |
| 1795 | data_count = TRKSIZE_SD; |
| 1796 | else |
| 1797 | data_count = TRKSIZE_DD; |
| 1798 | } |
| 1799 | |
| 1800 | buffer = (UINT8*)malloc(data_count); |
| 1801 | |
| 1802 | floppy_drive_read_track_data_info_buffer( current_floppy, w->register_w[DESIRED_HEAD]&0x0f, (char *)buffer, &data_count); |
| 1803 | sync_status_in(device); |
| 1804 | |
| 1805 | /* Transfer the buffer to the external memory. We assume the memory |
| 1806 | pointer has been set appropriately in the registers. */ |
| 1807 | set_dma_address(device, DMA23_16, DMA15_8, DMA7_0); |
| 1808 | |
| 1809 | if (transfer_only_ids) |
| 940 | 1810 | { |
| 941 | | /* unit is not ready */ |
| 942 | | hfdc[which].status |= ST_TC_RDIDERR; |
| 943 | | hfdc[which].regs[hfdc_reg_chip_stat] |= CS_SYNCERR; |
| 944 | | goto cleanup; |
| 1811 | logerror("smc92x4 read track: Ignoring transfer-only-ids. Reading complete track.\n"); |
| 945 | 1812 | } |
| 946 | 1813 | |
| 947 | | if ((hfdc[which].regs[hfdc_reg_term] & TC_TWPROT) |
| 948 | | && (get_disk_status(machine,which, select_mode, disk_unit) & DS_WRPROT)) |
| 1814 | smc92x4_set_dip(device, TRUE); |
| 1815 | for (i=0; i < data_count; i++) |
| 949 | 1816 | { |
| 950 | | /* unit is write protected */ |
| 951 | | hfdc[which].status |= ST_TC_RDIDERR; /* right??? */ |
| 952 | | goto cleanup; |
| 1817 | (*w->intf->dma_write_callback)(buffer[i]); |
| 953 | 1818 | } |
| 1819 | smc92x4_set_dip(device, FALSE); |
| 1820 | |
| 1821 | free(buffer); |
| 1822 | } |
| 954 | 1823 | |
| 1824 | static void read_harddisk_track(running_device *device, int transfer_only_ids) |
| 1825 | { |
| 1826 | smc92x4_state *w = get_safe_token(device); |
| 955 | 1827 | |
| 956 | | read_id(machine,which, select_mode, disk_unit, head, ! (mode & 0x40), cylinder); |
| 1828 | /* Determine the track size. We cannot allow different sizes in this |
| 1829 | design. */ |
| 1830 | int i; |
| 1831 | UINT8 *buffer; |
| 1832 | int data_count=0; |
| 957 | 1833 | |
| 958 | | while (hfdc[which].regs[hfdc_reg_sector_count]) |
| 959 | | { |
| 960 | | /* do write sector */ |
| 961 | | dma_address = dma_base_address; |
| 962 | | switch (select_mode) |
| 963 | | { |
| 964 | | case sm_undefined: |
| 965 | | default: |
| 966 | | break; |
| 1834 | sync_latches_out(device); |
| 1835 | |
| 1836 | /* buffer and data_count are allocated and set by the function. */ |
| 1837 | (*w->intf->mfmhd_read_track)(w->register_w[DESIRED_HEAD]&0x0f, &buffer, &data_count); |
| 1838 | sync_status_in(device); |
| 967 | 1839 | |
| 968 | | case sm_at_harddisk: |
| 969 | | break; |
| 1840 | /* Transfer the buffer to the external memory. We assume the memory |
| 1841 | pointer has been set appropriately in the registers. */ |
| 1842 | set_dma_address(device, DMA23_16, DMA15_8, DMA7_0); |
| 970 | 1843 | |
| 971 | | case sm_harddisk: |
| 972 | | if (!harddisk_write_sector(which, disk_unit, cylinder, head, sector, &dma_address)) |
| 973 | | goto cleanup; |
| 974 | | break; |
| 1844 | if (transfer_only_ids) |
| 1845 | { |
| 1846 | logerror("smc92x4 read track: Ignoring transfer-only-ids. Reading complete track.\n"); |
| 1847 | } |
| 975 | 1848 | |
| 976 | | case sm_floppy_slow: |
| 977 | | case sm_floppy_fast: |
| 978 | | if (!smc92x4_floppy_write_sector(machine,which, disk_unit, cylinder, head, 1, sector, &dma_address)) |
| 979 | | goto cleanup; |
| 980 | | break; |
| 981 | | } |
| 1849 | smc92x4_set_dip(device, TRUE); |
| 1850 | for (i=0; i < data_count; i++) |
| 1851 | { |
| 1852 | (*w->intf->dma_write_callback)(buffer[i]); |
| 1853 | } |
| 1854 | smc92x4_set_dip(device, FALSE); |
| 1855 | |
| 1856 | free(buffer); |
| 1857 | } |
| 982 | 1858 | |
| 983 | | hfdc[which].regs[hfdc_reg_sector_count]--; |
| 984 | | if (hfdc[which].regs[hfdc_reg_sector_count]) |
| 985 | | { |
| 986 | | /* read more sectors */ |
| 987 | 1859 | |
| 988 | | /* increment desired sector */ |
| 989 | | sector++; |
| 990 | | |
| 991 | | /* update DMA address */ |
| 992 | | dma_base_address = dma_address; |
| 993 | | } |
| 1860 | static void read_track(running_device *device) |
| 1861 | { |
| 1862 | smc92x4_state *w = get_safe_token(device); |
| 1863 | int transfer_only_ids = w->command & 0x01; |
| 1864 | |
| 1865 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 1866 | { |
| 1867 | read_floppy_track(device, transfer_only_ids); |
| 994 | 1868 | } |
| 1869 | else |
| 1870 | { |
| 1871 | read_harddisk_track(device, transfer_only_ids); |
| 1872 | } |
| 1873 | |
| 1874 | smc92x4_timed_track_request(device); |
| 1875 | } |
| 995 | 1876 | |
| 996 | | cleanup: |
| 997 | | /* update register state */ |
| 998 | | set_command_done(which); |
| 1877 | static void read_track_continue(running_device *device) |
| 1878 | { |
| 1879 | smc92x4_state *w = get_safe_token(device); |
| 1880 | w->to_be_continued = FALSE; |
| 1881 | set_command_done(device, ST_TC_SUCCESS); |
| 1882 | } |
| 999 | 1883 | |
| 1000 | | /* update DMA address */ |
| 1001 | | hfdc[which].regs[hfdc_reg_dma_low] = dma_base_address & 0xff; |
| 1002 | | hfdc[which].regs[hfdc_reg_dma_mid] = (dma_base_address >> 8) & 0xff; |
| 1003 | | hfdc[which].regs[hfdc_reg_dma_high] = (dma_base_address >> 16) & 0xff; |
| 1884 | static void format_track(running_device *device) |
| 1885 | { |
| 1886 | smc92x4_state *w = get_safe_token(device); |
| 1887 | int flags = w->command & 0x1f; |
| 1888 | |
| 1889 | if (w->selected_drive_type & TYPE_FLOPPY) |
| 1890 | format_floppy_track(device, flags); |
| 1891 | else |
| 1892 | format_harddisk_track(device, flags); |
| 1004 | 1893 | |
| 1005 | | /* update desired sector register */ |
| 1006 | | hfdc[which].regs[hfdc_reg_des_sector] = sector; |
| 1894 | smc92x4_timed_track_request(device); |
| 1895 | } |
| 1007 | 1896 | |
| 1008 | | /* set drive status */ |
| 1009 | | hfdc[which].regs[hfdc_reg_drive_stat] = get_disk_status(machine,which, select_mode, disk_unit); |
| 1897 | static void format_track_continue(running_device *device) |
| 1898 | { |
| 1899 | smc92x4_state *w = get_safe_token(device); |
| 1900 | w->to_be_continued = FALSE; |
| 1901 | set_command_done(device, ST_TC_SUCCESS); |
| 1010 | 1902 | } |
| 1011 | 1903 | |
| 1012 | 1904 | /* |
| 1905 | Continue to process after callback |
| 1906 | */ |
| 1907 | static void smc92x4_process_after_callback(running_device *device) |
| 1908 | { |
| 1909 | smc92x4_state *w = get_safe_token(device); |
| 1910 | UINT8 opcode = w->command; |
| 1911 | if (opcode >= 0x02 && opcode <= 0x03) |
| 1912 | { |
| 1913 | restore_continue(device); |
| 1914 | } |
| 1915 | else if (opcode >= 0x04 && opcode <= 0x07) |
| 1916 | { |
| 1917 | step_continue(device); |
| 1918 | } |
| 1919 | else if (opcode >= 0x50 && opcode <= 0x57) |
| 1920 | { |
| 1921 | seek_read_id_continue(device); |
| 1922 | } |
| 1923 | else if ((opcode >= 0x58 && opcode <= 0x59)||(opcode >= 0x5C && opcode <= 0x5f)) |
| 1924 | { |
| 1925 | read_sectors_continue(device); |
| 1926 | } |
| 1927 | else if (opcode >= 0x5a && opcode <= 0x5b) |
| 1928 | { |
| 1929 | read_track_continue(device); |
| 1930 | } |
| 1931 | else if (opcode >= 0x60 && opcode <= 0x7f) |
| 1932 | { |
| 1933 | format_track_continue(device); |
| 1934 | } |
| 1935 | else if (opcode >= 0x80) |
| 1936 | { |
| 1937 | write_sectors_continue(device); |
| 1938 | } |
| 1939 | else |
| 1940 | { |
| 1941 | logerror("smc92x4 warn: Invalid command %x or command changed while waiting for callback\n", opcode); |
| 1942 | } |
| 1943 | } |
| 1944 | |
| 1945 | /* |
| 1013 | 1946 | Process a command |
| 1014 | 1947 | */ |
| 1015 | | static void smc92x4_process_command(running_machine *machine,int which, int opcode) |
| 1948 | static void smc92x4_process_command(running_device *device, UINT8 opcode) |
| 1016 | 1949 | { |
| 1017 | | if (opcode < 0x80) |
| 1950 | smc92x4_state *w = get_safe_token(device); |
| 1951 | |
| 1952 | //logerror("smc92x4 process command %02x\n", opcode); |
| 1953 | if (w->to_be_continued) |
| 1018 | 1954 | { |
| 1019 | | switch (opcode >> 4) |
| 1955 | logerror("smc92x4 warn: previous command %02x not complete\n", w->command); |
| 1956 | } |
| 1957 | |
| 1958 | /* Reset DONE and BAD_SECTOR. */ |
| 1959 | w->register_r[INT_STATUS] &= ~(ST_DONE | ST_BADSECT); |
| 1960 | |
| 1961 | /* Reset interrupt line (not explicitly mentioned in spec, but seems |
| 1962 | reasonable) */ |
| 1963 | smc92x4_clear_interrupt(device); |
| 1964 | w->register_r[INT_STATUS] &= ~(ST_INTPEND | ST_RDYCHNG); |
| 1965 | |
| 1966 | w->command = opcode; |
| 1967 | w->found_id = FALSE; |
| 1968 | w->seek_count = 0; |
| 1969 | |
| 1970 | if (opcode == 0x00) |
| 1971 | { |
| 1972 | /* RESET */ |
| 1973 | /* same effect as the RST* pin being active */ |
| 1974 | logerror("smc92x4 info: reset command\n"); |
| 1975 | smc92x4_reset(device); |
| 1976 | } |
| 1977 | else if (opcode == 0x01) |
| 1978 | { |
| 1979 | /* DESELECT DRIVE */ |
| 1980 | /* done when no drive is in use */ |
| 1981 | logerror("smc92x4 drdeselect command\n"); |
| 1982 | w->output1 &= ~(OUT1_DRVSEL3|OUT1_DRVSEL2|OUT1_DRVSEL1|OUT1_DRVSEL0); |
| 1983 | w->output2 |= OUT2_DRVSEL3_; |
| 1984 | /* sync the latches on the PCB */ |
| 1985 | sync_latches_out(device); |
| 1986 | sync_status_in(device); |
| 1987 | } |
| 1988 | else if (opcode >= 0x02 && opcode <= 0x03) |
| 1989 | { |
| 1990 | /* RESTORE DRIVE */ |
| 1991 | /* bit 0: 0 -> command ends after last seek pulse, 1 -> command |
| 1992 | ends when the drive asserts the seek complete pin */ |
| 1993 | logerror("smc92x4 restore command %X\n", opcode); |
| 1994 | restore_drive(device); |
| 1995 | } |
| 1996 | else if (opcode >= 0x04 && opcode <= 0x07) |
| 1997 | { |
| 1998 | /* STEP IN/OUT ONE CYLINDER */ |
| 1999 | logerror("smc92x4 step in/out command %X\n", opcode); |
| 2000 | step_in_out(device); |
| 2001 | } |
| 2002 | else if (opcode >= 0x08 && opcode <= 0x0f) |
| 2003 | { |
| 2004 | /* TAPE BACKUP (08-0f)*/ |
| 2005 | logerror("smc92x4 warn: tape backup command %X not implemented\n", opcode); |
| 2006 | } |
| 2007 | else if (opcode >= 0x10 && opcode <= 0x1f) |
| 2008 | { |
| 2009 | /* POLLDRIVE */ |
| 2010 | logerror("smc92x4 polldrive command %X\n", opcode); |
| 2011 | poll_drives(device); |
| 2012 | } |
| 2013 | else if (opcode >= 0x20 && opcode <= 0x3f) |
| 2014 | { |
| 2015 | /* DRIVE SELECT */ |
| 2016 | logerror("smc92x4 drselect command %X\n", opcode); |
| 2017 | drive_select(device, opcode&0x1f); |
| 2018 | } |
| 2019 | else if (opcode >= 0x40 && opcode <= 0x4f) |
| 2020 | { |
| 2021 | /* SETREGPTR */ |
| 2022 | logerror("smc92x4 setregptr command %X\n", opcode); |
| 2023 | w->register_pointer = opcode & 0xf; |
| 2024 | /* Spec does not say anything about the effect of setting an |
| 2025 | invalid value (only "care should be taken") */ |
| 2026 | if (w->register_pointer > 10) |
| 1020 | 2027 | { |
| 1021 | | case 0x0: /* misc commands */ |
| 1022 | | if (opcode < 0x04) |
| 1023 | | { |
| 1024 | | switch (opcode) |
| 1025 | | { |
| 1026 | | case 0x00: |
| 1027 | | /* RESET */ |
| 1028 | | /* same effect as the RST* pin being active */ |
| 1029 | | logerror("smc92x4 reset command\n"); |
| 1030 | | smc92x4_reset(which); |
| 1031 | | break; |
| 1032 | | case 0x01: |
| 1033 | | /* DESELECT DRIVE */ |
| 1034 | | /* done when no drive is in use */ |
| 1035 | | logerror("smc92x4 drdeselect command\n"); |
| 1036 | | hfdc[which].disk_sel = disk_sel_none; |
| 1037 | | set_command_done(which); |
| 1038 | | break; |
| 1039 | | case 0x02: |
| 1040 | | case 0x03: |
| 1041 | | /* RESTORE DRIVE */ |
| 1042 | | /* bit 0: 0 -> command ends after last seek pulse, 1 -> command |
| 1043 | | ends when the drive asserts the seek complete pin */ |
| 1044 | | logerror("smc92x4 restore command %X\n", opcode & 0x01); |
| 1045 | | do_restore(machine,which, opcode & 0x01); |
| 1046 | | break; |
| 1047 | | } |
| 1048 | | } |
| 1049 | | else if (opcode < 0x08) |
| 1050 | | { |
| 1051 | | /* STEP IN/OUT ONE CYLINDER */ |
| 1052 | | /* bit 1: direction (0 -> inward, 1 -> outward i.e. toward cyl #0) */ |
| 1053 | | /* bit 0: 0 -> command ends after last seek pulse, 1 -> command |
| 1054 | | ends when the drive asserts the seek complete pin */ |
| 1055 | | logerror("smc92x4 step command %X\n", opcode & 0x3); |
| 1056 | | do_step(machine,which, opcode & 0x03); |
| 1057 | | } |
| 1058 | | else |
| 1059 | | { |
| 1060 | | /* TAPE BACKUP */ |
| 1061 | | logerror("smc92x4 tape backup command %X\n", opcode); |
| 1062 | | } |
| 1063 | | break; |
| 1064 | | case 0x1: |
| 1065 | | /* POLLDRIVE */ |
| 1066 | | /* bit 3-0: one bit for each drive to test */ |
| 1067 | | logerror("smc92x4 polldrive command %X\n", opcode & 0xf); |
| 1068 | | break; |
| 1069 | | case 0x2: |
| 1070 | | case 0x3: |
| 1071 | | /* DRSELECT */ |
| 1072 | | /* bit 4: if 1, apply head load delay */ |
| 1073 | | /* bit 3 & 2: disk type (0-3): 0 for hard disk in IBM-AT format, 1 |
| 1074 | | for hard disk in standard SMC format, 2 for high-speed (8" or |
| 1075 | | HD(?)) floppy, 3 for low-speed (5"1/4 DD?) floppy disk */ |
| 1076 | | /* bit 1 & 0: unit number (0-3)*/ |
| 1077 | | logerror("smc92x4 drselect command %X\n", opcode & 0xf); |
| 1078 | | hfdc[which].disk_sel = opcode & 0xf; |
| 1079 | | set_command_done(which); |
| 1080 | | break; |
| 1081 | | case 0x4: |
| 1082 | | /* SETREGPTR */ |
| 1083 | | /* bit 3-0: reg-number (should be in [0,10]) */ |
| 1084 | | logerror("smc92x4 setregptr command %X\n", opcode & 0xf); |
| 1085 | | hfdc[which].reg_ptr = opcode & 0xf; |
| 1086 | | set_command_done(which); |
| 1087 | | break; |
| 1088 | | case 0x5: |
| 1089 | | if (opcode < 0x58) |
| 1090 | | { |
| 1091 | | /* SEEK/READ ID */ |
| 1092 | | /* bit 2: step enable */ |
| 1093 | | /* bit 1: wait for seek complete signal */ |
| 1094 | | /* bit 0: verify ID */ |
| 1095 | | logerror("smc92x4 seekreadid command %X\n", opcode & 0x7); |
| 1096 | | } |
| 1097 | | else |
| 1098 | | { |
| 1099 | | /* READ */ |
| 1100 | | /* bits 2-1: 0 -> read physical, 1 -> read track, 2 -> read |
| 1101 | | logical with implied seek, 3 -> read logical with no |
| 1102 | | implied seek */ |
| 1103 | | /* bit 0: 0 -> do not transfer data (transfer ID fields for |
| 1104 | | read track command), 1 -> transfer data */ |
| 1105 | | switch ((opcode >> 1) & 0x3) |
| 1106 | | { |
| 1107 | | case 0: |
| 1108 | | logerror("smc92x4 read physical command %X\n", opcode & 0x1); |
| 1109 | | do_read(machine,which, 1, opcode & 0x3); |
| 1110 | | break; |
| 1111 | | case 1: |
| 1112 | | logerror("smc92x4 read track command %X\n", opcode & 0x1); |
| 1113 | | break; |
| 1114 | | case 2: |
| 1115 | | case 3: |
| 1116 | | logerror("smc92x4 read logical command %X\n", opcode & 0x3); |
| 1117 | | do_read(machine,which, 0, opcode & 0x3); |
| 1118 | | break; |
| 1119 | | } |
| 1120 | | } |
| 1121 | | break; |
| 1122 | | case 0x6: |
| 1123 | | case 0x7: |
| 1124 | | /* FORMAT TRACK */ |
| 1125 | | /* bit 4: 0 -> write deleted data mark instead of normal address |
| 1126 | | mark */ |
| 1127 | | /* bit 3: 1 -> write with reduced current */ |
| 1128 | | /* bit 2-0: write precompensation value */ |
| 1129 | | logerror("smc92x4 formattrack command %X\n", opcode & 0xf); |
| 1130 | | break; |
| 2028 | logerror("smc92x4 error: set register pointer: Invalid register number: %d. Setting to 10.\n", w->register_pointer); |
| 2029 | w->register_pointer = 10; |
| 1131 | 2030 | } |
| 1132 | 2031 | } |
| 2032 | else if (opcode >= 0x50 && opcode <= 0x57) |
| 2033 | { |
| 2034 | /* SEEK/READ ID */ |
| 2035 | logerror("smc92x4 seekreadid command %X\n", opcode); |
| 2036 | seek_read_id(device); |
| 2037 | } |
| 2038 | else if ((opcode >= 0x58 && opcode <= 0x59) |
| 2039 | || (opcode >= 0x5C && opcode <= 0x5f) |
| 2040 | || (opcode >= 0x80)) |
| 2041 | { |
| 2042 | /* READ/WRITE SECTORS PHYSICAL/LOGICAL */ |
| 2043 | logerror("smc92x4 read/write sector command %X\n", opcode); |
| 2044 | read_write_sectors(device); |
| 2045 | } |
| 2046 | else if (opcode >= 0x5A && opcode <= 0x5b) |
| 2047 | { |
| 2048 | /* READ TRACK */ |
| 2049 | logerror("smc92x4 read track command %X\n", opcode); |
| 2050 | read_track(device); |
| 2051 | } |
| 2052 | else if (opcode >= 0x60 && opcode <= 0x7f) |
| 2053 | { |
| 2054 | /* FORMAT TRACK */ |
| 2055 | logerror("smc92x4 format track command %X\n", opcode); |
| 2056 | format_track(device); |
| 2057 | } |
| 1133 | 2058 | else |
| 1134 | 2059 | { |
| 1135 | | /* WRITE */ |
| 1136 | | /* bits 6: 0 -> implied seek, 1-> no implied seek */ |
| 1137 | | /* bit 5: 0 -> write physical, 1 -> write logical */ |
| 1138 | | /* bit 4: 1 -> write deleted data mark instead of normal address mark */ |
| 1139 | | /* bit 3: 1 -> write with reduced current */ |
| 1140 | | /* bit 2-0: write precompensation value */ |
| 1141 | | logerror("smc92x4 write command %X\n", opcode & 0x7f); |
| 1142 | | switch ((opcode >> 5) & 0x3) |
| 1143 | | { |
| 1144 | | case 0: |
| 1145 | | logerror("smc92x4 write physical command %X\n", opcode & 0x7f); |
| 1146 | | do_write(machine,which, 1, opcode & 0x7f); |
| 1147 | | break; |
| 1148 | | case 1: |
| 1149 | | logerror("smc92x4 write logical command %X\n", opcode & 0x7f); |
| 1150 | | do_write(machine,which, 0, opcode & 0x7f); |
| 1151 | | break; |
| 1152 | | case 2: |
| 1153 | | logerror("smc92x4 write physical command??? %X\n", opcode & 0x7f); |
| 1154 | | do_write(machine,which, 1, opcode & 0x7f); |
| 1155 | | break; |
| 1156 | | case 3: |
| 1157 | | logerror("smc92x4 write logical command??? %X\n", opcode & 0x7f); |
| 1158 | | do_write(machine,which, 0, opcode & 0x7f); |
| 1159 | | break; |
| 1160 | | } |
| 2060 | logerror("smc92x4 warn: Invalid command %x, ignored\n", opcode); |
| 1161 | 2061 | } |
| 2062 | |
| 2063 | if (!w->to_be_continued) |
| 2064 | set_command_done(device); |
| 1162 | 2065 | } |
| 1163 | 2066 | |
| 1164 | | /* |
| 2067 | /*************************************************************************** |
| 1165 | 2068 | Memory accessors |
| 1166 | | */ |
| 2069 | ****************************************************************************/ |
| 1167 | 2070 | |
| 1168 | 2071 | /* |
| 1169 | | Read a byte of data from a smc99x4 controller |
| 2072 | Read a byte of data from a smc92x4 controller |
| 2073 | The address (offset) encodes the C/D* line (command and /data) |
| 1170 | 2074 | */ |
| 1171 | | int smc92x4_r(running_machine *machine,int which, int offset) |
| 2075 | READ8_DEVICE_HANDLER( smc92x4_r ) |
| 1172 | 2076 | { |
| 1173 | | int reply = 0; |
| 1174 | | |
| 1175 | | switch (offset & 1) |
| 2077 | UINT8 reply = 0; |
| 2078 | smc92x4_state *w = get_safe_token(device); |
| 2079 | |
| 2080 | if ((offset & 1) == 0) |
| 1176 | 2081 | { |
| 1177 | | case 0: |
| 1178 | 2082 | /* data register */ |
| 1179 | | logerror("smc92x4 data read\n"); |
| 1180 | | if (hfdc[which].reg_ptr < 10) |
| 1181 | | { |
| 1182 | | /* config register */ |
| 1183 | | reply = hfdc[which].regs[(hfdc[which].reg_ptr < 4) ? (hfdc[which].reg_ptr) : (hfdc[which].reg_ptr + 6)]; |
| 1184 | | hfdc[which].reg_ptr++; |
| 1185 | | } |
| 1186 | | else if (hfdc[which].reg_ptr == 10) |
| 1187 | | { |
| 1188 | | /* data register */ |
| 1189 | | } |
| 1190 | | else |
| 1191 | | { |
| 1192 | | /* ??? */ |
| 1193 | | } |
| 1194 | | break; |
| 2083 | reply = w->register_r[w->register_pointer]; |
| 2084 | // printf("smc92x4 register_r[%d] -> %02x\n", w->register_pointer, reply); |
| 1195 | 2085 | |
| 1196 | | case 1: |
| 2086 | /* Autoincrement until DATA is reached. */ |
| 2087 | if (w->register_pointer < DATA) |
| 2088 | w->register_pointer++; |
| 2089 | } |
| 2090 | else |
| 2091 | { |
| 1197 | 2092 | /* status register */ |
| 1198 | | logerror("smc92x4 status read\n"); |
| 1199 | | reply = hfdc[which].status; |
| 1200 | | smc92x4_set_interrupt(which, 0); |
| 1201 | | break; |
| 2093 | reply = w->register_r[INT_STATUS]; |
| 2094 | /* Spec (p.3) : The interrupt pin is reset to its inactive state |
| 2095 | when the UDC interrupt status register is read. */ |
| 2096 | // printf("smc92x4 interrupt status read = %02x\n", reply); |
| 2097 | smc92x4_clear_interrupt(device); |
| 2098 | /* Clear the bits due to int status register read. */ |
| 2099 | w->register_r[INT_STATUS] &= ~(ST_INTPEND | ST_RDYCHNG); |
| 1202 | 2100 | } |
| 1203 | | |
| 1204 | 2101 | return reply; |
| 1205 | 2102 | } |
| 1206 | 2103 | |
| 1207 | 2104 | /* |
| 1208 | | Write a byte to a smc99x4 controller |
| 2105 | Write a byte to a smc99x4 controller |
| 2106 | The address (offset) encodes the C/D* line (command and /data) |
| 1209 | 2107 | */ |
| 1210 | | void smc92x4_w(running_machine *machine,int which, int offset, int data) |
| 2108 | WRITE8_DEVICE_HANDLER( smc92x4_w ) |
| 1211 | 2109 | { |
| 2110 | smc92x4_state *w = get_safe_token(device); |
| 1212 | 2111 | data &= 0xff; |
| 1213 | 2112 | |
| 1214 | | switch (offset & 1) |
| 2113 | if ((offset & 1) == 0) |
| 1215 | 2114 | { |
| 1216 | | case 0: |
| 1217 | 2115 | /* data register */ |
| 1218 | | logerror("smc92x4 data write %X\n", data); |
| 1219 | | if (hfdc[which].reg_ptr < 10) |
| 1220 | | { |
| 1221 | | /* config register */ |
| 1222 | | hfdc[which].regs[hfdc[which].reg_ptr] = data; |
| 1223 | | hfdc[which].reg_ptr++; |
| 1224 | | } |
| 1225 | | else if (hfdc[which].reg_ptr == 10) |
| 1226 | | { |
| 1227 | | /* data register */ |
| 1228 | | } |
| 1229 | | else |
| 1230 | | { |
| 1231 | | /* ??? */ |
| 1232 | | } |
| 1233 | | break; |
| 2116 | // printf("smc92x4 register_w[%d] <- %X\n", w->register_pointer, data); |
| 2117 | w->register_w[w->register_pointer] = data; |
| 1234 | 2118 | |
| 1235 | | case 1: |
| 2119 | /* The DMA registers and the sector register for read and |
| 2120 | write are identical. */ |
| 2121 | if (w->register_pointer < DESIRED_HEAD) |
| 2122 | w->register_r[w->register_pointer] = data; |
| 2123 | |
| 2124 | /* Autoincrement until DATA is reached. */ |
| 2125 | if (w->register_pointer < DATA) |
| 2126 | w->register_pointer++; |
| 2127 | } |
| 2128 | else |
| 2129 | { |
| 1236 | 2130 | /* command register */ |
| 1237 | | smc92x4_process_command(machine,which, data); |
| 1238 | | break; |
| 2131 | smc92x4_process_command(device, data); |
| 1239 | 2132 | } |
| 1240 | 2133 | } |
| 1241 | 2134 | |
| 1242 | | READ8_HANDLER(smc92x4_0_r) |
| 2135 | |
| 2136 | |
| 2137 | /*************************************************************************** |
| 2138 | DEVICE FUNCTIONS |
| 2139 | ***************************************************************************/ |
| 2140 | |
| 2141 | static DEVICE_START( smc92x4 ) |
| 1243 | 2142 | { |
| 1244 | | return smc92x4_r(space->machine,0, offset); |
| 2143 | smc92x4_state *w = get_safe_token(device); |
| 2144 | assert(device->baseconfig().static_config != NULL); |
| 2145 | |
| 2146 | w->intf = (const smc92x4_interface*)device->baseconfig().static_config; |
| 2147 | devcb_resolve_write_line(&w->out_intrq_func, &w->intf->out_intrq_func, device); |
| 2148 | devcb_resolve_write_line(&w->out_dip_func, &w->intf->out_dip_func, device); |
| 2149 | devcb_resolve_write8(&w->out_auxbus_func, &w->intf->out_auxbus_func, device); |
| 2150 | devcb_resolve_read_line(&w->in_auxbus_func, &w->intf->in_auxbus_func, device); |
| 2151 | |
| 2152 | /* allocate timers */ |
| 2153 | /* |
| 2154 | w->timer_data = timer_alloc(device->machine, smc92x4_data_callback, (void *)device); */ |
| 2155 | w->timer_rs = timer_alloc(device->machine, smc92x4_read_sector_callback, (void *)device); |
| 2156 | w->timer_ws = timer_alloc(device->machine, smc92x4_write_sector_callback, (void *)device); |
| 2157 | w->timer_track = timer_alloc(device->machine, smc92x4_track_callback, (void *)device); |
| 2158 | w->timer_seek = timer_alloc(device->machine, smc92x4_seek_callback, (void *)device); |
| 2159 | |
| 2160 | w->use_real_timing = TRUE; |
| 1245 | 2161 | } |
| 1246 | 2162 | |
| 1247 | | WRITE8_HANDLER(smc92x4_0_w) |
| 2163 | static DEVICE_RESET( smc92x4 ) |
| 1248 | 2164 | { |
| 1249 | | smc92x4_w(space->machine,0, offset, data); |
| 2165 | smc92x4_state *w = get_safe_token(device); |
| 2166 | smc92x4_clear_interrupt(device); |
| 2167 | smc92x4_set_dip(device, FALSE); |
| 2168 | |
| 2169 | for (int i=0; i<11; i++) |
| 2170 | w->register_r[i] = w->register_w[i] = 0; |
| 1250 | 2171 | } |
| 1251 | 2172 | |
| 1252 | | static const struct harddisk_callback_config smc92x4_harddisk_config = |
| 2173 | void smc92x4_reset(running_device *device) |
| 1253 | 2174 | { |
| 1254 | | DEVICE_IMAGE_LOAD_NAME( smc92x4_hd ), |
| 1255 | | DEVICE_IMAGE_UNLOAD_NAME( smc92x4_hd ) |
| 1256 | | }; |
| 2175 | DEVICE_RESET_CALL( smc92x4 ); |
| 2176 | } |
| 1257 | 2177 | |
| 2178 | void smc92x4_set_timing(running_device *device, int realistic) |
| 2179 | { |
| 2180 | smc92x4_state *w = get_safe_token(device); |
| 2181 | w->use_real_timing = realistic; |
| 2182 | } |
| 1258 | 2183 | |
| 1259 | | MACHINE_DRIVER_START( smc92x4_hd ) |
| 1260 | | MDRV_DEVICE_ADD( "harddisk1", HARDDISK, 0 ) |
| 1261 | | MDRV_DEVICE_CONFIG( smc92x4_harddisk_config ) |
| 1262 | | MDRV_DEVICE_ADD( "harddisk2", HARDDISK, 0 ) |
| 1263 | | MDRV_DEVICE_CONFIG( smc92x4_harddisk_config ) |
| 1264 | | MDRV_DEVICE_ADD( "harddisk3", HARDDISK, 0 ) |
| 1265 | | MDRV_DEVICE_CONFIG( smc92x4_harddisk_config ) |
| 1266 | | MACHINE_DRIVER_END |
| 2184 | /*************************************************************************** |
| 2185 | DEVICE GETINFO |
| 2186 | ***************************************************************************/ |
| 2187 | |
| 2188 | static const char DEVTEMPLATE_SOURCE[] = __FILE__; |
| 2189 | |
| 2190 | #define DEVTEMPLATE_ID(p,s) p##smc92x4##s |
| 2191 | #define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET |
| 2192 | #define DEVTEMPLATE_NAME "SMC92x4" |
| 2193 | #define DEVTEMPLATE_FAMILY "SMC92x4" |
| 2194 | #define DEVTEMPLATE_VERSION "1.0" |
| 2195 | #define DEVTEMPLATE_CREDITS "Copyright MESS Team" |
| 2196 | #include "devtempl.h" |
| 2197 | |
src/mess/drivers/ti99_4x.c
| r8042 | r8043 | |
| 44 | 44 | #include "machine/rtc65271.h" |
| 45 | 45 | #include "devices/ti99cart.h" |
| 46 | 46 | #include "formats/ti99_dsk.h" |
| 47 | #include "devices/ti99_hd.h" |
| 47 | 48 | |
| 48 | 49 | /* |
| 49 | 50 | memory map |
| r8042 | r8043 | |
| 105 | 106 | /* TI99/4a: 48-key keyboard, plus two optional joysticks (2 shift keys) */ |
| 106 | 107 | static INPUT_PORTS_START(ti99_4a) |
| 107 | 108 | |
| 108 | | /* 1 port for config */ |
| 109 | | PORT_START("CFG") /* config */ |
| 110 | | PORT_DIPNAME( config_xRAM_mask << config_xRAM_bit, xRAM_kind_TI << config_xRAM_bit, "RAM extension") |
| 111 | | PORT_DIPSETTING( xRAM_kind_none << config_xRAM_bit, DEF_STR( None ) ) |
| 112 | | PORT_DIPSETTING( xRAM_kind_TI << config_xRAM_bit, "Texas Instruments 32kb") |
| 113 | | PORT_DIPSETTING( xRAM_kind_super_AMS << config_xRAM_bit, "Super AMS 1Mb") |
| 114 | | PORT_DIPSETTING( xRAM_kind_foundation_128k << config_xRAM_bit, "Foundation 128kb") |
| 115 | | PORT_DIPSETTING( xRAM_kind_foundation_512k << config_xRAM_bit, "Foundation 512kb") |
| 116 | | PORT_DIPSETTING( xRAM_kind_myarc_128k << config_xRAM_bit, "Myarc look-alike 128kb") |
| 117 | | PORT_DIPSETTING( xRAM_kind_myarc_512k << config_xRAM_bit, "Myarc look-alike 512kb") |
| 118 | | PORT_DIPNAME( config_speech_mask << config_speech_bit, 1 << config_speech_bit, "Speech synthesis") |
| 119 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 120 | | PORT_DIPSETTING( 1 << config_speech_bit, DEF_STR( On ) ) |
| 121 | | PORT_DIPNAME( config_fdc_mask << config_fdc_bit, fdc_kind_hfdc << config_fdc_bit, "Floppy disk controller") |
| 122 | | PORT_DIPSETTING( fdc_kind_none << config_fdc_bit, DEF_STR( None ) ) |
| 123 | | PORT_DIPSETTING( fdc_kind_TI << config_fdc_bit, "Texas Instruments SD" ) |
| 124 | | #if HAS_99CCFDC |
| 125 | | PORT_DIPSETTING( fdc_kind_CC << config_fdc_bit, "CorComp" ) |
| 126 | | #endif |
| 127 | | PORT_DIPSETTING( fdc_kind_BwG << config_fdc_bit, "SNUG's BwG" ) |
| 128 | | PORT_DIPSETTING( fdc_kind_hfdc << config_fdc_bit, "Myarc's HFDC" ) |
| 129 | | PORT_DIPNAME( config_ide_mask << config_ide_bit, 1 << config_ide_bit, "Nouspickel's IDE card") |
| 130 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 131 | | PORT_DIPSETTING( 1 << config_ide_bit, DEF_STR( On ) ) |
| 132 | | PORT_DIPNAME( config_rs232_mask << config_rs232_bit, 1 << config_rs232_bit, "TI RS232 card") |
| 133 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 134 | | PORT_DIPSETTING( 1 << config_rs232_bit, DEF_STR( On ) ) |
| 135 | | PORT_DIPNAME( config_hsgpl_mask << config_hsgpl_bit, 0/*1 << config_hsgpl_bit*/, "SNUG HSGPL card") |
| 136 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 137 | | PORT_DIPSETTING( 1 << config_hsgpl_bit, DEF_STR( On ) ) |
| 138 | | PORT_DIPNAME( config_mecmouse_mask << config_mecmouse_bit, 0, "Mechatronics Mouse") |
| 139 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 140 | | PORT_DIPSETTING( 1 << config_mecmouse_bit, DEF_STR( On ) ) |
| 141 | | PORT_DIPNAME( config_usbsm_mask << config_usbsm_bit, 1 << config_usbsm_bit, "Nouspickel's USB-SM card") |
| 142 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 143 | | PORT_DIPSETTING( 1 << config_usbsm_bit, DEF_STR( On ) ) |
| 144 | | PORT_DIPNAME( config_pcode_mask << config_pcode_bit, 0, "P-Code card") |
| 145 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 146 | | PORT_DIPSETTING( 1 << config_pcode_bit, DEF_STR( On ) ) |
| 109 | PORT_START( "RAM" ) /* config */ |
| 110 | PORT_CONFNAME( 0x07, 0x00, "RAM extension" ) |
| 111 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 112 | PORT_CONFSETTING( 0x01, "Texas Instruments 32 KiB" ) |
| 113 | PORT_CONFSETTING( 0x02, "Super AMS 1MiB" ) |
| 114 | PORT_CONFSETTING( 0x03, "Foundation 128 KiB" ) |
| 115 | PORT_CONFSETTING( 0x04, "Foundation 512 KiB" ) |
| 116 | PORT_CONFSETTING( 0x05, "Myarc 128 KiB" ) |
| 117 | PORT_CONFSETTING( 0x06, "Myarc 512 KiB" ) |
| 147 | 118 | |
| 148 | | PORT_DIPNAME( config_cartslot_mask << config_cartslot_bit, 0, "Active cartridge slot") |
| 149 | | PORT_DIPSETTING( 0, "auto" ) |
| 150 | | PORT_DIPSETTING( 1 << config_cartslot_bit, "Slot 1" ) |
| 151 | | PORT_DIPSETTING( 2 << config_cartslot_bit, "Slot 2" ) |
| 152 | | PORT_DIPSETTING( 3 << config_cartslot_bit, "Slot 3" ) |
| 153 | | PORT_DIPSETTING( 4 << config_cartslot_bit, "Slot 4" ) |
| 119 | PORT_START( "SPEECH" ) |
| 120 | PORT_CONFNAME( 0x01, 0x00, "Speech synthesizer" ) |
| 121 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 122 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) |
| 154 | 123 | |
| 124 | PORT_START( "DISKCTRL" ) |
| 125 | PORT_CONFNAME( 0x07, 0x00, "Disk controller" ) |
| 126 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 127 | PORT_CONFSETTING( 0x01, "TI SD Floppy Controller" ) |
| 128 | PORT_CONFSETTING( 0x02, "SNUG BwG Controller" ) |
| 129 | PORT_CONFSETTING( 0x03, "Myarc HFDC" ) |
| 130 | // PORT_CONFSETTING( 0x04, "Corcomp" ) |
| 131 | |
| 132 | PORT_START( "HDCTRL" ) |
| 133 | PORT_CONFNAME( 0x03, 0x00, "HD controller" ) |
| 134 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 135 | PORT_CONFSETTING( 0x01, "Nouspikel IDE Controller" ) |
| 136 | // PORT_CONFSETTING( 0x02, "WHTech SCSI Controller" ) |
| 137 | PORT_CONFNAME( 0x04, 0x00, "USB-SM card" ) |
| 138 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 139 | PORT_CONFSETTING( 0x04, DEF_STR( On ) ) |
| 140 | |
| 141 | PORT_START( "SERIAL" ) |
| 142 | PORT_CONFNAME( 0x03, 0x00, "Serial/Parallel interface" ) |
| 143 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 144 | PORT_CONFSETTING( 0x01, "TI RS-232 card" ) |
| 145 | |
| 146 | PORT_START( "EXTCARD" ) |
| 147 | PORT_CONFNAME( 0x01, 0x00, "HSGPL extension" ) |
| 148 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 149 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) |
| 150 | PORT_CONFNAME( 0x02, 0x00, "P-Code card" ) |
| 151 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 152 | PORT_CONFSETTING( 0x02, DEF_STR( On ) ) |
| 153 | |
| 154 | PORT_START( "HCI" ) |
| 155 | PORT_CONFNAME( 0x01, 0x00, "Mouse support" ) |
| 156 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 157 | PORT_CONFSETTING( 0x01, "Mechatronics Mouse" ) |
| 158 | |
| 159 | PORT_START( "CARTSLOT" ) |
| 160 | PORT_CONFNAME( 0x07, 0x00, "Cartridge slot" ) |
| 161 | PORT_CONFSETTING( 0x00, "Auto" ) |
| 162 | PORT_CONFSETTING( 0x01, "Slot 1" ) |
| 163 | PORT_CONFSETTING( 0x02, "Slot 2" ) |
| 164 | PORT_CONFSETTING( 0x03, "Slot 3" ) |
| 165 | PORT_CONFSETTING( 0x04, "Slot 4" ) |
| 166 | // PORT_CONFSETTING( 0x05, "GRAM Kracker" ) |
| 167 | |
| 168 | PORT_START( "HFDCDIP" ) |
| 169 | PORT_DIPNAME( 0xff, 0x55, "HFDC drive config" ) PORT_CONDITION( "DISKCTRL", 0x07, PORTCOND_EQUALS, 0x03 ) |
| 170 | PORT_DIPSETTING( 0x00, "40 track, 16 ms") |
| 171 | PORT_DIPSETTING( 0xaa, "40 track, 8 ms") |
| 172 | PORT_DIPSETTING( 0x55, "80 track, 2 ms") |
| 173 | PORT_DIPSETTING( 0xff, "80 track HD, 2 ms") |
| 174 | |
| 175 | PORT_START( "DRVSPD" ) |
| 176 | PORT_DIPNAME( 0x01, 0x01, "Floppy and HD speed" ) PORT_CONDITION( "DISKCTRL", 0x07, PORTCOND_EQUALS, 0x03 ) |
| 177 | PORT_DIPSETTING( 0x00, "No delay") |
| 178 | PORT_DIPSETTING( 0x01, "Realistic") |
| 179 | |
| 155 | 180 | /* 3 ports for mouse */ |
| 156 | 181 | PORT_START("MOUSEX") /* Mouse - X AXIS */ |
| 157 | 182 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) |
| r8042 | r8043 | |
| 254 | 279 | /* TI99/4: 41-key keyboard, plus two optional joysticks (2 space keys) */ |
| 255 | 280 | static INPUT_PORTS_START(ti99_4) |
| 256 | 281 | |
| 257 | | /* 1 port for config */ |
| 258 | | PORT_START("CFG") /* config */ |
| 259 | | PORT_DIPNAME( config_xRAM_mask << config_xRAM_bit, xRAM_kind_TI << config_xRAM_bit, "RAM extension") |
| 260 | | PORT_DIPSETTING( xRAM_kind_none << config_xRAM_bit, DEF_STR( None ) ) |
| 261 | | PORT_DIPSETTING( xRAM_kind_TI << config_xRAM_bit, "Texas Instruments 32kb") |
| 262 | | PORT_DIPSETTING( xRAM_kind_super_AMS << config_xRAM_bit, "Super AMS 1Mb") |
| 263 | | PORT_DIPSETTING( xRAM_kind_foundation_128k << config_xRAM_bit, "Foundation 128kb") |
| 264 | | PORT_DIPSETTING( xRAM_kind_foundation_512k << config_xRAM_bit, "Foundation 512kb") |
| 265 | | PORT_DIPSETTING( xRAM_kind_myarc_128k << config_xRAM_bit, "Myarc look-alike 128kb") |
| 266 | | PORT_DIPSETTING( xRAM_kind_myarc_512k << config_xRAM_bit, "Myarc look-alike 512kb") |
| 267 | | PORT_DIPNAME( config_speech_mask << config_speech_bit, 1 << config_speech_bit, "Speech synthesis") |
| 268 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 269 | | PORT_DIPSETTING( 1 << config_speech_bit, DEF_STR( On ) ) |
| 270 | | PORT_DIPNAME( config_fdc_mask << config_fdc_bit, fdc_kind_hfdc << config_fdc_bit, "Floppy disk controller") |
| 271 | | PORT_DIPSETTING( fdc_kind_none << config_fdc_bit, DEF_STR( None ) ) |
| 272 | | PORT_DIPSETTING( fdc_kind_TI << config_fdc_bit, "Texas Instruments SD" ) |
| 273 | | #if HAS_99CCFDC |
| 274 | | PORT_DIPSETTING( fdc_kind_CC << config_fdc_bit, "CorComp" ) |
| 275 | | #endif |
| 276 | | PORT_DIPSETTING( fdc_kind_BwG << config_fdc_bit, "SNUG's BwG" ) |
| 277 | | PORT_DIPSETTING( fdc_kind_hfdc << config_fdc_bit, "Myarc's HFDC" ) |
| 278 | | PORT_DIPNAME( config_ide_mask << config_ide_bit, /*1 << config_ide_bit*/0, "Nouspickel's IDE card") |
| 279 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 280 | | PORT_DIPSETTING( 1 << config_ide_bit, DEF_STR( On ) ) |
| 281 | | PORT_DIPNAME( config_rs232_mask << config_rs232_bit, 1 << config_rs232_bit, "TI RS232 card") |
| 282 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 283 | | PORT_DIPSETTING( 1 << config_rs232_bit, DEF_STR( On ) ) |
| 284 | | PORT_DIPNAME( config_handsets_mask << config_handsets_bit, /*1 << config_handsets_bit*/0, "I/R remote handset") |
| 285 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 286 | | PORT_DIPSETTING( 1 << config_handsets_bit, DEF_STR( On ) ) |
| 287 | | PORT_DIPNAME( config_hsgpl_mask << config_hsgpl_bit, 0/*1 << config_hsgpl_bit*/, "SNUG HSGPL card") |
| 288 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 289 | | PORT_DIPSETTING( 1 << config_hsgpl_bit, DEF_STR( On ) ) |
| 290 | | PORT_DIPNAME( config_mecmouse_mask << config_mecmouse_bit, 0, "Mechatronics Mouse") |
| 291 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 292 | | PORT_DIPSETTING( 1 << config_mecmouse_bit, DEF_STR( On ) ) |
| 293 | | PORT_DIPNAME( config_usbsm_mask << config_usbsm_bit, 1 << config_usbsm_bit, "Nouspickel's USB-SM card") |
| 294 | | PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) |
| 295 | | PORT_DIPSETTING( 1 << config_usbsm_bit, DEF_STR( On ) ) |
| 282 | PORT_START( "RAM" ) /* config */ |
| 283 | PORT_CONFNAME( 0x07, 0x00, "RAM extension" ) |
| 284 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 285 | PORT_CONFSETTING( 0x01, "Texas Instruments 32 KiB" ) |
| 286 | PORT_CONFSETTING( 0x02, "Super AMS 1MiB" ) |
| 287 | PORT_CONFSETTING( 0x03, "Foundation 128 KiB" ) |
| 288 | PORT_CONFSETTING( 0x04, "Foundation 512 KiB" ) |
| 289 | PORT_CONFSETTING( 0x05, "Myarc 128 KiB" ) |
| 290 | PORT_CONFSETTING( 0x06, "Myarc 512 KiB" ) |
| 296 | 291 | |
| 292 | PORT_START( "SPEECH" ) |
| 293 | PORT_CONFNAME( 0x01, 0x00, "Speech synthesizer" ) |
| 294 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 295 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) |
| 297 | 296 | |
| 297 | PORT_START( "DISKCTRL" ) |
| 298 | PORT_CONFNAME( 0x07, 0x00, "Disk controller" ) |
| 299 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 300 | PORT_CONFSETTING( 0x01, "TI SD Floppy Controller" ) |
| 301 | PORT_CONFSETTING( 0x02, "SNUG BwG Controller" ) |
| 302 | PORT_CONFSETTING( 0x03, "Myarc HFDC" ) |
| 303 | // PORT_CONFSETTING( 0x04, "Corcomp" ) |
| 304 | |
| 305 | PORT_START( "HDCTRL" ) |
| 306 | PORT_CONFNAME( 0x03, 0x00, "HD controller" ) |
| 307 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 308 | PORT_CONFSETTING( 0x01, "Nouspikel IDE Controller" ) |
| 309 | // PORT_CONFSETTING( 0x02, "WHTech SCSI Controller" ) |
| 310 | PORT_CONFNAME( 0x08, 0x00, "USB-SM card" ) |
| 311 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 312 | PORT_CONFSETTING( 0x08, DEF_STR( On ) ) |
| 313 | |
| 314 | PORT_START( "SERIAL" ) |
| 315 | PORT_CONFNAME( 0x03, 0x00, "Serial/Parallel interface" ) |
| 316 | PORT_CONFSETTING( 0x00, DEF_STR( None ) ) |
| 317 | PORT_CONFSETTING( 0x01, "TI RS-232 card" ) |
| 318 | |
| 319 | PORT_START( "EXTCARD" ) |
| 320 | PORT_CONFNAME( 0x01, 0x00, "HSGPL extension" ) |
| 321 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 322 | PORT_CONFSETTING( 0x01, DEF_STR( On ) ) |
| 323 | PORT_CONFNAME( 0x02, 0x00, "P-Code card" ) |
| 324 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 325 | PORT_CONFSETTING( 0x02, DEF_STR( On ) ) |
| 326 | |
| 327 | PORT_START( "HCI" ) |
| 328 | PORT_CONFNAME( 0x01, 0x00, "Mouse support" ) |
| 329 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 330 | PORT_CONFSETTING( 0x01, "Mechatronics Mouse" ) |
| 331 | PORT_CONFNAME( 0x04, 0x00, "IR Handset" ) |
| 332 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) |
| 333 | PORT_CONFSETTING( 0x04, DEF_STR( On ) ) |
| 334 | |
| 335 | PORT_START( "CARTSLOT" ) |
| 336 | PORT_CONFNAME( 0x07, 0x00, "Cartridge slot" ) |
| 337 | PORT_CONFSETTING( 0x00, "Auto" ) |
| 338 | PORT_CONFSETTING( 0x01, "Slot 1" ) |
| 339 | PORT_CONFSETTING( 0x02, "Slot 2" ) |
| 340 | PORT_CONFSETTING( 0x03, "Slot 3" ) |
| 341 | PORT_CONFSETTING( 0x04, "Slot 4" ) |
| 342 | // PORT_CONFSETTING( 0x05, "GRAM Kracker" ) |
| 343 | |
| 344 | PORT_START( "HFDCDIP" ) |
| 345 | PORT_DIPNAME( 0xff, 0x55, "HFDC drive config" ) PORT_CONDITION( "DISKCTRL", 0x07, PORTCOND_EQUALS, 0x03 ) |
| 346 | PORT_DIPSETTING( 0x00, "40 track, 16 ms") |
| 347 | PORT_DIPSETTING( 0xaa, "40 track, 8 ms") |
| 348 | PORT_DIPSETTING( 0x55, "80 track, 2 ms") |
| 349 | PORT_DIPSETTING( 0xff, "80 track HD, 2 ms") |
| 350 | |
| 351 | PORT_START( "DRVSPD" ) |
| 352 | PORT_DIPNAME( 0x01, 0x01, "Floppy and HD speed" ) PORT_CONDITION( "DISKCTRL", 0x07, PORTCOND_EQUALS, 0x03 ) |
| 353 | PORT_DIPSETTING( 0x00, "No delay") |
| 354 | PORT_DIPSETTING( 0x01, "Realistic") |
| 355 | |
| 298 | 356 | /* 3 ports for mouse */ |
| 299 | 357 | PORT_START("MOUSEX") /* Mouse - X AXIS */ |
| 300 | 358 | PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) |
| r8042 | r8043 | |
| 645 | 703 | |
| 646 | 704 | /* devices */ |
| 647 | 705 | MDRV_IDE_CONTROLLER_ADD( "ide", ti99_ide_interrupt ) /* FIXME */ |
| 648 | | |
| 649 | | MDRV_IMPORT_FROM( smc92x4_hd ) |
| 650 | | |
| 651 | | MDRV_IDE_HARDDISK_ADD( "ide_harddisk" ) |
| 652 | 706 | MDRV_RTC65271_ADD("ide_rtc", ti99_clk_interrupt_callback) |
| 653 | 707 | |
| 654 | 708 | MDRV_CASSETTE_ADD( "cassette1", default_cassette_config ) |
| r8042 | r8043 | |
| 659 | 713 | /* tms9901 */ |
| 660 | 714 | MDRV_TMS9901_ADD("tms9901", tms9901reset_param_ti99_4x) |
| 661 | 715 | |
| 716 | /* to be moved to controller */ |
| 662 | 717 | MDRV_WD179X_ADD("wd179x", ti99_wd17xx_interface ) |
| 718 | MDRV_SMC92X4_ADD("smc92x4", ti99_smc92x4_interface ) |
| 663 | 719 | |
| 664 | 720 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 665 | | |
| 721 | MDRV_MFMHD_3_DRIVES_ADD() |
| 722 | |
| 666 | 723 | MDRV_TI99_CARTRIDGE_ADD("ti99_multicart") |
| 667 | 724 | |
| 668 | 725 | MDRV_SMARTMEDIA_ADD("smartmedia") |
| r8042 | r8043 | |
| 700 | 757 | |
| 701 | 758 | /* devices */ |
| 702 | 759 | MDRV_IDE_CONTROLLER_ADD( "ide", ti99_ide_interrupt ) /* FIXME */ |
| 703 | | |
| 704 | | MDRV_IMPORT_FROM( smc92x4_hd ) |
| 705 | | |
| 706 | | MDRV_IDE_HARDDISK_ADD( "ide_harddisk" ) |
| 707 | 760 | MDRV_RTC65271_ADD("ide_rtc", ti99_clk_interrupt_callback) |
| 708 | 761 | |
| 709 | 762 | MDRV_CASSETTE_ADD( "cassette1", default_cassette_config ) |
| r8042 | r8043 | |
| 714 | 767 | /* tms9901 */ |
| 715 | 768 | MDRV_TMS9901_ADD("tms9901", tms9901reset_param_ti99_4x) |
| 716 | 769 | |
| 770 | /* to be moved to controller */ |
| 717 | 771 | MDRV_WD179X_ADD("wd179x", ti99_wd17xx_interface ) |
| 772 | MDRV_SMC92X4_ADD("smc92x4", ti99_smc92x4_interface ) |
| 773 | |
| 718 | 774 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 775 | MDRV_MFMHD_3_DRIVES_ADD() |
| 719 | 776 | |
| 720 | 777 | MDRV_TI99_CARTRIDGE_ADD("ti99_multicart") |
| 721 | 778 | |
| r8042 | r8043 | |
| 754 | 811 | |
| 755 | 812 | /* devices */ |
| 756 | 813 | MDRV_IDE_CONTROLLER_ADD( "ide", ti99_ide_interrupt ) /* FIXME */ |
| 757 | | |
| 758 | | MDRV_IMPORT_FROM( smc92x4_hd ) |
| 759 | | |
| 760 | | MDRV_IDE_HARDDISK_ADD( "ide_harddisk" ) |
| 761 | 814 | MDRV_RTC65271_ADD("ide_rtc", ti99_clk_interrupt_callback) |
| 762 | 815 | |
| 763 | 816 | MDRV_CASSETTE_ADD( "cassette1", default_cassette_config ) |
| r8042 | r8043 | |
| 769 | 822 | /* tms9901 */ |
| 770 | 823 | MDRV_TMS9901_ADD("tms9901", tms9901reset_param_ti99_4x) |
| 771 | 824 | |
| 825 | /* to be moved to controller */ |
| 772 | 826 | MDRV_WD179X_ADD("wd179x", ti99_wd17xx_interface ) |
| 827 | MDRV_SMC92X4_ADD("smc92x4", ti99_smc92x4_interface ) |
| 828 | |
| 773 | 829 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 830 | MDRV_MFMHD_3_DRIVES_ADD() |
| 774 | 831 | |
| 775 | 832 | MDRV_TI99_CARTRIDGE_ADD("ti99_multicart") |
| 776 | 833 | |
| r8042 | r8043 | |
| 810 | 867 | |
| 811 | 868 | /* devices */ |
| 812 | 869 | MDRV_IDE_CONTROLLER_ADD( "ide", ti99_ide_interrupt ) |
| 813 | | |
| 814 | | MDRV_IMPORT_FROM( smc92x4_hd ) |
| 815 | | |
| 816 | | MDRV_IDE_HARDDISK_ADD( "ide_harddisk" ) |
| 817 | 870 | MDRV_RTC65271_ADD("ide_rtc", ti99_clk_interrupt_callback) |
| 818 | 871 | |
| 819 | 872 | MDRV_CASSETTE_ADD( "cassette1", default_cassette_config ) |
| r8042 | r8043 | |
| 824 | 877 | /* tms9901 */ |
| 825 | 878 | MDRV_TMS9901_ADD("tms9901", tms9901reset_param_ti99_4x) |
| 826 | 879 | |
| 880 | /* to be moved to controller */ |
| 827 | 881 | MDRV_WD179X_ADD("wd179x", ti99_wd17xx_interface ) |
| 882 | MDRV_SMC92X4_ADD("smc92x4", ti99_smc92x4_interface ) |
| 883 | |
| 828 | 884 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 885 | MDRV_MFMHD_3_DRIVES_ADD() |
| 829 | 886 | |
| 830 | 887 | MDRV_TI99_CARTRIDGE_ADD("ti99_multicart") |
| 831 | 888 | |
| 832 | 889 | MDRV_SMARTMEDIA_ADD("smartmedia") |
| 833 | 890 | |
| 834 | | MDRV_TI99_4_RS232_CARD_ADD("rs232") |
| 891 | MDRV_TI99_4_RS232_CARD_ADD("rs232") |
| 835 | 892 | MACHINE_DRIVER_END |
| 836 | 893 | |
| 837 | 894 | |
| r8042 | r8043 | |
| 873 | 930 | |
| 874 | 931 | /* devices */ |
| 875 | 932 | MDRV_IDE_CONTROLLER_ADD( "ide", ti99_ide_interrupt ) /* FIXME */ |
| 876 | | |
| 877 | | MDRV_IMPORT_FROM( smc92x4_hd ) |
| 878 | | |
| 879 | | MDRV_IDE_HARDDISK_ADD( "ide_harddisk" ) |
| 880 | 933 | MDRV_RTC65271_ADD("ide_rtc", ti99_clk_interrupt_callback) |
| 881 | 934 | |
| 882 | 935 | MDRV_CASSETTE_ADD( "cassette1", default_cassette_config ) |
| r8042 | r8043 | |
| 887 | 940 | /* tms9901 */ |
| 888 | 941 | MDRV_TMS9901_ADD("tms9901", tms9901reset_param_ti99_4x) |
| 889 | 942 | |
| 943 | /* to be moved to controller */ |
| 890 | 944 | MDRV_WD179X_ADD("wd179x", ti99_wd17xx_interface ) |
| 945 | MDRV_SMC92X4_ADD("smc92x4", ti99_smc92x4_interface ) |
| 946 | |
| 891 | 947 | MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config) |
| 948 | MDRV_MFMHD_3_DRIVES_ADD() |
| 949 | |
| 892 | 950 | MDRV_TI99_CARTRIDGE_ADD("ti99_multicart") |
| 893 | 951 | MDRV_SMARTMEDIA_ADD("smartmedia") |
| 894 | 952 | |