2 * Copyright (c) 2004 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_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 #include "targetarch/isa_traits.hh"
57 IdeDisk::IdeDisk(const string
&name
, DiskImage
*img
, PhysicalMemory
*phys
,
59 : SimObject(name
), ctrl(NULL
), image(img
), physmem(phys
), diskDelay(delay
),
60 dmaTransferEvent(this), dmaReadWaitEvent(this),
61 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 hd_driveid
));
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 sprintf((char *)driveID
.model
, "5MI EDD si k");
96 // Set the maximum multisector transfer size
97 driveID
.max_multsect
= MAX_MULTSECT
;
98 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
99 driveID
.capability
= 0x7;
100 // UDMA support, EIDE support
101 driveID
.field_valid
= 0x6;
102 // Setup default C/H/S settings
103 driveID
.cyls
= cylinders
;
104 driveID
.sectors
= sectors
;
105 driveID
.heads
= heads
;
106 // Setup the current multisector transfer size
107 driveID
.multsect
= MAX_MULTSECT
;
108 driveID
.multsect_valid
= 0x1;
109 // Number of sectors on disk
110 driveID
.lba_capacity
= lba_size
;
111 // Multiword DMA mode 2 and below supported
112 driveID
.dma_mword
= 0x400;
113 // Set PIO mode 4 and 3 supported
114 driveID
.eide_pio_modes
= 0x3;
115 // Set DMA mode 4 and below supported
116 driveID
.dma_ultra
= 0x10;
117 // Statically set hardware config word
118 driveID
.hw_config
= 0x4001;
123 // destroy the data buffer
124 delete [] dataBuffer
;
128 IdeDisk::reset(int id
)
130 // initialize the data buffer and shadow registers
131 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
133 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
134 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
135 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
137 dmaInterfaceBytes
= 0;
146 // set the device state to idle
150 devState
= Device_Idle_S
;
152 } else if (id
== DEV1
) {
153 devState
= Device_Idle_NS
;
156 panic("Invalid device ID: %#x\n", id
);
159 // set the device ready bit
160 status
= STATUS_DRDY_BIT
;
168 IdeDisk::isDEVSelect()
170 return ctrl
->isDiskSelected(this);
174 IdeDisk::pciToDma(Addr pciAddr
)
177 return ctrl
->plat
->pciToDma(pciAddr
);
179 panic("Access to unset controller!\n");
183 IdeDisk::bytesInDmaPage(Addr curAddr
, uint32_t bytesLeft
)
185 uint32_t bytesInPage
= 0;
187 // First calculate how many bytes could be in the page
188 if (bytesLeft
> TheISA::PageBytes
)
189 bytesInPage
= TheISA::PageBytes
;
191 bytesInPage
= bytesLeft
;
193 // Next, see if we have crossed a page boundary, and adjust
194 Addr upperBound
= curAddr
+ bytesInPage
;
195 Addr pageBound
= TheISA::TruncPage(curAddr
) + TheISA::PageBytes
;
197 assert(upperBound
>= curAddr
&& "DMA read wraps around address space!\n");
199 if (upperBound
>= pageBound
)
200 bytesInPage
= pageBound
- curAddr
;
206 // Device registers read/write
210 IdeDisk::read(const Addr
&offset
, bool byte
, bool cmdBlk
, uint8_t *data
)
212 DevAction_t action
= ACT_NONE
;
215 if (offset
< 0 || offset
> sizeof(CommandReg_t
))
216 panic("Invalid disk command register offset: %#x\n", offset
);
218 if (!byte
&& offset
!= DATA_OFFSET
)
219 panic("Invalid 16-bit read, only allowed on data reg\n");
222 *(uint16_t *)data
= *(uint16_t *)&cmdReg
.data0
;
224 *data
= ((uint8_t *)&cmdReg
)[offset
];
226 // determine if an action needs to be taken on the state machine
227 if (offset
== STATUS_OFFSET
) {
228 action
= ACT_STAT_READ
;
229 *data
= status
; // status is in a shadow, explicity copy
230 } else if (offset
== DATA_OFFSET
) {
232 action
= ACT_DATA_READ_BYTE
;
234 action
= ACT_DATA_READ_SHORT
;
238 if (offset
!= ALTSTAT_OFFSET
)
239 panic("Invalid disk control register offset: %#x\n", offset
);
242 panic("Invalid 16-bit read from control block\n");
247 if (action
!= ACT_NONE
)
252 IdeDisk::write(const Addr
&offset
, bool byte
, bool cmdBlk
, const uint8_t *data
)
254 DevAction_t action
= ACT_NONE
;
257 if (offset
< 0 || offset
> sizeof(CommandReg_t
))
258 panic("Invalid disk command register offset: %#x\n", offset
);
260 if (!byte
&& offset
!= DATA_OFFSET
)
261 panic("Invalid 16-bit write, only allowed on data reg\n");
264 *((uint16_t *)&cmdReg
.data0
) = *(uint16_t *)data
;
266 ((uint8_t *)&cmdReg
)[offset
] = *data
;
268 // determine if an action needs to be taken on the state machine
269 if (offset
== COMMAND_OFFSET
) {
270 action
= ACT_CMD_WRITE
;
271 } else if (offset
== DATA_OFFSET
) {
273 action
= ACT_DATA_WRITE_BYTE
;
275 action
= ACT_DATA_WRITE_SHORT
;
276 } else if (offset
== SELECT_OFFSET
) {
277 action
= ACT_SELECT_WRITE
;
281 if (offset
!= CONTROL_OFFSET
)
282 panic("Invalid disk control register offset: %#x\n", offset
);
285 panic("Invalid 16-bit write to control block\n");
287 if (*data
& CONTROL_RST_BIT
) {
288 // force the device into the reset state
289 devState
= Device_Srst
;
290 action
= ACT_SRST_SET
;
291 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
)) {
292 action
= ACT_SRST_CLEAR
;
295 nIENBit
= (*data
& CONTROL_IEN_BIT
) ? true : false;
298 if (action
!= ACT_NONE
)
303 // Perform DMA transactions
307 IdeDisk::doDmaTransfer()
309 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
310 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
313 // first read the current PRD
315 if (dmaInterface
->busy()) {
316 // reschedule after waiting period
317 dmaTransferEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
321 dmaInterface
->doDMA(Read
, curPrdAddr
, sizeof(PrdEntry_t
), curTick
,
329 IdeDisk::dmaPrdReadDone()
331 // actually copy the PRD from physical memory
332 memcpy((void *)&curPrd
.entry
,
333 physmem
->dma_addr(curPrdAddr
, sizeof(PrdEntry_t
)),
337 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
338 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
339 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
340 curPrd
.getEOT(), curSector
);
342 // the prd pointer has already been translated, so just do an increment
343 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
354 /** @TODO we need to figure out what the delay actually will be */
355 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
357 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
358 diskDelay
, totalDiskDelay
);
360 if (dmaInterface
->busy()) {
361 // reschedule after waiting period
362 dmaReadWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
366 Addr dmaAddr
= pciToDma(curPrd
.getBaseAddr());
368 uint32_t bytesInPage
= bytesInDmaPage(curPrd
.getBaseAddr(),
369 (uint32_t)curPrd
.getByteCount());
371 dmaInterfaceBytes
= bytesInPage
;
373 dmaInterface
->doDMA(Read
, dmaAddr
, bytesInPage
,
374 curTick
+ totalDiskDelay
, &dmaReadEvent
);
376 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
377 dmaReadEvent
.schedule(curTick
+ totalDiskDelay
);
382 IdeDisk::dmaReadDone()
385 Addr curAddr
= 0, dmaAddr
= 0;
386 uint32_t bytesWritten
= 0, bytesInPage
= 0, bytesLeft
= 0;
388 // continue to use the DMA interface until all pages are read
389 if (dmaInterface
&& (dmaInterfaceBytes
< curPrd
.getByteCount())) {
390 // see if the interface is busy
391 if (dmaInterface
->busy()) {
392 // reschedule after waiting period
393 dmaReadEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
397 uint32_t bytesLeft
= curPrd
.getByteCount() - dmaInterfaceBytes
;
398 curAddr
= curPrd
.getBaseAddr() + dmaInterfaceBytes
;
399 dmaAddr
= pciToDma(curAddr
);
401 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
402 dmaInterfaceBytes
+= bytesInPage
;
404 dmaInterface
->doDMA(Read
, dmaAddr
, bytesInPage
,
405 curTick
, &dmaReadEvent
);
410 // set initial address
411 curAddr
= curPrd
.getBaseAddr();
413 // clear out the data buffer
414 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
416 // read the data from memory via DMA into a data buffer
417 while (bytesWritten
< curPrd
.getByteCount()) {
418 if (cmdBytesLeft
<= 0)
419 panic("DMA data is larger than # of sectors specified\n");
421 dmaAddr
= pciToDma(curAddr
);
423 // calculate how many bytes are in the current page
424 bytesLeft
= curPrd
.getByteCount() - bytesWritten
;
425 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
427 // copy the data from memory into the data buffer
428 memcpy((void *)(dataBuffer
+ bytesWritten
),
429 physmem
->dma_addr(dmaAddr
, bytesInPage
),
432 curAddr
+= bytesInPage
;
433 bytesWritten
+= bytesInPage
;
434 cmdBytesLeft
-= bytesInPage
;
437 // write the data to the disk image
438 for (bytesWritten
= 0;
439 bytesWritten
< curPrd
.getByteCount();
440 bytesWritten
+= SectorSize
) {
442 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
446 if (curPrd
.getEOT()) {
447 assert(cmdBytesLeft
== 0);
449 updateState(ACT_DMA_DONE
);
456 IdeDisk::doDmaWrite()
458 /** @TODO we need to figure out what the delay actually will be */
459 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
461 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
462 diskDelay
, totalDiskDelay
);
465 if (dmaInterface
->busy()) {
466 // reschedule after waiting period
467 dmaWriteWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
471 Addr dmaAddr
= pciToDma(curPrd
.getBaseAddr());
473 uint32_t bytesInPage
= bytesInDmaPage(curPrd
.getBaseAddr(),
474 (uint32_t)curPrd
.getByteCount());
476 dmaInterfaceBytes
= bytesInPage
;
478 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
479 bytesInPage
, curTick
+ totalDiskDelay
,
482 // schedule event with disk delay (dmaWriteDone)
483 dmaWriteEvent
.schedule(curTick
+ totalDiskDelay
);
488 IdeDisk::dmaWriteDone()
490 Addr curAddr
= 0, pageAddr
= 0, dmaAddr
= 0;
491 uint32_t bytesRead
= 0, bytesInPage
= 0;
493 // continue to use the DMA interface until all pages are read
494 if (dmaInterface
&& (dmaInterfaceBytes
< curPrd
.getByteCount())) {
495 // see if the interface is busy
496 if (dmaInterface
->busy()) {
497 // reschedule after waiting period
498 dmaWriteEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
502 uint32_t bytesLeft
= curPrd
.getByteCount() - dmaInterfaceBytes
;
503 curAddr
= curPrd
.getBaseAddr() + dmaInterfaceBytes
;
504 dmaAddr
= pciToDma(curAddr
);
506 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
507 dmaInterfaceBytes
+= bytesInPage
;
509 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
510 bytesInPage
, curTick
,
516 // setup the initial page and DMA address
517 curAddr
= curPrd
.getBaseAddr();
518 pageAddr
= TheISA::TruncPage(curAddr
);
519 dmaAddr
= pciToDma(curAddr
);
521 // clear out the data buffer
522 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
524 while (bytesRead
< curPrd
.getByteCount()) {
525 // see if we have crossed into a new page
526 if (pageAddr
!= TheISA::TruncPage(curAddr
)) {
527 // write the data to memory
528 memcpy(physmem
->dma_addr(dmaAddr
, bytesInPage
),
529 (void *)(dataBuffer
+ (bytesRead
- bytesInPage
)),
532 // update the DMA address and page address
533 pageAddr
= TheISA::TruncPage(curAddr
);
534 dmaAddr
= pciToDma(curAddr
);
539 if (cmdBytesLeft
<= 0)
540 panic("DMA requested data is larger than # sectors specified\n");
542 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
544 curAddr
+= SectorSize
;
545 bytesRead
+= SectorSize
;
546 bytesInPage
+= SectorSize
;
547 cmdBytesLeft
-= SectorSize
;
550 // write the last page worth read to memory
551 if (bytesInPage
!= 0) {
552 memcpy(physmem
->dma_addr(dmaAddr
, bytesInPage
),
553 (void *)(dataBuffer
+ (bytesRead
- bytesInPage
)),
558 if (curPrd
.getEOT()) {
559 assert(cmdBytesLeft
== 0);
561 updateState(ACT_DMA_DONE
);
568 // Disk utility routines
572 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
574 uint32_t bytesRead
= image
->read(data
, sector
);
576 if (bytesRead
!= SectorSize
)
577 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
578 name(), bytesRead
, SectorSize
, errno
);
582 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
584 uint32_t bytesWritten
= image
->write(data
, sector
);
586 if (bytesWritten
!= SectorSize
)
587 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
588 name(), bytesWritten
, SectorSize
, errno
);
592 // Setup and handle commands
596 IdeDisk::startDma(const uint32_t &prdTableBase
)
598 if (dmaState
!= Dma_Start
)
599 panic("Inconsistent DMA state, should be in Dma_Start!\n");
601 if (devState
!= Transfer_Data_Dma
)
602 panic("Inconsistent device state for DMA start!\n");
604 // PRD base address is given by bits 31:2
605 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
607 dmaState
= Dma_Transfer
;
609 // schedule dma transfer (doDmaTransfer)
610 dmaTransferEvent
.schedule(curTick
+ 1);
616 if (dmaState
== Dma_Idle
)
617 panic("Inconsistent DMA state, should be Start or Transfer!");
619 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
620 panic("Inconsistent device state, should be Transfer or Prepare!\n");
622 updateState(ACT_CMD_ERROR
);
626 IdeDisk::startCommand()
628 DevAction_t action
= ACT_NONE
;
633 switch (cmdReg
.command
) {
634 // Supported non-data commands
635 case WIN_READ_NATIVE_MAX
:
636 size
= image
->size() - 1;
637 cmdReg
.sec_num
= (size
& 0xff);
638 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
639 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
640 cmdReg
.head
= ((size
& 0xf000000) >> 24);
642 devState
= Command_Execution
;
643 action
= ACT_CMD_COMPLETE
;
648 case WIN_STANDBYNOW1
:
649 case WIN_FLUSH_CACHE
:
652 case WIN_SETFEATURES
:
654 devState
= Command_Execution
;
655 action
= ACT_CMD_COMPLETE
;
658 // Supported PIO data-in commands
660 cmdBytes
= cmdBytesLeft
= sizeof(struct hd_driveid
);
661 devState
= Prepare_Data_In
;
662 action
= ACT_DATA_READY
;
667 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
668 panic("Attempt to perform CHS access, only supports LBA\n");
670 if (cmdReg
.sec_count
== 0)
671 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
673 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
675 curSector
= getLBABase();
677 /** @todo make this a scheduled event to simulate disk delay */
678 devState
= Prepare_Data_In
;
679 action
= ACT_DATA_READY
;
682 // Supported PIO data-out commands
685 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
686 panic("Attempt to perform CHS access, only supports LBA\n");
688 if (cmdReg
.sec_count
== 0)
689 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
691 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
693 curSector
= getLBABase();
695 devState
= Prepare_Data_Out
;
696 action
= ACT_DATA_READY
;
699 // Supported DMA commands
701 dmaRead
= true; // a write to the disk is a DMA read from memory
703 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
704 panic("Attempt to perform CHS access, only supports LBA\n");
706 if (cmdReg
.sec_count
== 0)
707 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
709 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
711 curSector
= getLBABase();
713 devState
= Prepare_Data_Dma
;
714 action
= ACT_DMA_READY
;
718 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
721 if (action
!= ACT_NONE
) {
723 status
|= STATUS_BSY_BIT
;
725 status
&= ~STATUS_DRQ_BIT
;
727 status
&= ~STATUS_DF_BIT
;
734 // Handle setting and clearing interrupts
740 DPRINTF(IdeDisk
, "Posting Interrupt\n");
742 panic("Attempt to post an interrupt with one pending\n");
746 // talk to controller to set interrupt
754 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
756 panic("Attempt to clear a non-pending interrupt\n");
760 // talk to controller to clear interrupt
766 // Manage the device internal state machine
770 IdeDisk::updateState(DevAction_t action
)
774 if (action
== ACT_SRST_SET
) {
776 status
|= STATUS_BSY_BIT
;
777 } else if (action
== ACT_SRST_CLEAR
) {
779 status
&= ~STATUS_BSY_BIT
;
781 // reset the device state
787 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
788 devState
= Device_Idle_NS
;
789 } else if (action
== ACT_CMD_WRITE
) {
796 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
797 devState
= Device_Idle_NS
;
799 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
800 devState
= Device_Idle_S
;
802 } else if (action
== ACT_CMD_WRITE
) {
810 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
811 if (!isIENSet() && intrPending
) {
812 devState
= Device_Idle_SI
;
815 if (isIENSet() || !intrPending
) {
816 devState
= Device_Idle_S
;
821 case Command_Execution
:
822 if (action
== ACT_CMD_COMPLETE
) {
827 devState
= Device_Idle_SI
;
830 devState
= Device_Idle_S
;
835 case Prepare_Data_In
:
836 if (action
== ACT_CMD_ERROR
) {
841 devState
= Device_Idle_SI
;
844 devState
= Device_Idle_S
;
846 } else if (action
== ACT_DATA_READY
) {
848 status
&= ~STATUS_BSY_BIT
;
850 status
|= STATUS_DRQ_BIT
;
852 // copy the data into the data buffer
853 if (cmdReg
.command
== WIN_IDENTIFY
) {
854 // Reset the drqBytes for this block
855 drqBytesLeft
= sizeof(struct hd_driveid
);
857 memcpy((void *)dataBuffer
, (void *)&driveID
,
858 sizeof(struct hd_driveid
));
860 // Reset the drqBytes for this block
861 drqBytesLeft
= SectorSize
;
863 readDisk(curSector
++, dataBuffer
);
866 // put the first two bytes into the data register
867 memcpy((void *)&cmdReg
.data0
, (void *)dataBuffer
,
871 devState
= Data_Ready_INTRQ_In
;
874 devState
= Transfer_Data_In
;
879 case Data_Ready_INTRQ_In
:
880 if (action
== ACT_STAT_READ
) {
881 devState
= Transfer_Data_In
;
886 case Transfer_Data_In
:
887 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
888 if (action
== ACT_DATA_READ_BYTE
) {
889 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
894 // copy next short into data registers
896 memcpy((void *)&cmdReg
.data0
,
897 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
901 if (drqBytesLeft
== 0) {
902 if (cmdBytesLeft
== 0) {
905 devState
= Device_Idle_S
;
907 devState
= Prepare_Data_In
;
909 status
|= STATUS_BSY_BIT
;
911 status
&= ~STATUS_DRQ_BIT
;
913 /** @todo change this to a scheduled event to simulate
915 updateState(ACT_DATA_READY
);
921 case Prepare_Data_Out
:
922 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
927 devState
= Device_Idle_SI
;
930 devState
= Device_Idle_S
;
932 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
934 status
&= ~STATUS_BSY_BIT
;
936 status
|= STATUS_DRQ_BIT
;
938 // clear the data buffer to get it ready for writes
939 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
941 // reset the drqBytes for this block
942 drqBytesLeft
= SectorSize
;
944 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
945 devState
= Transfer_Data_Out
;
947 devState
= Data_Ready_INTRQ_Out
;
953 case Data_Ready_INTRQ_Out
:
954 if (action
== ACT_STAT_READ
) {
955 devState
= Transfer_Data_Out
;
960 case Transfer_Data_Out
:
961 if (action
== ACT_DATA_WRITE_BYTE
||
962 action
== ACT_DATA_WRITE_SHORT
) {
964 if (action
== ACT_DATA_READ_BYTE
) {
965 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
967 // copy the latest short into the data buffer
968 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
969 (void *)&cmdReg
.data0
,
976 if (drqBytesLeft
== 0) {
977 // copy the block to the disk
978 writeDisk(curSector
++, dataBuffer
);
981 status
|= STATUS_BSY_BIT
;
983 status
|= STATUS_SEEK_BIT
;
985 status
&= ~STATUS_DRQ_BIT
;
987 devState
= Prepare_Data_Out
;
989 /** @todo change this to a scheduled event to simulate
991 updateState(ACT_DATA_READY
);
996 case Prepare_Data_Dma
:
997 if (action
== ACT_CMD_ERROR
) {
1002 devState
= Device_Idle_SI
;
1005 devState
= Device_Idle_S
;
1007 } else if (action
== ACT_DMA_READY
) {
1008 // clear the BSY bit
1009 status
&= ~STATUS_BSY_BIT
;
1011 status
|= STATUS_DRQ_BIT
;
1013 devState
= Transfer_Data_Dma
;
1015 if (dmaState
!= Dma_Idle
)
1016 panic("Inconsistent DMA state, should be Dma_Idle\n");
1018 dmaState
= Dma_Start
;
1019 // wait for the write to the DMA start bit
1023 case Transfer_Data_Dma
:
1024 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
1025 // clear the BSY bit
1028 status
|= STATUS_SEEK_BIT
;
1029 // clear the controller state for DMA transfer
1030 ctrl
->setDmaComplete(this);
1033 devState
= Device_Idle_SI
;
1036 devState
= Device_Idle_S
;
1042 panic("Unknown IDE device state: %#x\n", devState
);
1047 IdeDisk::serialize(ostream
&os
)
1049 // Check all outstanding events to see if they are scheduled
1050 // these are all mutually exclusive
1051 Tick reschedule
= 0;
1052 Events_t event
= None
;
1056 if (dmaTransferEvent
.scheduled()) {
1057 reschedule
= dmaTransferEvent
.when();
1061 if (dmaReadWaitEvent
.scheduled()) {
1062 reschedule
= dmaReadWaitEvent
.when();
1066 if (dmaWriteWaitEvent
.scheduled()) {
1067 reschedule
= dmaWriteWaitEvent
.when();
1071 if (dmaPrdReadEvent
.scheduled()) {
1072 reschedule
= dmaPrdReadEvent
.when();
1076 if (dmaReadEvent
.scheduled()) {
1077 reschedule
= dmaReadEvent
.when();
1081 if (dmaWriteEvent
.scheduled()) {
1082 reschedule
= dmaWriteEvent
.when();
1087 assert(eventCount
<= 1);
1089 SERIALIZE_SCALAR(reschedule
);
1090 SERIALIZE_ENUM(event
);
1092 // Serialize device registers
1093 SERIALIZE_SCALAR(cmdReg
.data0
);
1094 SERIALIZE_SCALAR(cmdReg
.data1
);
1095 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1096 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1097 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1098 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1099 SERIALIZE_SCALAR(cmdReg
.drive
);
1100 SERIALIZE_SCALAR(cmdReg
.command
);
1101 SERIALIZE_SCALAR(status
);
1102 SERIALIZE_SCALAR(nIENBit
);
1103 SERIALIZE_SCALAR(devID
);
1105 // Serialize the PRD related information
1106 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1107 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1108 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1109 SERIALIZE_SCALAR(curPrdAddr
);
1111 // Serialize current transfer related information
1112 SERIALIZE_SCALAR(cmdBytesLeft
);
1113 SERIALIZE_SCALAR(cmdBytes
);
1114 SERIALIZE_SCALAR(drqBytesLeft
);
1115 SERIALIZE_SCALAR(curSector
);
1116 SERIALIZE_SCALAR(dmaRead
);
1117 SERIALIZE_SCALAR(dmaInterfaceBytes
);
1118 SERIALIZE_SCALAR(intrPending
);
1119 SERIALIZE_ENUM(devState
);
1120 SERIALIZE_ENUM(dmaState
);
1121 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1125 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1127 // Reschedule events that were outstanding
1128 // these are all mutually exclusive
1129 Tick reschedule
= 0;
1130 Events_t event
= None
;
1132 UNSERIALIZE_SCALAR(reschedule
);
1133 UNSERIALIZE_ENUM(event
);
1137 case Transfer
: dmaTransferEvent
.schedule(reschedule
); break;
1138 case ReadWait
: dmaReadWaitEvent
.schedule(reschedule
); break;
1139 case WriteWait
: dmaWriteWaitEvent
.schedule(reschedule
); break;
1140 case PrdRead
: dmaPrdReadEvent
.schedule(reschedule
); break;
1141 case DmaRead
: dmaReadEvent
.schedule(reschedule
); break;
1142 case DmaWrite
: dmaWriteEvent
.schedule(reschedule
); break;
1145 // Unserialize device registers
1146 UNSERIALIZE_SCALAR(cmdReg
.data0
);
1147 UNSERIALIZE_SCALAR(cmdReg
.data1
);
1148 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1149 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1150 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1151 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1152 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1153 UNSERIALIZE_SCALAR(cmdReg
.command
);
1154 UNSERIALIZE_SCALAR(status
);
1155 UNSERIALIZE_SCALAR(nIENBit
);
1156 UNSERIALIZE_SCALAR(devID
);
1158 // Unserialize the PRD related information
1159 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1160 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1161 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1162 UNSERIALIZE_SCALAR(curPrdAddr
);
1164 // Unserialize current transfer related information
1165 UNSERIALIZE_SCALAR(cmdBytes
);
1166 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1167 UNSERIALIZE_SCALAR(drqBytesLeft
);
1168 UNSERIALIZE_SCALAR(curSector
);
1169 UNSERIALIZE_SCALAR(dmaRead
);
1170 UNSERIALIZE_SCALAR(dmaInterfaceBytes
);
1171 UNSERIALIZE_SCALAR(intrPending
);
1172 UNSERIALIZE_ENUM(devState
);
1173 UNSERIALIZE_ENUM(dmaState
);
1174 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1177 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1179 enum DriveID
{ master
, slave
};
1180 static const char *DriveID_strings
[] = { "master", "slave" };
1181 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1183 SimObjectParam
<DiskImage
*> image
;
1184 SimObjectParam
<PhysicalMemory
*> physmem
;
1185 SimpleEnumParam
<DriveID
> driveID
;
1188 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1190 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1192 INIT_PARAM(image
, "Disk image"),
1193 INIT_PARAM(physmem
, "Physical memory"),
1194 INIT_ENUM_PARAM(driveID
, "Drive ID (0=master 1=slave)", DriveID_strings
),
1195 INIT_PARAM_DFLT(delay
, "Fixed disk delay in microseconds", 1)
1197 END_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1200 CREATE_SIM_OBJECT(IdeDisk
)
1202 return new IdeDisk(getInstanceName(), image
, physmem
, driveID
, delay
);
1205 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk
)
1207 #endif //DOXYGEN_SHOULD_SKIP_THIS