2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Andrew Schultz
33 * Device model implementation for an IDE disk
41 #include "base/chunk_generator.hh"
42 #include "base/cprintf.hh" // csprintf
43 #include "base/trace.hh"
44 #include "dev/disk_image.hh"
45 #include "dev/ide_disk.hh"
46 #include "dev/ide_ctrl.hh"
47 #include "dev/tsunami.hh"
48 #include "dev/tsunami_pchip.hh"
49 #include "sim/builder.hh"
50 #include "sim/sim_object.hh"
51 #include "sim/root.hh"
52 #include "arch/isa_traits.hh"
55 using namespace TheISA
;
57 IdeDisk::IdeDisk(const string
&name
, DiskImage
*img
,
59 : SimObject(name
), ctrl(NULL
), image(img
), diskDelay(delay
),
60 dmaTransferEvent(this), dmaReadCG(NULL
), dmaReadWaitEvent(this),
61 dmaWriteCG(NULL
), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
62 dmaReadEvent(this), dmaWriteEvent(this)
64 // Reset the device state
67 // fill out the drive ID structure
68 memset(&driveID
, 0, sizeof(struct ataparams
));
70 // Calculate LBA and C/H/S values
75 uint32_t lba_size
= image
->size();
76 if (lba_size
>= 16383*16*63) {
86 if ((lba_size
/ sectors
) >= 16)
89 heads
= (lba_size
/ sectors
);
91 cylinders
= lba_size
/ (heads
* sectors
);
94 // Setup the model name
95 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
96 sizeof(driveID
.atap_model
));
97 // Set the maximum multisector transfer size
98 driveID
.atap_multi
= MAX_MULTSECT
;
99 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
100 driveID
.atap_capabilities1
= 0x7;
101 // UDMA support, EIDE support
102 driveID
.atap_extensions
= 0x6;
103 // Setup default C/H/S settings
104 driveID
.atap_cylinders
= cylinders
;
105 driveID
.atap_sectors
= sectors
;
106 driveID
.atap_heads
= heads
;
107 // Setup the current multisector transfer size
108 driveID
.atap_curmulti
= MAX_MULTSECT
;
109 driveID
.atap_curmulti_valid
= 0x1;
110 // Number of sectors on disk
111 driveID
.atap_capacity
= lba_size
;
112 // Multiword DMA mode 2 and below supported
113 driveID
.atap_dmamode_supp
= 0x4;
114 // Set PIO mode 4 and 3 supported
115 driveID
.atap_piomode_supp
= 0x3;
116 // Set DMA mode 4 and below supported
117 driveID
.atap_udmamode_supp
= 0x1f;
118 // Statically set hardware config word
119 driveID
.atap_hwreset_res
= 0x4001;
121 //arbitrary for now...
122 driveID
.atap_ata_major
= WDC_VER_ATA7
;
127 // destroy the data buffer
128 delete [] dataBuffer
;
132 IdeDisk::reset(int id
)
134 // initialize the data buffer and shadow registers
135 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
137 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
138 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
139 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
149 // set the device state to idle
153 devState
= Device_Idle_S
;
155 } else if (id
== DEV1
) {
156 devState
= Device_Idle_NS
;
159 panic("Invalid device ID: %#x\n", id
);
162 // set the device ready bit
163 status
= STATUS_DRDY_BIT
;
165 /* The error register must be set to 0x1 on start-up to
166 indicate that no diagnostic error was detected */
175 IdeDisk::isDEVSelect()
177 return ctrl
->isDiskSelected(this);
181 IdeDisk::pciToDma(Addr pciAddr
)
184 return ctrl
->plat
->pciToDma(pciAddr
);
186 panic("Access to unset controller!\n");
190 // Device registers read/write
194 IdeDisk::read(const Addr
&offset
, IdeRegType reg_type
, uint8_t *data
)
196 DevAction_t action
= ACT_NONE
;
201 // Data transfers occur two bytes at a time
203 *(uint16_t*)data
= cmdReg
.data
;
204 action
= ACT_DATA_READ_SHORT
;
207 *data
= cmdReg
.error
;
210 *data
= cmdReg
.sec_count
;
213 *data
= cmdReg
.sec_num
;
216 *data
= cmdReg
.cyl_low
;
219 *data
= cmdReg
.cyl_high
;
222 *data
= cmdReg
.drive
;
226 action
= ACT_STAT_READ
;
229 panic("Invalid IDE command register offset: %#x\n", offset
);
233 if (offset
== ALTSTAT_OFFSET
)
236 panic("Invalid IDE control register offset: %#x\n", offset
);
239 panic("Unknown register block!\n");
241 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
,
244 if (action
!= ACT_NONE
)
249 IdeDisk::write(const Addr
&offset
, IdeRegType reg_type
, const uint8_t *data
)
251 DevAction_t action
= ACT_NONE
;
257 cmdReg
.data
= *(uint16_t*)data
;
258 action
= ACT_DATA_WRITE_SHORT
;
260 case FEATURES_OFFSET
:
263 cmdReg
.sec_count
= *data
;
266 cmdReg
.sec_num
= *data
;
269 cmdReg
.cyl_low
= *data
;
272 cmdReg
.cyl_high
= *data
;
275 cmdReg
.drive
= *data
;
276 action
= ACT_SELECT_WRITE
;
279 cmdReg
.command
= *data
;
280 action
= ACT_CMD_WRITE
;
283 panic("Invalid IDE command register offset: %#x\n", offset
);
287 if (offset
== CONTROL_OFFSET
) {
288 if (*data
& CONTROL_RST_BIT
) {
289 // force the device into the reset state
290 devState
= Device_Srst
;
291 action
= ACT_SRST_SET
;
292 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
))
293 action
= ACT_SRST_CLEAR
;
295 nIENBit
= (*data
& CONTROL_IEN_BIT
) ? true : false;
298 panic("Invalid IDE control register offset: %#x\n", offset
);
301 panic("Unknown register block!\n");
304 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
306 if (action
!= ACT_NONE
)
311 // Perform DMA transactions
315 IdeDisk::doDmaTransfer()
317 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
318 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
321 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
322 dmaTransferEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
325 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
326 (uint8_t*)&curPrd
.entry
);
330 IdeDisk::dmaPrdReadDone()
333 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
334 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
335 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
336 curPrd
.getEOT(), curSector
);
338 // the prd pointer has already been translated, so just do an increment
339 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
348 IdeDisk::doDmaDataRead()
350 /** @todo we need to figure out what the delay actually will be */
351 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
353 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
354 diskDelay
, totalDiskDelay
);
356 dmaReadWaitEvent
.schedule(curTick
+ totalDiskDelay
);
362 using namespace Stats
;
364 .name(name() + ".dma_read_full_pages")
365 .desc("Number of full page size DMA reads (not PRD).")
368 .name(name() + ".dma_read_bytes")
369 .desc("Number of bytes transfered via DMA reads (not PRD).")
372 .name(name() + ".dma_read_txs")
373 .desc("Number of DMA read transactions (not PRD).")
377 .name(name() + ".dma_write_full_pages")
378 .desc("Number of full page size DMA writes.")
381 .name(name() + ".dma_write_bytes")
382 .desc("Number of bytes transfered via DMA writes.")
385 .name(name() + ".dma_write_txs")
386 .desc("Number of DMA write transactions.")
395 // clear out the data buffer
396 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
397 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
398 curPrd
.getByteCount(), TheISA::PageBytes
);
401 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
402 dmaReadWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
404 } else if (!dmaReadCG
->done()) {
405 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
406 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
407 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
408 dmaReadBytes
+= dmaReadCG
->size();
410 if (dmaReadCG
->size() == TheISA::PageBytes
)
414 assert(dmaReadCG
->done());
422 IdeDisk::dmaReadDone()
425 uint32_t bytesWritten
= 0;
428 // write the data to the disk image
429 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
430 bytesWritten
+= SectorSize
) {
432 cmdBytesLeft
-= SectorSize
;
433 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
437 if (curPrd
.getEOT()) {
438 assert(cmdBytesLeft
== 0);
440 updateState(ACT_DMA_DONE
);
447 IdeDisk::doDmaDataWrite()
449 /** @todo we need to figure out what the delay actually will be */
450 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
451 uint32_t bytesRead
= 0;
453 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
454 diskDelay
, totalDiskDelay
);
456 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
457 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
458 while (bytesRead
< curPrd
.getByteCount()) {
459 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
460 bytesRead
+= SectorSize
;
461 cmdBytesLeft
-= SectorSize
;
464 dmaWriteWaitEvent
.schedule(curTick
+ totalDiskDelay
);
468 IdeDisk::doDmaWrite()
472 // clear out the data buffer
473 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
474 curPrd
.getByteCount(), TheISA::PageBytes
);
476 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
477 dmaWriteWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
479 } else if (!dmaWriteCG
->done()) {
480 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
481 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
482 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
483 dmaWriteBytes
+= dmaWriteCG
->size();
485 if (dmaWriteCG
->size() == TheISA::PageBytes
)
489 assert(dmaWriteCG
->done());
497 IdeDisk::dmaWriteDone()
500 if (curPrd
.getEOT()) {
501 assert(cmdBytesLeft
== 0);
503 updateState(ACT_DMA_DONE
);
510 // Disk utility routines
514 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
516 uint32_t bytesRead
= image
->read(data
, sector
);
518 if (bytesRead
!= SectorSize
)
519 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
520 name(), bytesRead
, SectorSize
, errno
);
524 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
526 uint32_t bytesWritten
= image
->write(data
, sector
);
528 if (bytesWritten
!= SectorSize
)
529 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
530 name(), bytesWritten
, SectorSize
, errno
);
534 // Setup and handle commands
538 IdeDisk::startDma(const uint32_t &prdTableBase
)
540 if (dmaState
!= Dma_Start
)
541 panic("Inconsistent DMA state, should be in Dma_Start!\n");
543 if (devState
!= Transfer_Data_Dma
)
544 panic("Inconsistent device state for DMA start!\n");
546 // PRD base address is given by bits 31:2
547 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
549 dmaState
= Dma_Transfer
;
551 // schedule dma transfer (doDmaTransfer)
552 dmaTransferEvent
.schedule(curTick
+ 1);
558 if (dmaState
== Dma_Idle
)
559 panic("Inconsistent DMA state, should be Start or Transfer!");
561 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
562 panic("Inconsistent device state, should be Transfer or Prepare!\n");
564 updateState(ACT_CMD_ERROR
);
568 IdeDisk::startCommand()
570 DevAction_t action
= ACT_NONE
;
575 switch (cmdReg
.command
) {
576 // Supported non-data commands
577 case WDSF_READ_NATIVE_MAX
:
578 size
= image
->size() - 1;
579 cmdReg
.sec_num
= (size
& 0xff);
580 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
581 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
582 cmdReg
.head
= ((size
& 0xf000000) >> 24);
584 devState
= Command_Execution
;
585 action
= ACT_CMD_COMPLETE
;
590 case WDCC_STANDBY_IMMED
:
591 case WDCC_FLUSHCACHE
:
596 devState
= Command_Execution
;
597 action
= ACT_CMD_COMPLETE
;
600 // Supported PIO data-in commands
602 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
603 devState
= Prepare_Data_In
;
604 action
= ACT_DATA_READY
;
609 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
610 panic("Attempt to perform CHS access, only supports LBA\n");
612 if (cmdReg
.sec_count
== 0)
613 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
615 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
617 curSector
= getLBABase();
619 /** @todo make this a scheduled event to simulate disk delay */
620 devState
= Prepare_Data_In
;
621 action
= ACT_DATA_READY
;
624 // Supported PIO data-out commands
625 case WDCC_WRITEMULTI
:
627 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
628 panic("Attempt to perform CHS access, only supports LBA\n");
630 if (cmdReg
.sec_count
== 0)
631 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
633 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
635 curSector
= getLBABase();
637 devState
= Prepare_Data_Out
;
638 action
= ACT_DATA_READY
;
641 // Supported DMA commands
643 dmaRead
= true; // a write to the disk is a DMA read from memory
645 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
646 panic("Attempt to perform CHS access, only supports LBA\n");
648 if (cmdReg
.sec_count
== 0)
649 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
651 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
653 curSector
= getLBABase();
655 devState
= Prepare_Data_Dma
;
656 action
= ACT_DMA_READY
;
660 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
663 if (action
!= ACT_NONE
) {
665 status
|= STATUS_BSY_BIT
;
667 status
&= ~STATUS_DRQ_BIT
;
669 status
&= ~STATUS_DF_BIT
;
676 // Handle setting and clearing interrupts
682 DPRINTF(IdeDisk
, "Posting Interrupt\n");
684 panic("Attempt to post an interrupt with one pending\n");
688 // talk to controller to set interrupt
690 ctrl
->bmi_regs
.bmis0
|= IDEINTS
;
698 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
700 panic("Attempt to clear a non-pending interrupt\n");
704 // talk to controller to clear interrupt
710 // Manage the device internal state machine
714 IdeDisk::updateState(DevAction_t action
)
718 if (action
== ACT_SRST_SET
) {
720 status
|= STATUS_BSY_BIT
;
721 } else if (action
== ACT_SRST_CLEAR
) {
723 status
&= ~STATUS_BSY_BIT
;
725 // reset the device state
731 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
732 devState
= Device_Idle_NS
;
733 } else if (action
== ACT_CMD_WRITE
) {
740 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
741 devState
= Device_Idle_NS
;
743 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
744 devState
= Device_Idle_S
;
746 } else if (action
== ACT_CMD_WRITE
) {
754 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
755 if (!isIENSet() && intrPending
) {
756 devState
= Device_Idle_SI
;
759 if (isIENSet() || !intrPending
) {
760 devState
= Device_Idle_S
;
765 case Command_Execution
:
766 if (action
== ACT_CMD_COMPLETE
) {
771 devState
= Device_Idle_SI
;
774 devState
= Device_Idle_S
;
779 case Prepare_Data_In
:
780 if (action
== ACT_CMD_ERROR
) {
785 devState
= Device_Idle_SI
;
788 devState
= Device_Idle_S
;
790 } else if (action
== ACT_DATA_READY
) {
792 status
&= ~STATUS_BSY_BIT
;
794 status
|= STATUS_DRQ_BIT
;
796 // copy the data into the data buffer
797 if (cmdReg
.command
== WDCC_IDENTIFY
) {
798 // Reset the drqBytes for this block
799 drqBytesLeft
= sizeof(struct ataparams
);
801 memcpy((void *)dataBuffer
, (void *)&driveID
,
802 sizeof(struct ataparams
));
804 // Reset the drqBytes for this block
805 drqBytesLeft
= SectorSize
;
807 readDisk(curSector
++, dataBuffer
);
810 // put the first two bytes into the data register
811 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
815 devState
= Data_Ready_INTRQ_In
;
818 devState
= Transfer_Data_In
;
823 case Data_Ready_INTRQ_In
:
824 if (action
== ACT_STAT_READ
) {
825 devState
= Transfer_Data_In
;
830 case Transfer_Data_In
:
831 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
832 if (action
== ACT_DATA_READ_BYTE
) {
833 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
838 // copy next short into data registers
840 memcpy((void *)&cmdReg
.data
,
841 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
845 if (drqBytesLeft
== 0) {
846 if (cmdBytesLeft
== 0) {
849 devState
= Device_Idle_S
;
851 devState
= Prepare_Data_In
;
853 status
|= STATUS_BSY_BIT
;
855 status
&= ~STATUS_DRQ_BIT
;
857 /** @todo change this to a scheduled event to simulate
859 updateState(ACT_DATA_READY
);
865 case Prepare_Data_Out
:
866 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
871 devState
= Device_Idle_SI
;
874 devState
= Device_Idle_S
;
876 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
878 status
&= ~STATUS_BSY_BIT
;
880 status
|= STATUS_DRQ_BIT
;
882 // clear the data buffer to get it ready for writes
883 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
885 // reset the drqBytes for this block
886 drqBytesLeft
= SectorSize
;
888 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
889 devState
= Transfer_Data_Out
;
891 devState
= Data_Ready_INTRQ_Out
;
897 case Data_Ready_INTRQ_Out
:
898 if (action
== ACT_STAT_READ
) {
899 devState
= Transfer_Data_Out
;
904 case Transfer_Data_Out
:
905 if (action
== ACT_DATA_WRITE_BYTE
||
906 action
== ACT_DATA_WRITE_SHORT
) {
908 if (action
== ACT_DATA_READ_BYTE
) {
909 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
911 // copy the latest short into the data buffer
912 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
913 (void *)&cmdReg
.data
,
920 if (drqBytesLeft
== 0) {
921 // copy the block to the disk
922 writeDisk(curSector
++, dataBuffer
);
925 status
|= STATUS_BSY_BIT
;
927 status
|= STATUS_SEEK_BIT
;
929 status
&= ~STATUS_DRQ_BIT
;
931 devState
= Prepare_Data_Out
;
933 /** @todo change this to a scheduled event to simulate
935 updateState(ACT_DATA_READY
);
940 case Prepare_Data_Dma
:
941 if (action
== ACT_CMD_ERROR
) {
946 devState
= Device_Idle_SI
;
949 devState
= Device_Idle_S
;
951 } else if (action
== ACT_DMA_READY
) {
953 status
&= ~STATUS_BSY_BIT
;
955 status
|= STATUS_DRQ_BIT
;
957 devState
= Transfer_Data_Dma
;
959 if (dmaState
!= Dma_Idle
)
960 panic("Inconsistent DMA state, should be Dma_Idle\n");
962 dmaState
= Dma_Start
;
963 // wait for the write to the DMA start bit
967 case Transfer_Data_Dma
:
968 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
972 status
|= STATUS_SEEK_BIT
;
973 // clear the controller state for DMA transfer
974 ctrl
->setDmaComplete(this);
977 devState
= Device_Idle_SI
;
980 devState
= Device_Idle_S
;
986 panic("Unknown IDE device state: %#x\n", devState
);
991 IdeDisk::serialize(ostream
&os
)
993 // Check all outstanding events to see if they are scheduled
994 // these are all mutually exclusive
996 Events_t event
= None
;
1000 if (dmaTransferEvent
.scheduled()) {
1001 reschedule
= dmaTransferEvent
.when();
1005 if (dmaReadWaitEvent
.scheduled()) {
1006 reschedule
= dmaReadWaitEvent
.when();
1010 if (dmaWriteWaitEvent
.scheduled()) {
1011 reschedule
= dmaWriteWaitEvent
.when();
1015 if (dmaPrdReadEvent
.scheduled()) {
1016 reschedule
= dmaPrdReadEvent
.when();
1020 if (dmaReadEvent
.scheduled()) {
1021 reschedule
= dmaReadEvent
.when();
1025 if (dmaWriteEvent
.scheduled()) {
1026 reschedule
= dmaWriteEvent
.when();
1031 assert(eventCount
<= 1);
1033 SERIALIZE_SCALAR(reschedule
);
1034 SERIALIZE_ENUM(event
);
1036 // Serialize device registers
1037 SERIALIZE_SCALAR(cmdReg
.data
);
1038 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1039 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1040 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1041 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1042 SERIALIZE_SCALAR(cmdReg
.drive
);
1043 SERIALIZE_SCALAR(cmdReg
.command
);
1044 SERIALIZE_SCALAR(status
);
1045 SERIALIZE_SCALAR(nIENBit
);
1046 SERIALIZE_SCALAR(devID
);
1048 // Serialize the PRD related information
1049 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1050 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1051 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1052 SERIALIZE_SCALAR(curPrdAddr
);
1054 /** @todo need to serialized chunk generator stuff!! */
1055 // Serialize current transfer related information
1056 SERIALIZE_SCALAR(cmdBytesLeft
);
1057 SERIALIZE_SCALAR(cmdBytes
);
1058 SERIALIZE_SCALAR(drqBytesLeft
);
1059 SERIALIZE_SCALAR(curSector
);
1060 SERIALIZE_SCALAR(dmaRead
);
1061 SERIALIZE_SCALAR(intrPending
);
1062 SERIALIZE_ENUM(devState
);
1063 SERIALIZE_ENUM(dmaState
);
1064 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1068 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1070 // Reschedule events that were outstanding
1071 // these are all mutually exclusive
1072 Tick reschedule
= 0;
1073 Events_t event
= None
;
1075 UNSERIALIZE_SCALAR(reschedule
);
1076 UNSERIALIZE_ENUM(event
);
1080 case Transfer
: dmaTransferEvent
.schedule(reschedule
); break;
1081 case ReadWait
: dmaReadWaitEvent
.schedule(reschedule
); break;
1082 case WriteWait
: dmaWriteWaitEvent
.schedule(reschedule
); break;
1083 case PrdRead
: dmaPrdReadEvent
.schedule(reschedule
); break;
1084 case DmaRead
: dmaReadEvent
.schedule(reschedule
); break;
1085 case DmaWrite
: dmaWriteEvent
.schedule(reschedule
); break;
1088 // Unserialize device registers
1089 UNSERIALIZE_SCALAR(cmdReg
.data
);
1090 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1091 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1092 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1093 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1094 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1095 UNSERIALIZE_SCALAR(cmdReg
.command
);
1096 UNSERIALIZE_SCALAR(status
);
1097 UNSERIALIZE_SCALAR(nIENBit
);
1098 UNSERIALIZE_SCALAR(devID
);
1100 // Unserialize the PRD related information
1101 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1102 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1103 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1104 UNSERIALIZE_SCALAR(curPrdAddr
);
1106 /** @todo need to serialized chunk generator stuff!! */
1107 // Unserialize current transfer related information
1108 UNSERIALIZE_SCALAR(cmdBytes
);
1109 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1110 UNSERIALIZE_SCALAR(drqBytesLeft
);
1111 UNSERIALIZE_SCALAR(curSector
);
1112 UNSERIALIZE_SCALAR(dmaRead
);
1113 UNSERIALIZE_SCALAR(intrPending
);
1114 UNSERIALIZE_ENUM(devState
);
1115 UNSERIALIZE_ENUM(dmaState
);
1116 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1119 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1121 enum DriveID
{ master
, slave
};
1122 static const char *DriveID_strings
[] = { "master", "slave" };
1123 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1125 SimObjectParam
<DiskImage
*> image
;
1126 SimpleEnumParam
<DriveID
> driveID
;
1129 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1131 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1133 INIT_PARAM(image
, "Disk image"),
1134 INIT_ENUM_PARAM(driveID
, "Drive ID (0=master 1=slave)", DriveID_strings
),
1135 INIT_PARAM_DFLT(delay
, "Fixed disk delay in microseconds", 1)
1137 END_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1140 CREATE_SIM_OBJECT(IdeDisk
)
1142 return new IdeDisk(getInstanceName(), image
, driveID
, delay
);
1145 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk
)
1147 #endif //DOXYGEN_SHOULD_SKIP_THIS