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 + -
显示快捷键?