Checkin of latest IDE and some separation between platforms (Tsunami and
[gem5.git] / dev / ide_disk.cc
1 /*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /** @file
30 * Device model implementation for an IDE disk
31 */
32
33 #include <cerrno>
34 #include <cstring>
35 #include <deque>
36 #include <string>
37
38 #include "base/cprintf.hh" // csprintf
39 #include "base/trace.hh"
40 #include "dev/disk_image.hh"
41 #include "dev/ide_disk.hh"
42 #include "dev/ide_ctrl.hh"
43 #include "dev/tsunami.hh"
44 #include "dev/tsunami_pchip.hh"
45 #include "mem/functional_mem/physical_memory.hh"
46 #include "mem/bus/bus.hh"
47 #include "mem/bus/dma_interface.hh"
48 #include "mem/bus/pio_interface.hh"
49 #include "mem/bus/pio_interface_impl.hh"
50 #include "sim/builder.hh"
51 #include "sim/sim_object.hh"
52 #include "sim/universe.hh"
53
54 using namespace std;
55
56 IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
57 int id, int delay)
58 : SimObject(name), ctrl(NULL), image(img), physmem(phys), dmaTransferEvent(this),
59 dmaReadWaitEvent(this), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
60 dmaReadEvent(this), dmaWriteEvent(this)
61 {
62 diskDelay = (delay * ticksPerSecond / 1000) / image->size();
63
64 // initialize the data buffer and shadow registers
65 dataBuffer = new uint8_t[MAX_DMA_SIZE];
66
67 memset(dataBuffer, 0, MAX_DMA_SIZE);
68 memset(&cmdReg, 0, sizeof(CommandReg_t));
69 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
70
71 curPrdAddr = 0;
72 curSector = 0;
73 curCommand = 0;
74 cmdBytesLeft = 0;
75 drqBytesLeft = 0;
76 dmaRead = false;
77 intrPending = false;
78
79 // fill out the drive ID structure
80 memset(&driveID, 0, sizeof(struct hd_driveid));
81
82 // Calculate LBA and C/H/S values
83 uint16_t cylinders;
84 uint8_t heads;
85 uint8_t sectors;
86
87 uint32_t lba_size = image->size();
88 if (lba_size >= 16383*16*63) {
89 cylinders = 16383;
90 heads = 16;
91 sectors = 63;
92 } else {
93 if (lba_size >= 63)
94 sectors = 63;
95 else
96 sectors = lba_size;
97
98 if ((lba_size / sectors) >= 16)
99 heads = 16;
100 else
101 heads = (lba_size / sectors);
102
103 cylinders = lba_size / (heads * sectors);
104 }
105
106 // Setup the model name
107 sprintf((char *)driveID.model, "5MI EDD si k");
108 // Set the maximum multisector transfer size
109 driveID.max_multsect = MAX_MULTSECT;
110 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
111 driveID.capability = 0x7;
112 // UDMA support, EIDE support
113 driveID.field_valid = 0x6;
114 // Setup default C/H/S settings
115 driveID.cyls = cylinders;
116 driveID.sectors = sectors;
117 driveID.heads = heads;
118 // Setup the current multisector transfer size
119 driveID.multsect = MAX_MULTSECT;
120 driveID.multsect_valid = 0x1;
121 // Number of sectors on disk
122 driveID.lba_capacity = lba_size;
123 // Multiword DMA mode 2 and below supported
124 driveID.dma_mword = 0x400;
125 // Set PIO mode 4 and 3 supported
126 driveID.eide_pio_modes = 0x3;
127 // Set DMA mode 4 and below supported
128 driveID.dma_ultra = 0x10;
129 // Statically set hardware config word
130 driveID.hw_config = 0x4001;
131
132 // set the device state to idle
133 dmaState = Dma_Idle;
134
135 if (id == DEV0) {
136 devState = Device_Idle_S;
137 devID = DEV0;
138 } else if (id == DEV1) {
139 devState = Device_Idle_NS;
140 devID = DEV1;
141 } else {
142 panic("Invalid device ID: %#x\n", id);
143 }
144
145 // set the device ready bit
146 cmdReg.status |= STATUS_DRDY_BIT;
147 }
148
149 IdeDisk::~IdeDisk()
150 {
151 // destroy the data buffer
152 delete [] dataBuffer;
153 }
154
155 ////
156 // Device registers read/write
157 ////
158
159 void
160 IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data)
161 {
162 DevAction_t action = ACT_NONE;
163
164 if (cmdBlk) {
165 if (offset < 0 || offset > sizeof(CommandReg_t))
166 panic("Invalid disk command register offset: %#x\n", offset);
167
168 if (!byte && offset != DATA_OFFSET)
169 panic("Invalid 16-bit read, only allowed on data reg\n");
170
171 if (!byte)
172 *(uint16_t *)data = *(uint16_t *)&cmdReg.data0;
173 else
174 *data = ((uint8_t *)&cmdReg)[offset];
175
176 // determine if an action needs to be taken on the state machine
177 if (offset == STATUS_OFFSET) {
178 action = ACT_STAT_READ;
179 } else if (offset == DATA_OFFSET) {
180 if (byte)
181 action = ACT_DATA_READ_BYTE;
182 else
183 action = ACT_DATA_READ_SHORT;
184 }
185
186 } else {
187 if (offset != ALTSTAT_OFFSET)
188 panic("Invalid disk control register offset: %#x\n", offset);
189
190 if (!byte)
191 panic("Invalid 16-bit read from control block\n");
192
193 *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET];
194 }
195
196 if (action != ACT_NONE)
197 updateState(action);
198 }
199
200 void
201 IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data)
202 {
203 DevAction_t action = ACT_NONE;
204
205 if (cmdBlk) {
206 if (offset < 0 || offset > sizeof(CommandReg_t))
207 panic("Invalid disk command register offset: %#x\n", offset);
208
209 if (!byte && offset != DATA_OFFSET)
210 panic("Invalid 16-bit write, only allowed on data reg\n");
211
212 if (!byte)
213 *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data;
214 else
215 ((uint8_t *)&cmdReg)[offset] = *data;
216
217 // determine if an action needs to be taken on the state machine
218 if (offset == COMMAND_OFFSET) {
219 action = ACT_CMD_WRITE;
220 } else if (offset == DATA_OFFSET) {
221 if (byte)
222 action = ACT_DATA_WRITE_BYTE;
223 else
224 action = ACT_DATA_WRITE_SHORT;
225 }
226
227 } else {
228 if (offset != CONTROL_OFFSET)
229 panic("Invalid disk control register offset: %#x\n", offset);
230
231 if (!byte)
232 panic("Invalid 16-bit write to control block\n");
233
234 if (*data & CONTROL_RST_BIT)
235 panic("Software reset not supported!\n");
236
237 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
238 }
239
240 if (action != ACT_NONE)
241 updateState(action);
242 }
243
244 ////
245 // Perform DMA transactions
246 ////
247
248 void
249 IdeDisk::doDmaTransfer()
250 {
251 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
252 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
253 dmaState, devState);
254
255 // first read the current PRD
256 if (dmaInterface) {
257 if (dmaInterface->busy()) {
258 // reschedule after waiting period
259 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
260 return;
261 }
262
263 dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick,
264 &dmaPrdReadEvent);
265 } else {
266 dmaPrdReadDone();
267 }
268 }
269
270 void
271 IdeDisk::dmaPrdReadDone()
272 {
273 // actually copy the PRD from physical memory
274 memcpy((void *)&curPrd.entry,
275 physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
276 sizeof(PrdEntry_t));
277
278 curPrdAddr += sizeof(PrdEntry_t);
279
280 if (dmaRead)
281 doDmaRead();
282 else
283 doDmaWrite();
284 }
285
286 void
287 IdeDisk::doDmaRead()
288 {
289 Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
290
291 if (dmaInterface) {
292 if (dmaInterface->busy()) {
293 // reschedule after waiting period
294 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
295 return;
296 }
297
298 Addr dmaAddr =
299 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
300 dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(),
301 curTick + totalDiskDelay, &dmaReadEvent);
302 } else {
303 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
304 dmaReadEvent.schedule(curTick + totalDiskDelay);
305 }
306 }
307
308 void
309 IdeDisk::dmaReadDone()
310 {
311 // actually copy the data from memory to data buffer
312 Addr dmaAddr =
313 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
314 memcpy((void *)dataBuffer,
315 physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
316 curPrd.getByteCount());
317
318 uint32_t bytesWritten = 0;
319
320 while (bytesWritten < curPrd.getByteCount()) {
321 if (cmdBytesLeft <= 0)
322 panic("DMA data is larger than # sectors specified\n");
323
324 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
325
326 bytesWritten += SectorSize;
327 cmdBytesLeft -= SectorSize;
328 }
329
330 // check for the EOT
331 if (curPrd.getEOT()){
332 assert(cmdBytesLeft == 0);
333 dmaState = Dma_Idle;
334 updateState(ACT_DMA_DONE);
335 } else {
336 doDmaTransfer();
337 }
338 }
339
340 void
341 IdeDisk::doDmaWrite()
342 {
343 Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
344
345 if (dmaInterface) {
346 if (dmaInterface->busy()) {
347 // reschedule after waiting period
348 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
349 return;
350 }
351
352 Addr dmaAddr =
353 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
354 dmaInterface->doDMA(WriteInvalidate, dmaAddr,
355 curPrd.getByteCount(), curTick + totalDiskDelay,
356 &dmaWriteEvent);
357 } else {
358 // schedule event with disk delay (dmaWriteDone)
359 dmaWriteEvent.schedule(curTick + totalDiskDelay);
360 }
361 }
362
363 void
364 IdeDisk::dmaWriteDone()
365 {
366 uint32_t bytesRead = 0;
367
368 // clear out the data buffer
369 memset(dataBuffer, 0, MAX_DMA_SIZE);
370
371 while (bytesRead < curPrd.getByteCount()) {
372 if (cmdBytesLeft <= 0)
373 panic("DMA requested data is larger than # sectors specified\n");
374
375 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
376
377 bytesRead += SectorSize;
378 cmdBytesLeft -= SectorSize;
379 }
380
381 // copy the data to memory
382 Addr dmaAddr =
383 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
384 memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
385 (void *)dataBuffer, curPrd.getByteCount());
386
387 // check for the EOT
388 if (curPrd.getEOT()) {
389 assert(cmdBytesLeft == 0);
390 dmaState = Dma_Idle;
391 updateState(ACT_DMA_DONE);
392 } else {
393 doDmaTransfer();
394 }
395 }
396
397 ////
398 // Disk utility routines
399 ///
400
401 void
402 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
403 {
404 uint32_t bytesRead = image->read(data, sector);
405
406 if (bytesRead != SectorSize)
407 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
408 name(), bytesRead, SectorSize, errno);
409 }
410
411 void
412 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
413 {
414 uint32_t bytesWritten = image->write(data, sector);
415
416 if (bytesWritten != SectorSize)
417 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
418 name(), bytesWritten, SectorSize, errno);
419 }
420
421 ////
422 // Setup and handle commands
423 ////
424
425 void
426 IdeDisk::startDma(const uint32_t &prdTableBase)
427 {
428 if (dmaState != Dma_Start)
429 panic("Inconsistent DMA state, should be in Dma_Start!\n");
430
431 if (devState != Transfer_Data_Dma)
432 panic("Inconsistent device state for DMA start!\n");
433
434 curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase);
435
436 dmaState = Dma_Transfer;
437
438 // schedule dma transfer (doDmaTransfer)
439 dmaTransferEvent.schedule(curTick + 1);
440 }
441
442 void
443 IdeDisk::abortDma()
444 {
445 if (dmaState == Dma_Idle)
446 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n");
447
448 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
449 panic("Inconsistent device state, should be in Transfer or Prepare!\n");
450
451 updateState(ACT_CMD_ERROR);
452 }
453
454 void
455 IdeDisk::startCommand()
456 {
457 DevAction_t action = ACT_NONE;
458 uint32_t size = 0;
459 dmaRead = false;
460
461 // copy the command to the shadow
462 curCommand = cmdReg.command;
463
464 // Decode commands
465 switch (cmdReg.command) {
466 // Supported non-data commands
467 case WIN_READ_NATIVE_MAX:
468 size = image->size() - 1;
469 cmdReg.sec_num = (size & 0xff);
470 cmdReg.cyl_low = ((size & 0xff00) >> 8);
471 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
472 cmdReg.head = ((size & 0xf000000) >> 24);
473
474 devState = Command_Execution;
475 action = ACT_CMD_COMPLETE;
476 break;
477
478 case WIN_RECAL:
479 case WIN_SPECIFY:
480 case WIN_FLUSH_CACHE:
481 case WIN_VERIFY:
482 case WIN_SEEK:
483 case WIN_SETFEATURES:
484 case WIN_SETMULT:
485 devState = Command_Execution;
486 action = ACT_CMD_COMPLETE;
487 break;
488
489 // Supported PIO data-in commands
490 case WIN_IDENTIFY:
491 cmdBytesLeft = drqBytesLeft = sizeof(struct hd_driveid);
492 devState = Prepare_Data_In;
493 action = ACT_DATA_READY;
494 break;
495
496 case WIN_MULTREAD:
497 case WIN_READ:
498 if (!(cmdReg.drive & DRIVE_LBA_BIT))
499 panic("Attempt to perform CHS access, only supports LBA\n");
500
501 if (cmdReg.sec_count == 0)
502 cmdBytesLeft = (256 * SectorSize);
503 else
504 cmdBytesLeft = (cmdReg.sec_count * SectorSize);
505
506 drqBytesLeft = SectorSize;
507 curSector = getLBABase();
508
509 devState = Prepare_Data_In;
510 action = ACT_DATA_READY;
511 break;
512
513 // Supported PIO data-out commands
514 case WIN_MULTWRITE:
515 case WIN_WRITE:
516 if (!(cmdReg.drive & DRIVE_LBA_BIT))
517 panic("Attempt to perform CHS access, only supports LBA\n");
518
519 if (cmdReg.sec_count == 0)
520 cmdBytesLeft = (256 * SectorSize);
521 else
522 cmdBytesLeft = (cmdReg.sec_count * SectorSize);
523
524 drqBytesLeft = SectorSize;
525 curSector = getLBABase();
526
527 devState = Prepare_Data_Out;
528 action = ACT_DATA_READY;
529 break;
530
531 // Supported DMA commands
532 case WIN_WRITEDMA:
533 dmaRead = true; // a write to the disk is a DMA read from memory
534 case WIN_READDMA:
535 if (!(cmdReg.drive & DRIVE_LBA_BIT))
536 panic("Attempt to perform CHS access, only supports LBA\n");
537
538 if (cmdReg.sec_count == 0)
539 cmdBytesLeft = (256 * SectorSize);
540 else
541 cmdBytesLeft = (cmdReg.sec_count * SectorSize);
542
543 drqBytesLeft = SectorSize;
544 curSector = getLBABase();
545
546 devState = Prepare_Data_Dma;
547 action = ACT_DMA_READY;
548 break;
549
550 default:
551 panic("Unsupported ATA command: %#x\n", cmdReg.command);
552 }
553
554 if (action != ACT_NONE) {
555 // set the BSY bit
556 cmdReg.status |= STATUS_BSY_BIT;
557 // clear the DRQ bit
558 cmdReg.status &= ~STATUS_DRQ_BIT;
559
560 updateState(action);
561 }
562 }
563
564 ////
565 // Handle setting and clearing interrupts
566 ////
567
568 void
569 IdeDisk::intrPost()
570 {
571 if (intrPending)
572 panic("Attempt to post an interrupt with one pending\n");
573
574 intrPending = true;
575
576 // talk to controller to set interrupt
577 if (ctrl)
578 ctrl->intrPost();
579 }
580
581 void
582 IdeDisk::intrClear()
583 {
584 if (!intrPending)
585 panic("Attempt to clear a non-pending interrupt\n");
586
587 intrPending = false;
588
589 // talk to controller to clear interrupt
590 if (ctrl)
591 ctrl->intrClear();
592 }
593
594 ////
595 // Manage the device internal state machine
596 ////
597
598 void
599 IdeDisk::updateState(DevAction_t action)
600 {
601 switch (devState) {
602 case Device_Idle_S:
603 if (!isDEVSelect())
604 devState = Device_Idle_NS;
605 else if (action == ACT_CMD_WRITE)
606 startCommand();
607
608 break;
609
610 case Device_Idle_SI:
611 if (!isDEVSelect()) {
612 devState = Device_Idle_NS;
613 intrClear();
614 } else if (action == ACT_STAT_READ || isIENSet()) {
615 devState = Device_Idle_S;
616 intrClear();
617 } else if (action == ACT_CMD_WRITE) {
618 intrClear();
619 startCommand();
620 }
621
622 break;
623
624 case Device_Idle_NS:
625 if (isDEVSelect()) {
626 if (!isIENSet() && intrPending) {
627 devState = Device_Idle_SI;
628 intrPost();
629 }
630 if (isIENSet() || !intrPending) {
631 devState = Device_Idle_S;
632 }
633 }
634 break;
635
636 case Command_Execution:
637 if (action == ACT_CMD_COMPLETE) {
638 // clear the BSY bit
639 setComplete();
640
641 if (!isIENSet()) {
642 devState = Device_Idle_SI;
643 intrPost();
644 } else {
645 devState = Device_Idle_S;
646 }
647 }
648 break;
649
650 case Prepare_Data_In:
651 if (action == ACT_CMD_ERROR) {
652 // clear the BSY bit
653 setComplete();
654
655 if (!isIENSet()) {
656 devState = Device_Idle_SI;
657 intrPost();
658 } else {
659 devState = Device_Idle_S;
660 }
661 } else if (action == ACT_DATA_READY) {
662 // clear the BSY bit
663 cmdReg.status &= ~STATUS_BSY_BIT;
664 // set the DRQ bit
665 cmdReg.status |= STATUS_DRQ_BIT;
666
667 // put the first two bytes into the data register
668 memcpy((void *)&cmdReg.data0, (void *)dataBuffer, sizeof(uint16_t));
669 // copy the data into the data buffer
670 if (curCommand == WIN_IDENTIFY)
671 memcpy((void *)dataBuffer, (void *)&driveID,
672 sizeof(struct hd_driveid));
673 else
674 readDisk(curSector++, dataBuffer);
675
676 if (!isIENSet()) {
677 devState = Data_Ready_INTRQ_In;
678 intrPost();
679 } else {
680 devState = Transfer_Data_In;
681 }
682 }
683 break;
684
685 case Data_Ready_INTRQ_In:
686 if (action == ACT_STAT_READ) {
687 devState = Transfer_Data_In;
688 intrClear();
689 }
690 break;
691
692 case Transfer_Data_In:
693 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
694 if (action == ACT_DATA_READ_BYTE) {
695 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
696 } else {
697 drqBytesLeft -= 2;
698 cmdBytesLeft -= 2;
699
700 // copy next short into data registers
701 memcpy((void *)&cmdReg.data0,
702 (void *)&dataBuffer[SectorSize - drqBytesLeft],
703 sizeof(uint16_t));
704 }
705
706 if (drqBytesLeft == 0) {
707 if (cmdBytesLeft == 0) {
708 // Clear the BSY bit
709 setComplete();
710 devState = Device_Idle_S;
711 } else {
712 devState = Prepare_Data_In;
713 cmdReg.status |= STATUS_BSY_BIT;
714 }
715 }
716 }
717 break;
718
719 case Prepare_Data_Out:
720 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
721 // clear the BSY bit
722 setComplete();
723
724 if (!isIENSet()) {
725 devState = Device_Idle_SI;
726 intrPost();
727 } else {
728 devState = Device_Idle_S;
729 }
730 } else if (cmdBytesLeft != 0) {
731 // clear the BSY bit
732 cmdReg.status &= ~STATUS_BSY_BIT;
733 // set the DRQ bit
734 cmdReg.status |= STATUS_DRQ_BIT;
735
736 // clear the data buffer to get it ready for writes
737 memset(dataBuffer, 0, MAX_DMA_SIZE);
738
739 if (!isIENSet()) {
740 devState = Data_Ready_INTRQ_Out;
741 intrPost();
742 } else {
743 devState = Transfer_Data_Out;
744 }
745 }
746 break;
747
748 case Data_Ready_INTRQ_Out:
749 if (action == ACT_STAT_READ) {
750 devState = Transfer_Data_Out;
751 intrClear();
752 }
753 break;
754
755 case Transfer_Data_Out:
756 if (action == ACT_DATA_WRITE_BYTE || action == ACT_DATA_WRITE_SHORT) {
757 if (action == ACT_DATA_READ_BYTE) {
758 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
759 } else {
760 // copy the latest short into the data buffer
761 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
762 (void *)&cmdReg.data0,
763 sizeof(uint16_t));
764
765 drqBytesLeft -= 2;
766 cmdBytesLeft -= 2;
767 }
768
769 if (drqBytesLeft == 0) {
770 // copy the block to the disk
771 writeDisk(curSector++, dataBuffer);
772
773 // set the BSY bit
774 cmdReg.status |= STATUS_BSY_BIT;
775 // clear the DRQ bit
776 cmdReg.status &= ~STATUS_DRQ_BIT;
777
778 devState = Prepare_Data_Out;
779 }
780 }
781 break;
782
783 case Prepare_Data_Dma:
784 if (action == ACT_CMD_ERROR) {
785 // clear the BSY bit
786 setComplete();
787
788 if (!isIENSet()) {
789 devState = Device_Idle_SI;
790 intrPost();
791 } else {
792 devState = Device_Idle_S;
793 }
794 } else if (action == ACT_DMA_READY) {
795 // clear the BSY bit
796 cmdReg.status &= ~STATUS_BSY_BIT;
797 // set the DRQ bit
798 cmdReg.status |= STATUS_DRQ_BIT;
799
800 devState = Transfer_Data_Dma;
801
802 if (dmaState != Dma_Idle)
803 panic("Inconsistent DMA state, should be Dma_Idle\n");
804
805 dmaState = Dma_Start;
806 // wait for the write to the DMA start bit
807 }
808 break;
809
810 case Transfer_Data_Dma:
811 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
812 // clear the BSY bit
813 setComplete();
814 // set the seek bit
815 cmdReg.status |= 0x10;
816 // clear the controller state for DMA transfer
817 ctrl->setDmaComplete(this);
818
819 if (!isIENSet()) {
820 devState = Device_Idle_SI;
821 intrPost();
822 } else {
823 devState = Device_Idle_S;
824 }
825 }
826 break;
827
828 default:
829 panic("Unknown IDE device state: %#x\n", devState);
830 }
831 }
832
833 void
834 IdeDisk::serialize(ostream &os)
835 {
836 }
837
838 void
839 IdeDisk::unserialize(Checkpoint *cp, const string &section)
840 {
841 }
842
843 #ifndef DOXYGEN_SHOULD_SKIP_THIS
844
845 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
846
847 SimObjectParam<DiskImage *> image;
848 SimObjectParam<PhysicalMemory *> physmem;
849 Param<int> driveID;
850 Param<int> disk_delay;
851
852 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
853
854 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
855
856 INIT_PARAM(image, "Disk image"),
857 INIT_PARAM(physmem, "Physical memory"),
858 INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
859 INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0)
860
861 END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
862
863
864 CREATE_SIM_OBJECT(IdeDisk)
865 {
866 return new IdeDisk(getInstanceName(), image, physmem, driveID, disk_delay);
867 }
868
869 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
870
871 #endif //DOXYGEN_SHOULD_SKIP_THIS