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 "arch/alpha/pmap.h"
39 #include "base/cprintf.hh" // csprintf
40 #include "base/trace.hh"
41 #include "dev/disk_image.hh"
42 #include "dev/ide_disk.hh"
43 #include "dev/ide_ctrl.hh"
44 #include "dev/tsunami.hh"
45 #include "dev/tsunami_pchip.hh"
46 #include "mem/functional_mem/physical_memory.hh"
47 #include "mem/bus/bus.hh"
48 #include "mem/bus/dma_interface.hh"
49 #include "mem/bus/pio_interface.hh"
50 #include "mem/bus/pio_interface_impl.hh"
51 #include "sim/builder.hh"
52 #include "sim/sim_object.hh"
53 #include "sim/universe.hh"
57 IdeDisk::IdeDisk(const string
&name
, DiskImage
*img
, PhysicalMemory
*phys
,
59 : SimObject(name
), ctrl(NULL
), image(img
), physmem(phys
),
60 dmaTransferEvent(this), dmaReadWaitEvent(this),
61 dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
62 dmaReadEvent(this), dmaWriteEvent(this)
64 // calculate disk delay in microseconds
65 diskDelay
= (delay
* ticksPerSecond
/ 100000);
67 // initialize the data buffer and shadow registers
68 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
70 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
71 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
72 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
74 dmaInterfaceBytes
= 0;
83 // fill out the drive ID structure
84 memset(&driveID
, 0, sizeof(struct hd_driveid
));
86 // Calculate LBA and C/H/S values
91 uint32_t lba_size
= image
->size();
92 if (lba_size
>= 16383*16*63) {
102 if ((lba_size
/ sectors
) >= 16)
105 heads
= (lba_size
/ sectors
);
107 cylinders
= lba_size
/ (heads
* sectors
);
110 // Setup the model name
111 sprintf((char *)driveID
.model
, "5MI EDD si k");
112 // Set the maximum multisector transfer size
113 driveID
.max_multsect
= MAX_MULTSECT
;
114 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
115 driveID
.capability
= 0x7;
116 // UDMA support, EIDE support
117 driveID
.field_valid
= 0x6;
118 // Setup default C/H/S settings
119 driveID
.cyls
= cylinders
;
120 driveID
.sectors
= sectors
;
121 driveID
.heads
= heads
;
122 // Setup the current multisector transfer size
123 driveID
.multsect
= MAX_MULTSECT
;
124 driveID
.multsect_valid
= 0x1;
125 // Number of sectors on disk
126 driveID
.lba_capacity
= lba_size
;
127 // Multiword DMA mode 2 and below supported
128 driveID
.dma_mword
= 0x400;
129 // Set PIO mode 4 and 3 supported
130 driveID
.eide_pio_modes
= 0x3;
131 // Set DMA mode 4 and below supported
132 driveID
.dma_ultra
= 0x10;
133 // Statically set hardware config word
134 driveID
.hw_config
= 0x4001;
136 // set the device state to idle
140 devState
= Device_Idle_S
;
142 } else if (id
== DEV1
) {
143 devState
= Device_Idle_NS
;
146 panic("Invalid device ID: %#x\n", id
);
149 // set the device ready bit
150 cmdReg
.status
|= STATUS_DRDY_BIT
;
155 // destroy the data buffer
156 delete [] dataBuffer
;
164 IdeDisk::pciToDma(Addr pciAddr
)
167 return ctrl
->tsunami
->pchip
->translatePciToDma(pciAddr
);
169 panic("Access to unset controller!\n");
173 IdeDisk::bytesInDmaPage(Addr curAddr
, uint32_t bytesLeft
)
175 uint32_t bytesInPage
= 0;
177 // First calculate how many bytes could be in the page
178 if (bytesLeft
> ALPHA_PGBYTES
)
179 bytesInPage
= ALPHA_PGBYTES
;
181 bytesInPage
= bytesLeft
;
183 // Next, see if we have crossed a page boundary, and adjust
184 Addr upperBound
= curAddr
+ bytesInPage
;
185 Addr pageBound
= alpha_trunc_page(curAddr
) + ALPHA_PGBYTES
;
187 assert(upperBound
>= curAddr
&& "DMA read wraps around address space!\n");
189 if (upperBound
>= pageBound
)
190 bytesInPage
= pageBound
- curAddr
;
196 // Device registers read/write
200 IdeDisk::read(const Addr
&offset
, bool byte
, bool cmdBlk
, uint8_t *data
)
202 DevAction_t action
= ACT_NONE
;
205 if (offset
< 0 || offset
> sizeof(CommandReg_t
))
206 panic("Invalid disk command register offset: %#x\n", offset
);
208 if (!byte
&& offset
!= DATA_OFFSET
)
209 panic("Invalid 16-bit read, only allowed on data reg\n");
212 *(uint16_t *)data
= *(uint16_t *)&cmdReg
.data0
;
214 *data
= ((uint8_t *)&cmdReg
)[offset
];
216 // determine if an action needs to be taken on the state machine
217 if (offset
== STATUS_OFFSET
) {
218 action
= ACT_STAT_READ
;
219 } else if (offset
== DATA_OFFSET
) {
221 action
= ACT_DATA_READ_BYTE
;
223 action
= ACT_DATA_READ_SHORT
;
227 if (offset
!= ALTSTAT_OFFSET
)
228 panic("Invalid disk control register offset: %#x\n", offset
);
231 panic("Invalid 16-bit read from control block\n");
233 *data
= ((uint8_t *)&cmdReg
)[STATUS_OFFSET
];
236 if (action
!= ACT_NONE
)
241 IdeDisk::write(const Addr
&offset
, bool byte
, bool cmdBlk
, const uint8_t *data
)
243 DevAction_t action
= ACT_NONE
;
246 if (offset
< 0 || offset
> sizeof(CommandReg_t
))
247 panic("Invalid disk command register offset: %#x\n", offset
);
249 if (!byte
&& offset
!= DATA_OFFSET
)
250 panic("Invalid 16-bit write, only allowed on data reg\n");
253 *((uint16_t *)&cmdReg
.data0
) = *(uint16_t *)data
;
255 ((uint8_t *)&cmdReg
)[offset
] = *data
;
257 // determine if an action needs to be taken on the state machine
258 if (offset
== COMMAND_OFFSET
) {
259 action
= ACT_CMD_WRITE
;
260 } else if (offset
== DATA_OFFSET
) {
262 action
= ACT_DATA_WRITE_BYTE
;
264 action
= ACT_DATA_WRITE_SHORT
;
268 if (offset
!= CONTROL_OFFSET
)
269 panic("Invalid disk control register offset: %#x\n", offset
);
272 panic("Invalid 16-bit write to control block\n");
274 if (*data
& CONTROL_RST_BIT
)
275 panic("Software reset not supported!\n");
277 nIENBit
= (*data
& CONTROL_IEN_BIT
) ? true : false;
280 if (action
!= ACT_NONE
)
285 // Perform DMA transactions
289 IdeDisk::doDmaTransfer()
291 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
292 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
295 // first read the current PRD
297 if (dmaInterface
->busy()) {
298 // reschedule after waiting period
299 dmaTransferEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
303 dmaInterface
->doDMA(Read
, curPrdAddr
, sizeof(PrdEntry_t
), curTick
,
311 IdeDisk::dmaPrdReadDone()
313 // actually copy the PRD from physical memory
314 memcpy((void *)&curPrd
.entry
,
315 physmem
->dma_addr(curPrdAddr
, sizeof(PrdEntry_t
)),
318 curPrdAddr
+= sizeof(PrdEntry_t
);
329 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
332 if (dmaInterface
->busy()) {
333 // reschedule after waiting period
334 dmaReadWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
338 Addr dmaAddr
= pciToDma(curPrd
.getBaseAddr());
340 uint32_t bytesInPage
= bytesInDmaPage(curPrd
.getBaseAddr(),
341 (uint32_t)curPrd
.getByteCount());
343 dmaInterfaceBytes
= bytesInPage
;
345 dmaInterface
->doDMA(Read
, dmaAddr
, bytesInPage
,
346 curTick
+ totalDiskDelay
, &dmaReadEvent
);
348 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
349 dmaReadEvent
.schedule(curTick
+ totalDiskDelay
);
354 IdeDisk::dmaReadDone()
357 Addr curAddr
= 0, dmaAddr
= 0;
358 uint32_t bytesWritten
= 0, bytesInPage
= 0, bytesLeft
= 0;
360 // continue to use the DMA interface until all pages are read
361 if (dmaInterface
&& (dmaInterfaceBytes
< curPrd
.getByteCount())) {
362 // see if the interface is busy
363 if (dmaInterface
->busy()) {
364 // reschedule after waiting period
365 dmaReadEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
369 uint32_t bytesLeft
= curPrd
.getByteCount() - dmaInterfaceBytes
;
370 curAddr
= curPrd
.getBaseAddr() + dmaInterfaceBytes
;
371 dmaAddr
= pciToDma(curAddr
);
373 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
374 dmaInterfaceBytes
+= bytesInPage
;
376 dmaInterface
->doDMA(Read
, dmaAddr
, bytesInPage
,
377 curTick
, &dmaReadEvent
);
382 // set initial address
383 curAddr
= curPrd
.getBaseAddr();
385 // clear out the data buffer
386 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
388 // read the data from memory via DMA into a data buffer
389 while (bytesWritten
< curPrd
.getByteCount()) {
390 if (cmdBytesLeft
<= 0)
391 panic("DMA data is larger than # of sectors specified\n");
393 dmaAddr
= pciToDma(curAddr
);
395 // calculate how many bytes are in the current page
396 bytesLeft
= curPrd
.getByteCount() - bytesWritten
;
397 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
399 // copy the data from memory into the data buffer
400 memcpy((void *)(dataBuffer
+ bytesWritten
),
401 physmem
->dma_addr(dmaAddr
, bytesInPage
),
404 curAddr
+= bytesInPage
;
405 bytesWritten
+= bytesInPage
;
406 cmdBytesLeft
-= bytesInPage
;
409 // write the data to the disk image
410 for (bytesWritten
= 0;
411 bytesWritten
< curPrd
.getByteCount();
412 bytesWritten
+= SectorSize
) {
414 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
418 // actually copy the data from memory to data buffer
420 ctrl
->tsunami
->pchip
->translatePciToDma(curPrd
.getBaseAddr());
421 memcpy((void *)dataBuffer
,
422 physmem
->dma_addr(dmaAddr
, curPrd
.getByteCount()),
423 curPrd
.getByteCount());
425 uint32_t bytesWritten
= 0;
427 while (bytesWritten
< curPrd
.getByteCount()) {
428 if (cmdBytesLeft
<= 0)
429 panic("DMA data is larger than # sectors specified\n");
431 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
433 bytesWritten
+= SectorSize
;
434 cmdBytesLeft
-= SectorSize
;
439 if (curPrd
.getEOT()){
440 assert(cmdBytesLeft
== 0);
442 updateState(ACT_DMA_DONE
);
449 IdeDisk::doDmaWrite()
451 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
454 if (dmaInterface
->busy()) {
455 // reschedule after waiting period
456 dmaWriteWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
460 Addr dmaAddr
= pciToDma(curPrd
.getBaseAddr());
462 uint32_t bytesInPage
= bytesInDmaPage(curPrd
.getBaseAddr(),
463 (uint32_t)curPrd
.getByteCount());
465 dmaInterfaceBytes
= bytesInPage
;
467 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
468 bytesInPage
, curTick
+ totalDiskDelay
,
471 // schedule event with disk delay (dmaWriteDone)
472 dmaWriteEvent
.schedule(curTick
+ totalDiskDelay
);
477 IdeDisk::dmaWriteDone()
479 Addr curAddr
= 0, pageAddr
= 0, dmaAddr
= 0;
480 uint32_t bytesRead
= 0, bytesInPage
= 0;
482 // continue to use the DMA interface until all pages are read
483 if (dmaInterface
&& (dmaInterfaceBytes
< curPrd
.getByteCount())) {
484 // see if the interface is busy
485 if (dmaInterface
->busy()) {
486 // reschedule after waiting period
487 dmaWriteEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
491 uint32_t bytesLeft
= curPrd
.getByteCount() - dmaInterfaceBytes
;
492 curAddr
= curPrd
.getBaseAddr() + dmaInterfaceBytes
;
493 dmaAddr
= pciToDma(curAddr
);
495 bytesInPage
= bytesInDmaPage(curAddr
, bytesLeft
);
496 dmaInterfaceBytes
+= bytesInPage
;
498 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
499 bytesInPage
, curTick
,
505 // setup the initial page and DMA address
506 curAddr
= curPrd
.getBaseAddr();
507 pageAddr
= alpha_trunc_page(curAddr
);
508 dmaAddr
= pciToDma(curAddr
);
510 // clear out the data buffer
511 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
513 while (bytesRead
< curPrd
.getByteCount()) {
514 // see if we have crossed into a new page
515 if (pageAddr
!= alpha_trunc_page(curAddr
)) {
516 // write the data to memory
517 memcpy(physmem
->dma_addr(dmaAddr
, bytesInPage
),
518 (void *)(dataBuffer
+ (bytesRead
- bytesInPage
)),
521 // update the DMA address and page address
522 pageAddr
= alpha_trunc_page(curAddr
);
523 dmaAddr
= pciToDma(curAddr
);
528 if (cmdBytesLeft
<= 0)
529 panic("DMA requested data is larger than # sectors specified\n");
531 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
533 curAddr
+= SectorSize
;
534 bytesRead
+= SectorSize
;
535 bytesInPage
+= SectorSize
;
536 cmdBytesLeft
-= SectorSize
;
539 // write the last page worth read to memory
540 if (bytesInPage
!= 0) {
541 memcpy(physmem
->dma_addr(dmaAddr
, bytesInPage
),
542 (void *)(dataBuffer
+ (bytesRead
- bytesInPage
)),
547 Addr dmaAddr
= ctrl
->tsunami
->pchip
->
548 translatePciToDma(curPrd
.getBaseAddr());
550 memcpy(physmem
->dma_addr(dmaAddr
, curPrd
.getByteCount()),
551 (void *)dataBuffer
, curPrd
.getByteCount());
555 if (curPrd
.getEOT()) {
556 assert(cmdBytesLeft
== 0);
558 updateState(ACT_DMA_DONE
);
565 // Disk utility routines
569 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
571 uint32_t bytesRead
= image
->read(data
, sector
);
573 if (bytesRead
!= SectorSize
)
574 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
575 name(), bytesRead
, SectorSize
, errno
);
579 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
581 uint32_t bytesWritten
= image
->write(data
, sector
);
583 if (bytesWritten
!= SectorSize
)
584 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
585 name(), bytesWritten
, SectorSize
, errno
);
589 // Setup and handle commands
593 IdeDisk::startDma(const uint32_t &prdTableBase
)
595 if (dmaState
!= Dma_Start
)
596 panic("Inconsistent DMA state, should be in Dma_Start!\n");
598 if (devState
!= Transfer_Data_Dma
)
599 panic("Inconsistent device state for DMA start!\n");
601 curPrdAddr
= pciToDma((Addr
)prdTableBase
);
603 dmaState
= Dma_Transfer
;
605 // schedule dma transfer (doDmaTransfer)
606 dmaTransferEvent
.schedule(curTick
+ 1);
612 if (dmaState
== Dma_Idle
)
613 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n");
615 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
616 panic("Inconsistent device state, should be in Transfer or Prepare!\n");
618 updateState(ACT_CMD_ERROR
);
622 IdeDisk::startCommand()
624 DevAction_t action
= ACT_NONE
;
628 // copy the command to the shadow
629 curCommand
= cmdReg
.command
;
632 switch (cmdReg
.command
) {
633 // Supported non-data commands
634 case WIN_READ_NATIVE_MAX
:
635 size
= image
->size() - 1;
636 cmdReg
.sec_num
= (size
& 0xff);
637 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
638 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
639 cmdReg
.head
= ((size
& 0xf000000) >> 24);
641 devState
= Command_Execution
;
642 action
= ACT_CMD_COMPLETE
;
647 case WIN_STANDBYNOW1
:
648 case WIN_FLUSH_CACHE
:
651 case WIN_SETFEATURES
:
653 devState
= Command_Execution
;
654 action
= ACT_CMD_COMPLETE
;
657 // Supported PIO data-in commands
659 cmdBytesLeft
= sizeof(struct hd_driveid
);
660 devState
= Prepare_Data_In
;
661 action
= ACT_DATA_READY
;
666 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
667 panic("Attempt to perform CHS access, only supports LBA\n");
669 if (cmdReg
.sec_count
== 0)
670 cmdBytesLeft
= (256 * SectorSize
);
672 cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
674 curSector
= getLBABase();
676 /** @todo make this a scheduled event to simulate disk delay */
677 devState
= Prepare_Data_In
;
678 action
= ACT_DATA_READY
;
681 // Supported PIO data-out commands
684 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
685 panic("Attempt to perform CHS access, only supports LBA\n");
687 if (cmdReg
.sec_count
== 0)
688 cmdBytesLeft
= (256 * SectorSize
);
690 cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
692 curSector
= getLBABase();
694 devState
= Prepare_Data_Out
;
695 action
= ACT_DATA_READY
;
698 // Supported DMA commands
700 dmaRead
= true; // a write to the disk is a DMA read from memory
702 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
703 panic("Attempt to perform CHS access, only supports LBA\n");
705 if (cmdReg
.sec_count
== 0)
706 cmdBytesLeft
= (256 * SectorSize
);
708 cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
710 curSector
= getLBABase();
712 devState
= Prepare_Data_Dma
;
713 action
= ACT_DMA_READY
;
717 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
720 if (action
!= ACT_NONE
) {
722 cmdReg
.status
|= STATUS_BSY_BIT
;
724 cmdReg
.status
&= ~STATUS_DRQ_BIT
;
731 // Handle setting and clearing interrupts
738 panic("Attempt to post an interrupt with one pending\n");
742 // talk to controller to set interrupt
751 panic("Attempt to clear a non-pending interrupt\n");
755 // talk to controller to clear interrupt
761 // Manage the device internal state machine
765 IdeDisk::updateState(DevAction_t action
)
770 devState
= Device_Idle_NS
;
771 else if (action
== ACT_CMD_WRITE
)
777 if (!isDEVSelect()) {
778 devState
= Device_Idle_NS
;
780 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
781 devState
= Device_Idle_S
;
783 } else if (action
== ACT_CMD_WRITE
) {
792 if (!isIENSet() && intrPending
) {
793 devState
= Device_Idle_SI
;
796 if (isIENSet() || !intrPending
) {
797 devState
= Device_Idle_S
;
802 case Command_Execution
:
803 if (action
== ACT_CMD_COMPLETE
) {
808 devState
= Device_Idle_SI
;
811 devState
= Device_Idle_S
;
816 case Prepare_Data_In
:
817 if (action
== ACT_CMD_ERROR
) {
822 devState
= Device_Idle_SI
;
825 devState
= Device_Idle_S
;
827 } else if (action
== ACT_DATA_READY
) {
829 cmdReg
.status
&= ~STATUS_BSY_BIT
;
831 cmdReg
.status
|= STATUS_DRQ_BIT
;
833 // copy the data into the data buffer
834 if (curCommand
== WIN_IDENTIFY
) {
835 // Reset the drqBytes for this block
836 drqBytesLeft
= sizeof(struct hd_driveid
);
838 memcpy((void *)dataBuffer
, (void *)&driveID
,
839 sizeof(struct hd_driveid
));
841 // Reset the drqBytes for this block
842 drqBytesLeft
= SectorSize
;
844 readDisk(curSector
++, dataBuffer
);
847 // put the first two bytes into the data register
848 memcpy((void *)&cmdReg
.data0
, (void *)dataBuffer
,
852 devState
= Data_Ready_INTRQ_In
;
855 devState
= Transfer_Data_In
;
860 case Data_Ready_INTRQ_In
:
861 if (action
== ACT_STAT_READ
) {
862 devState
= Transfer_Data_In
;
867 case Transfer_Data_In
:
868 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
869 if (action
== ACT_DATA_READ_BYTE
) {
870 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
875 // copy next short into data registers
877 memcpy((void *)&cmdReg
.data0
,
878 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
882 if (drqBytesLeft
== 0) {
883 if (cmdBytesLeft
== 0) {
886 devState
= Device_Idle_S
;
888 devState
= Prepare_Data_In
;
890 cmdReg
.status
|= STATUS_BSY_BIT
;
892 cmdReg
.status
&= ~STATUS_DRQ_BIT
;
894 /** @todo change this to a scheduled event to simulate
896 updateState(ACT_DATA_READY
);
902 case Prepare_Data_Out
:
903 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
908 devState
= Device_Idle_SI
;
911 devState
= Device_Idle_S
;
913 } else if (cmdBytesLeft
!= 0) {
915 cmdReg
.status
&= ~STATUS_BSY_BIT
;
917 cmdReg
.status
|= STATUS_DRQ_BIT
;
919 // clear the data buffer to get it ready for writes
920 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
923 devState
= Data_Ready_INTRQ_Out
;
926 devState
= Transfer_Data_Out
;
931 case Data_Ready_INTRQ_Out
:
932 if (action
== ACT_STAT_READ
) {
933 devState
= Transfer_Data_Out
;
938 case Transfer_Data_Out
:
939 if (action
== ACT_DATA_WRITE_BYTE
||
940 action
== ACT_DATA_WRITE_SHORT
) {
942 if (action
== ACT_DATA_READ_BYTE
) {
943 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
945 // copy the latest short into the data buffer
946 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
947 (void *)&cmdReg
.data0
,
954 if (drqBytesLeft
== 0) {
955 // copy the block to the disk
956 writeDisk(curSector
++, dataBuffer
);
959 cmdReg
.status
|= STATUS_BSY_BIT
;
961 cmdReg
.status
&= ~STATUS_DRQ_BIT
;
963 devState
= Prepare_Data_Out
;
965 /** @todo change this to a scheduled event to simulate
967 updateState(ACT_DATA_READY
);
972 case Prepare_Data_Dma
:
973 if (action
== ACT_CMD_ERROR
) {
978 devState
= Device_Idle_SI
;
981 devState
= Device_Idle_S
;
983 } else if (action
== ACT_DMA_READY
) {
985 cmdReg
.status
&= ~STATUS_BSY_BIT
;
987 cmdReg
.status
|= STATUS_DRQ_BIT
;
989 devState
= Transfer_Data_Dma
;
991 if (dmaState
!= Dma_Idle
)
992 panic("Inconsistent DMA state, should be Dma_Idle\n");
994 dmaState
= Dma_Start
;
995 // wait for the write to the DMA start bit
999 case Transfer_Data_Dma
:
1000 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
1001 // clear the BSY bit
1004 cmdReg
.status
|= 0x10;
1005 // clear the controller state for DMA transfer
1006 ctrl
->setDmaComplete(this);
1009 devState
= Device_Idle_SI
;
1012 devState
= Device_Idle_S
;
1018 panic("Unknown IDE device state: %#x\n", devState
);
1023 IdeDisk::serialize(ostream
&os
)
1025 // Check all outstanding events to see if they are scheduled
1026 // these are all mutually exclusive
1027 Tick reschedule
= 0;
1028 Events_t event
= None
;
1030 if (dmaTransferEvent
.scheduled()) {
1031 reschedule
= dmaTransferEvent
.when();
1033 } else if (dmaReadWaitEvent
.scheduled()) {
1034 reschedule
= dmaReadWaitEvent
.when();
1036 } else if (dmaWriteWaitEvent
.scheduled()) {
1037 reschedule
= dmaWriteWaitEvent
.when();
1039 } else if (dmaPrdReadEvent
.scheduled()) {
1040 reschedule
= dmaPrdReadEvent
.when();
1042 } else if (dmaReadEvent
.scheduled()) {
1043 reschedule
= dmaReadEvent
.when();
1045 } else if (dmaWriteEvent
.scheduled()) {
1046 reschedule
= dmaWriteEvent
.when();
1050 SERIALIZE_SCALAR(reschedule
);
1051 SERIALIZE_ENUM(event
);
1053 // Serialize device registers
1054 SERIALIZE_SCALAR(cmdReg
.data0
);
1055 SERIALIZE_SCALAR(cmdReg
.data1
);
1056 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1057 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1058 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1059 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1060 SERIALIZE_SCALAR(cmdReg
.drive
);
1061 SERIALIZE_SCALAR(cmdReg
.status
);
1062 SERIALIZE_SCALAR(nIENBit
);
1063 SERIALIZE_SCALAR(devID
);
1065 // Serialize the PRD related information
1066 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1067 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1068 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1069 SERIALIZE_SCALAR(curPrdAddr
);
1071 // Serialize current transfer related information
1072 SERIALIZE_SCALAR(cmdBytesLeft
);
1073 SERIALIZE_SCALAR(drqBytesLeft
);
1074 SERIALIZE_SCALAR(curSector
);
1075 SERIALIZE_SCALAR(curCommand
);
1076 SERIALIZE_SCALAR(dmaRead
);
1077 SERIALIZE_SCALAR(dmaInterfaceBytes
);
1078 SERIALIZE_SCALAR(intrPending
);
1079 SERIALIZE_ENUM(devState
);
1080 SERIALIZE_ENUM(dmaState
);
1081 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1085 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1087 // Reschedule events that were outstanding
1088 // these are all mutually exclusive
1089 Tick reschedule
= 0;
1090 Events_t event
= None
;
1092 UNSERIALIZE_SCALAR(reschedule
);
1093 UNSERIALIZE_ENUM(event
);
1097 case Transfer
: dmaTransferEvent
.schedule(reschedule
); break;
1098 case ReadWait
: dmaReadWaitEvent
.schedule(reschedule
); break;
1099 case WriteWait
: dmaWriteWaitEvent
.schedule(reschedule
); break;
1100 case PrdRead
: dmaPrdReadEvent
.schedule(reschedule
); break;
1101 case DmaRead
: dmaReadEvent
.schedule(reschedule
); break;
1102 case DmaWrite
: dmaWriteEvent
.schedule(reschedule
); break;
1105 // Unserialize device registers
1106 UNSERIALIZE_SCALAR(cmdReg
.data0
);
1107 UNSERIALIZE_SCALAR(cmdReg
.data1
);
1108 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1109 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1110 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1111 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1112 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1113 UNSERIALIZE_SCALAR(cmdReg
.status
);
1114 UNSERIALIZE_SCALAR(nIENBit
);
1115 UNSERIALIZE_SCALAR(devID
);
1117 // Unserialize the PRD related information
1118 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1119 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1120 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1121 UNSERIALIZE_SCALAR(curPrdAddr
);
1123 // Unserialize current transfer related information
1124 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1125 UNSERIALIZE_SCALAR(drqBytesLeft
);
1126 UNSERIALIZE_SCALAR(curSector
);
1127 UNSERIALIZE_SCALAR(curCommand
);
1128 UNSERIALIZE_SCALAR(dmaRead
);
1129 UNSERIALIZE_SCALAR(dmaInterfaceBytes
);
1130 UNSERIALIZE_SCALAR(intrPending
);
1131 UNSERIALIZE_ENUM(devState
);
1132 UNSERIALIZE_ENUM(dmaState
);
1133 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1136 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1138 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1140 SimObjectParam
<DiskImage
*> image
;
1141 SimObjectParam
<PhysicalMemory
*> physmem
;
1143 Param
<int> disk_delay
;
1145 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
1147 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1149 INIT_PARAM(image
, "Disk image"),
1150 INIT_PARAM(physmem
, "Physical memory"),
1151 INIT_PARAM(driveID
, "Drive ID (0=master 1=slave)"),
1152 INIT_PARAM_DFLT(disk_delay
, "Fixed disk delay in microseconds", 1)
1154 END_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
1157 CREATE_SIM_OBJECT(IdeDisk
)
1159 return new IdeDisk(getInstanceName(), image
, physmem
, driveID
,
1163 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk
)
1165 #endif //DOXYGEN_SHOULD_SKIP_THIS