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.
30 * Device model implementation for an IDE disk
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/physical.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/root.hh"
53 #include "arch/isa_traits.hh"
56 using namespace TheISA
;
58 IdeDisk::IdeDisk(const string
&name
, DiskImage
*img
, PhysicalMemory
*phys
,
60 : SimObject(name
), ctrl(NULL
), image(img
), physmem(phys
), diskDelay(delay
),
61 dmaTransferEvent(this), dmaReadWaitEvent(this),
62 dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
63 dmaReadEvent(this), dmaWriteEvent(this)
65 // Reset the device state
68 // fill out the drive ID structure
69 memset(&driveID
, 0, sizeof(struct ataparams
));
71 // Calculate LBA and C/H/S values
76 uint32_t lba_size
= image
->size();
77 if (lba_size
>= 16383*16*63) {
87 if ((lba_size
/ sectors
) >= 16)
90 heads
= (lba_size
/ sectors
);
92 cylinders
= lba_size
/ (heads
* sectors
);
95 // Setup the model name
96 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
97 sizeof(driveID
.atap_model
));
98 // Set the maximum multisector transfer size
99 driveID
.atap_multi
= MAX_MULTSECT
;
100 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
101 driveID
.atap_capabilities1
= 0x7;
102 // UDMA support, EIDE support
103 driveID
.atap_extensions
= 0x6;
104 // Setup default C/H/S settings
105 driveID
.atap_cylinders
= cylinders
;
106 driveID
.atap_sectors
= sectors
;
107 driveID
.atap_heads
= heads
;
108 // Setup the current multisector transfer size
109 driveID
.atap_curmulti
= MAX_MULTSECT
;
110 driveID
.atap_curmulti_valid
= 0x1;
111 // Number of sectors on disk
112 driveID
.atap_capacity
= lba_size
;
113 // Multiword DMA mode 2 and below supported
114 driveID
.atap_dmamode_supp
= 0x400;
115 // Set PIO mode 4 and 3 supported
116 driveID
.atap_piomode_supp
= 0x3;
117 // Set DMA mode 4 and below supported
118 driveID
.atap_udmamode_supp
= 0x1f;
119 // Statically set hardware config word
120 driveID
.atap_hwreset_res
= 0x4001;
122 //arbitrary for now...
123 driveID
.atap_ata_major
= WDC_VER_ATA7
;
128 // destroy the data buffer
129 delete [] dataBuffer
;
133 IdeDisk::reset(int id
)
135 // initialize the data buffer and shadow registers
136 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
138 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
139 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
140 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
142 dmaInterfaceBytes
= 0;
151 // set the device state to idle
155 devState
= Device_Idle_S
;
157 } else if (id
== DEV1
) {
158 devState
= Device_Idle_NS
;
161 panic("Invalid device ID: %#x\n", id
);
164 // set the device ready bit
165 status
= STATUS_DRDY_BIT
;
167 /* The error register must be set to 0x1 on start-up to
168 indicate that no diagnostic error was detected */
177 IdeDisk::isDEVSelect()
179 return ctrl
->isDiskSelected(this);
183 IdeDisk::pciToDma(Addr pciAddr
)
186 return ctrl
->plat
->pciToDma(pciAddr
);
188 panic("Access to unset controller!\n");
192 IdeDisk::bytesInDmaPage(Addr curAddr
, uint32_t bytesLeft
)
194 uint32_t bytesInPage
= 0;
196 // First calculate how many bytes could be in the page
197 if (bytesLeft
> TheISA::PageBytes
)
198 bytesInPage
= TheISA::PageBytes
;
200 bytesInPage
= bytesLeft
;
202 // Next, see if we have crossed a page boundary, and adjust
203 Addr upperBound
= curAddr
+ bytesInPage
;
204 Addr pageBound
= TheISA::TruncPage(curAddr
) + TheISA::PageBytes
;
206 assert(upperBound
>= curAddr
&& "DMA read wraps around address space!\n");
208 if (upperBound
>= pageBound
)
209 bytesInPage
= pageBound
- curAddr
;
215 // Device registers read/write
219 IdeDisk::read(const Addr
&offset
, IdeRegType reg_type
, uint8_t *data
)
221 DevAction_t action
= ACT_NONE
;
226 // Data transfers occur two bytes at a time
228 *(uint16_t*)data
= cmdReg
.data
;
229 action
= ACT_DATA_READ_SHORT
;
232 *data
= cmdReg
.error
;
235 *data
= cmdReg
.sec_count
;
238 *data
= cmdReg
.sec_num
;
241 *data
= cmdReg
.cyl_low
;
244 *data
= cmdReg
.cyl_high
;
247 *data
= cmdReg
.drive
;
251 action
= ACT_STAT_READ
;
254 panic("Invalid IDE command register offset: %#x\n", offset
);
258 if (offset
== ALTSTAT_OFFSET
)
261 panic("Invalid IDE control register offset: %#x\n", offset
);
264 panic("Unknown register block!\n");
267 if (action
!= ACT_NONE
)
272 IdeDisk::write(const Addr
&offset
, IdeRegType reg_type
, const uint8_t *data
)
274 DevAction_t action
= ACT_NONE
;
280 cmdReg
.data
= *(uint16_t*)data
;
281 action
= ACT_DATA_WRITE_SHORT
;
283 case FEATURES_OFFSET
:
286 cmdReg
.sec_count
= *data
;
289 cmdReg
.sec_num
= *data
;
292 cmdReg
.cyl_low
= *data
;
295 cmdReg
.cyl_high
= *data
;
298 cmdReg
.drive
= *data
;
299 action
= ACT_SELECT_WRITE
;
302 cmdReg
.command
= *data
;
303 action
= ACT_CMD_WRITE
;
306 panic("Invalid IDE command register offset: %#x\n", offset
);
310 if (offset
== CONTROL_OFFSET
) {
311 if (*data
& CONTROL_RST_BIT
) {
312 // force the device into the reset state
313 devState
= Device_Srst
;
314 action
= ACT_SRST_SET
;
315 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
))
316 action
= ACT_SRST_CLEAR
;
318 nIENBit
= (*data
& CONTROL_IEN_BIT
) ? true : false;
321 panic("Invalid IDE control register offset: %#x\n", offset
);
324 panic("Unknown register block!\n");
327 if (action
!= ACT_NONE
)
332 // Perform DMA transactions
336 IdeDisk::doDmaTransfer()
338 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
339 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
342 // first read the current PRD
344 if (dmaInterface
->busy()) {
345 // reschedule after waiting period
346 dmaTransferEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
350 dmaInterface
->doDMA(Read
, curPrdAddr
, sizeof(PrdEntry_t
), curTick
,
358 IdeDisk::dmaPrdReadDone()
360 // actually copy the PRD from physical memory
361 memcpy((void *)&curPrd
.entry
,
362 physmem
->dma_addr(curPrdAddr
, sizeof(PrdEntry_t
)),
366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
368 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
369 curPrd
.getEOT(), curSector
);
371 // the prd pointer has already been translated, so just do an increment
372 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
383 /** @todo we need to figure out what the delay actually will be */
384 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
386 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
387 diskDelay
, totalDiskDelay
);
389 if (dmaInterface
->busy()) {
390 // reschedule after waiting period
391 dmaReadWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
395 Addr dmaAddr
= pciToDma(curPrd
.getBaseAddr());
397 uint32_t bytesInPage
= bytesInDmaPage(curPrd
.getBaseAddr(),
398 (uint32_t)curPrd
.getByteCount());
400 dmaInterfaceBytes
= bytesInPage
;
402 dmaInterface
->doDMA(Read
, dmaAddr
, bytesInPage
,
403 curTick
+ totalDiskDelay
, &dmaReadEvent
);
405 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
406 dmaReadEvent
.schedule(curTick
+ totalDiskDelay
);
411 IdeDisk::dmaReadDone()
414 Addr curAddr
= 0, dmaAddr
= 0;
415 uint32_t bytesWritten
= 0, bytesInPage
= 0, bytesLeft
= 0;
417 // continue to use the DMA interface until all pages are read
418 if (dmaInterface
&& (dmaInterfaceBytes
< curPrd
.getByteCount())) {
419 // see if the interface is busy
420 if (dmaInterface
->busy()) {
421 // reschedule after waiting period
422 dmaReadEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
426 uint32_t bytesLeft
= curPrd
.getByteCount() - dmaInterfaceBytes
;
427 curAddr
= curPrd
.getBaseAddr() + dmaInterfaceBytes
;
428 dmaAddr
= pciToDma(curAddr
);
430 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
431 dmaInterfaceBytes
+= bytesInPage
;
433 dmaInterface
->doDMA(Read
, dmaAddr
, bytesInPage
,
434 curTick
, &dmaReadEvent
);
439 // set initial address
440 curAddr
= curPrd
.getBaseAddr();
442 // clear out the data buffer
443 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
445 // read the data from memory via DMA into a data buffer
446 while (bytesWritten
< curPrd
.getByteCount()) {
447 if (cmdBytesLeft
<= 0)
448 panic("DMA data is larger than # of sectors specified\n");
450 dmaAddr
= pciToDma(curAddr
);
452 // calculate how many bytes are in the current page
453 bytesLeft
= curPrd
.getByteCount() - bytesWritten
;
454 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
456 // copy the data from memory into the data buffer
457 memcpy((void *)(dataBuffer
+ bytesWritten
),
458 physmem
->dma_addr(dmaAddr
, bytesInPage
),
461 curAddr
+= bytesInPage
;
462 bytesWritten
+= bytesInPage
;
463 cmdBytesLeft
-= bytesInPage
;
466 // write the data to the disk image
467 for (bytesWritten
= 0;
468 bytesWritten
< curPrd
.getByteCount();
469 bytesWritten
+= SectorSize
) {
471 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
475 if (curPrd
.getEOT()) {
476 assert(cmdBytesLeft
== 0);
478 updateState(ACT_DMA_DONE
);
485 IdeDisk::doDmaWrite()
487 /** @todo we need to figure out what the delay actually will be */
488 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
490 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
491 diskDelay
, totalDiskDelay
);
494 if (dmaInterface
->busy()) {
495 // reschedule after waiting period
496 dmaWriteWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
500 Addr dmaAddr
= pciToDma(curPrd
.getBaseAddr());
502 uint32_t bytesInPage
= bytesInDmaPage(curPrd
.getBaseAddr(),
503 (uint32_t)curPrd
.getByteCount());
505 dmaInterfaceBytes
= bytesInPage
;
507 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
508 bytesInPage
, curTick
+ totalDiskDelay
,
511 // schedule event with disk delay (dmaWriteDone)
512 dmaWriteEvent
.schedule(curTick
+ totalDiskDelay
);
517 IdeDisk::dmaWriteDone()
519 Addr curAddr
= 0, pageAddr
= 0, dmaAddr
= 0;
520 uint32_t bytesRead
= 0, bytesInPage
= 0;
522 // continue to use the DMA interface until all pages are read
523 if (dmaInterface
&& (dmaInterfaceBytes
< curPrd
.getByteCount())) {
524 // see if the interface is busy
525 if (dmaInterface
->busy()) {
526 // reschedule after waiting period
527 dmaWriteEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
531 uint32_t bytesLeft
= curPrd
.getByteCount() - dmaInterfaceBytes
;
532 curAddr
= curPrd
.getBaseAddr() + dmaInterfaceBytes
;
533 dmaAddr
= pciToDma(curAddr
);
535 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
536 dmaInterfaceBytes
+= bytesInPage
;
538 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
539 bytesInPage
, curTick
,
545 // setup the initial page and DMA address
546 curAddr
= curPrd
.getBaseAddr();
547 pageAddr
= TheISA::TruncPage(curAddr
);
548 dmaAddr
= pciToDma(curAddr
);
550 // clear out the data buffer
551 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
553 while (bytesRead
< curPrd
.getByteCount()) {
554 // see if we have crossed into a new page
555 if (pageAddr
!= TheISA::TruncPage(curAddr
)) {
556 // write the data to memory
557 memcpy(physmem
->dma_addr(dmaAddr
, bytesInPage
),
558 (void *)(dataBuffer
+ (bytesRead
- bytesInPage
)),
561 // update the DMA address and page address
562 pageAddr
= TheISA::TruncPage(curAddr
);
563 dmaAddr
= pciToDma(curAddr
);
568 if (cmdBytesLeft
<= 0)
569 panic("DMA requested data is larger than # sectors specified\n");
571 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
573 curAddr
+= SectorSize
;
574 bytesRead
+= SectorSize
;
575 bytesInPage
+= SectorSize
;
576 cmdBytesLeft
-= SectorSize
;
579 // write the last page worth read to memory
580 if (bytesInPage
!= 0) {
581 memcpy(physmem
->dma_addr(dmaAddr
, bytesInPage
),
582 (void *)(dataBuffer
+ (bytesRead
- bytesInPage
)),
587 if (curPrd
.getEOT()) {
588 assert(cmdBytesLeft
== 0);
590 updateState(ACT_DMA_DONE
);
597 // Disk utility routines
601 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
603 uint32_t bytesRead
= image
->read(data
, sector
);
605 if (bytesRead
!= SectorSize
)
606 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
607 name(), bytesRead
, SectorSize
, errno
);
611 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
613 uint32_t bytesWritten
= image
->write(data
, sector
);
615 if (bytesWritten
!= SectorSize
)
616 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
617 name(), bytesWritten
, SectorSize
, errno
);
621 // Setup and handle commands
625 IdeDisk::startDma(const uint32_t &prdTableBase
)
627 if (dmaState
!= Dma_Start
)
628 panic("Inconsistent DMA state, should be in Dma_Start!\n");
630 if (devState
!= Transfer_Data_Dma
)
631 panic("Inconsistent device state for DMA start!\n");
633 // PRD base address is given by bits 31:2
634 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
636 dmaState
= Dma_Transfer
;
638 // schedule dma transfer (doDmaTransfer)
639 dmaTransferEvent
.schedule(curTick
+ 1);
645 if (dmaState
== Dma_Idle
)
646 panic("Inconsistent DMA state, should be Start or Transfer!");
648 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
649 panic("Inconsistent device state, should be Transfer or Prepare!\n");
651 updateState(ACT_CMD_ERROR
);
655 IdeDisk::startCommand()
657 DevAction_t action
= ACT_NONE
;
662 switch (cmdReg
.command
) {
663 // Supported non-data commands
664 case WDSF_READ_NATIVE_MAX
:
665 size
= image
->size() - 1;
666 cmdReg
.sec_num
= (size
& 0xff);
667 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
668 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
669 cmdReg
.head
= ((size
& 0xf000000) >> 24);
671 devState
= Command_Execution
;
672 action
= ACT_CMD_COMPLETE
;
677 case WDCC_STANDBY_IMMED
:
678 case WDCC_FLUSHCACHE
:
683 devState
= Command_Execution
;
684 action
= ACT_CMD_COMPLETE
;
687 // Supported PIO data-in commands
689 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
690 devState
= Prepare_Data_In
;
691 action
= ACT_DATA_READY
;
696 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
697 panic("Attempt to perform CHS access, only supports LBA\n");
699 if (cmdReg
.sec_count
== 0)
700 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
702 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
704 curSector
= getLBABase();
706 /** @todo make this a scheduled event to simulate disk delay */
707 devState
= Prepare_Data_In
;
708 action
= ACT_DATA_READY
;
711 // Supported PIO data-out commands
712 case WDCC_WRITEMULTI
:
714 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
715 panic("Attempt to perform CHS access, only supports LBA\n");
717 if (cmdReg
.sec_count
== 0)
718 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
720 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
722 curSector
= getLBABase();
724 devState
= Prepare_Data_Out
;
725 action
= ACT_DATA_READY
;
728 // Supported DMA commands
730 dmaRead
= true; // a write to the disk is a DMA read from memory
732 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
733 panic("Attempt to perform CHS access, only supports LBA\n");
735 if (cmdReg
.sec_count
== 0)
736 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
738 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
740 curSector
= getLBABase();
742 devState
= Prepare_Data_Dma
;
743 action
= ACT_DMA_READY
;
747 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
750 if (action
!= ACT_NONE
) {
752 status
|= STATUS_BSY_BIT
;
754 status
&= ~STATUS_DRQ_BIT
;
756 status
&= ~STATUS_DF_BIT
;
763 // Handle setting and clearing interrupts
769 DPRINTF(IdeDisk
, "Posting Interrupt\n");
771 panic("Attempt to post an interrupt with one pending\n");
775 // talk to controller to set interrupt
777 ctrl
->bmi_regs
.bmis0
|= IDEINTS
;
785 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
787 panic("Attempt to clear a non-pending interrupt\n");
791 // talk to controller to clear interrupt
797 // Manage the device internal state machine
801 IdeDisk::updateState(DevAction_t action
)
805 if (action
== ACT_SRST_SET
) {
807 status
|= STATUS_BSY_BIT
;
808 } else if (action
== ACT_SRST_CLEAR
) {
810 status
&= ~STATUS_BSY_BIT
;
812 // reset the device state
818 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
819 devState
= Device_Idle_NS
;
820 } else if (action
== ACT_CMD_WRITE
) {
827 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
828 devState
= Device_Idle_NS
;
830 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
831 devState
= Device_Idle_S
;
833 } else if (action
== ACT_CMD_WRITE
) {
841 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
842 if (!isIENSet() && intrPending
) {
843 devState
= Device_Idle_SI
;
846 if (isIENSet() || !intrPending
) {
847 devState
= Device_Idle_S
;
852 case Command_Execution
:
853 if (action
== ACT_CMD_COMPLETE
) {
858 devState
= Device_Idle_SI
;
861 devState
= Device_Idle_S
;
866 case Prepare_Data_In
:
867 if (action
== ACT_CMD_ERROR
) {
872 devState
= Device_Idle_SI
;
875 devState
= Device_Idle_S
;
877 } else if (action
== ACT_DATA_READY
) {
879 status
&= ~STATUS_BSY_BIT
;
881 status
|= STATUS_DRQ_BIT
;
883 // copy the data into the data buffer
884 if (cmdReg
.command
== WDCC_IDENTIFY
) {
885 // Reset the drqBytes for this block
886 drqBytesLeft
= sizeof(struct ataparams
);
888 memcpy((void *)dataBuffer
, (void *)&driveID
,
889 sizeof(struct ataparams
));
891 // Reset the drqBytes for this block
892 drqBytesLeft
= SectorSize
;
894 readDisk(curSector
++, dataBuffer
);
897 // put the first two bytes into the data register
898 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
902 devState
= Data_Ready_INTRQ_In
;
905 devState
= Transfer_Data_In
;
910 case Data_Ready_INTRQ_In
:
911 if (action
== ACT_STAT_READ
) {
912 devState
= Transfer_Data_In
;
917 case Transfer_Data_In
:
918 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
919 if (action
== ACT_DATA_READ_BYTE
) {
920 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
925 // copy next short into data registers
927 memcpy((void *)&cmdReg
.data
,
928 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
932 if (drqBytesLeft
== 0) {
933 if (cmdBytesLeft
== 0) {
936 devState
= Device_Idle_S
;
938 devState
= Prepare_Data_In
;
940 status
|= STATUS_BSY_BIT
;
942 status
&= ~STATUS_DRQ_BIT
;
944 /** @todo change this to a scheduled event to simulate
946 updateState(ACT_DATA_READY
);
952 case Prepare_Data_Out
:
953 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
958 devState
= Device_Idle_SI
;
961 devState
= Device_Idle_S
;
963 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
965 status
&= ~STATUS_BSY_BIT
;
967 status
|= STATUS_DRQ_BIT
;
969 // clear the data buffer to get it ready for writes
970 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
972 // reset the drqBytes for this block
973 drqBytesLeft
= SectorSize
;
975 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
976 devState
= Transfer_Data_Out
;
978 devState
= Data_Ready_INTRQ_Out
;
984 case Data_Ready_INTRQ_Out
:
985 if (action
== ACT_STAT_READ
) {
986 devState
= Transfer_Data_Out
;
991 case Transfer_Data_Out
:
992 if (action
== ACT_DATA_WRITE_BYTE
||
993 action
== ACT_DATA_WRITE_SHORT
) {
995 if (action
== ACT_DATA_READ_BYTE
) {
996 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
998 // copy the latest short into the data buffer
999 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
1000 (void *)&cmdReg
.data
,
1007 if (drqBytesLeft
== 0) {
1008 // copy the block to the disk
1009 writeDisk(curSector
++, dataBuffer
);
1012 status
|= STATUS_BSY_BIT
;
1014 status
|= STATUS_SEEK_BIT
;
1015 // clear the DRQ bit
1016 status
&= ~STATUS_DRQ_BIT
;
1018 devState
= Prepare_Data_Out
;
1020 /** @todo change this to a scheduled event to simulate
1022 updateState(ACT_DATA_READY
);
1027 case Prepare_Data_Dma
:
1028 if (action
== ACT_CMD_ERROR
) {
1029 // clear the BSY bit
1033 devState
= Device_Idle_SI
;
1036 devState
= Device_Idle_S
;
1038 } else if (action
== ACT_DMA_READY
) {
1039 // clear the BSY bit
1040 status
&= ~STATUS_BSY_BIT
;
1042 status
|= STATUS_DRQ_BIT
;
1044 devState
= Transfer_Data_Dma
;
1046 if (dmaState
!= Dma_Idle
)
1047 panic("Inconsistent DMA state, should be Dma_Idle\n");
1049 dmaState
= Dma_Start
;
1050 // wait for the write to the DMA start bit
1054 case Transfer_Data_Dma
:
1055 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
1056 // clear the BSY bit
1059 status
|= STATUS_SEEK_BIT
;
1060 // clear the controller state for DMA transfer
1061 ctrl
->setDmaComplete(this);
1064 devState
= Device_Idle_SI
;
1067 devState
= Device_Idle_S
;
1073 panic("Unknown IDE device state: %#x\n", devState
);
1078 IdeDisk::serialize(ostream
&os
)
1080 // Check all outstanding events to see if they are scheduled
1081 // these are all mutually exclusive
1082 Tick reschedule
= 0;
1083 Events_t event
= None
;
1087 if (dmaTransferEvent
.scheduled()) {
1088 reschedule
= dmaTransferEvent
.when();
1092 if (dmaReadWaitEvent
.scheduled()) {
1093 reschedule
= dmaReadWaitEvent
.when();
1097 if (dmaWriteWaitEvent
.scheduled()) {
1098 reschedule
= dmaWriteWaitEvent
.when();
1102 if (dmaPrdReadEvent
.scheduled()) {
1103 reschedule
= dmaPrdReadEvent
.when();
1107 if (dmaReadEvent
.scheduled()) {
1108 reschedule
= dmaReadEvent
.when();
1112 if (dmaWriteEvent
.scheduled()) {
1113 reschedule
= dmaWriteEvent
.when();
1118 assert(eventCount
<= 1);
1120 SERIALIZE_SCALAR(reschedule
);
1121 SERIALIZE_ENUM(event
);
1123 // Serialize device registers
1124 SERIALIZE_SCALAR(cmdReg
.data
);
1125 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1126 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1127 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1128 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1129 SERIALIZE_SCALAR(cmdReg
.drive
);
1130 SERIALIZE_SCALAR(cmdReg
.command
);
1131 SERIALIZE_SCALAR(status
);
1132 SERIALIZE_SCALAR(nIENBit
);
1133 SERIALIZE_SCALAR(devID
);
1135 // Serialize the PRD related information
1136 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1137 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1138 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1139 SERIALIZE_SCALAR(curPrdAddr
);
1141 // Serialize current transfer related information
1142 SERIALIZE_SCALAR(cmdBytesLeft
);
1143 SERIALIZE_SCALAR(cmdBytes
);
1144 SERIALIZE_SCALAR(drqBytesLeft
);
1145 SERIALIZE_SCALAR(curSector
);
1146 SERIALIZE_SCALAR(dmaRead
);
1147 SERIALIZE_SCALAR(dmaInterfaceBytes
);
1148 SERIALIZE_SCALAR(intrPending
);
1149 SERIALIZE_ENUM(devState
);
1150 SERIALIZE_ENUM(dmaState
);
1151 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1155 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1157 // Reschedule events that were outstanding
1158 // these are all mutually exclusive
1159 Tick reschedule
= 0;
1160 Events_t event
= None
;
1162 UNSERIALIZE_SCALAR(reschedule
);
1163 UNSERIALIZE_ENUM(event
);
1167 case Transfer
: dmaTransferEvent
.schedule(reschedule
); break;
1168 case ReadWait
: dmaReadWaitEvent
.schedule(reschedule
); break;
1169 case WriteWait
: dmaWriteWaitEvent
.schedule(reschedule
); break;
1170 case PrdRead
: dmaPrdReadEvent
.schedule(reschedule
); break;
1171 case DmaRead
: dmaReadEvent
.schedule(reschedule
); break;
1172 case DmaWrite
: dmaWriteEvent
.schedule(reschedule
); break;
1175 // Unserialize device registers
1176 UNSERIALIZE_SCALAR(cmdReg
.data
);
1177 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1178 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1179 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1180 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1181 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1182 UNSERIALIZE_SCALAR(cmdReg
.command
);
1183 UNSERIALIZE_SCALAR(status
);
1184 UNSERIALIZE_SCALAR(nIENBit
);
1185 UNSERIALIZE_SCALAR(devID
);
1187 // Unserialize the PRD related information
1188 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1189 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1190 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1191 UNSERIALIZE_SCALAR(curPrdAddr
);
1193 // Unserialize current transfer related information
1194 UNSERIALIZE_SCALAR(cmdBytes
);
1195 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1196 UNSERIALIZE_SCALAR(drqBytesLeft
);
1197 UNSERIALIZE_SCALAR(curSector
);
1198 UNSERIALIZE_SCALAR(dmaRead
);
1199 UNSERIALIZE_SCALAR(dmaInterfaceBytes
);
1200 UNSERIALIZE_SCALAR(intrPending
);
1201 UNSERIALIZE_ENUM(devState
);
1202 UNSERIALIZE_ENUM(dmaState
);
1203 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1206 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1208 enum DriveID
{ master
, slave
};
1209 static const char *DriveID_strings
[] = { "master", "slave" };
1210 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1212 SimObjectParam
<DiskImage
*> image
;
1213 SimObjectParam
<PhysicalMemory
*> physmem
;
1214 SimpleEnumParam
<DriveID
> driveID
;
1217 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1219 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1221 INIT_PARAM(image
, "Disk image"),
1222 INIT_PARAM(physmem
, "Physical memory"),
1223 INIT_ENUM_PARAM(driveID
, "Drive ID (0=master 1=slave)", DriveID_strings
),
1224 INIT_PARAM_DFLT(delay
, "Fixed disk delay in microseconds", 1)
1226 END_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1229 CREATE_SIM_OBJECT(IdeDisk
)
1231 return new IdeDisk(getInstanceName(), image
, physmem
, driveID
, delay
);
1234 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk
)
1236 #endif //DOXYGEN_SHOULD_SKIP_THIS