~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Bochs x86 Emulator
bochs/iodev/floppy.cc

Version: ~ [ 2.4 ] ~ [ 2.4.5 ] ~

** Warning: Cannot open xref database.

1 ///////////////////////////////////////////////////////////////////////// 2 // $Id: floppy.cc,v 1.120 2009/04/24 14:57:24 vruppert Exp $ 3 ///////////////////////////////////////////////////////////////////////// 4 // 5 // Copyright (C) 2002 MandrakeSoft S.A. 6 // 7 // MandrakeSoft S.A. 8 // 43, rue d'Aboukir 9 // 75002 Paris - France 10 // http://www.linux-mandrake.com/ 11 // http://www.mandrakesoft.com/ 12 // 13 // This library is free software; you can redistribute it and/or 14 // modify it under the terms of the GNU Lesser General Public 15 // License as published by the Free Software Foundation; either 16 // version 2 of the License, or (at your option) any later version. 17 // 18 // This library is distributed in the hope that it will be useful, 19 // but WITHOUT ANY WARRANTY; without even the implied warranty of 20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 // Lesser General Public License for more details. 22 // 23 // You should have received a copy of the GNU Lesser General Public 24 // License along with this library; if not, write to the Free Software 25 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 // 27 ///////////////////////////////////////////////////////////////////////// 28 29 // 30 // Floppy Disk Controller Docs: 31 // Intel 82077A Data sheet 32 // ftp://void-core.2y.net/pub/docs/fdc/82077AA_FloppyControllerDatasheet.pdf 33 // Intel 82078 Data sheet 34 // ftp://download.intel.com/design/periphrl/datashts/29047403.PDF 35 // Other FDC references 36 // http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html 37 // And a port list: 38 // http://mudlist.eorbit.net/~adam/pickey/ports.html 39 // 40 41 // Define BX_PLUGGABLE in files that can be compiled into plugins. For 42 // platforms that require a special tag on exported symbols, BX_PLUGGABLE 43 // is used to know when we are exporting symbols and when we are importing. 44 #define BX_PLUGGABLE 45 46 47 extern "C" { 48 #include <errno.h> 49 } 50 51 #ifdef __linux__ 52 extern "C" { 53 #include <sys/ioctl.h> 54 #include <linux/fd.h> 55 } 56 #endif 57 #include "iodev.h" 58 #include "floppy.h" 59 // windows.h included by bochs.h 60 #ifdef WIN32 61 extern "C" { 62 #include <winioctl.h> 63 } 64 #endif 65 #define LOG_THIS theFloppyController-> 66 67 bx_floppy_ctrl_c *theFloppyController; 68 69 /* for main status register */ 70 #define FD_MS_MRQ 0x80 71 #define FD_MS_DIO 0x40 72 #define FD_MS_NDMA 0x20 73 #define FD_MS_BUSY 0x10 74 #define FD_MS_ACTD 0x08 75 #define FD_MS_ACTC 0x04 76 #define FD_MS_ACTB 0x02 77 #define FD_MS_ACTA 0x01 78 79 #define FROM_FLOPPY 10 80 #define TO_FLOPPY 11 81 82 #define FLOPPY_DMA_CHAN 2 83 84 #define FDRIVE_NONE 0x00 85 #define FDRIVE_525DD 0x01 86 #define FDRIVE_525HD 0x02 87 #define FDRIVE_350DD 0x04 88 #define FDRIVE_350HD 0x08 89 #define FDRIVE_350ED 0x10 90 91 typedef struct { 92 unsigned id; 93 Bit8u trk; 94 Bit8u hd; 95 Bit8u spt; 96 unsigned sectors; 97 Bit8u drive_mask; 98 } floppy_type_t; 99 100 static floppy_type_t floppy_type[8] = { 101 {BX_FLOPPY_160K, 40, 1, 8, 320, 0x03}, 102 {BX_FLOPPY_180K, 40, 1, 9, 360, 0x03}, 103 {BX_FLOPPY_320K, 40, 2, 8, 640, 0x03}, 104 {BX_FLOPPY_360K, 40, 2, 9, 720, 0x03}, 105 {BX_FLOPPY_720K, 80, 2, 9, 1440, 0x1f}, 106 {BX_FLOPPY_1_2, 80, 2, 15, 2400, 0x02}, 107 {BX_FLOPPY_1_44, 80, 2, 18, 2880, 0x18}, 108 {BX_FLOPPY_2_88, 80, 2, 36, 5760, 0x10} 109 }; 110 111 static Bit16u drate_in_k[4] = { 112 500, 300, 250, 1000 113 }; 114 115 116 int libfloppy_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[]) 117 { 118 theFloppyController = new bx_floppy_ctrl_c(); 119 bx_devices.pluginFloppyDevice = theFloppyController; 120 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theFloppyController, BX_PLUGIN_FLOPPY); 121 return(0); // Success 122 } 123 124 void libfloppy_LTX_plugin_fini(void) 125 { 126 delete theFloppyController; 127 } 128 129 bx_floppy_ctrl_c::bx_floppy_ctrl_c() 130 { 131 put("FDD"); 132 s.floppy_timer_index = BX_NULL_TIMER_HANDLE; 133 } 134 135 bx_floppy_ctrl_c::~bx_floppy_ctrl_c() 136 { 137 BX_DEBUG(("Exit")); 138 } 139 140 void bx_floppy_ctrl_c::init(void) 141 { 142 Bit8u i, devtype, cmos_value; 143 144 BX_DEBUG(("Init $Id: floppy.cc,v 1.120 2009/04/24 14:57:24 vruppert Exp $")); 145 DEV_dma_register_8bit_channel(2, dma_read, dma_write, "Floppy Drive"); 146 DEV_register_irq(6, "Floppy Drive"); 147 for (unsigned addr=0x03F2; addr<=0x03F7; addr++) { 148 DEV_register_ioread_handler(this, read_handler, addr, "Floppy Drive", 1); 149 DEV_register_iowrite_handler(this, write_handler, addr, "Floppy Drive", 1); 150 } 151 152 153 cmos_value = 0x00; /* start out with: no drive 0, no drive 1 */ 154 155 BX_FD_THIS s.num_supported_floppies = 0; 156 157 for (i=0; i<4; i++) { 158 BX_FD_THIS s.media[i].type = BX_FLOPPY_NONE; 159 BX_FD_THIS s.media[i].sectors_per_track = 0; 160 BX_FD_THIS s.media[i].tracks = 0; 161 BX_FD_THIS s.media[i].heads = 0; 162 BX_FD_THIS s.media[i].sectors = 0; 163 BX_FD_THIS s.media[i].fd = -1; 164 BX_FD_THIS s.media_present[i] = 0; 165 BX_FD_THIS s.device_type[i] = FDRIVE_NONE; 166 } 167 168 // 169 // Floppy A setup 170 // 171 172 devtype = SIM->get_param_enum(BXPN_FLOPPYA_DEVTYPE)->get(); 173 cmos_value = (devtype << 4); 174 if (devtype != BX_FDD_NONE) { 175 BX_FD_THIS s.device_type[0] = 1 << (devtype - 1); 176 BX_FD_THIS s.num_supported_floppies++; 177 BX_FD_THIS s.statusbar_id[0] = bx_gui->register_statusitem(" A: "); 178 } else { 179 BX_FD_THIS s.statusbar_id[0] = -1; 180 } 181 182 if (SIM->get_param_enum(BXPN_FLOPPYA_TYPE)->get() != BX_FLOPPY_NONE) { 183 if (SIM->get_param_bool(BXPN_FLOPPYA_STATUS)->get()) { 184 if (evaluate_media(BX_FD_THIS s.device_type[0], SIM->get_param_enum(BXPN_FLOPPYA_TYPE)->get(), 185 SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), & BX_FD_THIS s.media[0])) { 186 BX_FD_THIS s.media_present[0] = 1; 187 #define MED (BX_FD_THIS s.media[0]) 188 BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", 189 SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), 190 MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track)); 191 #undef MED 192 } else { 193 SIM->get_param_bool(BXPN_FLOPPYA_STATUS)->set(0); 194 } 195 } 196 } 197 198 // 199 // Floppy B setup 200 // 201 202 devtype = SIM->get_param_enum(BXPN_FLOPPYB_DEVTYPE)->get(); 203 cmos_value |= devtype; 204 if (devtype != BX_FDD_NONE) { 205 BX_FD_THIS s.device_type[1] = 1 << (devtype - 1); 206 BX_FD_THIS s.num_supported_floppies++; 207 BX_FD_THIS s.statusbar_id[1] = bx_gui->register_statusitem(" B: "); 208 } else { 209 BX_FD_THIS s.statusbar_id[1] = -1; 210 } 211 212 if (SIM->get_param_enum(BXPN_FLOPPYB_TYPE)->get() != BX_FLOPPY_NONE) { 213 if (SIM->get_param_bool(BXPN_FLOPPYB_STATUS)->get()) { 214 if (evaluate_media(BX_FD_THIS s.device_type[1], SIM->get_param_enum(BXPN_FLOPPYB_TYPE)->get(), 215 SIM->get_param_string(BXPN_FLOPPYB_PATH)->getptr(), & BX_FD_THIS s.media[1])) { 216 BX_FD_THIS s.media_present[1] = 1; 217 #define MED (BX_FD_THIS s.media[1]) 218 BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", 219 SIM->get_param_string(BXPN_FLOPPYB_PATH)->getptr(), 220 MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track)); 221 #undef MED 222 } else { 223 SIM->get_param_bool(BXPN_FLOPPYB_STATUS)->set(0); 224 } 225 } 226 } 227 228 /* CMOS Floppy Type and Equipment Byte register */ 229 DEV_cmos_set_reg(0x10, cmos_value); 230 if (BX_FD_THIS s.num_supported_floppies > 0) { 231 DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e) | 232 ((BX_FD_THIS s.num_supported_floppies-1) << 6) | 1); 233 } else { 234 DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e)); 235 } 236 237 if (BX_FD_THIS s.floppy_timer_index == BX_NULL_TIMER_HANDLE) { 238 BX_FD_THIS s.floppy_timer_index = 239 bx_pc_system.register_timer(this, timer_handler, 250, 0, 0, "floppy"); 240 } 241 /* phase out s.non_dma in favor of using FD_MS_NDMA, more like hardware */ 242 BX_FD_THIS s.main_status_reg &= ~FD_MS_NDMA; // enable DMA from start 243 /* these registers are not cleared by reset */ 244 BX_FD_THIS s.SRT = 0; 245 BX_FD_THIS s.HUT = 0; 246 BX_FD_THIS s.HLT = 0; 247 } 248 249 void bx_floppy_ctrl_c::reset(unsigned type) 250 { 251 Bit32u i; 252 253 BX_FD_THIS s.pending_irq = 0; 254 BX_FD_THIS s.reset_sensei = 0; /* no reset result present */ 255 256 BX_FD_THIS s.main_status_reg = 0; 257 BX_FD_THIS s.status_reg0 = 0; 258 BX_FD_THIS s.status_reg1 = 0; 259 BX_FD_THIS s.status_reg2 = 0; 260 BX_FD_THIS s.status_reg3 = 0; 261 262 // software reset (via DOR port 0x3f2 bit 2) does not change DOR 263 if (type == BX_RESET_HARDWARE) { 264 BX_FD_THIS s.DOR = 0x0c; 265 // motor off, drive 3..0 266 // DMA/INT enabled 267 // normal operation 268 // drive select 0 269 270 // DIR and CCR affected only by hard reset 271 for (i=0; i<4; i++) { 272 BX_FD_THIS s.DIR[i] |= 0x80; // disk changed 273 } 274 BX_FD_THIS s.data_rate = 2; /* 250 Kbps */ 275 BX_FD_THIS s.lock = 0; 276 } else { 277 BX_INFO(("controller reset in software")); 278 } 279 if (BX_FD_THIS s.lock == 0) { 280 BX_FD_THIS s.config = 0; 281 BX_FD_THIS s.pretrk = 0; 282 } 283 BX_FD_THIS s.perp_mode = 0; 284 285 for (i=0; i<4; i++) { 286 BX_FD_THIS s.cylinder[i] = 0; 287 BX_FD_THIS s.head[i] = 0; 288 BX_FD_THIS s.sector[i] = 0; 289 BX_FD_THIS s.eot[i] = 0; 290 } 291 292 DEV_pic_lower_irq(6); 293 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 294 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); 295 } 296 enter_idle_phase(); 297 } 298 299 void bx_floppy_ctrl_c::register_state(void) 300 { 301 unsigned i; 302 char name[8]; 303 bx_list_c *drive; 304 305 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "floppy", "Floppy State", 35); 306 new bx_shadow_num_c(list, "data_rate", &BX_FD_THIS s.data_rate); 307 bx_list_c *command = new bx_list_c(list, "command", 10); 308 for (i=0; i<10; i++) { 309 sprintf(name, "%d", i); 310 new bx_shadow_num_c(command, name, &BX_FD_THIS s.command[i], BASE_HEX); 311 } 312 new bx_shadow_num_c(list, "command_index", &BX_FD_THIS s.command_index); 313 new bx_shadow_num_c(list, "command_size", &BX_FD_THIS s.command_size); 314 new bx_shadow_bool_c(list, "command_complete", &BX_FD_THIS s.command_complete); 315 new bx_shadow_num_c(list, "pending_command", &BX_FD_THIS s.pending_command, BASE_HEX); 316 new bx_shadow_bool_c(list, "multi_track", &BX_FD_THIS s.multi_track); 317 new bx_shadow_bool_c(list, "pending_irq", &BX_FD_THIS s.pending_irq); 318 new bx_shadow_num_c(list, "reset_sensei", &BX_FD_THIS s.reset_sensei); 319 new bx_shadow_num_c(list, "format_count", &BX_FD_THIS s.format_count); 320 new bx_shadow_num_c(list, "format_fillbyte", &BX_FD_THIS s.format_fillbyte, BASE_HEX); 321 bx_list_c *result = new bx_list_c(list, "result", 10); 322 for (i=0; i<10; i++) { 323 sprintf(name, "%d", i); 324 new bx_shadow_num_c(result, name, &BX_FD_THIS s.result[i], BASE_HEX); 325 } 326 new bx_shadow_num_c(list, "result_index", &BX_FD_THIS s.result_index); 327 new bx_shadow_num_c(list, "result_size", &BX_FD_THIS s.result_size); 328 new bx_shadow_num_c(list, "DOR", &BX_FD_THIS s.DOR, BASE_HEX); 329 new bx_shadow_num_c(list, "TDR", &BX_FD_THIS s.TDR, BASE_HEX); 330 new bx_shadow_bool_c(list, "TC", &BX_FD_THIS s.TC); 331 new bx_shadow_num_c(list, "main_status_reg", &BX_FD_THIS s.main_status_reg, BASE_HEX); 332 new bx_shadow_num_c(list, "status_reg0", &BX_FD_THIS s.status_reg0, BASE_HEX); 333 new bx_shadow_num_c(list, "status_reg1", &BX_FD_THIS s.status_reg1, BASE_HEX); 334 new bx_shadow_num_c(list, "status_reg2", &BX_FD_THIS s.status_reg2, BASE_HEX); 335 new bx_shadow_num_c(list, "status_reg3", &BX_FD_THIS s.status_reg3, BASE_HEX); 336 new bx_shadow_num_c(list, "floppy_buffer_index", &BX_FD_THIS s.floppy_buffer_index); 337 new bx_shadow_bool_c(list, "lock", &BX_FD_THIS s.lock); 338 new bx_shadow_num_c(list, "SRT", &BX_FD_THIS s.SRT, BASE_HEX); 339 new bx_shadow_num_c(list, "HUT", &BX_FD_THIS s.HUT, BASE_HEX); 340 new bx_shadow_num_c(list, "HLT", &BX_FD_THIS s.HLT, BASE_HEX); 341 new bx_shadow_num_c(list, "config", &BX_FD_THIS s.config, BASE_HEX); 342 new bx_shadow_num_c(list, "pretrk", &BX_FD_THIS s.pretrk); 343 new bx_shadow_num_c(list, "perp_mode", &BX_FD_THIS s.perp_mode); 344 new bx_shadow_data_c(list, "buffer", BX_FD_THIS s.floppy_buffer, 512); 345 for (i=0; i<4; i++) { 346 sprintf(name, "drive%d", i); 347 drive = new bx_list_c(list, name, 6); 348 new bx_shadow_num_c(drive, "cylinder", &BX_FD_THIS s.cylinder[i]); 349 new bx_shadow_num_c(drive, "head", &BX_FD_THIS s.head[i]); 350 new bx_shadow_num_c(drive, "sector", &BX_FD_THIS s.sector[i]); 351 new bx_shadow_num_c(drive, "eot", &BX_FD_THIS s.eot[i]); 352 new bx_shadow_bool_c(drive, "media_present", &BX_FD_THIS s.media_present[i]); 353 new bx_shadow_num_c(drive, "DIR", &BX_FD_THIS s.DIR[i], BASE_HEX); 354 } 355 } 356 357 // static IO port read callback handler 358 // redirects to non-static class handler to avoid virtual functions 359 360 Bit32u bx_floppy_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len) 361 { 362 #if !BX_USE_FD_SMF 363 bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr; 364 365 return class_ptr->read(address, io_len); 366 } 367 368 /* reads from the floppy io ports */ 369 Bit32u bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len) 370 { 371 #else 372 UNUSED(this_ptr); 373 #endif // !BX_USE_FD_SMF 374 Bit8u value = 0, drive; 375 376 Bit8u pending_command = BX_FD_THIS s.pending_command; 377 switch (address) { 378 #if BX_DMA_FLOPPY_IO 379 case 0x3F2: // diskette controller digital output register 380 value = BX_FD_THIS s.DOR; 381 break; 382 383 case 0x3F4: /* diskette controller main status register */ 384 value = BX_FD_THIS s.main_status_reg; 385 break; 386 387 case 0x3F5: /* diskette controller data */ 388 if ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) && 389 ((BX_FD_THIS s.pending_command & 0x4f) == 0x46)) { 390 dma_write(&value); 391 lower_interrupt(); 392 // don't enter idle phase until we've given CPU last data byte 393 if (BX_FD_THIS s.TC) enter_idle_phase(); 394 } else if (BX_FD_THIS s.result_size == 0) { 395 BX_ERROR(("port 0x3f5: no results to read")); 396 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 397 value = BX_FD_THIS s.result[0]; 398 } else { 399 value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++]; 400 BX_FD_THIS s.main_status_reg &= 0xF0; 401 BX_FD_THIS lower_interrupt(); 402 if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) { 403 enter_idle_phase(); 404 } 405 } 406 break; 407 #endif // #if BX_DMA_FLOPPY_IO 408 409 case 0x3F3: // Tape Drive Register 410 drive = BX_FD_THIS s.DOR & 0x03; 411 if (BX_FD_THIS s.media_present[drive]) { 412 switch (BX_FD_THIS s.media[drive].type) { 413 case BX_FLOPPY_160K: 414 case BX_FLOPPY_180K: 415 case BX_FLOPPY_320K: 416 case BX_FLOPPY_360K: 417 case BX_FLOPPY_1_2: 418 value = 0x00; 419 break; 420 case BX_FLOPPY_720K: 421 value = 0xc0; 422 break; 423 case BX_FLOPPY_1_44: 424 value = 0x80; 425 break; 426 case BX_FLOPPY_2_88: 427 value = 0x40; 428 break; 429 default: // BX_FLOPPY_NONE 430 value = 0x20; 431 break; 432 } 433 } else { 434 value = 0x20; 435 } 436 break; 437 438 case 0x3F6: // Reserved for future floppy controllers 439 // This address shared with the hard drive controller 440 value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len); 441 break; 442 443 case 0x3F7: // diskette controller digital input register 444 // This address shared with the hard drive controller: 445 // Bit 7 : floppy 446 // Bits 6..0: hard drive 447 value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len); 448 value &= 0x7f; 449 // add in diskette change line if motor is on 450 drive = BX_FD_THIS s.DOR & 0x03; 451 if (BX_FD_THIS s.DOR & (1<<(drive+4))) { 452 value |= (BX_FD_THIS s.DIR[drive] & 0x80); 453 } 454 break; 455 456 default: 457 BX_ERROR(("io_read: unsupported address 0x%04x", (unsigned) address)); 458 return(0); 459 break; 460 } 461 BX_DEBUG(("read(): during command 0x%02x, port 0x%04x returns 0x%02x", 462 pending_command, address, value)); 463 return (value); 464 } 465 466 // static IO port write callback handler 467 // redirects to non-static class handler to avoid virtual functions 468 469 void bx_floppy_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len) 470 { 471 #if !BX_USE_FD_SMF 472 bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr; 473 class_ptr->write(address, value, io_len); 474 } 475 476 /* writes to the floppy io ports */ 477 void bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len) 478 { 479 #else 480 UNUSED(this_ptr); 481 #endif // !BX_USE_FD_SMF 482 Bit8u dma_and_interrupt_enable; 483 Bit8u normal_operation, prev_normal_operation; 484 Bit8u drive_select; 485 Bit8u motor_on_drive0, motor_on_drive1; 486 487 BX_DEBUG(("write access to port 0x%04x, value=0x%02x", address, value)); 488 489 switch (address) { 490 #if BX_DMA_FLOPPY_IO 491 case 0x3F2: /* diskette controller digital output register */ 492 motor_on_drive0 = value & 0x10; 493 motor_on_drive1 = value & 0x20; 494 /* set status bar conditions for Floppy 0 and Floppy 1 */ 495 if (BX_FD_THIS s.statusbar_id[0] >= 0) { 496 if (motor_on_drive0 != (BX_FD_THIS s.DOR & 0x10)) 497 bx_gui->statusbar_setitem(BX_FD_THIS s.statusbar_id[0], motor_on_drive0); 498 } 499 if (BX_FD_THIS s.statusbar_id[1] >= 0) { 500 if (motor_on_drive1 != (BX_FD_THIS s.DOR & 0x20)) 501 bx_gui->statusbar_setitem(BX_FD_THIS s.statusbar_id[1], motor_on_drive1); 502 } 503 dma_and_interrupt_enable = value & 0x08; 504 if (!dma_and_interrupt_enable) 505 BX_DEBUG(("DMA and interrupt capabilities disabled")); 506 normal_operation = value & 0x04; 507 drive_select = value & 0x03; 508 509 prev_normal_operation = BX_FD_THIS s.DOR & 0x04; 510 BX_FD_THIS s.DOR = value; 511 512 if (prev_normal_operation==0 && normal_operation) { 513 // transition from RESET to NORMAL 514 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 250, 0); 515 } else if (prev_normal_operation && normal_operation==0) { 516 // transition from NORMAL to RESET 517 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 518 BX_FD_THIS s.pending_command = 0xfe; // RESET pending 519 } 520 BX_DEBUG(("io_write: digital output register")); 521 BX_DEBUG((" motor on, drive1 = %d", motor_on_drive1 > 0)); 522 BX_DEBUG((" motor on, drive0 = %d", motor_on_drive0 > 0)); 523 BX_DEBUG((" dma_and_interrupt_enable=%02x", 524 (unsigned) dma_and_interrupt_enable)); 525 BX_DEBUG((" normal_operation=%02x", 526 (unsigned) normal_operation)); 527 BX_DEBUG((" drive_select=%02x", 528 (unsigned) drive_select)); 529 if (BX_FD_THIS s.device_type[drive_select] == FDRIVE_NONE) { 530 BX_DEBUG(("WARNING: non existing drive selected")); 531 } 532 break; 533 534 case 0x3f4: /* diskette controller data rate select register */ 535 BX_FD_THIS s.data_rate = value & 0x03; 536 if (value & 0x80) { 537 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 538 BX_FD_THIS s.pending_command = 0xfe; // RESET pending 539 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 250, 0); 540 } 541 if ((value & 0x7c) > 0) { 542 BX_ERROR(("write to data rate select register: unsupported bits set")); 543 } 544 break; 545 546 case 0x3F5: /* diskette controller data */ 547 BX_DEBUG(("command = 0x%02x", (unsigned) value)); 548 if ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) && ((BX_FD_THIS s.pending_command & 0x4f) == 0x45)) { 549 BX_FD_THIS dma_read((Bit8u *) &value); 550 BX_FD_THIS lower_interrupt(); 551 break; 552 } else if (BX_FD_THIS s.command_complete) { 553 if (BX_FD_THIS s.pending_command != 0) 554 BX_PANIC(("write 0x03f5: receiving new command 0x%02x, old one (0x%02x) pending", 555 value, BX_FD_THIS s.pending_command)); 556 BX_FD_THIS s.command[0] = value; 557 BX_FD_THIS s.command_complete = 0; 558 BX_FD_THIS s.command_index = 1; 559 /* read/write command in progress */ 560 BX_FD_THIS s.main_status_reg &= ~FD_MS_DIO; // leave drive status untouched 561 BX_FD_THIS s.main_status_reg |= FD_MS_MRQ | FD_MS_BUSY; 562 switch (value) { 563 case 0x03: /* specify */ 564 BX_FD_THIS s.command_size = 3; 565 break; 566 case 0x04: // get status 567 BX_FD_THIS s.command_size = 2; 568 break; 569 case 0x07: /* recalibrate */ 570 BX_FD_THIS s.command_size = 2; 571 break; 572 case 0x08: /* sense interrupt status */ 573 BX_FD_THIS s.command_size = 1; 574 break; 575 case 0x0f: /* seek */ 576 BX_FD_THIS s.command_size = 3; 577 break; 578 case 0x4a: /* read ID */ 579 BX_FD_THIS s.command_size = 2; 580 break; 581 case 0x4d: /* format track */ 582 BX_FD_THIS s.command_size = 6; 583 break; 584 case 0x45: 585 case 0xc5: /* write normal data */ 586 BX_FD_THIS s.command_size = 9; 587 break; 588 case 0x46: 589 case 0x66: 590 case 0xc6: 591 case 0xe6: /* read normal data */ 592 BX_FD_THIS s.command_size = 9; 593 break; 594 595 case 0x0e: // dump registers (Enhanced drives) 596 case 0x10: // Version command, enhanced controller returns 0x90 597 case 0x14: // Unlock command (Enhanced) 598 case 0x94: // Lock command (Enhanced) 599 BX_FD_THIS s.command_size = 0; 600 BX_FD_THIS s.pending_command = value; 601 enter_result_phase(); 602 break; 603 case 0x12: // Perpendicular mode (Enhanced) 604 BX_FD_THIS s.command_size = 2; 605 break; 606 case 0x13: // Configure command (Enhanced) 607 BX_FD_THIS s.command_size = 4; 608 break; 609 610 case 0x18: // National Semiconductor version command; return 80h 611 // These commands are not implemented on the standard 612 // controller and return an error. They are available on 613 // the enhanced controller. 614 BX_DEBUG(("io_write: 0x3f5: unsupported floppy command 0x%02x", 615 (unsigned) value)); 616 BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command 617 BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command 618 enter_result_phase(); 619 break; 620 621 default: 622 BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x", 623 (unsigned) value)); 624 BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command 625 BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command 626 enter_result_phase(); 627 break; 628 } 629 } else { 630 BX_FD_THIS s.command[BX_FD_THIS s.command_index++] = 631 value; 632 } 633 if (BX_FD_THIS s.command_index == 634 BX_FD_THIS s.command_size) { 635 /* read/write command not in progress any more */ 636 floppy_command(); 637 BX_FD_THIS s.command_complete = 1; 638 } 639 BX_DEBUG(("io_write: diskette controller data")); 640 return; 641 break; 642 #endif // #if BX_DMA_FLOPPY_IO 643 644 case 0x3F6: /* diskette controller (reserved) */ 645 BX_DEBUG(("io_write: reserved register 0x3f6 unsupported")); 646 // this address shared with the hard drive controller 647 DEV_hd_write_handler(bx_devices.pluginHardDrive, address, value, io_len); 648 break; 649 650 #if BX_DMA_FLOPPY_IO 651 case 0x3F7: /* diskette controller configuration control register */ 652 if ((value & 0x03) != BX_FD_THIS s.data_rate) 653 BX_INFO(("io_write: config control register: 0x%02x", value)); 654 BX_FD_THIS s.data_rate = value & 0x03; 655 switch (BX_FD_THIS s.data_rate) { 656 case 0: BX_DEBUG((" 500 Kbps")); break; 657 case 1: BX_DEBUG((" 300 Kbps")); break; 658 case 2: BX_DEBUG((" 250 Kbps")); break; 659 case 3: BX_DEBUG((" 1 Mbps")); break; 660 } 661 break; 662 663 default: 664 BX_ERROR(("io_write ignored: 0x%04x = 0x%02x", (unsigned) address, (unsigned) value)); 665 break; 666 #endif // #if BX_DMA_FLOPPY_IO 667 } 668 } 669 670 void bx_floppy_ctrl_c::floppy_command(void) 671 { 672 #if BX_PROVIDE_CPU_MEMORY==0 673 BX_PANIC(("floppy_command(): uses DMA: not supported for" 674 " external environment")); 675 #else 676 unsigned i; 677 Bit8u motor_on; 678 Bit8u head, drive, cylinder, sector, eot; 679 Bit8u sector_size, data_length; 680 Bit32u logical_sector, sector_time, step_delay; 681 682 // Print command 683 char buf[9+(9*5)+1], *p = buf; 684 p += sprintf(p, "COMMAND: "); 685 for (i=0; i<BX_FD_THIS s.command_size; i++) { 686 p += sprintf(p, "[%02x] ", (unsigned) BX_FD_THIS s.command[i]); 687 } 688 BX_DEBUG((buf)); 689 690 BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0]; 691 switch (BX_FD_THIS s.pending_command) { 692 case 0x03: // specify 693 // execution: specified parameters are loaded 694 // result: no result bytes, no interrupt 695 BX_FD_THIS s.SRT = BX_FD_THIS s.command[1] >> 4; 696 BX_FD_THIS s.HUT = BX_FD_THIS s.command[1] & 0x0f; 697 BX_FD_THIS s.HLT = BX_FD_THIS s.command[2] >> 1; 698 BX_FD_THIS s.main_status_reg |= (BX_FD_THIS s.command[2] & 0x01) ? FD_MS_NDMA : 0; 699 if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) 700 BX_ERROR(("non DMA mode not fully implemented yet")); 701 enter_idle_phase(); 702 return; 703 704 case 0x04: // get status 705 drive = (BX_FD_THIS s.command[1] & 0x03); 706 BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01; 707 BX_FD_THIS s.status_reg3 = 0x28 | (BX_FD_THIS s.head[drive]<<2) | drive 708 | (BX_FD_THIS s.media[drive].write_protected ? 0x40 : 0x00); 709 if ((BX_FD_THIS s.device_type[drive] != FDRIVE_NONE) && 710 (BX_FD_THIS s.cylinder[drive] == 0)) 711 BX_FD_THIS s.status_reg3 |= 0x10; 712 enter_result_phase(); 713 return; 714 715 case 0x07: // recalibrate 716 drive = (BX_FD_THIS s.command[1] & 0x03); 717 BX_FD_THIS s.DOR &= 0xfc; 718 BX_FD_THIS s.DOR |= drive; 719 BX_DEBUG(("floppy_command(): recalibrate drive %u", 720 (unsigned) drive)); 721 step_delay = calculate_step_delay(drive, 0); 722 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, step_delay, 0); 723 /* command head to track 0 724 * controller set to non-busy 725 * error condition noted in Status reg 0's equipment check bit 726 * seek end bit set to 1 in Status reg 0 regardless of outcome 727 * The last two are taken care of in timer(). 728 */ 729 BX_FD_THIS s.cylinder[drive] = 0; 730 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 731 BX_FD_THIS s.main_status_reg |= (1 << drive); 732 return; 733 734 case 0x08: /* sense interrupt status */ 735 /* execution: 736 * get status 737 * result: 738 * no interupt 739 * byte0 = status reg0 740 * byte1 = current cylinder number (0 to 79) 741 */ 742 if (BX_FD_THIS s.reset_sensei > 0) { 743 drive = 4 - BX_FD_THIS s.reset_sensei; 744 BX_FD_THIS s.status_reg0 &= 0xf8; 745 BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2) | drive; 746 BX_FD_THIS s.reset_sensei--; 747 } else if (!BX_FD_THIS s.pending_irq) { 748 BX_FD_THIS s.status_reg0 = 0x80; 749 } 750 BX_DEBUG(("sense interrupt status")); 751 enter_result_phase(); 752 return; 753 754 case 0x0f: /* seek */ 755 /* command: 756 * byte0 = 0F 757 * byte1 = drive & head select 758 * byte2 = cylinder number 759 * execution: 760 * postion head over specified cylinder 761 * result: 762 * no result bytes, issues an interrupt 763 */ 764 drive = BX_FD_THIS s.command[1] & 0x03; 765 BX_FD_THIS s.DOR &= 0xfc; 766 BX_FD_THIS s.DOR |= drive; 767 768 BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01; 769 step_delay = calculate_step_delay(drive, BX_FD_THIS s.command[2]); 770 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, step_delay, 0); 771 /* ??? should also check cylinder validity */ 772 BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.command[2]; 773 /* data reg not ready, drive not busy */ 774 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 775 BX_FD_THIS s.main_status_reg |= (1 << drive); 776 return; 777 778 case 0x13: // Configure 779 BX_DEBUG(("configure (eis = 0x%02x)", BX_FD_THIS s.command[2] & 0x40)); 780 BX_DEBUG(("configure (efifo = 0x%02x)", BX_FD_THIS s.command[2] & 0x20)); 781 BX_DEBUG(("configure (no poll = 0x%02x)", BX_FD_THIS s.command[2] & 0x10)); 782 BX_DEBUG(("configure (fifothr = 0x%02x)", BX_FD_THIS s.command[2] & 0x0f)); 783 BX_DEBUG(("configure (pretrk = 0x%02x)", BX_FD_THIS s.command[3])); 784 BX_FD_THIS s.config = BX_FD_THIS s.command[2]; 785 BX_FD_THIS s.pretrk = BX_FD_THIS s.command[3]; 786 enter_idle_phase(); 787 return; 788 789 case 0x4a: // read ID 790 drive = BX_FD_THIS s.command[1] & 0x03; 791 BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01; 792 BX_FD_THIS s.DOR &= 0xfc; 793 BX_FD_THIS s.DOR |= drive; 794 795 motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01; 796 if (motor_on == 0) { 797 BX_ERROR(("floppy_command(): read ID: motor not on")); 798 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 799 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 800 return; // Hang controller 801 } 802 if (BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) { 803 BX_ERROR(("floppy_command(): read ID: bad drive #%d", drive)); 804 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 805 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 806 return; // Hang controller 807 } 808 if (BX_FD_THIS s.media_present[drive] == 0) { 809 BX_INFO(("attempt to read sector ID with media not present")); 810 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 811 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 812 return; // Hang controller 813 } 814 BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive; 815 // time to read one sector at 300 rpm 816 sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; 817 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, sector_time, 0); 818 /* data reg not ready, controller busy */ 819 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 820 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 821 return; 822 823 case 0x4d: // format track 824 drive = BX_FD_THIS s.command[1] & 0x03; 825 BX_FD_THIS s.DOR &= 0xfc; 826 BX_FD_THIS s.DOR |= drive; 827 828 motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01; 829 if (motor_on == 0) 830 BX_PANIC(("floppy_command(): format track: motor not on")); 831 BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01; 832 sector_size = BX_FD_THIS s.command[2]; 833 BX_FD_THIS s.format_count = BX_FD_THIS s.command[3]; 834 BX_FD_THIS s.format_fillbyte = BX_FD_THIS s.command[5]; 835 if (BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) 836 BX_PANIC(("floppy_command(): format track: bad drive #%d", drive)); 837 838 if (sector_size != 0x02) { // 512 bytes 839 BX_PANIC(("format track: sector size %d not supported", 128<<sector_size)); 840 } 841 if (BX_FD_THIS s.format_count != BX_FD_THIS s.media[drive].sectors_per_track) { 842 BX_PANIC(("format track: %d sectors/track requested (%d expected)", 843 BX_FD_THIS s.format_count, BX_FD_THIS s.media[drive].sectors_per_track)); 844 } 845 if (BX_FD_THIS s.media_present[drive] == 0) { 846 BX_INFO(("attempt to format track with media not present")); 847 return; // Hang controller 848 } 849 if (BX_FD_THIS s.media[drive].write_protected) { 850 // media write-protected, return error 851 BX_INFO(("attempt to format track with media write-protected")); 852 BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination 853 BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111 854 BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001 855 enter_result_phase(); 856 return; 857 } 858 859 /* 4 header bytes per sector are required */ 860 BX_FD_THIS s.format_count <<= 2; 861 862 if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) { 863 BX_DEBUG(("non-DMA floppy format unimplemented")); 864 } else { 865 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); 866 } 867 /* data reg not ready, controller busy */ 868 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 869 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 870 BX_DEBUG(("format track")); 871 return; 872 873 case 0x46: // read normal data, MT=0, SK=0 874 case 0x66: // read normal data, MT=0, SK=1 875 case 0xc6: // read normal data, MT=1, SK=0 876 case 0xe6: // read normal data, MT=1, SK=1 877 case 0x45: // write normal data, MT=0 878 case 0xc5: // write normal data, MT=1 879 BX_FD_THIS s.multi_track = (BX_FD_THIS s.command[0] >> 7); 880 if ((BX_FD_THIS s.DOR & 0x08) == 0) 881 BX_PANIC(("read/write command with DMA and int disabled")); 882 drive = BX_FD_THIS s.command[1] & 0x03; 883 BX_FD_THIS s.DOR &= 0xfc; 884 BX_FD_THIS s.DOR |= drive; 885 886 motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01; 887 if (motor_on == 0) 888 BX_PANIC(("floppy_command(): read/write: motor not on")); 889 head = BX_FD_THIS s.command[3] & 0x01; 890 cylinder = BX_FD_THIS s.command[2]; /* 0..79 depending */ 891 sector = BX_FD_THIS s.command[4]; /* 1..36 depending */ 892 eot = BX_FD_THIS s.command[6]; /* 1..36 depending */ 893 sector_size = BX_FD_THIS s.command[5]; 894 data_length = BX_FD_THIS s.command[8]; 895 BX_DEBUG(("read/write normal data")); 896 BX_DEBUG(("BEFORE")); 897 BX_DEBUG((" drive = %u", (unsigned) drive)); 898 BX_DEBUG((" head = %u", (unsigned) head)); 899 BX_DEBUG((" cylinder = %u", (unsigned) cylinder)); 900 BX_DEBUG((" sector = %u", (unsigned) sector)); 901 BX_DEBUG((" eot = %u", (unsigned) eot)); 902 if (BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) 903 BX_PANIC(("floppy_command(): read/write: bad drive #%d", drive)); 904 905 // check that head number in command[1] bit two matches the head 906 // reported in the head number field. Real floppy drives are 907 // picky about this, as reported in SF bug #439945, (Floppy drive 908 // read input error checking). 909 if (head != ((BX_FD_THIS s.command[1]>>2)&1)) { 910 BX_ERROR(("head number in command[1] doesn't match head field")); 911 BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination 912 BX_FD_THIS s.status_reg1 = 0x04; // 0000 0100 913 BX_FD_THIS s.status_reg2 = 0x00; // 0000 0000 914 enter_result_phase(); 915 return; 916 } 917 918 if (BX_FD_THIS s.media_present[drive] == 0) { 919 BX_INFO(("attempt to read/write sector %u with media not present", (unsigned) sector)); 920 return; // Hang controller 921 } 922 923 if (sector_size != 0x02) { // 512 bytes 924 BX_PANIC(("read/write command: sector size %d not supported", 128<<sector_size)); 925 } 926 927 if (cylinder >= BX_FD_THIS s.media[drive].tracks) { 928 BX_PANIC(("io: norm r/w parms out of range: sec#%02xh cyl#%02xh eot#%02xh head#%02xh", 929 (unsigned) sector, (unsigned) cylinder, (unsigned) eot, 930 (unsigned) head)); 931 return; 932 } 933 934 if (sector > BX_FD_THIS s.media[drive].sectors_per_track) { 935 BX_INFO(("attempt to read/write sector %u past last sector %u", 936 (unsigned) sector, 937 (unsigned) BX_FD_THIS s.media[drive].sectors_per_track)); 938 BX_FD_THIS s.cylinder[drive] = cylinder; 939 BX_FD_THIS s.head[drive] = head; 940 BX_FD_THIS s.sector[drive] = sector; 941 942 BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; 943 BX_FD_THIS s.status_reg1 = 0x04; 944 BX_FD_THIS s.status_reg2 = 0x00; 945 enter_result_phase(); 946 return; 947 } 948 949 if (cylinder != BX_FD_THIS s.cylinder[drive]) { 950 BX_DEBUG(("io: cylinder request != current cylinder")); 951 reset_changeline(); 952 } 953 954 logical_sector = (cylinder * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) + 955 (head * BX_FD_THIS s.media[drive].sectors_per_track) + 956 (sector - 1); 957 958 if (logical_sector >= BX_FD_THIS s.media[drive].sectors) { 959 BX_PANIC(("io: logical sector out of bounds")); 960 } 961 // This hack makes older versions of the Bochs BIOS work 962 if (eot == 0) { 963 eot = BX_FD_THIS s.media[drive].sectors_per_track; 964 } 965 BX_FD_THIS s.cylinder[drive] = cylinder; 966 BX_FD_THIS s.head[drive] = head; 967 BX_FD_THIS s.sector[drive] = sector; 968 BX_FD_THIS s.eot[drive] = eot; 969 970 if ((BX_FD_THIS s.command[0] & 0x4f) == 0x46) { // read 971 floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 972 512, FROM_FLOPPY); 973 /* controller busy; if DMA mode, data reg not ready */ 974 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 975 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 976 if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) { 977 BX_FD_THIS s.main_status_reg |= (FD_MS_MRQ | FD_MS_DIO); 978 } 979 // time to read one sector at 300 rpm 980 sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; 981 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 982 sector_time , 0); 983 } else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write 984 /* controller busy; if DMA mode, data reg not ready */ 985 BX_FD_THIS s.main_status_reg &= FD_MS_NDMA; 986 BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; 987 if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) { 988 BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; 989 } else { 990 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); 991 } 992 } else { 993 BX_PANIC(("floppy_command(): unknown read/write command")); 994 return; 995 } 996 break; 997 998 case 0x12: // Perpendicular mode 999 BX_FD_THIS s.perp_mode = BX_FD_THIS s.command[1]; 1000 BX_INFO(("perpendicular mode: config=0x%02x", BX_FD_THIS s.perp_mode)); 1001 enter_idle_phase(); 1002 break; 1003 1004 default: // invalid or unsupported command; these are captured in write() above 1005 BX_PANIC(("You should never get here! cmd = 0x%02x", 1006 BX_FD_THIS s.command[0])); 1007 } 1008 #endif 1009 } 1010 1011 void bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, 1012 Bit32u bytes, Bit8u direction) 1013 { 1014 int ret = 0; 1015 1016 if (BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) 1017 BX_PANIC(("floppy_xfer: bad drive #%d", drive)); 1018 1019 BX_DEBUG(("floppy_xfer: drive=%u, offset=%u, bytes=%u, direction=%s floppy", 1020 drive, offset, bytes, (direction==FROM_FLOPPY)? "from" : "to")); 1021 1022 #if BX_WITH_MACOS 1023 if (strcmp(SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), SuperDrive)) 1024 #endif 1025 { 1026 // don't need to seek the file if we are using Win95 type direct access 1027 if (!BX_FD_THIS s.media[drive].raw_floppy_win95) { 1028 ret = (int)lseek(BX_FD_THIS s.media[drive].fd, offset, SEEK_SET); 1029 if (ret < 0) { 1030 BX_PANIC(("could not perform lseek() to %d on floppy image file", offset)); 1031 return; 1032 } 1033 } 1034 } 1035 1036 if (direction == FROM_FLOPPY) { 1037 #if BX_WITH_MACOS 1038 if (!strcmp(SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), SuperDrive)) 1039 ret = fd_read((char *) buffer, offset, bytes); 1040 else 1041 #endif 1042 #ifdef WIN32 1043 // if using Win95 direct access 1044 if (BX_FD_THIS s.media[drive].raw_floppy_win95) { 1045 DWORD ret_cnt = 0; 1046 DIOC_REGISTERS reg; 1047 HANDLE hFile = CreateFile("\\\\.\\vwin32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL); 1048 if (hFile == INVALID_HANDLE_VALUE) 1049 BX_PANIC(("Could not open floppy device under Win95 for read")); 1050 reg.reg_ECX = bytes >> 9; // / 512 1051 reg.reg_EDX = offset >> 9; // / 512 1052 reg.reg_EBX = (DWORD) buffer; 1053 reg.reg_EAX = BX_FD_THIS s.media[drive].raw_floppy_win95_drv; 1054 DeviceIoControl(hFile, VWIN32_DIOC_DOS_INT25, 1055 &reg, sizeof(reg), &reg, sizeof(reg), &ret_cnt, NULL); 1056 CloseHandle(hFile); 1057 // I don't know why this returns 28 instead of 512, but it works 1058 if (ret_cnt == 28) 1059 ret = 512; 1060 } else { 1061 #endif 1062 ret = ::read(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes); 1063 #ifdef WIN32 1064 } 1065 #endif 1066 if (ret < int(bytes)) { 1067 /* ??? */ 1068 if (ret > 0) { 1069 BX_INFO(("partial read() on floppy image returns %u/%u", 1070 (unsigned) ret, (unsigned) bytes)); 1071 memset(buffer + ret, 0, bytes - ret); 1072 } 1073 else { 1074 BX_INFO(("read() on floppy image returns 0")); 1075 memset(buffer, 0, bytes); 1076 } 1077 } 1078 } 1079 1080 else { // TO_FLOPPY 1081 BX_ASSERT (!BX_FD_THIS s.media[drive].write_protected); 1082 #if BX_WITH_MACOS 1083 if (!strcmp(SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), SuperDrive)) 1084 ret = fd_write((char *) buffer, offset, bytes); 1085 else 1086 #endif 1087 #ifdef WIN32 1088 // if using Win95 direct access 1089 if (BX_FD_THIS s.media[drive].raw_floppy_win95) { 1090 DWORD ret_cnt = 0; 1091 DIOC_REGISTERS reg; 1092 HANDLE hFile = CreateFile("\\\\.\\vwin32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL); 1093 if (hFile == INVALID_HANDLE_VALUE) 1094 BX_PANIC(("Could not open floppy device under Win95")); 1095 reg.reg_ECX = bytes >> 9; // / 512 1096 reg.reg_EDX = offset >> 9; // / 512 1097 reg.reg_EBX = (DWORD) buffer; 1098 reg.reg_EAX = BX_FD_THIS s.media[drive].raw_floppy_win95_drv; 1099 DeviceIoControl(hFile, VWIN32_DIOC_DOS_INT26, 1100 &reg, sizeof(reg), &reg, sizeof(reg), (LPDWORD) &ret_cnt, NULL); 1101 CloseHandle(hFile); 1102 // I don't know why this returns 28 instead of 512, but it works 1103 if (ret_cnt == 28) 1104 ret = 512; 1105 } else { 1106 #endif 1107 ret = ::write(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes); 1108 #ifdef WIN32 1109 } 1110 #endif 1111 if (ret < int(bytes)) { 1112 BX_PANIC(("could not perform write() on floppy image file")); 1113 } 1114 } 1115 } 1116 1117 void bx_floppy_ctrl_c::timer_handler(void *this_ptr) 1118 { 1119 bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr; 1120 class_ptr->timer(); 1121 } 1122 1123 void bx_floppy_ctrl_c::timer() 1124 { 1125 Bit8u drive, motor_on; 1126 1127 drive = BX_FD_THIS s.DOR & 0x03; 1128 switch (BX_FD_THIS s.pending_command) { 1129 case 0x07: // recal 1130 BX_FD_THIS s.status_reg0 = 0x20 | drive; 1131 motor_on = ((BX_FD_THIS s.DOR>>(drive+4)) & 0x01); 1132 if ((BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) || (motor_on == 0)) { 1133 BX_FD_THIS s.status_reg0 |= 0x50; 1134 } 1135 enter_idle_phase(); 1136 BX_FD_THIS raise_interrupt(); 1137 break; 1138 1139 case 0x0f: // seek 1140 BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive]<<2) | drive; 1141 enter_idle_phase(); 1142 BX_FD_THIS raise_interrupt(); 1143 break; 1144 1145 case 0x4a: /* read ID */ 1146 enter_result_phase(); 1147 break; 1148 1149 case 0x45: /* write normal data */ 1150 case 0xc5: 1151 if (BX_FD_THIS s.TC) { // Terminal Count line, done 1152 BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive; 1153 BX_FD_THIS s.status_reg1 = 0; 1154 BX_FD_THIS s.status_reg2 = 0; 1155 1156 BX_DEBUG(("<<WRITE DONE>>")); 1157 BX_DEBUG(("AFTER")); 1158 BX_DEBUG((" drive = %u", drive)); 1159 BX_DEBUG((" head = %u", BX_FD_THIS s.head[drive])); 1160 BX_DEBUG((" cylinder = %u", BX_FD_THIS s.cylinder[drive])); 1161 BX_DEBUG((" sector = %u", BX_FD_THIS s.sector[drive])); 1162 1163 enter_result_phase(); 1164 } else { 1165 // transfer next sector 1166 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 1167 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); 1168 } 1169 } 1170 break; 1171 1172 case 0x46: /* read normal data */ 1173 case 0x66: 1174 case 0xc6: 1175 case 0xe6: 1176 // transfer next sector 1177 if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) { 1178 BX_FD_THIS s.main_status_reg &= ~FD_MS_BUSY; // clear busy bit 1179 BX_FD_THIS s.main_status_reg |= FD_MS_MRQ | FD_MS_DIO; // data byte waiting 1180 } else { 1181 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); 1182 } 1183 break; 1184 1185 case 0x4d: /* format track */ 1186 if ((BX_FD_THIS s.format_count == 0) || BX_FD_THIS s.TC) { 1187 BX_FD_THIS s.format_count = 0; 1188 BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive; 1189 enter_result_phase(); 1190 } else { 1191 // transfer next sector 1192 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 1193 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); 1194 } 1195 } 1196 break; 1197 1198 case 0xfe: // (contrived) RESET 1199 theFloppyController->reset(BX_RESET_SOFTWARE); 1200 BX_FD_THIS s.pending_command = 0; 1201 BX_FD_THIS s.status_reg0 = 0xc0; 1202 BX_FD_THIS raise_interrupt(); 1203 BX_FD_THIS s.reset_sensei = 4; 1204 break; 1205 1206 case 0x00: // nothing pending? 1207 break; 1208 1209 default: 1210 BX_PANIC(("floppy:timer(): unknown case %02x", 1211 (unsigned) BX_FD_THIS s.pending_command)); 1212 } 1213 } 1214 1215 void bx_floppy_ctrl_c::dma_write(Bit8u *data_byte) 1216 { 1217 // A DMA write is from I/O to Memory 1218 // We need to return the next data byte from the floppy buffer 1219 // to be transfered via the DMA to memory. (read block from floppy) 1220 1221 Bit8u drive; 1222 1223 drive = BX_FD_THIS s.DOR & 0x03; 1224 *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++]; 1225 1226 BX_FD_THIS s.TC = get_tc(); 1227 if ((BX_FD_THIS s.floppy_buffer_index >= 512) || (BX_FD_THIS s.TC)) { 1228 1229 if (BX_FD_THIS s.floppy_buffer_index >= 512) { 1230 increment_sector(); // increment to next sector before retrieving next one 1231 BX_FD_THIS s.floppy_buffer_index = 0; 1232 } 1233 if (BX_FD_THIS s.TC) { // Terminal Count line, done 1234 BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive; 1235 BX_FD_THIS s.status_reg1 = 0; 1236 BX_FD_THIS s.status_reg2 = 0; 1237 1238 BX_DEBUG(("<<READ DONE>>")); 1239 BX_DEBUG(("AFTER")); 1240 BX_DEBUG((" drive = %u", drive)); 1241 BX_DEBUG((" head = %u", BX_FD_THIS s.head[drive])); 1242 BX_DEBUG((" cylinder = %u", BX_FD_THIS s.cylinder[drive])); 1243 BX_DEBUG((" sector = %u", BX_FD_THIS s.sector[drive])); 1244 1245 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 1246 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); 1247 } 1248 enter_result_phase(); 1249 } else { // more data to transfer 1250 Bit32u logical_sector, sector_time; 1251 1252 // remember that not all floppies have two sides, multiply by s.head[drive] 1253 logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * 1254 BX_FD_THIS s.media[drive].sectors_per_track) + 1255 (BX_FD_THIS s.head[drive] * 1256 BX_FD_THIS s.media[drive].sectors_per_track) + 1257 (BX_FD_THIS s.sector[drive] - 1); 1258 1259 floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 1260 512, FROM_FLOPPY); 1261 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 1262 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); 1263 } 1264 // time to read one sector at 300 rpm 1265 sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; 1266 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 1267 sector_time , 0); 1268 } 1269 } 1270 } 1271 1272 void bx_floppy_ctrl_c::dma_read(Bit8u *data_byte) 1273 { 1274 // A DMA read is from Memory to I/O 1275 // We need to write the data_byte which was already transfered from memory 1276 // via DMA to I/O (write block to floppy) 1277 1278 Bit8u drive; 1279 Bit32u logical_sector, sector_time; 1280 1281 drive = BX_FD_THIS s.DOR & 0x03; 1282 if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress 1283 BX_FD_THIS s.format_count--; 1284 switch (3 - (BX_FD_THIS s.format_count & 0x03)) { 1285 case 0: 1286 BX_FD_THIS s.cylinder[drive] = *data_byte; 1287 break; 1288 case 1: 1289 if (*data_byte != BX_FD_THIS s.head[drive]) 1290 BX_ERROR(("head number does not match head field")); 1291 break; 1292 case 2: 1293 BX_FD_THIS s.sector[drive] = *data_byte; 1294 break; 1295 case 3: 1296 if (*data_byte != 2) BX_ERROR(("dma_read: sector size %d not supported", 128<<(*data_byte))); 1297 BX_DEBUG(("formatting cylinder %u head %u sector %u", 1298 BX_FD_THIS s.cylinder[drive], BX_FD_THIS s.head[drive], 1299 BX_FD_THIS s.sector[drive])); 1300 for (unsigned i = 0; i < 512; i++) { 1301 BX_FD_THIS s.floppy_buffer[i] = BX_FD_THIS s.format_fillbyte; 1302 } 1303 logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) + 1304 (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) + 1305 (BX_FD_THIS s.sector[drive] - 1); 1306 floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 1307 512, TO_FLOPPY); 1308 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 1309 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); 1310 } 1311 // time to write one sector at 300 rpm 1312 sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; 1313 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 1314 sector_time , 0); 1315 break; 1316 } 1317 } else { // write normal data 1318 BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte; 1319 1320 BX_FD_THIS s.TC = get_tc(); 1321 if ((BX_FD_THIS s.floppy_buffer_index >= 512) || (BX_FD_THIS s.TC)) { 1322 logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) + 1323 (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) + 1324 (BX_FD_THIS s.sector[drive] - 1); 1325 if (BX_FD_THIS s.media[drive].write_protected) { 1326 // write protected error 1327 BX_INFO(("tried to write disk %u, which is write-protected", drive)); 1328 // ST0: IC1,0=01 (abnormal termination: started execution but failed) 1329 BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; 1330 // ST1: DataError=1, NDAT=1, NotWritable=1, NID=1 1331 BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111 1332 // ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1. 1333 BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001 1334 enter_result_phase(); 1335 return; 1336 } 1337 floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 1338 512, TO_FLOPPY); 1339 increment_sector(); // increment to next sector after writing current one 1340 BX_FD_THIS s.floppy_buffer_index = 0; 1341 if (!(BX_FD_THIS s.main_status_reg & FD_MS_NDMA)) { 1342 DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); 1343 } 1344 // time to write one sector at 300 rpm 1345 sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; 1346 bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 1347 sector_time , 0); 1348 // the following is a kludge; i (jc) don't know how to work with the timer 1349 if ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) && BX_FD_THIS s.TC) { 1350 enter_result_phase(); 1351 } 1352 } 1353 } 1354 } 1355 1356 void bx_floppy_ctrl_c::raise_interrupt(void) 1357 { 1358 DEV_pic_raise_irq(6); 1359 BX_FD_THIS s.pending_irq = 1; 1360 BX_FD_THIS s.reset_sensei = 0; 1361 } 1362 1363 void bx_floppy_ctrl_c::lower_interrupt(void) 1364 { 1365 if (BX_FD_THIS s.pending_irq) { 1366 DEV_pic_lower_irq(6); 1367 BX_FD_THIS s.pending_irq = 0; 1368 } 1369 } 1370 1371 void bx_floppy_ctrl_c::increment_sector(void) 1372 { 1373 Bit8u drive; 1374 1375 drive = BX_FD_THIS s.DOR & 0x03; 1376 1377 // values after completion of data xfer 1378 // ??? calculation depends on base_count being multiple of 512 1379 BX_FD_THIS s.sector[drive] ++; 1380 if ((BX_FD_THIS s.sector[drive] > BX_FD_THIS s.eot[drive]) || 1381 (BX_FD_THIS s.sector[drive] > BX_FD_THIS s.media[drive].sectors_per_track)) { 1382 BX_FD_THIS s.sector[drive] = 1; 1383 if (BX_FD_THIS s.multi_track) { 1384 BX_FD_THIS s.head[drive] ++; 1385 if (BX_FD_THIS s.head[drive] > 1) { 1386 BX_FD_THIS s.head[drive] = 0; 1387 BX_FD_THIS s.cylinder[drive] ++; 1388 reset_changeline(); 1389 } 1390 } else { 1391 BX_FD_THIS s.cylinder[drive] ++; 1392 reset_changeline(); 1393 } 1394 if (BX_FD_THIS s.cylinder[drive] >= BX_FD_THIS s.media[drive].tracks) { 1395 // Set to 1 past last possible cylinder value. 1396 // I notice if I set it to tracks-1, prama linux won't boot. 1397 BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.media[drive].tracks; 1398 BX_INFO(("increment_sector: clamping cylinder to max")); 1399 } 1400 } 1401 } 1402 1403 unsigned bx_floppy_ctrl_c::set_media_status(unsigned drive, unsigned status) 1404 { 1405 char *path; 1406 unsigned type; 1407 1408 if (drive == 0) 1409 type = SIM->get_param_enum(BXPN_FLOPPYA_TYPE)->get(); 1410 else 1411 type = SIM->get_param_enum(BXPN_FLOPPYB_TYPE)->get(); 1412 1413 // if setting to the current value, nothing to do 1414 if ((status == BX_FD_THIS s.media_present[drive]) && 1415 ((status == 0) || (type == BX_FD_THIS s.media[drive].type))) 1416 return(status); 1417 1418 if (status == 0) { 1419 // eject floppy 1420 if (BX_FD_THIS s.media[drive].fd >= 0) { 1421 close(BX_FD_THIS s.media[drive].fd); 1422 BX_FD_THIS s.media[drive].fd = -1; 1423 } 1424 BX_FD_THIS s.media_present[drive] = 0; 1425 if (drive == 0) { 1426 SIM->get_param_bool(BXPN_FLOPPYA_STATUS)->set(0); 1427 } else { 1428 SIM->get_param_bool(BXPN_FLOPPYB_STATUS)->set(0); 1429 } 1430 BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line 1431 return(0); 1432 } else { 1433 // insert floppy 1434 if (drive == 0) { 1435 path = SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(); 1436 } else { 1437 path = SIM->get_param_string(BXPN_FLOPPYB_PATH)->getptr(); 1438 } 1439 if (!strcmp(path, "none")) 1440 return(0); 1441 if (evaluate_media(BX_FD_THIS s.device_type[drive], type, path, & BX_FD_THIS s.media[drive])) { 1442 BX_FD_THIS s.media_present[drive] = 1; 1443 if (drive == 0) { 1444 #define MED (BX_FD_THIS s.media[0]) 1445 BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), 1446 MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track)); 1447 #undef MED 1448 SIM->get_param_bool(BXPN_FLOPPYA_STATUS)->set(1); 1449 } else { 1450 #define MED (BX_FD_THIS s.media[1]) 1451 BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", SIM->get_param_string(BXPN_FLOPPYB_PATH)->getptr(), 1452 MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track)); 1453 #undef MED 1454 SIM->get_param_bool(BXPN_FLOPPYB_STATUS)->set(1); 1455 } 1456 return(1); 1457 } else { 1458 BX_FD_THIS s.media_present[drive] = 0; 1459 if (drive == 0) { 1460 SIM->get_param_bool(BXPN_FLOPPYA_STATUS)->set(0); 1461 SIM->get_param_enum(BXPN_FLOPPYA_TYPE)->set(BX_FLOPPY_NONE); 1462 } else { 1463 SIM->get_param_bool(BXPN_FLOPPYB_STATUS)->set(0); 1464 SIM->get_param_enum(BXPN_FLOPPYB_TYPE)->set(BX_FLOPPY_NONE); 1465 } 1466 return(0); 1467 } 1468 } 1469 } 1470 1471 unsigned bx_floppy_ctrl_c::get_media_status(unsigned drive) 1472 { 1473 return BX_FD_THIS s.media_present[drive]; 1474 } 1475 1476 #ifdef O_BINARY 1477 #define BX_RDONLY O_RDONLY | O_BINARY 1478 #define BX_RDWR O_RDWR | O_BINARY 1479 #else 1480 #define BX_RDONLY O_RDONLY 1481 #define BX_RDWR O_RDWR 1482 #endif 1483 1484 bx_bool bx_floppy_ctrl_c::evaluate_media(Bit8u devtype, Bit8u type, char *path, floppy_t *media) 1485 { 1486 struct stat stat_buf; 1487 int i, ret; 1488 int type_idx = -1; 1489 #ifdef __linux__ 1490 struct floppy_struct floppy_geom; 1491 #endif 1492 #ifdef WIN32 1493 char sTemp[1024]; 1494 bx_bool raw_floppy = 0; 1495 HANDLE hFile; 1496 DWORD bytes; 1497 DISK_GEOMETRY dg; 1498 unsigned tracks = 0, heads = 0, spt = 0; 1499 #endif 1500 1501 //If media file is already open, close it before reopening. 1502 if(media->fd >=0) { 1503 close(media->fd); 1504 media->fd=-1; 1505 } 1506 1507 // check media type 1508 if (type == BX_FLOPPY_NONE) { 1509 return 0; 1510 } 1511 for (i = 0; i < 8; i++) { 1512 if (type == floppy_type[i].id) type_idx = i; 1513 } 1514 if (type_idx == -1) { 1515 BX_ERROR(("evaluate_media: unknown media type %d", type)); 1516 return 0; 1517 } 1518 if ((floppy_type[type_idx].drive_mask & devtype) == 0) { 1519 BX_ERROR(("evaluate_media: media type %d not valid for this floppy drive", type)); 1520 return 0; 1521 } 1522 1523 // open media file (image file or device) 1524 media->write_protected = 0; 1525 media->raw_floppy_win95 = 0; 1526 #ifdef macintosh 1527 media->fd = 0; 1528 if (strcmp(SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), SuperDrive)) 1529 #endif 1530 #ifdef WIN32 1531 if ((isalpha(path[0])) && (path[1] == ':') && (strlen(path) == 2)) { 1532 raw_floppy = 1; 1533 wsprintf(sTemp, "\\\\.\\%s", path); 1534 hFile = CreateFile(sTemp, GENERIC_READ, FILE_SHARE_WRITE, NULL, 1535 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 1536 if (hFile == INVALID_HANDLE_VALUE) { 1537 // try to open it with Win95 style 1538 hFile = CreateFile("\\\\.\\vwin32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL); 1539 if (hFile == INVALID_HANDLE_VALUE) { 1540 BX_ERROR(("Cannot open floppy drive")); 1541 return(0); 1542 } 1543 media->raw_floppy_win95 = 1; 1544 media->raw_floppy_win95_drv = toupper(path[0]) - 'A'; 1545 } 1546 // if using Win95 direct access, get params this way 1547 if (media->raw_floppy_win95) { 1548 DWORD ret_cnt = 0; 1549 DIOC_REGISTERS reg; 1550 BLOCK_DEV_PARAMS params; 1551 reg.reg_EAX = 0x440D; 1552 reg.reg_ECX = 0x0860; 1553 reg.reg_EDX = (DWORD) &params; 1554 reg.reg_EBX = media->raw_floppy_win95_drv+1; 1555 //reg.reg_Flags = 0x0001; // assume error (carry flag is set) 1556 if (DeviceIoControl(hFile, VWIN32_DIOC_DOS_IOCTL , 1557 &reg, sizeof(reg), &reg, sizeof(reg), &ret_cnt, NULL)) { 1558 tracks = params.cylinders; 1559 heads = params.num_heads; 1560 spt = params.sects_per_track; 1561 } else { 1562 CloseHandle(hFile); 1563 return(0); 1564 } 1565 } else { 1566 if (!DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytes, NULL)) { 1567 BX_ERROR(("No media in floppy drive")); 1568 CloseHandle(hFile); 1569 return(0); 1570 } else { 1571 tracks = (unsigned)dg.Cylinders.QuadPart; 1572 heads = (unsigned)dg.TracksPerCylinder; 1573 spt = (unsigned)dg.SectorsPerTrack; 1574 } 1575 } 1576 CloseHandle(hFile); 1577 // if using Win95 direct access, don't open the file 1578 if (!media->raw_floppy_win95) 1579 media->fd = open(sTemp, BX_RDWR); 1580 } else { 1581 media->fd = open(path, BX_RDWR); 1582 } 1583 #else 1584 media->fd = open(path, BX_RDWR); 1585 #endif 1586 1587 // Don't open the handle if using Win95 style direct access 1588 if (!media->raw_floppy_win95) { 1589 if (media->fd < 0) { 1590 BX_INFO(("tried to open '%s' read/write: %s",path,strerror(errno))); 1591 // try opening the file read-only 1592 media->write_protected = 1; 1593 #ifdef macintosh 1594 media->fd = 0; 1595 if (strcmp(SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), SuperDrive)) 1596 #endif 1597 #ifdef WIN32 1598 if (raw_floppy == 1) { 1599 media->fd = open(sTemp, BX_RDONLY); 1600 } else { 1601 media->fd = open(path, BX_RDONLY); 1602 } 1603 #else 1604 media->fd = open(path, BX_RDONLY); 1605 #endif 1606 if (media->fd < 0) { 1607 // failed to open read-only too 1608 BX_INFO(("tried to open '%s' read only: %s",path,strerror(errno))); 1609 media->type = type; 1610 return(0); 1611 } 1612 } 1613 } 1614 1615 #if BX_WITH_MACOS 1616 if (!strcmp(SIM->get_param_string(BXPN_FLOPPYA_PATH)->getptr(), SuperDrive)) 1617 ret = fd_stat(&stat_buf); 1618 else 1619 ret = fstat(media->fd, &stat_buf); 1620 #elif defined(WIN32) 1621 if (raw_floppy) { 1622 memset (&stat_buf, 0, sizeof(stat_buf)); 1623 stat_buf.st_mode = S_IFCHR; 1624 ret = 0; 1625 } else { 1626 ret = fstat(media->fd, &stat_buf); 1627 } 1628 #else 1629 // unix 1630 ret = fstat(media->fd, &stat_buf); 1631 #endif 1632 if (ret) { 1633 BX_PANIC(("fstat floppy 0 drive image file returns error: %s", strerror(errno))); 1634 return(0); 1635 } 1636 1637 if (S_ISREG(stat_buf.st_mode)) { 1638 // regular file 1639 switch (type) { 1640 // use CMOS reserved types 1641 case BX_FLOPPY_160K: // 160K 5.25" 1642 case BX_FLOPPY_180K: // 180K 5.25" 1643 case BX_FLOPPY_320K: // 320K 5.25" 1644 // standard floppy types 1645 case BX_FLOPPY_360K: // 360K 5.25" 1646 case BX_FLOPPY_720K: // 720K 3.5" 1647 case BX_FLOPPY_1_2: // 1.2M 5.25" 1648 case BX_FLOPPY_2_88: // 2.88M 3.5" 1649 media->type = type; 1650 media->tracks = floppy_type[type_idx].trk; 1651 media->heads = floppy_type[type_idx].hd; 1652 media->sectors_per_track = floppy_type[type_idx].spt; 1653 media->sectors = floppy_type[type_idx].sectors; 1654 if (stat_buf.st_size > (media->sectors * 512)) { 1655 BX_ERROR(("evaluate_media: size of file '%s' (%lu) too large for selected type", 1656 path, (unsigned long) stat_buf.st_size)); 1657 return 0; 1658 } 1659 break; 1660 default: // 1.44M 3.5" 1661 media->type = type; 1662 if (stat_buf.st_size <= 1474560) { 1663 media->tracks = floppy_type[type_idx].trk; 1664 media->heads = floppy_type[type_idx].hd; 1665 media->sectors_per_track = floppy_type[type_idx].spt; 1666 } 1667 else if (stat_buf.st_size == 1720320) 1668 { 1669 media->sectors_per_track = 21; 1670 media->tracks = 80; 1671 media->heads = 2; 1672 } 1673 else if (stat_buf.st_size == 1763328) 1674 { 1675 media->sectors_per_track = 21; 1676 media->tracks = 82; 1677 media->heads = 2; 1678 } 1679 else if (stat_buf.st_size == 1884160) 1680 { 1681 media->sectors_per_track = 23; 1682 media->tracks = 80; 1683 media->heads = 2; 1684 } 1685 else 1686 { 1687 BX_ERROR(("evaluate_media: file '%s' of unknown size %lu", 1688 path, (unsigned long) stat_buf.st_size)); 1689 return 0; 1690 } 1691 media->sectors = media->heads * media->tracks * media->sectors_per_track; 1692 } 1693 return (media->sectors > 0); // success 1694 } 1695 1696 else if (S_ISCHR(stat_buf.st_mode) 1697 #if BX_WITH_MACOS == 0 1698 #ifdef S_ISBLK 1699 || S_ISBLK(stat_buf.st_mode) 1700 #endif 1701 #endif 1702 ) { 1703 // character or block device 1704 // assume media is formatted to typical geometry for drive 1705 media->type = type; 1706 #ifdef __linux__ 1707 if (ioctl(media->fd, FDGETPRM, &floppy_geom) < 0) { 1708 BX_ERROR(("cannot determine media geometry, trying to use defaults")); 1709 media->tracks = floppy_type[type_idx].trk; 1710 media->heads = floppy_type[type_idx].hd; 1711 media->sectors_per_track = floppy_type[type_idx].spt; 1712 media->sectors = floppy_type[type_idx].sectors; 1713 return (media->sectors > 0); 1714 } 1715 media->tracks = floppy_geom.track; 1716 media->heads = floppy_geom.head; 1717 media->sectors_per_track = floppy_geom.sect; 1718 media->sectors = floppy_geom.size; 1719 #elif defined(WIN32) 1720 media->tracks = tracks; 1721 media->heads = heads; 1722 media->sectors_per_track = spt; 1723 media->sectors = media->heads * media->tracks * media->sectors_per_track; 1724 #else 1725 media->tracks = floppy_type[type_idx].trk; 1726 media->heads = floppy_type[type_idx].hd; 1727 media->sectors_per_track = floppy_type[type_idx].spt; 1728 media->sectors = floppy_type[type_idx].sectors; 1729 #endif 1730 return (media->sectors > 0); // success 1731 } else { 1732 // unknown file type 1733 BX_ERROR(("unknown mode type")); 1734 return 0; 1735 } 1736 } 1737 1738 void bx_floppy_ctrl_c::enter_result_phase(void) 1739 { 1740 Bit8u drive; 1741 unsigned i; 1742 1743 drive = BX_FD_THIS s.DOR & 0x03; 1744 1745 /* these are always the same */ 1746 BX_FD_THIS s.result_index = 0; 1747 // not necessary to clear any status bits, we're about to set them all 1748 BX_FD_THIS s.main_status_reg |= FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; 1749 1750 /* invalid command */ 1751 if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x80) { 1752 BX_FD_THIS s.result_size = 1; 1753 BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; 1754 return; 1755 } 1756 1757 switch (BX_FD_THIS s.pending_command) { 1758 case 0x04: // get status 1759 BX_FD_THIS s.result_size = 1; 1760 BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg3; 1761 break; 1762 case 0x08: // sense interrupt 1763 BX_FD_THIS s.result_size = 2; 1764 BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; 1765 BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive]; 1766 break; 1767 case 0x0e: // dump registers 1768 BX_FD_THIS s.result_size = 10; 1769 for (i = 0; i < 4; i++) { 1770 BX_FD_THIS s.result[i] = BX_FD_THIS s.cylinder[i]; 1771 } 1772 BX_FD_THIS s.result[4] = (BX_FD_THIS s.SRT << 4) | BX_FD_THIS s.HUT; 1773 BX_FD_THIS s.result[5] = (BX_FD_THIS s.HLT << 1) | ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) ? 1 : 0); 1774 BX_FD_THIS s.result[6] = BX_FD_THIS s.eot[drive]; 1775 BX_FD_THIS s.result[7] = (BX_FD_THIS s.lock << 7) | (BX_FD_THIS s.perp_mode & 0x7f); 1776 BX_FD_THIS s.result[8] = BX_FD_THIS s.config; 1777 BX_FD_THIS s.result[9] = BX_FD_THIS s.pretrk; 1778 break; 1779 case 0x10: // version 1780 BX_FD_THIS s.result_size = 1; 1781 BX_FD_THIS s.result[0] = 0x90; 1782 break; 1783 case 0x14: // unlock 1784 case 0x94: // lock 1785 BX_FD_THIS s.lock = (BX_FD_THIS s.pending_command >> 7); 1786 BX_FD_THIS s.result_size = 1; 1787 BX_FD_THIS s.result[0] = (BX_FD_THIS s.lock << 4); 1788 break; 1789 case 0x4a: // read ID 1790 case 0x4d: // format track 1791 case 0x46: // read normal data 1792 case 0x66: 1793 case 0xc6: 1794 case 0xe6: 1795 case 0x45: // write normal data 1796 case 0xc5: 1797 BX_FD_THIS s.result_size = 7; 1798 BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; 1799 BX_FD_THIS s.result[1] = BX_FD_THIS s.status_reg1; 1800 BX_FD_THIS s.result[2] = BX_FD_THIS s.status_reg2; 1801 BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive]; 1802 BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive]; 1803 BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive]; 1804 BX_FD_THIS s.result[6] = 2; /* sector size code */ 1805 BX_FD_THIS raise_interrupt(); 1806 break; 1807 } 1808 1809 // Print command result (max. 10 bytes) 1810 char buf[8+(10*5)+1], *p = buf; 1811 p += sprintf(p, "RESULT: "); 1812 for (i=0; i<BX_FD_THIS s.result_size; i++) { 1813 p += sprintf(p, "[%02x] ", (unsigned) BX_FD_THIS s.result[i]); 1814 } 1815 BX_DEBUG((buf)); 1816 } 1817 1818 void bx_floppy_ctrl_c::enter_idle_phase(void) 1819 { 1820 BX_FD_THIS s.main_status_reg &= (FD_MS_NDMA | 0x0f); // leave drive status untouched 1821 BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready 1822 1823 BX_FD_THIS s.command_complete = 1; /* waiting for new command */ 1824 BX_FD_THIS s.command_index = 0; 1825 BX_FD_THIS s.command_size = 0; 1826 BX_FD_THIS s.pending_command = 0; 1827 1828 BX_FD_THIS s.floppy_buffer_index = 0; 1829 } 1830 1831 Bit32u bx_floppy_ctrl_c::calculate_step_delay(Bit8u drive, Bit8u new_cylinder) 1832 { 1833 Bit8u steps; 1834 Bit32u one_step_delay; 1835 1836 if (new_cylinder == BX_FD_THIS s.cylinder[drive]) { 1837 steps = 1; 1838 } else { 1839 steps = abs(new_cylinder - BX_FD_THIS s.cylinder[drive]); 1840 reset_changeline(); 1841 } 1842 one_step_delay = ((BX_FD_THIS s.SRT ^ 0x0f) + 1) * 500000 / drate_in_k[BX_FD_THIS s.data_rate]; 1843 return (steps * one_step_delay); 1844 } 1845 1846 void bx_floppy_ctrl_c::reset_changeline(void) 1847 { 1848 Bit8u drive = BX_FD_THIS s.DOR & 0x03; 1849 if (BX_FD_THIS s.media_present[drive]) 1850 BX_FD_THIS s.DIR[drive] &= ~0x80; 1851 } 1852 1853 bx_bool bx_floppy_ctrl_c::get_tc(void) 1854 { 1855 Bit8u drive; 1856 bx_bool terminal_count; 1857 if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) { 1858 drive = BX_FD_THIS s.DOR & 0x03; 1859 /* figure out if we've sent all the data, in non-DMA mode... 1860 * the drive stays on the same cylinder for a read or write, so that's 1861 * not going to be an issue. EOT stands for the last sector to be I/Od. 1862 * it does all the head 0 sectors first, then the second if any. 1863 * now, regarding reaching the end of the sector: 1864 * == 512 would make it more precise, allowing one to spot bugs... 1865 * >= 512 makes it more robust, but allows for sloppy code... 1866 * pick your poison? 1867 * note: byte and head are 0-based; eot, sector, and heads are 1-based. */ 1868 terminal_count = ((BX_FD_THIS s.floppy_buffer_index == 512) && 1869 (BX_FD_THIS s.sector[drive] == BX_FD_THIS s.eot[drive]) && 1870 (BX_FD_THIS s.head[drive] == (BX_FD_THIS s.media[drive].heads - 1))); 1871 } else { 1872 terminal_count = DEV_dma_get_tc(); 1873 } 1874 return terminal_count; 1875 } 1876

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.