ide_disk.cc
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,120 行 · 第 1/3 页
CC
1,120 行
; dmaWriteBytes .name(name() + ".dma_write_bytes") .desc("Number of bytes transfered via DMA writes.") ; dmaWriteTxs .name(name() + ".dma_write_txs") .desc("Number of DMA write transactions.") ;}voidIdeDisk::doDmaRead(){ if (!dmaReadCG) { // clear out the data buffer memset(dataBuffer, 0, MAX_DMA_SIZE); dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), curPrd.getByteCount(), TheISA::PageBytes); } if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); return; } else if (!dmaReadCG->done()) { assert(dmaReadCG->complete() < MAX_DMA_SIZE); ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); dmaReadBytes += dmaReadCG->size(); dmaReadTxs++; if (dmaReadCG->size() == TheISA::PageBytes) dmaReadFullPages++; dmaReadCG->next(); } else { assert(dmaReadCG->done()); delete dmaReadCG; dmaReadCG = NULL; dmaReadDone(); }}voidIdeDisk::dmaReadDone(){ uint32_t bytesWritten = 0; // write the data to the disk image for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); bytesWritten += SectorSize) { cmdBytesLeft -= SectorSize; writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); } // check for the EOT if (curPrd.getEOT()) { assert(cmdBytesLeft == 0); dmaState = Dma_Idle; updateState(ACT_DMA_DONE); } else { doDmaTransfer(); }}voidIdeDisk::doDmaDataWrite(){ /** @todo we need to figure out what the delay actually will be */ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); uint32_t bytesRead = 0; DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", diskDelay, totalDiskDelay); memset(dataBuffer, 0, MAX_DMA_SIZE); assert(cmdBytesLeft <= MAX_DMA_SIZE); while (bytesRead < curPrd.getByteCount()) { readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); bytesRead += SectorSize; cmdBytesLeft -= SectorSize; } dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);}voidIdeDisk::doDmaWrite(){ if (!dmaWriteCG) { // clear out the data buffer dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), curPrd.getByteCount(), TheISA::PageBytes); } if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); return; } else if (!dmaWriteCG->done()) { assert(dmaWriteCG->complete() < MAX_DMA_SIZE); ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); dmaWriteBytes += dmaWriteCG->size(); dmaWriteTxs++; if (dmaWriteCG->size() == TheISA::PageBytes) dmaWriteFullPages++; dmaWriteCG->next(); } else { assert(dmaWriteCG->done()); delete dmaWriteCG; dmaWriteCG = NULL; dmaWriteDone(); }}voidIdeDisk::dmaWriteDone(){ // check for the EOT if (curPrd.getEOT()) { assert(cmdBytesLeft == 0); dmaState = Dma_Idle; updateState(ACT_DMA_DONE); } else { doDmaTransfer(); }}////// Disk utility routines///voidIdeDisk::readDisk(uint32_t sector, uint8_t *data){ uint32_t bytesRead = image->read(data, sector); if (bytesRead != SectorSize) panic("Can't read from %s. Only %d of %d read. errno=%d\n", name(), bytesRead, SectorSize, errno);}voidIdeDisk::writeDisk(uint32_t sector, uint8_t *data){ uint32_t bytesWritten = image->write(data, sector); if (bytesWritten != SectorSize) panic("Can't write to %s. Only %d of %d written. errno=%d\n", name(), bytesWritten, SectorSize, errno);}////// Setup and handle commands////voidIdeDisk::startDma(const uint32_t &prdTableBase){ if (dmaState != Dma_Start) panic("Inconsistent DMA state, should be in Dma_Start!\n"); if (devState != Transfer_Data_Dma) panic("Inconsistent device state for DMA start!\n"); // PRD base address is given by bits 31:2 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); dmaState = Dma_Transfer; // schedule dma transfer (doDmaTransfer) dmaTransferEvent.schedule(curTick + 1);}voidIdeDisk::abortDma(){ if (dmaState == Dma_Idle) panic("Inconsistent DMA state, should be Start or Transfer!"); if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) panic("Inconsistent device state, should be Transfer or Prepare!\n"); updateState(ACT_CMD_ERROR);}voidIdeDisk::startCommand(){ DevAction_t action = ACT_NONE; uint32_t size = 0; dmaRead = false; // Decode commands switch (cmdReg.command) { // Supported non-data commands case WDSF_READ_NATIVE_MAX: size = image->size() - 1; cmdReg.sec_num = (size & 0xff); cmdReg.cyl_low = ((size & 0xff00) >> 8); cmdReg.cyl_high = ((size & 0xff0000) >> 16); cmdReg.head = ((size & 0xf000000) >> 24); devState = Command_Execution; action = ACT_CMD_COMPLETE; break; case WDCC_RECAL: case WDCC_IDP: case WDCC_STANDBY_IMMED: case WDCC_FLUSHCACHE: case WDSF_VERIFY: case WDSF_SEEK: case SET_FEATURES: case WDCC_SETMULTI: devState = Command_Execution; action = ACT_CMD_COMPLETE; break; // Supported PIO data-in commands case WDCC_IDENTIFY: cmdBytes = cmdBytesLeft = sizeof(struct ataparams); devState = Prepare_Data_In; action = ACT_DATA_READY; break; case WDCC_READMULTI: case WDCC_READ: if (!(cmdReg.drive & DRIVE_LBA_BIT)) panic("Attempt to perform CHS access, only supports LBA\n"); if (cmdReg.sec_count == 0) cmdBytes = cmdBytesLeft = (256 * SectorSize); else cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); curSector = getLBABase(); /** @todo make this a scheduled event to simulate disk delay */ devState = Prepare_Data_In; action = ACT_DATA_READY; break; // Supported PIO data-out commands case WDCC_WRITEMULTI: case WDCC_WRITE: if (!(cmdReg.drive & DRIVE_LBA_BIT)) panic("Attempt to perform CHS access, only supports LBA\n"); if (cmdReg.sec_count == 0) cmdBytes = cmdBytesLeft = (256 * SectorSize); else cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); curSector = getLBABase(); devState = Prepare_Data_Out; action = ACT_DATA_READY; break; // Supported DMA commands case WDCC_WRITEDMA: dmaRead = true; // a write to the disk is a DMA read from memory case WDCC_READDMA: if (!(cmdReg.drive & DRIVE_LBA_BIT)) panic("Attempt to perform CHS access, only supports LBA\n"); if (cmdReg.sec_count == 0) cmdBytes = cmdBytesLeft = (256 * SectorSize); else cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); curSector = getLBABase(); devState = Prepare_Data_Dma; action = ACT_DMA_READY; break; default: panic("Unsupported ATA command: %#x\n", cmdReg.command); } if (action != ACT_NONE) { // set the BSY bit status |= STATUS_BSY_BIT; // clear the DRQ bit status &= ~STATUS_DRQ_BIT; // clear the DF bit status &= ~STATUS_DF_BIT; updateState(action); }}////// Handle setting and clearing interrupts////voidIdeDisk::intrPost(){ DPRINTF(IdeDisk, "Posting Interrupt\n"); if (intrPending) panic("Attempt to post an interrupt with one pending\n"); intrPending = true; // talk to controller to set interrupt if (ctrl) { ctrl->bmi_regs.bmis0 |= IDEINTS; ctrl->intrPost(); }}voidIdeDisk::intrClear(){ DPRINTF(IdeDisk, "Clearing Interrupt\n"); if (!intrPending) panic("Attempt to clear a non-pending interrupt\n"); intrPending = false; // talk to controller to clear interrupt if (ctrl) ctrl->intrClear();}////// Manage the device internal state machine////voidIdeDisk::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 (action == ACT_SELECT_WRITE && !isDEVSelect()) { devState = Device_Idle_NS; } else if (action == ACT_CMD_WRITE) { startCommand(); } break; case Device_Idle_SI: if (action == ACT_SELECT_WRITE && !isDEVSelect()) { devState = Device_Idle_NS; intrClear(); } else if (action == ACT_STAT_READ || isIENSet()) { devState = Device_Idle_S; intrClear(); } else if (action == ACT_CMD_WRITE) { intrClear(); startCommand(); } break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?