X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=dev%2Fide_disk.cc;h=99724f07788c1c5f7b5cde237ccf465274da6319;hb=239183cfe675684aeca1a2b24362ca5e0a82809d;hp=38d6a919be0de5893f577d440ce65e7dfe2777f6;hpb=3bfb59f70d4bf8ca7b9e6a0bdbcacdbbebf41403;p=gem5.git diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc index 38d6a919b..99724f077 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -1,5 +1,5 @@ /* - * 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 @@ -61,22 +61,11 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, dmaWriteWaitEvent(this), dmaPrdReadEvent(this), dmaReadEvent(this), dmaWriteEvent(this) { - diskDelay = (delay * ticksPerSecond / 100000); + // 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)); @@ -130,6 +119,32 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, 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; @@ -145,17 +160,21 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, } // 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) +IdeDisk::pciToDma(Addr pciAddr) { if (ctrl) return ctrl->tsunami->pchip->translatePciToDma(pciAddr); @@ -163,6 +182,29 @@ IdeDisk::pciToDma(Addr &pciAddr) 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 > ALPHA_PGBYTES) + bytesInPage = ALPHA_PGBYTES; + else + bytesInPage = bytesLeft; + + // Next, see if we have crossed a page boundary, and adjust + Addr upperBound = curAddr + bytesInPage; + Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES; + + assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); + + if (upperBound >= pageBound) + bytesInPage = pageBound - curAddr; + + return bytesInPage; +} + //// // Device registers read/write //// @@ -187,6 +229,7 @@ IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) // 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; @@ -201,7 +244,7 @@ IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) if (!byte) panic("Invalid 16-bit read from control block\n"); - *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET]; + *data = status; } if (action != ACT_NONE) @@ -233,6 +276,8 @@ IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) action = ACT_DATA_WRITE_BYTE; else action = ACT_DATA_WRITE_SHORT; + } else if (offset == SELECT_OFFSET) { + action = ACT_SELECT_WRITE; } } else { @@ -242,8 +287,13 @@ IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) 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; } @@ -286,7 +336,13 @@ IdeDisk::dmaPrdReadDone() 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(); @@ -297,7 +353,7 @@ IdeDisk::dmaPrdReadDone() void IdeDisk::doDmaRead() { - Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize); + Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); if (dmaInterface) { if (dmaInterface->busy()) { @@ -306,9 +362,14 @@ IdeDisk::doDmaRead() 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) @@ -323,6 +384,28 @@ IdeDisk::dmaReadDone() 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(); @@ -338,15 +421,9 @@ IdeDisk::dmaReadDone() // calculate how many bytes are in the current page bytesLeft = curPrd.getByteCount() - bytesWritten; - bytesInPage = (bytesLeft > ALPHA_PGBYTES) ? ALPHA_PGBYTES : bytesLeft; - // check to make sure we don't cross a page boundary - if ((curAddr + bytesInPage) > - (alpha_trunc_page(curAddr) + ALPHA_PGBYTES)) - - bytesInPage = alpha_round_page(curAddr) - curAddr; + bytesInPage = bytesInDmaPage(curAddr, bytesLeft); // copy the data from memory into the data buffer - /** @todo Use real DMA with interfaces here */ memcpy((void *)(dataBuffer + bytesWritten), physmem->dma_addr(dmaAddr, bytesInPage), bytesInPage); @@ -359,33 +436,13 @@ IdeDisk::dmaReadDone() // write the data to the disk image for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); - bytesWritten += SectorSize) + bytesWritten += SectorSize) { writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); - -#if 0 - // 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; - - while (bytesWritten < curPrd.getByteCount()) { - if (cmdBytesLeft <= 0) - panic("DMA data is larger than # sectors specified\n"); - - writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); - - bytesWritten += SectorSize; - cmdBytesLeft -= SectorSize; } -#endif // check for the EOT - if (curPrd.getEOT()){ + if (curPrd.getEOT()) { assert(cmdBytesLeft == 0); dmaState = Dma_Idle; updateState(ACT_DMA_DONE); @@ -397,7 +454,7 @@ IdeDisk::dmaReadDone() void IdeDisk::doDmaWrite() { - Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize); + Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); if (dmaInterface) { if (dmaInterface->busy()) { @@ -406,10 +463,15 @@ IdeDisk::doDmaWrite() 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) @@ -423,6 +485,29 @@ IdeDisk::dmaWriteDone() 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 = alpha_trunc_page(curAddr); @@ -435,7 +520,6 @@ IdeDisk::dmaWriteDone() // see if we have crossed into a new page if (pageAddr != alpha_trunc_page(curAddr)) { // write the data to memory - /** @todo Do real DMA using interfaces here */ memcpy(physmem->dma_addr(dmaAddr, bytesInPage), (void *)(dataBuffer + (bytesRead - bytesInPage)), bytesInPage); @@ -459,21 +543,12 @@ IdeDisk::dmaWriteDone() } // write the last page worth read to memory - /** @todo Do real DMA using interfaces here */ if (bytesInPage != 0) { memcpy(physmem->dma_addr(dmaAddr, bytesInPage), (void *)(dataBuffer + (bytesRead - bytesInPage)), bytesInPage); } -#if 0 - Addr dmaAddr = ctrl->tsunami->pchip-> - translatePciToDma(curPrd.getBaseAddr()); - - memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()), - (void *)dataBuffer, curPrd.getByteCount()); -#endif - // check for the EOT if (curPrd.getEOT()) { assert(cmdBytesLeft == 0); @@ -521,7 +596,8 @@ IdeDisk::startDma(const uint32_t &prdTableBase) 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; @@ -548,9 +624,6 @@ IdeDisk::startCommand() uint32_t size = 0; dmaRead = false; - // copy the command to the shadow - curCommand = cmdReg.command; - // Decode commands switch (cmdReg.command) { // Supported non-data commands @@ -567,6 +640,7 @@ IdeDisk::startCommand() case WIN_RECAL: case WIN_SPECIFY: + case WIN_STANDBYNOW1: case WIN_FLUSH_CACHE: case WIN_VERIFY: case WIN_SEEK: @@ -578,7 +652,7 @@ IdeDisk::startCommand() // 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; @@ -589,13 +663,13 @@ IdeDisk::startCommand() 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; @@ -607,11 +681,10 @@ IdeDisk::startCommand() 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; @@ -626,11 +699,10 @@ IdeDisk::startCommand() 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; @@ -643,9 +715,11 @@ IdeDisk::startCommand() 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); } @@ -689,16 +763,30 @@ void 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()) { @@ -712,7 +800,7 @@ IdeDisk::updateState(DevAction_t action) break; case Device_Idle_NS: - if (isDEVSelect()) { + if (action == ACT_SELECT_WRITE && isDEVSelect()) { if (!isIENSet() && intrPending) { devState = Device_Idle_SI; intrPost(); @@ -750,20 +838,27 @@ IdeDisk::updateState(DevAction_t action) } } 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; @@ -790,9 +885,10 @@ IdeDisk::updateState(DevAction_t action) 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) { @@ -802,7 +898,14 @@ IdeDisk::updateState(DevAction_t action) 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); } } } @@ -819,20 +922,23 @@ IdeDisk::updateState(DevAction_t action) } 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; @@ -865,11 +971,17 @@ IdeDisk::updateState(DevAction_t action) 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; @@ -887,9 +999,9 @@ IdeDisk::updateState(DevAction_t action) } } 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; @@ -906,7 +1018,7 @@ IdeDisk::updateState(DevAction_t action) // 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); @@ -927,11 +1039,132 @@ IdeDisk::updateState(DevAction_t action) 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 @@ -950,7 +1183,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 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)