- 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
This commit is contained in:
Volker Ruppert 2001-12-27 09:30:31 +00:00
parent 84f0593409
commit 328bd4fb84

View File

@ -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);