Bochs/bochs/patches/patch.floppy-athiel

375 lines
12 KiB
Plaintext
Raw Normal View History

----------------------------------------------------------------------
Patch name: patch.floppy-athiel
Author: Alex Thiel (uploaded by cbothamy)
Date: 8 Nov 2002
2003-06-17 00:41:12 +04:00
Status: Proposed
Detailed description:
This patch introduces the implicit termination of data transfer via
end-of-track and data overrun/underrun conditions, as well as non-DMA mode.
The code cleanup is present in CVS now (Volker Ruppert, Dec 1st 2002).
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
2003-06-17 00:41:12 +04:00
retrieving revision 1.61
diff -u -r1.61 floppy.cc
--- iodev/floppy.cc 2003-02-07 13:47:40 +0100
+++ iodev/floppy.cc 2003-06-16 20:50:39 +0200
@@ -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
2003-06-17 00:41:12 +04:00
@@ -250,7 +254,8 @@
}
}
-
+#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 */
2003-06-17 00:41:12 +04:00
if (BX_FD_THIS s.num_supported_floppies > 0) {
@@ -356,6 +361,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;
2003-06-17 00:41:12 +04:00
@@ -487,6 +506,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)
2003-06-17 00:41:12 +04:00
@@ -620,11 +653,6 @@
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
-
BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
switch (BX_FD_THIS s.pending_command) {
case 0x03: // specify
2003-06-17 00:41:12 +04:00
@@ -633,8 +661,9 @@
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.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;
2003-06-17 00:41:12 +04:00
@@ -802,10 +831,15 @@
/* 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;
+ 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;
2003-06-17 00:41:12 +04:00
@@ -920,19 +954,27 @@
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
512, FROM_FLOPPY);
- DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
-
- /* data reg not ready, controller busy */
- BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
- 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
- DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
-
- /* data reg not ready, controller busy */
- BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
- 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"));
2003-06-17 00:41:12 +04:00
@@ -1044,18 +1086,43 @@
BX_FD_THIS s.DIR[drive] &= ~0x80; // clear disk change line
enter_idle_phase();
- raise_interrupt();
+ BX_FD_THIS raise_interrupt();
break;
case 0x4a: /* read ID */
enter_result_phase();
break;
+ case 0x4d: // format track
+ case 0x46: // read normal data
+ case 0x66:
+ case 0xc6:
+ case 0xe6:
+ case 0x45: // write normal data
+ 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;
2003-06-17 00:41:12 +04:00
@@ -1076,9 +1143,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;
2003-06-17 00:41:12 +04:00
@@ -1087,7 +1156,6 @@
BX_FD_THIS s.floppy_buffer_index = 0;
if (DEV_dma_get_tc()) { // Terminal Count line, done
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
- BX_FD_THIS s.status_reg1 = 0;
BX_FD_THIS s.status_reg2 = 0;
if (bx_dbg.floppy) {
2003-06-17 00:41:12 +04:00
@@ -1128,6 +1196,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;
2003-06-17 00:41:12 +04:00
@@ -1192,7 +1263,6 @@
BX_FD_THIS s.floppy_buffer_index = 0;
if (DEV_dma_get_tc()) { // Terminal Count line, done
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
- BX_FD_THIS s.status_reg1 = 0;
BX_FD_THIS s.status_reg2 = 0;
if (bx_dbg.floppy) {
2003-06-17 00:41:12 +04:00
@@ -1220,6 +1290,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)
2003-06-17 00:41:12 +04:00
@@ -1228,6 +1305,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] ++;
2003-06-17 00:41:12 +04:00
@@ -1250,6 +1335,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
2003-06-17 00:41:12 +04:00
@@ -1591,14 +1681,23 @@
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 0x4a: // read ID
- case 0x4d: // format track
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;
2003-06-17 00:41:12 +04:00
@@ -1607,7 +1706,9 @@
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 */
- raise_interrupt();
+
+ bx_pc_system.deactivate_timer( BX_FD_THIS s.floppy_timer_index ); // clear pending timeout
+ BX_FD_THIS raise_interrupt();
break;
}
}
2003-06-17 00:41:12 +04:00
@@ -1618,6 +1719,11 @@
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
2003-06-17 00:41:12 +04:00
+ /* 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;
2003-06-17 00:41:12 +04:00
+
BX_FD_THIS s.command_complete = 1; /* waiting for new command */
BX_FD_THIS s.command_index = 0;
2003-06-17 00:41:12 +04:00
BX_FD_THIS s.command_size = 0;
Index: iodev/floppy.h
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/floppy.h,v
retrieving revision 1.16
diff -u -r1.16 floppy.h
2003-06-17 00:41:12 +04:00
--- iodev/floppy.h 2002-11-30 10:39:29 +0100
+++ iodev/floppy.h 2003-06-16 20:50:39 +0200
@@ -114,6 +114,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,9 +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);
+ 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 *);
+ static void timer_handler(void *);
public:
BX_FD_SMF void timer(void);