From 328bd4fb84f152e996aec92fa331447c0c31b58f Mon Sep 17 00:00:00 2001 From: Volker Ruppert Date: Thu, 27 Dec 2001 09:30:31 +0000 Subject: [PATCH] - fixed the behaviour of some floppy commands (Windows 95 driver works now) * diskette controller data register returns last result if no new data is available * reset will be activated when the reset bit is changed to normal operation * reset sets the error bits in status register 0 * write access to port 0x3f4 will cause a BX_ERROR now * unsupported and invalid floppy commands are setting the error status bit 'invalid command' - BX_PANIC not necessary * flag FS_MS_DIO is not set while a floppy command is pending * floppy command 'specify': cause a BX_ERROR when non-DMA mode is selected * floppy command 'sense interrupt status' returns an error is no interrupt is pending * floppy command 'read ID' sets the 'busy' flag and returns no data if the motor is not on * removed SIMX86 section (not defined in bochs) * define variable 'sTemp' for win32 only --- bochs/iodev/floppy.cc | 167 ++++++++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 70 deletions(-) diff --git a/bochs/iodev/floppy.cc b/bochs/iodev/floppy.cc index 6a95cc354..5952eb5b8 100644 --- a/bochs/iodev/floppy.cc +++ b/bochs/iodev/floppy.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: floppy.cc,v 1.26 2001-10-07 03:28:45 bdenney Exp $ +// $Id: floppy.cc,v 1.27 2001-12-27 09:30:31 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001 MandrakeSoft S.A. @@ -87,7 +87,7 @@ bx_floppy_ctrl_c::~bx_floppy_ctrl_c(void) void bx_floppy_ctrl_c::init(bx_devices_c *d, bx_cmos_c *cmos) { - BX_DEBUG(("Init $Id: floppy.cc,v 1.26 2001-10-07 03:28:45 bdenney Exp $")); + BX_DEBUG(("Init $Id: floppy.cc,v 1.27 2001-12-27 09:30:31 vruppert Exp $")); BX_FD_THIS devices = d; BX_FD_THIS devices->register_irq(6, "Floppy Drive"); @@ -132,7 +132,7 @@ bx_floppy_ctrl_c::init(bx_devices_c *d, bx_cmos_c *cmos) cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0x0f) | 0x50; break; default: - BX_PANIC(( "unknown floppya type" )); + BX_PANIC(("unknown floppya type")); } if (bx_options.floppya.Otype->get () != BX_FLOPPY_NONE) { @@ -226,6 +226,8 @@ bx_floppy_ctrl_c::reset(unsigned source) BX_FD_THIS s.command_size = 0; BX_FD_THIS s.pending_command = 0; + BX_FD_THIS s.pending_irq = 0; + BX_FD_THIS s.result_index = 0; BX_FD_THIS s.result_size = 0; @@ -307,13 +309,17 @@ bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len) case 0x3F5: /* diskette controller data */ if (BX_FD_THIS s.result_size == 0) { - BX_PANIC(("diskette controller:port3f5: no results to read")); + BX_ERROR(("port 0x3f5: no results to read")); + BX_FD_THIS s.main_status_reg = 0; + return BX_FD_THIS s.result[0]; } value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++]; + BX_FD_THIS s.main_status_reg &= 0xF0; if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) { BX_FD_THIS s.result_size = 0; BX_FD_THIS s.result_index = 0; + BX_FD_THIS s.result[0] = value; BX_FD_THIS s.main_status_reg = FD_MS_MRQ; } return(value); @@ -399,22 +405,14 @@ bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len) if (prev_normal_operation==0 && normal_operation) { // transition from RESET to NORMAL -#if 0 - - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; - BX_FD_THIS s.pending_command = 0xfe; // RESET pending - bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, bx_options.Ofloppy_command_delay->get (), 0 ); -#endif } else if (prev_normal_operation && normal_operation==0) { // transition from NORMAL to RESET BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = 0xfe; // RESET pending - bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, - bx_options.Ofloppy_command_delay->get (), 0 ); } BX_DEBUG(("io_write: digital output register")); BX_DEBUG((" motor on, drive1 = %d", motor_on_drive1 > 0)); @@ -431,7 +429,7 @@ bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len) break; case 0x3f4: /* diskette controller data rate select register */ - BX_PANIC(("io_write: data rate select register")); + BX_ERROR(("io_write: data rate select register unsupported")); break; case 0x3F5: /* diskette controller data */ @@ -457,8 +455,6 @@ bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len) break; case 0x08: /* sense interrupt status */ BX_FD_THIS s.command_size = 1; - floppy_command(); - BX_FD_THIS s.command_complete = 1; break; case 0x0f: /* seek */ BX_FD_THIS s.command_size = 3; @@ -483,29 +479,29 @@ bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len) // These commands are not implemented on the standard // controller and return an error. They are available on // the enhanced controller. + BX_DEBUG(("io_write: 0x3f5: unsupported floppy command 0x%02x", + (unsigned) value)); BX_FD_THIS s.command_size = 1; - BX_FD_THIS s.result[0] = 0x80; - BX_FD_THIS s.result_size = 1; - BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; - BX_FD_THIS s.command_complete = 1; + BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command break; default: - BX_PANIC(("io write:3f5: unsupported case 0x%02x", + BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x", (unsigned) value)); + BX_FD_THIS s.command_size = 1; + BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command break; } } else { BX_FD_THIS s.command[BX_FD_THIS s.command_index++] = value; - if (BX_FD_THIS s.command_index == - BX_FD_THIS s.command_size) { - /* read/write command not in progress any more */ - floppy_command(); - BX_FD_THIS s.command_complete = 1; - } + } + if (BX_FD_THIS s.command_index == + BX_FD_THIS s.command_size) { + /* read/write command not in progress any more */ + floppy_command(); + BX_FD_THIS s.command_complete = 1; } BX_DEBUG(("io_write: diskette controller data")); return; @@ -568,12 +564,13 @@ bx_floppy_ctrl_c::floppy_command(void) switch (BX_FD_THIS s.command[0]) { case 0x03: // specify -//BX_INFO(("floppy_command specify")); // execution: specified parameters are loaded // result: no result bytes, no interrupt step_rate_time = BX_FD_THIS s.command[1] >> 4; head_unload_time = BX_FD_THIS s.command[1] & 0x0f; head_load_time = BX_FD_THIS s.command[2] >> 1; + if (BX_FD_THIS s.command[2] & 0x01) + BX_ERROR(("non DMA mode selected")); BX_FD_THIS s.main_status_reg = FD_MS_MRQ; return; break; @@ -589,7 +586,6 @@ bx_floppy_ctrl_c::floppy_command(void) break; case 0x07: // recalibrate -//BX_INFO(("floppy_command recalibrate")); drive = (BX_FD_THIS s.command[1] & 0x03); BX_FD_THIS s.DOR &= 0xfc; BX_FD_THIS s.DOR |= drive; @@ -616,13 +612,12 @@ bx_floppy_ctrl_c::floppy_command(void) * seek end bit set to 1 in Status reg 0 regardless of outcome */ /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = 0x07; // recalibrate pending return; break; case 0x08: /* sense interrupt status */ -//BX_INFO(("floppy_command sense interrupt status")); /* execution: * get status * result: @@ -630,21 +625,27 @@ bx_floppy_ctrl_c::floppy_command(void) * byte0 = status reg0 * byte1 = current cylinder number (0 to 79) */ - /*BX_FD_THIS s.status_reg0 = ;*/ drive = BX_FD_THIS s.DOR & 0x03; - BX_FD_THIS s.result[0] = 0x20 | drive; + if (BX_FD_THIS s.pending_irq) { + BX_FD_THIS s.pending_irq = 0; + } + else { + BX_FD_THIS s.status_reg0 = 0x80; + } + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive]; BX_FD_THIS s.result_size = 2; BX_FD_THIS s.result_index = 0; + BX_FD_THIS s.status_reg0 = 0; /* read ready */ - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg &= 0x0f; + BX_FD_THIS s.main_status_reg |= (FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY); BX_DEBUG(("sense interrupt status")); return; break; case 0x0f: /* seek */ -//BX_INFO(("floppy_command seek")); /* command: * byte0 = 0F * byte1 = drive & head select @@ -666,7 +667,7 @@ bx_floppy_ctrl_c::floppy_command(void) bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, bx_options.Ofloppy_command_delay->get (), 0 ); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = 0x0f; /* seek pending */ return; break; @@ -682,38 +683,38 @@ bx_floppy_ctrl_c::floppy_command(void) break; case 0x4a: // read ID -//BX_INFO(("floppy_command read ID")); // ??? drive = BX_FD_THIS s.command[1] & 0x03; BX_FD_THIS s.DOR &= 0xfc; BX_FD_THIS s.DOR |= drive; motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01; - if (motor_on == 0) - BX_PANIC(("floppy_command(): 4a: motor not on")); + if (motor_on == 0) { + BX_ERROR(("floppy_command(): 0x4a: motor not on")); + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + return; + } if (drive > 1) BX_PANIC(("io: 4a: bad drive #")); BX_FD_THIS s.result_size = 7; BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.result[0] = 0; /* ??? */ - BX_FD_THIS s.result[1] = 0; - BX_FD_THIS s.result[2] = 0; + // setting result[0] in timer handler + BX_FD_THIS s.result[1] = BX_FD_THIS s.status_reg1; + BX_FD_THIS s.result[2] = BX_FD_THIS s.status_reg2; BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive]; - BX_FD_THIS s.result[4] = 0; /* head */ - BX_FD_THIS s.result[5] = 0; /* sector at completion */ - BX_FD_THIS s.result[6] = 2; + BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive]; + BX_FD_THIS s.result[5] = 1; /* sector at completion */ + BX_FD_THIS s.result[6] = 2; // sector size code bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, bx_options.Ofloppy_command_delay->get (), 0 ); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = 0x4a; /* read ID pending */ return; break; case 0xe6: // read normal data -//BX_INFO(("floppy_command read normal data")); case 0xc5: // write normal data -//BX_INFO(("floppy_command write normal data")); if ( (BX_FD_THIS s.DOR & 0x08) == 0 ) BX_PANIC(("read/write command with DMA and int disabled")); drive = BX_FD_THIS s.command[1] & 0x03; @@ -749,7 +750,8 @@ bx_floppy_ctrl_c::floppy_command(void) BX_ERROR(("head number in command[1] doesn't match head field")); BX_FD_THIS s.result_size = 7; BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.result[0] = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination + BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; BX_FD_THIS s.result[1] = 0x04; // 0000 0100 BX_FD_THIS s.result[2] = 0x00; // 0000 0000 BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive]; @@ -760,6 +762,7 @@ bx_floppy_ctrl_c::floppy_command(void) BX_FD_THIS s.pending_command = 0; BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; return; } @@ -771,7 +774,8 @@ bx_floppy_ctrl_c::floppy_command(void) (unsigned) BX_FD_THIS s.media[drive].sectors_per_track)); BX_FD_THIS s.result_size = 7; BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.result[0] = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination + BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; BX_FD_THIS s.result[1] = 0x25; // 0010 0101 BX_FD_THIS s.result[2] = 0x31; // 0011 0001 BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive]; @@ -782,6 +786,7 @@ bx_floppy_ctrl_c::floppy_command(void) BX_FD_THIS s.pending_command = 0; BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; return; } @@ -810,7 +815,8 @@ bx_floppy_ctrl_c::floppy_command(void) BX_FD_THIS s.result_index = 0; // 0100 0HDD abnormal termination - BX_FD_THIS s.result[0] = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; + BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; // 1000 0101 end of cyl/NDAT/NID BX_FD_THIS s.result[1] = 0x86; // 0000 0000 @@ -823,7 +829,7 @@ bx_floppy_ctrl_c::floppy_command(void) bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, bx_options.Ofloppy_command_delay->get (), 0 ); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0]; return; } @@ -856,7 +862,7 @@ bx_floppy_ctrl_c::floppy_command(void) bx_pc_system.set_DRQ(FLOPPY_DMA_CHAN, 1); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0]; return; } @@ -866,7 +872,7 @@ bx_floppy_ctrl_c::floppy_command(void) bx_pc_system.set_DRQ(FLOPPY_DMA_CHAN, 1); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_BUSY; BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0]; return; } @@ -876,10 +882,13 @@ bx_floppy_ctrl_c::floppy_command(void) return; break; - default: - BX_PANIC(("floppy_command(): unknown function")); + default: // invalid or unsupported command + BX_FD_THIS s.result_size = 1; + BX_FD_THIS s.result_index = 0; + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; + BX_FD_THIS s.status_reg0 = 0; + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; } - BX_PANIC(("floppy_command()")); #endif } @@ -949,9 +958,6 @@ bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, void bx_floppy_ctrl_c::timer_handler(void *this_ptr) { -#if defined(SIMX86) - printf("Floppy timer"); -#endif bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr; @@ -961,38 +967,56 @@ bx_floppy_ctrl_c::timer_handler(void *this_ptr) void bx_floppy_ctrl_c::timer() { + Bit8u drive; + + drive = BX_FD_THIS s.DOR & 0x03; switch ( BX_FD_THIS s.pending_command ) { case 0x07: // recal BX_FD_THIS s.pending_command = 0; /* write ready, not busy */ - BX_FD_THIS s.main_status_reg = FD_MS_MRQ; + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | (1 << drive); + BX_FD_THIS s.status_reg0 = 0x20 | drive; BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; goto reset_changeline; break; case 0x0f: // seek BX_FD_THIS s.pending_command = 0; /* write ready, not busy */ - BX_FD_THIS s.main_status_reg = FD_MS_MRQ; + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | (1 << drive); + BX_FD_THIS s.status_reg0 = 0x20 | drive; BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; goto reset_changeline; break; - case 0x4a: /* read ID */ + BX_FD_THIS s.pending_command = 0; + /* read ready, busy */ + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO; + BX_FD_THIS s.status_reg0 = 0x20 | drive; + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; + BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; + break; + case 0xc5: // write normal data case 0xe6: // read normal data BX_FD_THIS s.pending_command = 0; /* read ready, busy */ - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO; + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | (1 << drive); + BX_FD_THIS s.status_reg0 = 0x20 | drive; BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; break; case 0xfe: // (contrived) RESET reset(BX_RESET_SOFTWARE); BX_FD_THIS s.pending_command = 0; - BX_FD_THIS s.main_status_reg = FD_MS_MRQ; + BX_FD_THIS s.status_reg0 = 0xc0; BX_FD_THIS devices->pic->trigger_irq(6); + BX_FD_THIS s.pending_irq = 1; break; default: @@ -1002,7 +1026,6 @@ bx_floppy_ctrl_c::timer() return; reset_changeline: - unsigned drive = BX_FD_THIS s.DOR & 0x3; if (drive > 1) return; if (BX_FD_THIS s.media_present[drive]) BX_FD_THIS s.DIR &= ~0x80; // clear disk change line @@ -1026,10 +1049,11 @@ bx_floppy_ctrl_c::dma_write(Bit8u *data_byte) BX_FD_THIS s.floppy_buffer_index = 0; if (bx_pc_system.TC) { // Terminal Count line, done BX_FD_THIS s.pending_command = 0; - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY | (1 << drive); BX_FD_THIS s.result_size = 7; BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.result[0] = (BX_FD_THIS s.head[drive] << 2) | drive; + BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive] << 2) | drive; + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; BX_FD_THIS s.result[1] = 0; BX_FD_THIS s.result[2] = 0; BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive]; @@ -1096,7 +1120,7 @@ bx_floppy_ctrl_c::dma_read(Bit8u *data_byte) BX_FD_THIS s.result[6] = 2; // sector size = 512 BX_FD_THIS s.pending_command = 0; - BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY | (1 << drive); BX_FD_THIS devices->pic->trigger_irq(6); return; } @@ -1109,7 +1133,8 @@ bx_floppy_ctrl_c::dma_read(Bit8u *data_byte) BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; BX_FD_THIS s.result_size = 7; BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.result[0] = (BX_FD_THIS s.head[drive] << 2) | drive; + BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive] << 2) | drive; + BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0; BX_FD_THIS s.result[1] = 0; BX_FD_THIS s.result[2] = 0; BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive]; @@ -1222,7 +1247,9 @@ bx_floppy_ctrl_c::evaluate_media(unsigned type, char *path, floppy_t *media) { struct stat stat_buf; int ret; +#if BX_WITH_WIN32 char sTemp[1024]; +#endif if (type == BX_FLOPPY_NONE) return(0);