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

Bochs x86 Emulator
bochs/iodev/floppy.cc

Version: ~ [ SVN-2014-01-05 ] ~ [ 2.6.2 ] ~

** Warning: Cannot open xref database.

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

~ [ 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.