1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
----------------------------------------------------------------------
Patch name: patch.floppy-athiel
Author: Alex Thiel (uploaded by cbothamy)
Date: 8 Nov 2002
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).
We still have no test case for the non-DMA mode and the overrun/underrun (timeout)
code fails if cpu speedups are enabled. The timeout code expects at least one DMA
cycle within 15 usec (Volker Ruppert, Mar 12th 2005).
Patch was created with:
cvs diff -u
Apply patch to what version:
cvs checked out on 11 Mar 2005
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.77
diff -u -r1.77 floppy.cc
--- iodev/floppy.cc 2005-03-11 21:12:52 +0100
+++ iodev/floppy.cc 2005-03-12 15:23:40 +0200
@@ -73,11 +73,18 @@
#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
#define FLOPPY_DMA_CHAN 2
+#define FD_TIMEOUT 15 // for FIFO overrun/underrun
+#define FD_IRQ_DELAY 2 // delay so the system can detect a INT change
+
typedef struct {
unsigned id;
Bit8u trk;
@@ -391,6 +398,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 cpu
+
+ /* 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;
@@ -527,6 +548,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 cpu 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)
@@ -670,7 +705,7 @@
head_load_time = BX_FD_THIS s.command[2] >> 1;
BX_FD_THIS s.non_dma = BX_FD_THIS s.command[2] & 0x01;
if (BX_FD_THIS s.non_dma)
- BX_ERROR(("non DMA mode not implemented yet"));
+ BX_INFO(("non DMA mode selected"));
enter_idle_phase();
return;
break;
@@ -839,10 +874,14 @@
/* 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;
@@ -957,21 +996,25 @@
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;
- }
- 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_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
+
+ 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
+ } else
BX_PANIC(("floppy_command(): unknown read/write command"));
return;
@@ -1138,6 +1181,31 @@
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
+ // FIXME: this code requires at least one DMA cycle within 15 usec
+ //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;
@@ -1163,9 +1231,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;
@@ -1174,7 +1244,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) {
@@ -1215,6 +1284,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;
@@ -1279,7 +1351,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) {
@@ -1322,6 +1393,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] ++;
@@ -1344,6 +1423,12 @@
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
@@ -1702,14 +1787,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;
@@ -1718,6 +1812,8 @@
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;
}
@@ -1729,6 +1825,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
+ /* 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;
|