Fixed compilation error
[bochs-mirror.git] / patches / patch.floppy-athiel
blobcb8c6f2b469fa65bcde97b4f342d7e04cfc65be9
1 ----------------------------------------------------------------------
2 Patch name: patch.floppy-athiel
3 Author: Alex Thiel (uploaded by cbothamy)
4 Date: 8 Nov 2002
5 Status: Proposed 
7 Detailed description:
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:
18   cvs diff -u
19 Apply patch to what version:
20   cvs checked out on 11 Mar 2005
21 Instructions:
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
32 @@ -73,11 +73,18 @@
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
41  #define TO_FLOPPY   11
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
48  typedef struct {
49    unsigned id;
50    Bit8u trk;
51 @@ -391,6 +398,20 @@
52        break;
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, 
65 +                                    FD_IRQ_DELAY, 0); 
66 +        return(value);
67 +      }
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;
72 @@ -527,6 +548,20 @@
73        break;
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,
86 +                                    FD_IRQ_DELAY, 0); 
87 +        break;
88 +      }
90        BX_DEBUG(("command = %02x", (unsigned) value));
91        if (BX_FD_THIS s.command_complete) {
92          if (BX_FD_THIS s.pending_command!=0)
93 @@ -670,7 +705,7 @@
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"));
99        enter_idle_phase();
100        return;
101        break;
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();
113 +      } else {
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);
117 +      }
118        BX_DEBUG(("format track"));
119        return;
120        break;
121 @@ -957,21 +996,25 @@
122          floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
123                      512, FROM_FLOPPY);
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;
129 -        return;
130 -        }
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;
137 -        return;
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();
141 +        } else {
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);
145 +        }
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();
151 +        } else {
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);
155          }
156 -      else
157 +      } else
158          BX_PANIC(("floppy_command(): unknown read/write command"));
160        return;
161 @@ -1138,6 +1181,31 @@
162        enter_result_phase();
163        break;
165 +    case 0x4d: // format track
166 +    case 0x46: // read normal data
167 +    case 0x66: 
168 +    case 0xc6:
169 +    case 0xe6:
170 +    case 0x45: // write normal data
171 +    case 0xc5: 
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, 
182 +                                    FD_TIMEOUT, 0 ); 
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();
187 +      } 
188 +      break;
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) {
204      Bit8u drive;
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;
213        if (bx_dbg.floppy) {
214 @@ -1215,6 +1284,9 @@
215    Bit8u drive;
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;
231        if (bx_dbg.floppy) {
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();
241 +    return;
242 +  }
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"));
249        }
250      }
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;
256 +  }
259    unsigned
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];
263      break;
264 -  case 0x4a: // read ID
265 -  case 0x4d: // format track
266    case 0x46: // read normal data
267    case 0x66:
268    case 0xc6:
269    case 0xe6:
270    case 0x45: // write normal data
271    case 0xc5:
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);
280 +    }
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();
293      break;
294    }
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;