/*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2004 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "sim/builder.hh"
#include "sim/sim_object.hh"
#include "sim/universe.hh"
+#include "targetarch/isa_traits.hh"
using namespace std;
dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
dmaReadEvent(this), dmaWriteEvent(this)
{
- diskDelay = (delay * ticksPerSecond / 1000) / image->size();
+ // Reset the device state
+ reset(id);
- // initialize the data buffer and shadow registers
- dataBuffer = new uint8_t[MAX_DMA_SIZE];
-
- memset(dataBuffer, 0, MAX_DMA_SIZE);
- memset(&cmdReg, 0, sizeof(CommandReg_t));
- memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
-
- curPrdAddr = 0;
- curSector = 0;
- curCommand = 0;
- cmdBytesLeft = 0;
- drqBytesLeft = 0;
- dmaRead = false;
- intrPending = false;
+ // calculate disk delay in microseconds
+ diskDelay = (delay * ticksPerSecond / 100000);
// fill out the drive ID structure
memset(&driveID, 0, sizeof(struct hd_driveid));
driveID.dma_ultra = 0x10;
// Statically set hardware config word
driveID.hw_config = 0x4001;
+}
+
+IdeDisk::~IdeDisk()
+{
+ // destroy the data buffer
+ delete [] dataBuffer;
+}
+
+void
+IdeDisk::reset(int id)
+{
+ // initialize the data buffer and shadow registers
+ dataBuffer = new uint8_t[MAX_DMA_SIZE];
+
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ memset(&cmdReg, 0, sizeof(CommandReg_t));
+ memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
+
+ dmaInterfaceBytes = 0;
+ curPrdAddr = 0;
+ curSector = 0;
+ cmdBytes = 0;
+ cmdBytesLeft = 0;
+ drqBytesLeft = 0;
+ dmaRead = false;
+ intrPending = false;
// set the device state to idle
dmaState = Dma_Idle;
}
// set the device ready bit
- cmdReg.status |= STATUS_DRDY_BIT;
+ status = STATUS_DRDY_BIT;
}
-IdeDisk::~IdeDisk()
+////
+// Utility functions
+////
+
+bool
+IdeDisk::isDEVSelect()
{
- // destroy the data buffer
- delete [] dataBuffer;
+ return ctrl->isDiskSelected(this);
+}
+
+Addr
+IdeDisk::pciToDma(Addr pciAddr)
+{
+ if (ctrl)
+ return ctrl->plat->pciToDma(pciAddr);
+ else
+ panic("Access to unset controller!\n");
+}
+
+uint32_t
+IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
+{
+ uint32_t bytesInPage = 0;
+
+ // First calculate how many bytes could be in the page
+ if (bytesLeft > TheISA::PageBytes)
+ bytesInPage = TheISA::PageBytes;
+ else
+ bytesInPage = bytesLeft;
+
+ // Next, see if we have crossed a page boundary, and adjust
+ Addr upperBound = curAddr + bytesInPage;
+ Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes;
+
+ assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
+
+ if (upperBound >= pageBound)
+ bytesInPage = pageBound - curAddr;
+
+ return bytesInPage;
}
////
// determine if an action needs to be taken on the state machine
if (offset == STATUS_OFFSET) {
action = ACT_STAT_READ;
+ *data = status; // status is in a shadow, explicity copy
} else if (offset == DATA_OFFSET) {
if (byte)
action = ACT_DATA_READ_BYTE;
if (!byte)
panic("Invalid 16-bit read from control block\n");
- *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET];
+ *data = status;
}
if (action != ACT_NONE)
action = ACT_DATA_WRITE_BYTE;
else
action = ACT_DATA_WRITE_SHORT;
+ } else if (offset == SELECT_OFFSET) {
+ action = ACT_SELECT_WRITE;
}
} else {
if (!byte)
panic("Invalid 16-bit write to control block\n");
- if (*data & CONTROL_RST_BIT)
- panic("Software reset not supported!\n");
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ action = ACT_SRST_SET;
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
+ action = ACT_SRST_CLEAR;
+ }
nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
}
physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
sizeof(PrdEntry_t));
- curPrdAddr += sizeof(PrdEntry_t);
+ DPRINTF(IdeDisk, "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
+ curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
+ curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
+ curPrd.getEOT(), curSector);
+
+ // the prd pointer has already been translated, so just do an increment
+ curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
if (dmaRead)
doDmaRead();
void
IdeDisk::doDmaRead()
{
- Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
if (dmaInterface) {
if (dmaInterface->busy()) {
return;
}
- Addr dmaAddr =
- ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
- dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(),
+ Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
+
+ uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
+ (uint32_t)curPrd.getByteCount());
+
+ dmaInterfaceBytes = bytesInPage;
+
+ dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
curTick + totalDiskDelay, &dmaReadEvent);
} else {
// schedule dmaReadEvent with sectorDelay (dmaReadDone)
void
IdeDisk::dmaReadDone()
{
- // actually copy the data from memory to data buffer
- Addr dmaAddr =
- ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
- memcpy((void *)dataBuffer,
- physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
- curPrd.getByteCount());
- uint32_t bytesWritten = 0;
+ Addr curAddr = 0, dmaAddr = 0;
+ uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
+
+ // continue to use the DMA interface until all pages are read
+ if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
+ // see if the interface is busy
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
+ curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
+ dmaAddr = pciToDma(curAddr);
+
+ bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+ dmaInterfaceBytes += bytesInPage;
+
+ dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
+ curTick, &dmaReadEvent);
+
+ return;
+ }
+
+ // set initial address
+ curAddr = curPrd.getBaseAddr();
+ // clear out the data buffer
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+
+ // read the data from memory via DMA into a data buffer
while (bytesWritten < curPrd.getByteCount()) {
if (cmdBytesLeft <= 0)
- panic("DMA data is larger than # sectors specified\n");
+ panic("DMA data is larger than # of sectors specified\n");
- writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
+ dmaAddr = pciToDma(curAddr);
- bytesWritten += SectorSize;
- cmdBytesLeft -= SectorSize;
+ // calculate how many bytes are in the current page
+ bytesLeft = curPrd.getByteCount() - bytesWritten;
+ bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+
+ // copy the data from memory into the data buffer
+ memcpy((void *)(dataBuffer + bytesWritten),
+ physmem->dma_addr(dmaAddr, bytesInPage),
+ bytesInPage);
+
+ curAddr += bytesInPage;
+ bytesWritten += bytesInPage;
+ cmdBytesLeft -= bytesInPage;
+ }
+
+ // write the data to the disk image
+ for (bytesWritten = 0;
+ bytesWritten < curPrd.getByteCount();
+ bytesWritten += SectorSize) {
+
+ writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
}
// check for the EOT
- if (curPrd.getEOT()){
+ if (curPrd.getEOT()) {
assert(cmdBytesLeft == 0);
dmaState = Dma_Idle;
updateState(ACT_DMA_DONE);
void
IdeDisk::doDmaWrite()
{
- Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
if (dmaInterface) {
if (dmaInterface->busy()) {
return;
}
- Addr dmaAddr =
- ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
+ Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
+
+ uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
+ (uint32_t)curPrd.getByteCount());
+
+ dmaInterfaceBytes = bytesInPage;
+
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
- curPrd.getByteCount(), curTick + totalDiskDelay,
+ bytesInPage, curTick + totalDiskDelay,
&dmaWriteEvent);
} else {
// schedule event with disk delay (dmaWriteDone)
void
IdeDisk::dmaWriteDone()
{
- uint32_t bytesRead = 0;
+ Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
+ uint32_t bytesRead = 0, bytesInPage = 0;
+
+ // continue to use the DMA interface until all pages are read
+ if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
+ // see if the interface is busy
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
+ curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
+ dmaAddr = pciToDma(curAddr);
+
+ bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+ dmaInterfaceBytes += bytesInPage;
+
+ dmaInterface->doDMA(WriteInvalidate, dmaAddr,
+ bytesInPage, curTick,
+ &dmaWriteEvent);
+
+ return;
+ }
+
+ // setup the initial page and DMA address
+ curAddr = curPrd.getBaseAddr();
+ pageAddr = TheISA::TruncPage(curAddr);
+ dmaAddr = pciToDma(curAddr);
// clear out the data buffer
memset(dataBuffer, 0, MAX_DMA_SIZE);
while (bytesRead < curPrd.getByteCount()) {
+ // see if we have crossed into a new page
+ if (pageAddr != TheISA::TruncPage(curAddr)) {
+ // write the data to memory
+ memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
+ (void *)(dataBuffer + (bytesRead - bytesInPage)),
+ bytesInPage);
+
+ // update the DMA address and page address
+ pageAddr = TheISA::TruncPage(curAddr);
+ dmaAddr = pciToDma(curAddr);
+
+ bytesInPage = 0;
+ }
+
if (cmdBytesLeft <= 0)
panic("DMA requested data is larger than # sectors specified\n");
readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
+ curAddr += SectorSize;
bytesRead += SectorSize;
+ bytesInPage += SectorSize;
cmdBytesLeft -= SectorSize;
}
- // copy the data to memory
- Addr dmaAddr = ctrl->tsunami->pchip->
- translatePciToDma(curPrd.getBaseAddr());
-
- memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
- (void *)dataBuffer, curPrd.getByteCount());
+ // write the last page worth read to memory
+ if (bytesInPage != 0) {
+ memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
+ (void *)(dataBuffer + (bytesRead - bytesInPage)),
+ bytesInPage);
+ }
// check for the EOT
if (curPrd.getEOT()) {
if (devState != Transfer_Data_Dma)
panic("Inconsistent device state for DMA start!\n");
- curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase);
+ // PRD base address is given by bits 31:2
+ curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
dmaState = Dma_Transfer;
uint32_t size = 0;
dmaRead = false;
- // copy the command to the shadow
- curCommand = cmdReg.command;
-
// Decode commands
switch (cmdReg.command) {
// Supported non-data commands
case WIN_RECAL:
case WIN_SPECIFY:
+ case WIN_STANDBYNOW1:
case WIN_FLUSH_CACHE:
case WIN_VERIFY:
case WIN_SEEK:
// Supported PIO data-in commands
case WIN_IDENTIFY:
- cmdBytesLeft = drqBytesLeft = sizeof(struct hd_driveid);
+ cmdBytes = cmdBytesLeft = sizeof(struct hd_driveid);
devState = Prepare_Data_In;
action = ACT_DATA_READY;
break;
panic("Attempt to perform CHS access, only supports LBA\n");
if (cmdReg.sec_count == 0)
- cmdBytesLeft = (256 * SectorSize);
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
else
- cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
- drqBytesLeft = SectorSize;
curSector = getLBABase();
+ /** @todo make this a scheduled event to simulate disk delay */
devState = Prepare_Data_In;
action = ACT_DATA_READY;
break;
panic("Attempt to perform CHS access, only supports LBA\n");
if (cmdReg.sec_count == 0)
- cmdBytesLeft = (256 * SectorSize);
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
else
- cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
- drqBytesLeft = SectorSize;
curSector = getLBABase();
devState = Prepare_Data_Out;
panic("Attempt to perform CHS access, only supports LBA\n");
if (cmdReg.sec_count == 0)
- cmdBytesLeft = (256 * SectorSize);
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
else
- cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
- drqBytesLeft = SectorSize;
curSector = getLBABase();
devState = Prepare_Data_Dma;
if (action != ACT_NONE) {
// set the BSY bit
- cmdReg.status |= STATUS_BSY_BIT;
+ status |= STATUS_BSY_BIT;
// clear the DRQ bit
- cmdReg.status &= ~STATUS_DRQ_BIT;
+ status &= ~STATUS_DRQ_BIT;
+ // clear the DF bit
+ status &= ~STATUS_DF_BIT;
updateState(action);
}
void
IdeDisk::intrPost()
{
+ DPRINTF(IdeDisk, "IDE Disk Posting Interrupt\n");
if (intrPending)
panic("Attempt to post an interrupt with one pending\n");
void
IdeDisk::intrClear()
{
+ DPRINTF(IdeDisk, "IDE Disk Clearing Interrupt\n");
if (!intrPending)
panic("Attempt to clear a non-pending interrupt\n");
IdeDisk::updateState(DevAction_t action)
{
switch (devState) {
+ case Device_Srst:
+ if (action == ACT_SRST_SET) {
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ } else if (action == ACT_SRST_CLEAR) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+
+ // reset the device state
+ reset(devID);
+ }
+ break;
+
case Device_Idle_S:
- if (!isDEVSelect())
+ if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
devState = Device_Idle_NS;
- else if (action == ACT_CMD_WRITE)
+ } else if (action == ACT_CMD_WRITE) {
startCommand();
+ }
break;
case Device_Idle_SI:
- if (!isDEVSelect()) {
+ if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
devState = Device_Idle_NS;
intrClear();
} else if (action == ACT_STAT_READ || isIENSet()) {
break;
case Device_Idle_NS:
- if (isDEVSelect()) {
+ if (action == ACT_SELECT_WRITE && isDEVSelect()) {
if (!isIENSet() && intrPending) {
devState = Device_Idle_SI;
intrPost();
}
} else if (action == ACT_DATA_READY) {
// clear the BSY bit
- cmdReg.status &= ~STATUS_BSY_BIT;
+ status &= ~STATUS_BSY_BIT;
// set the DRQ bit
- cmdReg.status |= STATUS_DRQ_BIT;
-
- // put the first two bytes into the data register
- memcpy((void *)&cmdReg.data0, (void *)dataBuffer,
- sizeof(uint16_t));
+ status |= STATUS_DRQ_BIT;
// copy the data into the data buffer
- if (curCommand == WIN_IDENTIFY)
+ if (cmdReg.command == WIN_IDENTIFY) {
+ // Reset the drqBytes for this block
+ drqBytesLeft = sizeof(struct hd_driveid);
+
memcpy((void *)dataBuffer, (void *)&driveID,
sizeof(struct hd_driveid));
- else
+ } else {
+ // Reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
readDisk(curSector++, dataBuffer);
+ }
+
+ // put the first two bytes into the data register
+ memcpy((void *)&cmdReg.data0, (void *)dataBuffer,
+ sizeof(uint16_t));
if (!isIENSet()) {
devState = Data_Ready_INTRQ_In;
cmdBytesLeft -= 2;
// copy next short into data registers
- memcpy((void *)&cmdReg.data0,
- (void *)&dataBuffer[SectorSize - drqBytesLeft],
- sizeof(uint16_t));
+ if (drqBytesLeft)
+ memcpy((void *)&cmdReg.data0,
+ (void *)&dataBuffer[SectorSize - drqBytesLeft],
+ sizeof(uint16_t));
}
if (drqBytesLeft == 0) {
devState = Device_Idle_S;
} else {
devState = Prepare_Data_In;
- cmdReg.status |= STATUS_BSY_BIT;
+ // set the BSY_BIT
+ status |= STATUS_BSY_BIT;
+ // clear the DRQ_BIT
+ status &= ~STATUS_DRQ_BIT;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
}
}
}
} else {
devState = Device_Idle_S;
}
- } else if (cmdBytesLeft != 0) {
+ } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
// clear the BSY bit
- cmdReg.status &= ~STATUS_BSY_BIT;
+ status &= ~STATUS_BSY_BIT;
// set the DRQ bit
- cmdReg.status |= STATUS_DRQ_BIT;
+ status |= STATUS_DRQ_BIT;
// clear the data buffer to get it ready for writes
memset(dataBuffer, 0, MAX_DMA_SIZE);
- if (!isIENSet()) {
+ // reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
+ if (cmdBytesLeft == cmdBytes || isIENSet()) {
+ devState = Transfer_Data_Out;
+ } else {
devState = Data_Ready_INTRQ_Out;
intrPost();
- } else {
- devState = Transfer_Data_Out;
}
}
break;
writeDisk(curSector++, dataBuffer);
// set the BSY bit
- cmdReg.status |= STATUS_BSY_BIT;
+ status |= STATUS_BSY_BIT;
+ // set the seek bit
+ status |= STATUS_SEEK_BIT;
// clear the DRQ bit
- cmdReg.status &= ~STATUS_DRQ_BIT;
+ status &= ~STATUS_DRQ_BIT;
devState = Prepare_Data_Out;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
}
}
break;
}
} else if (action == ACT_DMA_READY) {
// clear the BSY bit
- cmdReg.status &= ~STATUS_BSY_BIT;
+ status &= ~STATUS_BSY_BIT;
// set the DRQ bit
- cmdReg.status |= STATUS_DRQ_BIT;
+ status |= STATUS_DRQ_BIT;
devState = Transfer_Data_Dma;
// clear the BSY bit
setComplete();
// set the seek bit
- cmdReg.status |= 0x10;
+ status |= STATUS_SEEK_BIT;
// clear the controller state for DMA transfer
ctrl->setDmaComplete(this);
void
IdeDisk::serialize(ostream &os)
{
+ // Check all outstanding events to see if they are scheduled
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ int eventCount = 0;
+
+ if (dmaTransferEvent.scheduled()) {
+ reschedule = dmaTransferEvent.when();
+ event = Transfer;
+ eventCount++;
+ }
+ if (dmaReadWaitEvent.scheduled()) {
+ reschedule = dmaReadWaitEvent.when();
+ event = ReadWait;
+ eventCount++;
+ }
+ if (dmaWriteWaitEvent.scheduled()) {
+ reschedule = dmaWriteWaitEvent.when();
+ event = WriteWait;
+ eventCount++;
+ }
+ if (dmaPrdReadEvent.scheduled()) {
+ reschedule = dmaPrdReadEvent.when();
+ event = PrdRead;
+ eventCount++;
+ }
+ if (dmaReadEvent.scheduled()) {
+ reschedule = dmaReadEvent.when();
+ event = DmaRead;
+ eventCount++;
+ }
+ if (dmaWriteEvent.scheduled()) {
+ reschedule = dmaWriteEvent.when();
+ event = DmaWrite;
+ eventCount++;
+ }
+
+ assert(eventCount <= 1);
+
+ SERIALIZE_SCALAR(reschedule);
+ SERIALIZE_ENUM(event);
+
+ // Serialize device registers
+ SERIALIZE_SCALAR(cmdReg.data0);
+ SERIALIZE_SCALAR(cmdReg.data1);
+ SERIALIZE_SCALAR(cmdReg.sec_count);
+ SERIALIZE_SCALAR(cmdReg.sec_num);
+ SERIALIZE_SCALAR(cmdReg.cyl_low);
+ SERIALIZE_SCALAR(cmdReg.cyl_high);
+ SERIALIZE_SCALAR(cmdReg.drive);
+ SERIALIZE_SCALAR(cmdReg.command);
+ SERIALIZE_SCALAR(status);
+ SERIALIZE_SCALAR(nIENBit);
+ SERIALIZE_SCALAR(devID);
+
+ // Serialize the PRD related information
+ SERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ SERIALIZE_SCALAR(curPrd.entry.byteCount);
+ SERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ SERIALIZE_SCALAR(curPrdAddr);
+
+ // Serialize current transfer related information
+ SERIALIZE_SCALAR(cmdBytesLeft);
+ SERIALIZE_SCALAR(cmdBytes);
+ SERIALIZE_SCALAR(drqBytesLeft);
+ SERIALIZE_SCALAR(curSector);
+ SERIALIZE_SCALAR(dmaRead);
+ SERIALIZE_SCALAR(dmaInterfaceBytes);
+ SERIALIZE_SCALAR(intrPending);
+ SERIALIZE_ENUM(devState);
+ SERIALIZE_ENUM(dmaState);
+ SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
}
void
IdeDisk::unserialize(Checkpoint *cp, const string §ion)
{
+ // Reschedule events that were outstanding
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ UNSERIALIZE_SCALAR(reschedule);
+ UNSERIALIZE_ENUM(event);
+
+ switch (event) {
+ case None : break;
+ case Transfer : dmaTransferEvent.schedule(reschedule); break;
+ case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
+ case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
+ case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
+ case DmaRead : dmaReadEvent.schedule(reschedule); break;
+ case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
+ }
+
+ // Unserialize device registers
+ UNSERIALIZE_SCALAR(cmdReg.data0);
+ UNSERIALIZE_SCALAR(cmdReg.data1);
+ UNSERIALIZE_SCALAR(cmdReg.sec_count);
+ UNSERIALIZE_SCALAR(cmdReg.sec_num);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_low);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_high);
+ UNSERIALIZE_SCALAR(cmdReg.drive);
+ UNSERIALIZE_SCALAR(cmdReg.command);
+ UNSERIALIZE_SCALAR(status);
+ UNSERIALIZE_SCALAR(nIENBit);
+ UNSERIALIZE_SCALAR(devID);
+
+ // Unserialize the PRD related information
+ UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
+ UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ UNSERIALIZE_SCALAR(curPrdAddr);
+
+ // Unserialize current transfer related information
+ UNSERIALIZE_SCALAR(cmdBytes);
+ UNSERIALIZE_SCALAR(cmdBytesLeft);
+ UNSERIALIZE_SCALAR(drqBytesLeft);
+ UNSERIALIZE_SCALAR(curSector);
+ UNSERIALIZE_SCALAR(dmaRead);
+ UNSERIALIZE_SCALAR(dmaInterfaceBytes);
+ UNSERIALIZE_SCALAR(intrPending);
+ UNSERIALIZE_ENUM(devState);
+ UNSERIALIZE_ENUM(dmaState);
+ UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
INIT_PARAM(image, "Disk image"),
INIT_PARAM(physmem, "Physical memory"),
INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
- INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0)
+ INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in microseconds", 1)
END_INIT_SIM_OBJECT_PARAMS(IdeDisk)