Bochs/bochs/patches/patch.floppy-athiel
2002-11-08 20:44:09 +00:00

995 lines
36 KiB
Plaintext

----------------------------------------------------------------------
Patch name: patch.floppy-athiel
Author: Alex Thiel (uploaded by cbothamy)
Date: 8 Nov 2002
Detailed description:
The first part only does some cleanup and should not break anything. I have
only tested it with Linux as the guest OS though, so it would be nice if
someone could test it with some other OSes, especially Microsoft's.
The second part introduces the implicit termination of data transfer via
end-of-track and data overrun/underrun conditions, as well as non-DMA mode.
Patch was created with:
cvs diff -u
Apply patch to what version:
cvs checked out on 8 Nov 2002
Instructions:
To patch, go to main bochs directory.
Type "patch -p0 < THIS_PATCH_FILE".
----------------------------------------------------------------------
Index: iodev/floppy.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/floppy.cc,v
retrieving revision 1.57
diff -u -r1.57 floppy.cc
--- iodev/floppy.cc 25 Oct 2002 11:44:39 -0000 1.57
+++ iodev/floppy.cc 8 Nov 2002 20:28:40 -0000
@@ -61,6 +61,10 @@
#define FD_MS_ACTB 0x02
#define FD_MS_ACTA 0x01
+/* for status registers */
+#define FD_ST_EOT 0x80
+#define FD_ST_OVERRUN 0x10
+
#define FROM_FLOPPY 10
#define TO_FLOPPY 11
@@ -161,10 +165,10 @@
& BX_FD_THIS s.media[0]))
BX_FD_THIS s.media_present[0] = 1;
else
- bx_options.floppya.Ostatus->set(BX_EJECTED);
+ bx_options.floppya.Ostatus->set(BX_EJECTED);
#define MED (BX_FD_THIS s.media[0])
- BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
- MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+ BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
+ MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
#undef MED
}
}
@@ -212,15 +216,16 @@
& BX_FD_THIS s.media[1]))
BX_FD_THIS s.media_present[1] = 1;
else
- bx_options.floppyb.Ostatus->set(BX_EJECTED);
+ bx_options.floppyb.Ostatus->set(BX_EJECTED);
#define MED (BX_FD_THIS s.media[1])
- BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
- MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+ BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
+ MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
#undef MED
}
}
-
+#define FD_TIMEOUT 15 // for FIFO overrun/underrun
+#define FD_IRQ_DELAY 2 // delay so the system can detect a INT change
/* CMOS Equipment Byte register */
if (BX_FD_THIS s.num_supported_floppies > 0)
@@ -233,7 +238,7 @@
if (BX_FD_THIS s.floppy_timer_index == BX_NULL_TIMER_HANDLE) {
BX_FD_THIS s.floppy_timer_index =
bx_pc_system.register_timer( this, timer_handler,
- bx_options.Ofloppy_command_delay->get (), 0,0, "floppy");
+ bx_options.Ofloppy_command_delay->get (), 0,0, "floppy");
}
BX_DEBUG(("bx_options.Ofloppy_command_delay = %u",
@@ -247,19 +252,10 @@
{
Bit32u i;
- BX_FD_THIS s.command_complete = 1; /* waiting for new command */
- BX_FD_THIS s.command_index = 0;
- 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.reset_sensei = 0; /* no reset result present */
- BX_FD_THIS s.result_index = 0;
- BX_FD_THIS s.result_size = 0;
-
- /* data register ready, not in DMA mode */
- BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+ BX_FD_THIS s.main_status_reg = 0;
BX_FD_THIS s.status_reg0 = 0;
BX_FD_THIS s.status_reg1 = 0;
BX_FD_THIS s.status_reg2 = 0;
@@ -286,10 +282,9 @@
BX_FD_THIS s.sector[i] = 0;
}
- BX_FD_THIS s.floppy_buffer_index = 0;
-
DEV_pic_lower_irq(6);
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_idle_phase();
}
@@ -335,6 +330,20 @@
break;
case 0x3F5: /* diskette controller data */
+
+ /* data transfer in non-DMA mode */
+ if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) {
+ BX_FD_THIS dma_write(&value); // write: from controller to memory
+
+ /* This simulates the FIFO latency, see comment in timer() below. */
+ BX_FD_THIS lower_interrupt();
+ BX_FD_THIS s.main_status_reg &= ~FD_MS_MRQ;
+ // overrides the timer set in dma_write()
+ bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index,
+ FD_IRQ_DELAY, 0);
+ return(value);
+ }
+
if (BX_FD_THIS s.result_size == 0) {
BX_ERROR(("port 0x3f5: no results to read"));
BX_FD_THIS s.main_status_reg = 0;
@@ -344,12 +353,9 @@
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;
if (!BX_FD_THIS s.reset_sensei) BX_FD_THIS s.pending_irq = 0;
- DEV_pic_lower_irq(6);
+ DEV_pic_lower_irq(6);
+ enter_idle_phase();
}
return(value);
break;
@@ -360,12 +366,12 @@
switch( BX_FD_THIS s.DOR & 0x03 )
{
- case 0x00:
- if( (BX_FD_THIS s.DOR & 0x10) == 0) break;
- return(2);
- case 0x01:
- if( (BX_FD_THIS s.DOR & 0x20) == 0) break;
- return(1);
+ case 0x00:
+ if( (BX_FD_THIS s.DOR & 0x10) == 0) break;
+ return(2);
+ case 0x01:
+ if( (BX_FD_THIS s.DOR & 0x20) == 0) break;
+ return(1);
}
return(3);
@@ -469,6 +475,20 @@
break;
case 0x3F5: /* diskette controller data */
+
+ /* data transfer in non-DMA mode */
+ if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) {
+ BX_FD_THIS dma_read((Bit8u *) &value); // read: from memory to controller
+
+ /* This simulates the FIFO latency, see comment in timer() below. */
+ BX_FD_THIS lower_interrupt();
+ BX_FD_THIS s.main_status_reg &= ~FD_MS_MRQ;
+ // overrides the timer set in dma_read()
+ bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index,
+ FD_IRQ_DELAY, 0);
+ break;
+ }
+
BX_DEBUG(("command = %02x", (unsigned) value));
if (BX_FD_THIS s.command_complete) {
if (BX_FD_THIS s.pending_command!=0)
@@ -524,15 +544,17 @@
// 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.command_size = 0; // make sure we don't try to process this command
BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
+ enter_result_phase();
break;
default:
BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x",
(unsigned) value));
- BX_FD_THIS s.command_size = 1;
+ BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command
BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
+ enter_result_phase();
break;
}
}
@@ -600,33 +622,28 @@
for (i=0; i<BX_FD_THIS s.command_size; i++)
BX_DEBUG(("[%02x] ", (unsigned) BX_FD_THIS s.command[i]));
-#if 0
- /* execute phase of command is in progress (non DMA mode) */
- BX_FD_THIS s.main_status_reg |= 20;
-#endif
-
- switch (BX_FD_THIS s.command[0]) {
+ BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
+ switch (BX_FD_THIS s.pending_command) {
case 0x03: // 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;
+ BX_FD_THIS s.non_dma = BX_FD_THIS s.command[2] & 0x01;
+ if (BX_FD_THIS s.non_dma)
+ BX_INFO(("non DMA mode selected"));
+ enter_idle_phase();
return;
break;
case 0x04: // get status
drive = (BX_FD_THIS s.command[1] & 0x03);
BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
- BX_FD_THIS s.result[0] = 0x28 | (BX_FD_THIS s.head[drive]<<2) | drive
+ BX_FD_THIS s.status_reg3 = 0x28 | (BX_FD_THIS s.head[drive]<<2) | drive
| (BX_FD_THIS s.media[drive].write_protected ? 0x40 : 0x00);
- if (BX_FD_THIS s.cylinder[drive] == 0) BX_FD_THIS s.result[0] |= 0x10;
- 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;
+ if (BX_FD_THIS s.cylinder[drive] == 0) BX_FD_THIS s.status_reg3 |= 0x10;
+ enter_result_phase();
return;
break;
@@ -651,10 +668,10 @@
* controller set to non-busy
* error condition noted in Status reg 0's equipment check bit
* seek end bit set to 1 in Status reg 0 regardless of outcome
+ * The last two are taken care of in timer().
*/
- /* data reg not ready, drive busy */
+ BX_FD_THIS s.cylinder[drive] = 0;
BX_FD_THIS s.main_status_reg = (1 << drive);
- BX_FD_THIS s.pending_command = 0x07; // recalibrate pending
return;
break;
@@ -669,7 +686,6 @@
drive = BX_FD_THIS s.DOR & 0x03;
if (!BX_FD_THIS s.pending_irq) {
BX_FD_THIS s.status_reg0 = 0x80;
- BX_FD_THIS s.result_size = 1;
}
else {
if (BX_FD_THIS s.reset_sensei > 0) {
@@ -677,17 +693,11 @@
BX_FD_THIS s.status_reg0 &= 0xf8;
BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2) | drive;
BX_FD_THIS s.reset_sensei--;
- }
- BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
- BX_FD_THIS s.result_size = 2;
- }
- BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
- BX_FD_THIS s.result_index = 0;
-
- /* read ready */
- 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"));
+ enter_result_phase();
return;
break;
@@ -712,7 +722,6 @@
bx_options.Ofloppy_command_delay->get (), 0 );
/* data reg not ready, drive busy */
BX_FD_THIS s.main_status_reg = (1 << drive);
- BX_FD_THIS s.pending_command = 0x0f; /* seek pending */
return;
break;
@@ -722,10 +731,7 @@
BX_DEBUG(("configure (no poll = 0x%02x)", BX_FD_THIS s.command[2] & 0x10 ));
BX_DEBUG(("configure (fifothr = 0x%02x)", BX_FD_THIS s.command[2] & 0x0f ));
BX_DEBUG(("configure (pretrk = 0x%02x)", BX_FD_THIS s.command[3] ));
- BX_FD_THIS s.result_size = 0;
- BX_FD_THIS s.result_index = 0;
- BX_FD_THIS s.pending_command = 0;
- BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_BUSY;
+ enter_idle_phase();
return;
break;
@@ -743,20 +749,11 @@
}
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
BX_PANIC(("floppy_command(): read ID: bad drive #%d", drive));
- BX_FD_THIS s.result_size = 7;
- BX_FD_THIS s.result_index = 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] = 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_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive;
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_BUSY;
- BX_FD_THIS s.pending_command = 0x4a; /* read ID pending */
return;
break;
@@ -784,42 +781,34 @@
if ( BX_FD_THIS s.media_present[drive] == 0 ) {
// media not in drive, return error
BX_INFO(("attempt to format track with media not present"));
- BX_FD_THIS s.result_size = 7;
- BX_FD_THIS s.result_index = 0;
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
- // 4 result bytes are unused
- BX_FD_THIS s.pending_command = 0;
- BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
- raise_interrupt();
+ BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
return;
}
if (BX_FD_THIS s.media[drive].write_protected) {
// media write-protected, return error
BX_INFO(("attempt to format track with media write-protected"));
- BX_FD_THIS s.result_size = 7;
- BX_FD_THIS s.result_index = 0;
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] = 0x27; // 0010 0111
- BX_FD_THIS s.result[2] = 0x31; // 0011 0001
- // 4 result bytes are unused
- BX_FD_THIS s.pending_command = 0;
- BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
- raise_interrupt();
+ BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
return;
}
/* 4 header bytes per sector are required */
BX_FD_THIS s.format_count <<= 2;
- DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
-
- /* data reg not ready, controller busy */
- BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
- BX_FD_THIS s.pending_command = 0x4d; /* format track pending */
+ if (BX_FD_THIS s.non_dma) {
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_NDMA | FD_MS_BUSY;
+ BX_FD_THIS raise_interrupt();
+ }
+ else {
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+ }
BX_DEBUG(("format track"));
return;
break;
@@ -862,20 +851,10 @@
// read input error checking).
if (head != ((BX_FD_THIS s.command[1]>>2)&1)) {
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.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];
- BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
- BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
- 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;
- raise_interrupt();
+ BX_FD_THIS s.status_reg1 = 0x04; // 0000 0100
+ BX_FD_THIS s.status_reg2 = 0x00; // 0000 0000
+ enter_result_phase();
return;
}
@@ -885,20 +864,10 @@
BX_INFO(("attempt to read/write sector %u,"
" sectors/track=%u", (unsigned) sector,
(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.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];
- BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
- BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
- 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;
- raise_interrupt();
+ BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
return;
}
@@ -906,9 +875,9 @@
BX_PANIC(("sector_size not 512"));
}
if ( cylinder >= BX_FD_THIS s.media[drive].tracks ) {
- BX_PANIC(("io: norm r/w parms out of range: sec#%02xh cyl#%02xh eot#%02xh head#%02xh",
- (unsigned) sector, (unsigned) cylinder, (unsigned) eot,
- (unsigned) head));
+ BX_PANIC(("io: norm r/w parms out of range: sec#%02xh cyl#%02xh eot#%02xh head#%02xh",
+ (unsigned) sector, (unsigned) cylinder, (unsigned) eot,
+ (unsigned) head));
return;
}
@@ -923,34 +892,20 @@
BX_FD_THIS s.head[drive] = head;
BX_FD_THIS s.sector[drive] = BX_FD_THIS s.media[drive].sectors_per_track;
- BX_FD_THIS s.result_size = 7;
-
- BX_FD_THIS s.result_index = 0;
// 0100 0HDD abnormal termination
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] = 0x85;
+ BX_FD_THIS s.status_reg1 = 0x85;
// 0000 0000
- BX_FD_THIS s.result[2] = 0x00;
- BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
- BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
- BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
- BX_FD_THIS s.result[6] = 2; // sector size = 512
+ BX_FD_THIS s.status_reg2 = 0x00;
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_BUSY;
- BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
return;
}
-#if 0
- if (eot != BX_FD_THIS s.media[drive].sectors_per_track)
- BX_DEBUG(("io: bad eot #%02xh", (unsigned) eot));
-#endif
-
if (cylinder != BX_FD_THIS s.cylinder[drive])
BX_DEBUG(("io: cylinder request != current cylinder"));
@@ -969,24 +924,28 @@
if ((BX_FD_THIS s.command[0] & 0x4f) == 0x46) { // read
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
512, FROM_FLOPPY);
- BX_FD_THIS s.floppy_buffer_index = 0;
- DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
-
- /* data reg not ready, controller busy */
- BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
- BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
- return;
+ if (BX_FD_THIS s.non_dma) {
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_NDMA | FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS raise_interrupt();
+ }
+ else {
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+ }
}
else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write
- BX_FD_THIS s.floppy_buffer_index = 0;
-
- DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
- /* data reg not ready, controller busy */
- BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
- BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
- return;
+ if (BX_FD_THIS s.non_dma) {
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_NDMA | FD_MS_BUSY;
+ BX_FD_THIS raise_interrupt();
+ }
+ else {
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+ }
}
else
BX_PANIC(("floppy_command(): unknown read/write command"));
@@ -994,12 +953,9 @@
return;
break;
- 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;
+ default: // invalid or unsupported command; these are captured in write() above
+ BX_PANIC(("You should never get here! cmd = 0x%02x",
+ BX_FD_THIS s.command[0]));
}
#endif
}
@@ -1084,27 +1040,7 @@
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.cylinder[drive] = 0;
- BX_FD_THIS s.main_status_reg = FD_MS_MRQ | (1 << drive);
- BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive]<<2) | drive;
- if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE) {
- BX_FD_THIS s.status_reg0 |= 0x50;
- }
- else if (BX_FD_THIS s.media_present[drive] == 0) {
- BX_FD_THIS s.status_reg0 |= 0x40;
- BX_FD_THIS s.status_reg1 = 0x25;
- BX_FD_THIS s.status_reg2 = 0x31;
- }
- raise_interrupt();
- 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 | (1 << drive);
BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive]<<2) | drive;
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE) {
BX_FD_THIS s.status_reg0 |= 0x50;
@@ -1114,36 +1050,50 @@
BX_FD_THIS s.status_reg1 = 0x25;
BX_FD_THIS s.status_reg2 = 0x31;
}
- raise_interrupt();
- goto reset_changeline;
+
+ /* reset changeline */
+ if (drive > 1) return;
+ if (BX_FD_THIS s.media_present[drive])
+ BX_FD_THIS s.DIR[drive] &= ~0x80; // clear disk change line
+
+ enter_idle_phase();
+ BX_FD_THIS raise_interrupt();
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.result[0] = BX_FD_THIS s.status_reg0;
- raise_interrupt();
+ enter_result_phase();
break;
+ case 0x4d: // format track
case 0x46: // read normal data
- case 0x66:
+ case 0x66:
case 0xc6:
case 0xe6:
case 0x45: // write normal data
- case 0xc5:
- BX_FD_THIS s.pending_command = 0;
- /* read ready, busy */
- BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY | (1 << drive);
- BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive;
- raise_interrupt();
+ case 0xc5:
+ /* During non-DMA operation, the state of the FDC oscillates
+ between IRQ low/MRQ clear (set after data is transferred via 0x3f5)
+ and IRQ high/MRQ set.
+ Whenever the timer is triggered in DMA mode, or in non-DMA mode with
+ MRQ set, we have a data overrun/underrun. */
+ if ((BX_FD_THIS s.main_status_reg & (FD_MS_MRQ | FD_MS_NDMA))
+ == FD_MS_NDMA) { // NDMA & !MRQ
+ BX_FD_THIS raise_interrupt();
+ BX_FD_THIS s.main_status_reg |= FD_MS_MRQ;
+ bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index,
+ FD_TIMEOUT, 0 );
+ }
+ else { // timeout
+ BX_FD_THIS s.status_reg1 |= FD_ST_OVERRUN;
+ enter_result_phase();
+ }
break;
case 0xfe: // (contrived) RESET
theFloppyController->reset(BX_RESET_SOFTWARE);
BX_FD_THIS s.pending_command = 0;
BX_FD_THIS s.status_reg0 = 0xc0;
- raise_interrupt();
+ BX_FD_THIS raise_interrupt();
BX_FD_THIS s.reset_sensei = 4;
break;
@@ -1155,11 +1105,6 @@
(unsigned) BX_FD_THIS s.pending_command));
}
return;
-
-reset_changeline:
- if (drive > 1) return;
- if (BX_FD_THIS s.media_present[drive])
- BX_FD_THIS s.DIR[drive] &= ~0x80; // clear disk change line
}
void
@@ -1169,9 +1114,11 @@
// We need to return then next data byte from the floppy buffer
// to be transfered via the DMA to memory. (read block from floppy)
-
*data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
+ // reschedule timeout
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, FD_TIMEOUT, 0 );
+
if (BX_FD_THIS s.floppy_buffer_index >= 512) {
Bit8u drive;
@@ -1179,18 +1126,8 @@
increment_sector(); // increment to next sector before retrieving next one
BX_FD_THIS s.floppy_buffer_index = 0;
if (DEV_dma_get_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 | (1 << drive);
- BX_FD_THIS s.result_size = 7;
- BX_FD_THIS s.result_index = 0;
BX_FD_THIS s.status_reg0 = (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];
- BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
- BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
- BX_FD_THIS s.result[6] = 2;
+ BX_FD_THIS s.status_reg2 = 0;
if (bx_dbg.floppy) {
BX_INFO(("<<READ DONE>>"));
@@ -1201,8 +1138,8 @@
BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
}
- raise_interrupt();
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
}
else { // more data to transfer
Bit32u logical_sector;
@@ -1227,6 +1164,9 @@
Bit8u drive;
Bit32u logical_sector;
+ // reschedule timeout
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, FD_TIMEOUT, 0 );
+
drive = BX_FD_THIS s.DOR & 0x03;
if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
--BX_FD_THIS s.format_count;
@@ -1258,17 +1198,9 @@
}
if ((BX_FD_THIS s.format_count == 0) || (DEV_dma_get_tc())) {
BX_FD_THIS s.format_count = 0;
- BX_FD_THIS s.pending_command = 0;
- 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.status_reg0 = (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] = BX_FD_THIS s.status_reg1;
- BX_FD_THIS s.result[2] = BX_FD_THIS s.status_reg2;
- // 4 result bytes are unused
- raise_interrupt();
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
}
return;
}
@@ -1282,22 +1214,13 @@
if ( BX_FD_THIS s.media[drive].write_protected ) {
// write protected error
BX_INFO(("tried to write disk %u, which is write-protected", drive));
- BX_FD_THIS s.result_size = 7;
- BX_FD_THIS s.result_index = 0;
// ST0: IC1,0=01 (abnormal termination: started execution but failed)
- 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;
// ST1: DataError=1, NDAT=1, NotWritable=1, NID=1
- BX_FD_THIS s.result[1] = 0x27; // 0010 0111
+ BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
// ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
- BX_FD_THIS s.result[2] = 0x31; // 0011 0001
- BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
- BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
- BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
- 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 | (1 << drive);
- raise_interrupt();
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
return;
}
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
@@ -1305,18 +1228,9 @@
increment_sector(); // increment to next sector after writing current one
BX_FD_THIS s.floppy_buffer_index = 0;
if (DEV_dma_get_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.result_size = 7;
- BX_FD_THIS s.result_index = 0;
BX_FD_THIS s.status_reg0 = (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];
- BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
- BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
- BX_FD_THIS s.result[6] = 2;
+ BX_FD_THIS s.status_reg2 = 0;
+
if (bx_dbg.floppy) {
BX_INFO(("<<WRITE DONE>>"));
BX_INFO(("AFTER"));
@@ -1326,8 +1240,8 @@
BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
}
- raise_interrupt();
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
}
else { // more data to transfer
} // else
@@ -1342,6 +1256,13 @@
BX_FD_THIS s.reset_sensei = 0;
}
+ void
+bx_floppy_ctrl_c::lower_interrupt(void)
+{
+ DEV_pic_lower_irq(6);
+ BX_FD_THIS s.pending_irq = 0;
+}
+
void
bx_floppy_ctrl_c::increment_sector(void)
@@ -1350,6 +1271,14 @@
drive = BX_FD_THIS s.DOR & 0x03;
+ if (BX_FD_THIS s.status_reg1 & FD_ST_EOT) {
+ /* increment past EOT: abnormal termination */
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
+ return;
+ }
+
// values after completion of data xfer
// ??? calculation depends on base_count being multiple of 512
BX_FD_THIS s.sector[drive] ++;
@@ -1372,6 +1301,11 @@
BX_INFO(("increment_sector: clamping cylinder to max"));
}
}
+
+ /* check end-of-track condition */
+ if ((BX_FD_THIS s.multi_track == BX_FD_THIS s.head[drive]) &&
+ (BX_FD_THIS s.sector[drive] == BX_FD_THIS s.media[drive].sectors_per_track))
+ BX_FD_THIS s.status_reg1 |= FD_ST_EOT;
}
unsigned
@@ -1475,11 +1409,11 @@
#endif
#ifdef WIN32
if ( (path[1] == ':') && (strlen(path) == 2) ) {
- wsprintf(sTemp, "\\\\.\\%s", path);
- media->fd = open(sTemp, BX_RDWR);
- } else {
- media->fd = open(path, BX_RDWR);
- }
+ wsprintf(sTemp, "\\\\.\\%s", path);
+ media->fd = open(sTemp, BX_RDWR);
+ } else {
+ media->fd = open(path, BX_RDWR);
+ }
#else
media->fd = open(path, BX_RDWR);
#endif
@@ -1494,11 +1428,11 @@
#endif
#ifdef WIN32
if ( (path[1] == ':') && (strlen(path) == 2) ) {
- wsprintf(sTemp, "\\\\.\\%s", path);
- media->fd = open(sTemp, BX_RDONLY);
- } else {
- media->fd = open(path, BX_RDONLY);
- }
+ wsprintf(sTemp, "\\\\.\\%s", path);
+ media->fd = open(sTemp, BX_RDONLY);
+ } else {
+ media->fd = open(path, BX_RDONLY);
+ }
#else
media->fd = open(path, BX_RDONLY);
#endif
@@ -1566,11 +1500,11 @@
media->tracks = 80;
media->heads = 2;
}
- else if (stat_buf.st_size == 1763328) {
+ else if (stat_buf.st_size == 1763328) {
media->sectors_per_track = 21;
media->tracks = 82;
media->heads = 2;
- }
+ }
else {
BX_INFO(("evaluate_media: file '%s' of unknown size %lu",
path, (unsigned long) stat_buf.st_size));
@@ -1641,5 +1575,86 @@
BX_INFO(("unknown mode type"));
return(0);
}
+}
+
+
+void
+bx_floppy_ctrl_c::enter_result_phase(void)
+{
+
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+
+ /* these are always the same */
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+
+ /* invalid command */
+ if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x80) {
+ BX_FD_THIS s.result_size = 1;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+ return;
+ }
+
+ switch (BX_FD_THIS s.pending_command) {
+ case 0x04: // get status
+ BX_FD_THIS s.result_size = 1;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg3;
+ break;
+ case 0x08: // sense interrupt
+ BX_FD_THIS s.result_size = 2;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+ BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
+ break;
+ case 0x46: // read normal data
+ case 0x66:
+ case 0xc6:
+ case 0xe6:
+ case 0x45: // write normal data
+ case 0xc5:
+ /* increment sector once more if we terminated normally at EOT */
+ if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x00 &&
+ (BX_FD_THIS s.status_reg1 & FD_ST_EOT)) {
+ BX_FD_THIS s.status_reg1 &= ~FD_ST_EOT; // clear EOT flag
+ increment_sector();
+ // reset the head bit
+ BX_FD_THIS s.status_reg0 &= 0xfb;
+ BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2);
+ }
+ case 0x4a: // read ID
+ case 0x4d: // format track
+ BX_FD_THIS s.result_size = 7;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+ 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] = BX_FD_THIS s.head[drive];
+ BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+ BX_FD_THIS s.result[6] = 2; /* sector size code */
+
+ bx_pc_system.deactivate_timer( BX_FD_THIS s.floppy_timer_index ); // clear pending timeout
+ BX_FD_THIS raise_interrupt();
+ break;
+ }
+}
+
+void
+bx_floppy_ctrl_c::enter_idle_phase(void)
+{
+ BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched
+ BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready
+
+ /* do not touch ST0 and ST3 since these may be queried later via
+ commands 0x08 and 0x04, respectively. */
+ BX_FD_THIS s.status_reg1 = 0;
+ BX_FD_THIS s.status_reg2 = 0;
+
+ BX_FD_THIS s.command_complete = 1; /* waiting for new command */
+ BX_FD_THIS s.command_index = 0;
+ BX_FD_THIS s.command_size = 0;
+ BX_FD_THIS s.pending_command = 0;
+
+ BX_FD_THIS s.floppy_buffer_index = 0;
}
Index: iodev/floppy.h
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/floppy.h,v
retrieving revision 1.14
diff -u -r1.14 floppy.h
--- iodev/floppy.h 25 Oct 2002 11:44:40 -0000 1.14
+++ iodev/floppy.h 8 Nov 2002 20:28:49 -0000
@@ -116,6 +116,7 @@
Bit8u DIR[4]; // Digital Input Register:
// b7: 0=diskette is present and has not been changed
// 1=diskette missing or changed
+ Bit8u non_dma;
} s; // state information
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
@@ -127,7 +128,10 @@
BX_FD_SMF void floppy_command(void);
BX_FD_SMF void floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
BX_FD_SMF void raise_interrupt(void);
- static void timer_handler(void *);
+ BX_FD_SMF void lower_interrupt(void);
+ BX_FD_SMF void enter_idle_phase(void);
+ BX_FD_SMF void enter_result_phase(void);
+ static void timer_handler(void *);
public:
BX_FD_SMF void timer(void);