1 ----------------------------------------------------------------------
2 Patch name: patch.floppy-athiel
3 Author: Alex Thiel (uploaded by cbothamy)
8 This patch introduces the implicit termination of data transfer via
9 end-of-track and data overrun/underrun conditions, as well as non-DMA mode.
11 The code cleanup is present in CVS now (Volker Ruppert, Dec 1st 2002).
13 We still have no test case for the non-DMA mode and the overrun/underrun (timeout)
14 code fails if cpu speedups are enabled. The timeout code expects at least one DMA
15 cycle within 15 usec (Volker Ruppert, Mar 12th 2005).
17 Patch was created with:
19 Apply patch to what version:
20 cvs checked out on 11 Mar 2005
22 To patch, go to main bochs directory.
23 Type "patch -p0 < THIS_PATCH_FILE".
24 ----------------------------------------------------------------------
25 Index: iodev/floppy.cc
26 ===================================================================
27 RCS file: /cvsroot/bochs/bochs/iodev/floppy.cc,v
28 retrieving revision 1.77
29 diff -u -r1.77 floppy.cc
30 --- iodev/floppy.cc 2005-03-11 21:12:52 +0100
31 +++ iodev/floppy.cc 2005-03-12 15:23:40 +0200
33 #define FD_MS_ACTB 0x02
34 #define FD_MS_ACTA 0x01
36 +/* for status registers */
37 +#define FD_ST_EOT 0x80
38 +#define FD_ST_OVERRUN 0x10
40 #define FROM_FLOPPY 10
43 #define FLOPPY_DMA_CHAN 2
45 +#define FD_TIMEOUT 15 // for FIFO overrun/underrun
46 +#define FD_IRQ_DELAY 2 // delay so the system can detect a INT change
54 case 0x3F5: /* diskette controller data */
56 + /* data transfer in non-DMA mode */
57 + if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) {
58 + BX_FD_THIS dma_write(&value); // write: from controller to cpu
60 + /* This simulates the FIFO latency, see comment in timer() below. */
61 + BX_FD_THIS lower_interrupt();
62 + BX_FD_THIS s.main_status_reg &= ~FD_MS_MRQ;
63 + // overrides the timer set in dma_write()
64 + bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index,
69 if (BX_FD_THIS s.result_size == 0) {
70 BX_ERROR(("port 0x3f5: no results to read"));
71 BX_FD_THIS s.main_status_reg = 0;
75 case 0x3F5: /* diskette controller data */
77 + /* data transfer in non-DMA mode */
78 + if (BX_FD_THIS s.main_status_reg & FD_MS_NDMA) {
79 + BX_FD_THIS dma_read((Bit8u *) &value); // read: from cpu to controller
81 + /* This simulates the FIFO latency, see comment in timer() below. */
82 + BX_FD_THIS lower_interrupt();
83 + BX_FD_THIS s.main_status_reg &= ~FD_MS_MRQ;
84 + // overrides the timer set in dma_read()
85 + bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index,
90 BX_DEBUG(("command = %02x", (unsigned) value));
91 if (BX_FD_THIS s.command_complete) {
92 if (BX_FD_THIS s.pending_command!=0)
94 head_load_time = BX_FD_THIS s.command[2] >> 1;
95 BX_FD_THIS s.non_dma = BX_FD_THIS s.command[2] & 0x01;
96 if (BX_FD_THIS s.non_dma)
97 - BX_ERROR(("non DMA mode not implemented yet"));
98 + BX_INFO(("non DMA mode selected"));
102 @@ -839,10 +874,14 @@
103 /* 4 header bytes per sector are required */
104 BX_FD_THIS s.format_count <<= 2;
106 - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
108 - /* data reg not ready, controller busy */
109 - BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
110 + if (BX_FD_THIS s.non_dma) {
111 + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_NDMA | FD_MS_BUSY;
112 + BX_FD_THIS raise_interrupt();
114 + /* data reg not ready, controller busy */
115 + BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
116 + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
118 BX_DEBUG(("format track"));
121 @@ -957,21 +996,25 @@
122 floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
125 - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
127 - /* data reg not ready, controller busy */
128 - BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
131 - else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write
133 - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
135 - /* data reg not ready, controller busy */
136 - BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
138 + if (BX_FD_THIS s.non_dma) {
139 + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_NDMA | FD_MS_DIO | FD_MS_BUSY;
140 + BX_FD_THIS raise_interrupt();
142 + /* data reg not ready, controller busy */
143 + BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
144 + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
146 + } else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write
148 + if (BX_FD_THIS s.non_dma) {
149 + BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_NDMA | FD_MS_BUSY;
150 + BX_FD_THIS raise_interrupt();
152 + /* data reg not ready, controller busy */
153 + BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
154 + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
158 BX_PANIC(("floppy_command(): unknown read/write command"));
161 @@ -1138,6 +1181,31 @@
162 enter_result_phase();
165 + case 0x4d: // format track
166 + case 0x46: // read normal data
170 + case 0x45: // write normal data
172 + /* During non-DMA operation, the state of the FDC oscillates
173 + between IRQ low/MRQ clear (set after data is transferred via 0x3f5)
174 + and IRQ high/MRQ set.
175 + Whenever the timer is triggered in DMA mode, or in non-DMA mode with
176 + MRQ set, we have a data overrun/underrun. */
177 + if ((BX_FD_THIS s.main_status_reg & (FD_MS_MRQ | FD_MS_NDMA))
178 + == FD_MS_NDMA) { // NDMA & !MRQ
179 + BX_FD_THIS raise_interrupt();
180 + BX_FD_THIS s.main_status_reg |= FD_MS_MRQ;
181 + bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index,
183 + } else { // timeout
184 + // FIXME: this code requires at least one DMA cycle within 15 usec
185 + //BX_FD_THIS s.status_reg1 |= FD_ST_OVERRUN;
186 + //enter_result_phase();
190 case 0xfe: // (contrived) RESET
191 theFloppyController->reset(BX_RESET_SOFTWARE);
192 BX_FD_THIS s.pending_command = 0;
193 @@ -1163,9 +1231,11 @@
194 // We need to return then next data byte from the floppy buffer
195 // to be transfered via the DMA to memory. (read block from floppy)
198 *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
200 + // reschedule timeout
201 + bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, FD_TIMEOUT, 0 );
203 if (BX_FD_THIS s.floppy_buffer_index >= 512) {
206 @@ -1174,7 +1244,6 @@
207 BX_FD_THIS s.floppy_buffer_index = 0;
208 if (DEV_dma_get_tc()) { // Terminal Count line, done
209 BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
210 - BX_FD_THIS s.status_reg1 = 0;
211 BX_FD_THIS s.status_reg2 = 0;
214 @@ -1215,6 +1284,9 @@
216 Bit32u logical_sector;
218 + // reschedule timeout
219 + bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index, FD_TIMEOUT, 0 );
221 drive = BX_FD_THIS s.DOR & 0x03;
222 if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
223 --BX_FD_THIS s.format_count;
224 @@ -1279,7 +1351,6 @@
225 BX_FD_THIS s.floppy_buffer_index = 0;
226 if (DEV_dma_get_tc()) { // Terminal Count line, done
227 BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
228 - BX_FD_THIS s.status_reg1 = 0;
229 BX_FD_THIS s.status_reg2 = 0;
232 @@ -1322,6 +1393,14 @@
234 drive = BX_FD_THIS s.DOR & 0x03;
236 + if (BX_FD_THIS s.status_reg1 & FD_ST_EOT) {
237 + /* increment past EOT: abnormal termination */
238 + BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
239 + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
240 + enter_result_phase();
244 // values after completion of data xfer
245 // ??? calculation depends on base_count being multiple of 512
246 BX_FD_THIS s.sector[drive] ++;
247 @@ -1344,6 +1423,12 @@
248 BX_INFO(("increment_sector: clamping cylinder to max"));
252 + /* check end-of-track condition */
253 + if ((BX_FD_THIS s.multi_track == BX_FD_THIS s.head[drive]) &&
254 + (BX_FD_THIS s.sector[drive] == BX_FD_THIS s.media[drive].sectors_per_track)) {
255 + BX_FD_THIS s.status_reg1 |= FD_ST_EOT;
260 @@ -1702,14 +1787,23 @@
261 BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
262 BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
264 - case 0x4a: // read ID
265 - case 0x4d: // format track
266 case 0x46: // read normal data
270 case 0x45: // write normal data
272 + /* increment sector once more if we terminated normally at EOT */
273 + if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x00 &&
274 + (BX_FD_THIS s.status_reg1 & FD_ST_EOT)) {
275 + BX_FD_THIS s.status_reg1 &= ~FD_ST_EOT; // clear EOT flag
276 + increment_sector();
277 + // reset the head bit
278 + BX_FD_THIS s.status_reg0 &= 0xfb;
279 + BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2);
281 + case 0x4a: // read ID
282 + case 0x4d: // format track
283 BX_FD_THIS s.result_size = 7;
284 BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
285 BX_FD_THIS s.result[1] = BX_FD_THIS s.status_reg1;
286 @@ -1718,6 +1812,8 @@
287 BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
288 BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
289 BX_FD_THIS s.result[6] = 2; /* sector size code */
291 + bx_pc_system.deactivate_timer( BX_FD_THIS s.floppy_timer_index ); // clear pending timeout
292 BX_FD_THIS raise_interrupt();
295 @@ -1729,6 +1825,11 @@
296 BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched
297 BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready
299 + /* do not touch ST0 and ST3 since these may be queried later via
300 + commands 0x08 and 0x04, respectively. */
301 + BX_FD_THIS s.status_reg1 = 0;
302 + BX_FD_THIS s.status_reg2 = 0;
304 BX_FD_THIS s.command_complete = 1; /* waiting for new command */
305 BX_FD_THIS s.command_index = 0;
306 BX_FD_THIS s.command_size = 0;