ide_disk.cc revision 989
12SN/A/* 22188SN/A * Copyright (c) 2004 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665SN/A */ 282665SN/A 292665SN/A/** @file 302SN/A * Device model implementation for an IDE disk 312SN/A */ 322683Sktlim@umich.edu 332683Sktlim@umich.edu#include <cerrno> 342SN/A#include <cstring> 356313Sgblack@eecs.umich.edu#include <deque> 362190SN/A#include <string> 373776Sgblack@eecs.umich.edu 384997Sgblack@eecs.umich.edu#include "arch/alpha/pmap.h" 396216Snate@binkert.org#include "base/cprintf.hh" // csprintf 401858SN/A#include "base/trace.hh" 412680SN/A#include "dev/disk_image.hh" 422683Sktlim@umich.edu#include "dev/ide_disk.hh" 432395SN/A#include "dev/ide_ctrl.hh" 442190SN/A#include "dev/tsunami.hh" 452188SN/A#include "dev/tsunami_pchip.hh" 46217SN/A#include "mem/functional_mem/physical_memory.hh" 472SN/A#include "mem/bus/bus.hh" 482SN/A#include "mem/bus/dma_interface.hh" 492SN/A#include "mem/bus/pio_interface.hh" 501858SN/A#include "mem/bus/pio_interface_impl.hh" 512SN/A#include "sim/builder.hh" 521070SN/A#include "sim/sim_object.hh" 531070SN/A#include "sim/universe.hh" 541917SN/A 551917SN/Ausing namespace std; 562521SN/A 572521SN/AIdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, 582521SN/A int id, int delay) 593548Sgblack@eecs.umich.edu : SimObject(name), ctrl(NULL), image(img), physmem(phys), 603548Sgblack@eecs.umich.edu dmaTransferEvent(this), dmaReadWaitEvent(this), 613548Sgblack@eecs.umich.edu dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 623548Sgblack@eecs.umich.edu dmaReadEvent(this), dmaWriteEvent(this) 632330SN/A{ 642330SN/A // Reset the device state 652SN/A reset(id); 662SN/A 67360SN/A // calculate disk delay in microseconds 682462SN/A diskDelay = (delay * ticksPerSecond / 100000); 692420SN/A 702SN/A // fill out the drive ID structure 712SN/A memset(&driveID, 0, sizeof(struct hd_driveid)); 722SN/A 732683Sktlim@umich.edu // Calculate LBA and C/H/S values 742683Sktlim@umich.edu uint16_t cylinders; 752683Sktlim@umich.edu uint8_t heads; 762683Sktlim@umich.edu uint8_t sectors; 772683Sktlim@umich.edu 782683Sktlim@umich.edu uint32_t lba_size = image->size(); 792683Sktlim@umich.edu if (lba_size >= 16383*16*63) { 802683Sktlim@umich.edu cylinders = 16383; 812683Sktlim@umich.edu heads = 16; 822683Sktlim@umich.edu sectors = 63; 832683Sktlim@umich.edu } else { 842683Sktlim@umich.edu if (lba_size >= 63) 852683Sktlim@umich.edu sectors = 63; 862683Sktlim@umich.edu else 872683Sktlim@umich.edu sectors = lba_size; 882SN/A 892683Sktlim@umich.edu if ((lba_size / sectors) >= 16) 902SN/A heads = 16; 912107SN/A else 922107SN/A heads = (lba_size / sectors); 932107SN/A 942159SN/A cylinders = lba_size / (heads * sectors); 952455SN/A } 962455SN/A 972SN/A // Setup the model name 982680SN/A sprintf((char *)driveID.model, "5MI EDD si k"); 992SN/A // Set the maximum multisector transfer size 1002190SN/A driveID.max_multsect = MAX_MULTSECT; 1015543Ssaidi@eecs.umich.edu // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 1026315Sgblack@eecs.umich.edu driveID.capability = 0x7; 1036315Sgblack@eecs.umich.edu // UDMA support, EIDE support 1046315Sgblack@eecs.umich.edu driveID.field_valid = 0x6; 1056315Sgblack@eecs.umich.edu // Setup default C/H/S settings 1066313Sgblack@eecs.umich.edu driveID.cyls = cylinders; 1072SN/A driveID.sectors = sectors; 1082190SN/A driveID.heads = heads; 1092683Sktlim@umich.edu // Setup the current multisector transfer size 1102SN/A driveID.multsect = MAX_MULTSECT; 1112SN/A driveID.multsect_valid = 0x1; 1122683Sktlim@umich.edu // Number of sectors on disk 1132188SN/A driveID.lba_capacity = lba_size; 1142378SN/A // Multiword DMA mode 2 and below supported 1152400SN/A driveID.dma_mword = 0x400; 1166022Sgblack@eecs.umich.edu // Set PIO mode 4 and 3 supported 1176022Sgblack@eecs.umich.edu driveID.eide_pio_modes = 0x3; 1182SN/A // Set DMA mode 4 and below supported 1192683Sktlim@umich.edu driveID.dma_ultra = 0x10; 1201858SN/A // Statically set hardware config word 1212683Sktlim@umich.edu driveID.hw_config = 0x4001; 1226022Sgblack@eecs.umich.edu} 1232683Sktlim@umich.edu 1242SN/AIdeDisk::~IdeDisk() 1254997Sgblack@eecs.umich.edu{ 1266022Sgblack@eecs.umich.edu // destroy the data buffer 1272SN/A delete [] dataBuffer; 1282862Sktlim@umich.edu} 1292864Sktlim@umich.edu 1302862Sktlim@umich.eduvoid 1312683Sktlim@umich.eduIdeDisk::reset(int id) 1322SN/A{ 1332680SN/A // initialize the data buffer and shadow registers 134180SN/A dataBuffer = new uint8_t[MAX_DMA_SIZE]; 1352SN/A 1362SN/A memset(dataBuffer, 0, MAX_DMA_SIZE); 1372864Sktlim@umich.edu memset(&cmdReg, 0, sizeof(CommandReg_t)); 1382864Sktlim@umich.edu memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 1392862Sktlim@umich.edu 1402862Sktlim@umich.edu dmaInterfaceBytes = 0; 141217SN/A curPrdAddr = 0; 142237SN/A curSector = 0; 143217SN/A cmdBytes = 0; 1442683Sktlim@umich.edu cmdBytesLeft = 0; 1452683Sktlim@umich.edu drqBytesLeft = 0; 1465891Sgblack@eecs.umich.edu dmaRead = false; 1472683Sktlim@umich.edu intrPending = false; 1482190SN/A 1492683Sktlim@umich.edu // set the device state to idle 1502683Sktlim@umich.edu dmaState = Dma_Idle; 1512683Sktlim@umich.edu 1522683Sktlim@umich.edu if (id == DEV0) { 1532680SN/A devState = Device_Idle_S; 1542190SN/A devID = DEV0; 1555358Sgblack@eecs.umich.edu } else if (id == DEV1) { 1565358Sgblack@eecs.umich.edu devState = Device_Idle_NS; 1575358Sgblack@eecs.umich.edu devID = DEV1; 1585358Sgblack@eecs.umich.edu } else { 1595358Sgblack@eecs.umich.edu panic("Invalid device ID: %#x\n", id); 1605358Sgblack@eecs.umich.edu } 1615358Sgblack@eecs.umich.edu 1625358Sgblack@eecs.umich.edu // set the device ready bit 1635358Sgblack@eecs.umich.edu status = STATUS_DRDY_BIT; 1645358Sgblack@eecs.umich.edu} 1655358Sgblack@eecs.umich.edu 1665358Sgblack@eecs.umich.edu//// 1675358Sgblack@eecs.umich.edu// Utility functions 1685358Sgblack@eecs.umich.edu//// 1695358Sgblack@eecs.umich.edu 1705358Sgblack@eecs.umich.edubool 1714997Sgblack@eecs.umich.eduIdeDisk::isDEVSelect() 1726313Sgblack@eecs.umich.edu{ 1736313Sgblack@eecs.umich.edu return ctrl->isDiskSelected(this); 1744997Sgblack@eecs.umich.edu} 1752683Sktlim@umich.edu 1762521SN/AAddr 1775702Ssaidi@eecs.umich.eduIdeDisk::pciToDma(Addr pciAddr) 1785702Ssaidi@eecs.umich.edu{ 1795702Ssaidi@eecs.umich.edu if (ctrl) 1805702Ssaidi@eecs.umich.edu return ctrl->tsunami->pchip->translatePciToDma(pciAddr); 1812683Sktlim@umich.edu else 1822SN/A panic("Access to unset controller!\n"); 1832683Sktlim@umich.edu} 1842683Sktlim@umich.edu 1852683Sktlim@umich.eduuint32_t 1862683Sktlim@umich.eduIdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) 1872683Sktlim@umich.edu{ 1882683Sktlim@umich.edu uint32_t bytesInPage = 0; 1896022Sgblack@eecs.umich.edu 1902683Sktlim@umich.edu // First calculate how many bytes could be in the page 1916022Sgblack@eecs.umich.edu if (bytesLeft > ALPHA_PGBYTES) 1922683Sktlim@umich.edu bytesInPage = ALPHA_PGBYTES; 1934997Sgblack@eecs.umich.edu else 1944997Sgblack@eecs.umich.edu bytesInPage = bytesLeft; 1955803Snate@binkert.org 1962683Sktlim@umich.edu // Next, see if we have crossed a page boundary, and adjust 1972683Sktlim@umich.edu Addr upperBound = curAddr + bytesInPage; 1985499Ssaidi@eecs.umich.edu Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES; 1995499Ssaidi@eecs.umich.edu 2005499Ssaidi@eecs.umich.edu assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); 2015499Ssaidi@eecs.umich.edu 2025499Ssaidi@eecs.umich.edu if (upperBound >= pageBound) 2032SN/A bytesInPage = pageBound - curAddr; 2042SN/A 2052683Sktlim@umich.edu return bytesInPage; 2062683Sktlim@umich.edu} 2072683Sktlim@umich.edu 2082683Sktlim@umich.edu//// 2092683Sktlim@umich.edu// Device registers read/write 2102683Sktlim@umich.edu//// 2112683Sktlim@umich.edu 2122683Sktlim@umich.eduvoid 2132683Sktlim@umich.eduIdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) 2142683Sktlim@umich.edu{ 2152683Sktlim@umich.edu DevAction_t action = ACT_NONE; 2162683Sktlim@umich.edu 2172683Sktlim@umich.edu if (cmdBlk) { 2182683Sktlim@umich.edu if (offset < 0 || offset > sizeof(CommandReg_t)) 2192SN/A panic("Invalid disk command register offset: %#x\n", offset); 2202SN/A 2212532SN/A if (!byte && offset != DATA_OFFSET) 222716SN/A panic("Invalid 16-bit read, only allowed on data reg\n"); 2232378SN/A 2242378SN/A if (!byte) 2252423SN/A *(uint16_t *)data = *(uint16_t *)&cmdReg.data0; 226716SN/A else 227716SN/A *data = ((uint8_t *)&cmdReg)[offset]; 2282683Sktlim@umich.edu 2292190SN/A // determine if an action needs to be taken on the state machine 2306315Sgblack@eecs.umich.edu if (offset == STATUS_OFFSET) { 2316315Sgblack@eecs.umich.edu action = ACT_STAT_READ; 2326315Sgblack@eecs.umich.edu *data = status; // status is in a shadow, explicity copy 2336315Sgblack@eecs.umich.edu } else if (offset == DATA_OFFSET) { 2346315Sgblack@eecs.umich.edu if (byte) 2352190SN/A action = ACT_DATA_READ_BYTE; 2362SN/A else 2372SN/A action = ACT_DATA_READ_SHORT; 2382SN/A } 2392SN/A 2402SN/A } else { 2416313Sgblack@eecs.umich.edu if (offset != ALTSTAT_OFFSET) 2425082Sgblack@eecs.umich.edu panic("Invalid disk control register offset: %#x\n", offset); 2432SN/A 2442SN/A if (!byte) 2452455SN/A panic("Invalid 16-bit read from control block\n"); 2462SN/A 2476313Sgblack@eecs.umich.edu *data = status; 2486315Sgblack@eecs.umich.edu } 2492SN/A 2502SN/A if (action != ACT_NONE) 2512455SN/A updateState(action); 2522455SN/A} 2536313Sgblack@eecs.umich.edu 2546315Sgblack@eecs.umich.eduvoid 2552SN/AIdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) 2562SN/A{ 2572SN/A DevAction_t action = ACT_NONE; 2582SN/A 2596313Sgblack@eecs.umich.edu if (cmdBlk) { 2605082Sgblack@eecs.umich.edu if (offset < 0 || offset > sizeof(CommandReg_t)) 2612SN/A panic("Invalid disk command register offset: %#x\n", offset); 2622SN/A 2632455SN/A if (!byte && offset != DATA_OFFSET) 2642SN/A panic("Invalid 16-bit write, only allowed on data reg\n"); 2656313Sgblack@eecs.umich.edu 2666315Sgblack@eecs.umich.edu if (!byte) 2672SN/A *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data; 2682SN/A else 2692455SN/A ((uint8_t *)&cmdReg)[offset] = *data; 2702455SN/A 2716313Sgblack@eecs.umich.edu // determine if an action needs to be taken on the state machine 2726315Sgblack@eecs.umich.edu if (offset == COMMAND_OFFSET) { 2732SN/A action = ACT_CMD_WRITE; 2742SN/A } else if (offset == DATA_OFFSET) { 2752SN/A if (byte) 2762SN/A action = ACT_DATA_WRITE_BYTE; 2772525SN/A else 2782SN/A action = ACT_DATA_WRITE_SHORT; 2792SN/A } else if (offset == SELECT_OFFSET) { 2802190SN/A action = ACT_SELECT_WRITE; 2812190SN/A } 2822525SN/A 2832190SN/A } else { 2842190SN/A if (offset != CONTROL_OFFSET) 2853276Sgblack@eecs.umich.edu panic("Invalid disk control register offset: %#x\n", offset); 2863276Sgblack@eecs.umich.edu 2873276Sgblack@eecs.umich.edu if (!byte) 2883276Sgblack@eecs.umich.edu panic("Invalid 16-bit write to control block\n"); 2893276Sgblack@eecs.umich.edu 2903276Sgblack@eecs.umich.edu if (*data & CONTROL_RST_BIT) { 2913276Sgblack@eecs.umich.edu // force the device into the reset state 2923276Sgblack@eecs.umich.edu devState = Device_Srst; 2933276Sgblack@eecs.umich.edu action = ACT_SRST_SET; 2943276Sgblack@eecs.umich.edu } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) { 2952190SN/A action = ACT_SRST_CLEAR; 2962190SN/A } 2972525SN/A 2982190SN/A nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 2992190SN/A } 3002SN/A 3012SN/A if (action != ACT_NONE) 3022525SN/A updateState(action); 3032SN/A} 3042SN/A 3053276Sgblack@eecs.umich.edu//// 3063276Sgblack@eecs.umich.edu// Perform DMA transactions 3073276Sgblack@eecs.umich.edu//// 3083276Sgblack@eecs.umich.edu 3093276Sgblack@eecs.umich.eduvoid 3103276Sgblack@eecs.umich.eduIdeDisk::doDmaTransfer() 3113276Sgblack@eecs.umich.edu{ 3123276Sgblack@eecs.umich.edu if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 3133276Sgblack@eecs.umich.edu panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 3143276Sgblack@eecs.umich.edu dmaState, devState); 3152252SN/A 3162252SN/A // first read the current PRD 3172525SN/A if (dmaInterface) { 3182252SN/A if (dmaInterface->busy()) { 3192252SN/A // reschedule after waiting period 3202251SN/A dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 3212251SN/A return; 3222525SN/A } 3232251SN/A 3242251SN/A dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, 3256221Snate@binkert.org &dmaPrdReadEvent); 3266221Snate@binkert.org } else { 3274172Ssaidi@eecs.umich.edu dmaPrdReadDone(); 3286313Sgblack@eecs.umich.edu } 3294172Ssaidi@eecs.umich.edu} 3304172Ssaidi@eecs.umich.edu 3316221Snate@binkert.orgvoid 3326221Snate@binkert.orgIdeDisk::dmaPrdReadDone() 3332SN/A{ 3346313Sgblack@eecs.umich.edu // actually copy the PRD from physical memory 3352SN/A memcpy((void *)&curPrd.entry, 3362SN/A physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), 3376221Snate@binkert.org sizeof(PrdEntry_t)); 3386221Snate@binkert.org 3392SN/A DPRINTF(IdeDisk, "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 3406313Sgblack@eecs.umich.edu curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 3412SN/A curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 3422SN/A curPrd.getEOT(), curSector); 3436221Snate@binkert.org 3446221Snate@binkert.org // the prd pointer has already been translated, so just do an increment 3452SN/A curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 3466313Sgblack@eecs.umich.edu 3476313Sgblack@eecs.umich.edu if (dmaRead) 3486313Sgblack@eecs.umich.edu doDmaRead(); 3496313Sgblack@eecs.umich.edu else 3506313Sgblack@eecs.umich.edu doDmaWrite(); 3516313Sgblack@eecs.umich.edu} 3526313Sgblack@eecs.umich.edu 3536313Sgblack@eecs.umich.eduvoid 3546313Sgblack@eecs.umich.eduIdeDisk::doDmaRead() 3556313Sgblack@eecs.umich.edu{ 3566313Sgblack@eecs.umich.edu Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 3576313Sgblack@eecs.umich.edu 3586313Sgblack@eecs.umich.edu if (dmaInterface) { 3592SN/A if (dmaInterface->busy()) { 3602SN/A // reschedule after waiting period 3612190SN/A dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 3622190SN/A return; 3632190SN/A } 3642190SN/A 3652190SN/A Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); 3661858SN/A 3672561SN/A uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), 3682SN/A (uint32_t)curPrd.getByteCount()); 3692680SN/A 3702SN/A dmaInterfaceBytes = bytesInPage; 3712SN/A 3722SN/A dmaInterface->doDMA(Read, dmaAddr, bytesInPage, 3732SN/A curTick + totalDiskDelay, &dmaReadEvent); 3742SN/A } else { 3752SN/A // schedule dmaReadEvent with sectorDelay (dmaReadDone) 3762SN/A dmaReadEvent.schedule(curTick + totalDiskDelay); 3772683Sktlim@umich.edu } 3782SN/A} 3792SN/A 3802SN/Avoid 3812SN/AIdeDisk::dmaReadDone() 3822190SN/A{ 383 384 Addr curAddr = 0, dmaAddr = 0; 385 uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; 386 387 // continue to use the DMA interface until all pages are read 388 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { 389 // see if the interface is busy 390 if (dmaInterface->busy()) { 391 // reschedule after waiting period 392 dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 393 return; 394 } 395 396 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; 397 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; 398 dmaAddr = pciToDma(curAddr); 399 400 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 401 dmaInterfaceBytes += bytesInPage; 402 403 dmaInterface->doDMA(Read, dmaAddr, bytesInPage, 404 curTick, &dmaReadEvent); 405 406 return; 407 } 408 409 // set initial address 410 curAddr = curPrd.getBaseAddr(); 411 412 // clear out the data buffer 413 memset(dataBuffer, 0, MAX_DMA_SIZE); 414 415 // read the data from memory via DMA into a data buffer 416 while (bytesWritten < curPrd.getByteCount()) { 417 if (cmdBytesLeft <= 0) 418 panic("DMA data is larger than # of sectors specified\n"); 419 420 dmaAddr = pciToDma(curAddr); 421 422 // calculate how many bytes are in the current page 423 bytesLeft = curPrd.getByteCount() - bytesWritten; 424 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 425 426 // copy the data from memory into the data buffer 427 memcpy((void *)(dataBuffer + bytesWritten), 428 physmem->dma_addr(dmaAddr, bytesInPage), 429 bytesInPage); 430 431 curAddr += bytesInPage; 432 bytesWritten += bytesInPage; 433 cmdBytesLeft -= bytesInPage; 434 } 435 436 // write the data to the disk image 437 for (bytesWritten = 0; 438 bytesWritten < curPrd.getByteCount(); 439 bytesWritten += SectorSize) { 440 441 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 442 } 443 444 // check for the EOT 445 if (curPrd.getEOT()) { 446 assert(cmdBytesLeft == 0); 447 dmaState = Dma_Idle; 448 updateState(ACT_DMA_DONE); 449 } else { 450 doDmaTransfer(); 451 } 452} 453 454void 455IdeDisk::doDmaWrite() 456{ 457 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 458 459 if (dmaInterface) { 460 if (dmaInterface->busy()) { 461 // reschedule after waiting period 462 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 463 return; 464 } 465 466 Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); 467 468 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), 469 (uint32_t)curPrd.getByteCount()); 470 471 dmaInterfaceBytes = bytesInPage; 472 473 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 474 bytesInPage, curTick + totalDiskDelay, 475 &dmaWriteEvent); 476 } else { 477 // schedule event with disk delay (dmaWriteDone) 478 dmaWriteEvent.schedule(curTick + totalDiskDelay); 479 } 480} 481 482void 483IdeDisk::dmaWriteDone() 484{ 485 Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; 486 uint32_t bytesRead = 0, bytesInPage = 0; 487 488 // continue to use the DMA interface until all pages are read 489 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { 490 // see if the interface is busy 491 if (dmaInterface->busy()) { 492 // reschedule after waiting period 493 dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 494 return; 495 } 496 497 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; 498 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; 499 dmaAddr = pciToDma(curAddr); 500 501 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 502 dmaInterfaceBytes += bytesInPage; 503 504 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 505 bytesInPage, curTick, 506 &dmaWriteEvent); 507 508 return; 509 } 510 511 // setup the initial page and DMA address 512 curAddr = curPrd.getBaseAddr(); 513 pageAddr = alpha_trunc_page(curAddr); 514 dmaAddr = pciToDma(curAddr); 515 516 // clear out the data buffer 517 memset(dataBuffer, 0, MAX_DMA_SIZE); 518 519 while (bytesRead < curPrd.getByteCount()) { 520 // see if we have crossed into a new page 521 if (pageAddr != alpha_trunc_page(curAddr)) { 522 // write the data to memory 523 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 524 (void *)(dataBuffer + (bytesRead - bytesInPage)), 525 bytesInPage); 526 527 // update the DMA address and page address 528 pageAddr = alpha_trunc_page(curAddr); 529 dmaAddr = pciToDma(curAddr); 530 531 bytesInPage = 0; 532 } 533 534 if (cmdBytesLeft <= 0) 535 panic("DMA requested data is larger than # sectors specified\n"); 536 537 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 538 539 curAddr += SectorSize; 540 bytesRead += SectorSize; 541 bytesInPage += SectorSize; 542 cmdBytesLeft -= SectorSize; 543 } 544 545 // write the last page worth read to memory 546 if (bytesInPage != 0) { 547 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 548 (void *)(dataBuffer + (bytesRead - bytesInPage)), 549 bytesInPage); 550 } 551 552 // check for the EOT 553 if (curPrd.getEOT()) { 554 assert(cmdBytesLeft == 0); 555 dmaState = Dma_Idle; 556 updateState(ACT_DMA_DONE); 557 } else { 558 doDmaTransfer(); 559 } 560} 561 562//// 563// Disk utility routines 564/// 565 566void 567IdeDisk::readDisk(uint32_t sector, uint8_t *data) 568{ 569 uint32_t bytesRead = image->read(data, sector); 570 571 if (bytesRead != SectorSize) 572 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 573 name(), bytesRead, SectorSize, errno); 574} 575 576void 577IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 578{ 579 uint32_t bytesWritten = image->write(data, sector); 580 581 if (bytesWritten != SectorSize) 582 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 583 name(), bytesWritten, SectorSize, errno); 584} 585 586//// 587// Setup and handle commands 588//// 589 590void 591IdeDisk::startDma(const uint32_t &prdTableBase) 592{ 593 if (dmaState != Dma_Start) 594 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 595 596 if (devState != Transfer_Data_Dma) 597 panic("Inconsistent device state for DMA start!\n"); 598 599 // PRD base address is given by bits 31:2 600 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 601 602 dmaState = Dma_Transfer; 603 604 // schedule dma transfer (doDmaTransfer) 605 dmaTransferEvent.schedule(curTick + 1); 606} 607 608void 609IdeDisk::abortDma() 610{ 611 if (dmaState == Dma_Idle) 612 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n"); 613 614 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 615 panic("Inconsistent device state, should be in Transfer or Prepare!\n"); 616 617 updateState(ACT_CMD_ERROR); 618} 619 620void 621IdeDisk::startCommand() 622{ 623 DevAction_t action = ACT_NONE; 624 uint32_t size = 0; 625 dmaRead = false; 626 627 // Decode commands 628 switch (cmdReg.command) { 629 // Supported non-data commands 630 case WIN_READ_NATIVE_MAX: 631 size = image->size() - 1; 632 cmdReg.sec_num = (size & 0xff); 633 cmdReg.cyl_low = ((size & 0xff00) >> 8); 634 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 635 cmdReg.head = ((size & 0xf000000) >> 24); 636 637 devState = Command_Execution; 638 action = ACT_CMD_COMPLETE; 639 break; 640 641 case WIN_RECAL: 642 case WIN_SPECIFY: 643 case WIN_STANDBYNOW1: 644 case WIN_FLUSH_CACHE: 645 case WIN_VERIFY: 646 case WIN_SEEK: 647 case WIN_SETFEATURES: 648 case WIN_SETMULT: 649 devState = Command_Execution; 650 action = ACT_CMD_COMPLETE; 651 break; 652 653 // Supported PIO data-in commands 654 case WIN_IDENTIFY: 655 cmdBytes = cmdBytesLeft = sizeof(struct hd_driveid); 656 devState = Prepare_Data_In; 657 action = ACT_DATA_READY; 658 break; 659 660 case WIN_MULTREAD: 661 case WIN_READ: 662 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 663 panic("Attempt to perform CHS access, only supports LBA\n"); 664 665 if (cmdReg.sec_count == 0) 666 cmdBytes = cmdBytesLeft = (256 * SectorSize); 667 else 668 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 669 670 curSector = getLBABase(); 671 672 /** @todo make this a scheduled event to simulate disk delay */ 673 devState = Prepare_Data_In; 674 action = ACT_DATA_READY; 675 break; 676 677 // Supported PIO data-out commands 678 case WIN_MULTWRITE: 679 case WIN_WRITE: 680 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 681 panic("Attempt to perform CHS access, only supports LBA\n"); 682 683 if (cmdReg.sec_count == 0) 684 cmdBytes = cmdBytesLeft = (256 * SectorSize); 685 else 686 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 687 688 curSector = getLBABase(); 689 690 devState = Prepare_Data_Out; 691 action = ACT_DATA_READY; 692 break; 693 694 // Supported DMA commands 695 case WIN_WRITEDMA: 696 dmaRead = true; // a write to the disk is a DMA read from memory 697 case WIN_READDMA: 698 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 699 panic("Attempt to perform CHS access, only supports LBA\n"); 700 701 if (cmdReg.sec_count == 0) 702 cmdBytes = cmdBytesLeft = (256 * SectorSize); 703 else 704 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 705 706 curSector = getLBABase(); 707 708 devState = Prepare_Data_Dma; 709 action = ACT_DMA_READY; 710 break; 711 712 default: 713 panic("Unsupported ATA command: %#x\n", cmdReg.command); 714 } 715 716 if (action != ACT_NONE) { 717 // set the BSY bit 718 status |= STATUS_BSY_BIT; 719 // clear the DRQ bit 720 status &= ~STATUS_DRQ_BIT; 721 // clear the DF bit 722 status &= ~STATUS_DF_BIT; 723 724 updateState(action); 725 } 726} 727 728//// 729// Handle setting and clearing interrupts 730//// 731 732void 733IdeDisk::intrPost() 734{ 735 if (intrPending) 736 panic("Attempt to post an interrupt with one pending\n"); 737 738 intrPending = true; 739 740 // talk to controller to set interrupt 741 if (ctrl) 742 ctrl->intrPost(); 743} 744 745void 746IdeDisk::intrClear() 747{ 748 if (!intrPending) 749 panic("Attempt to clear a non-pending interrupt\n"); 750 751 intrPending = false; 752 753 // talk to controller to clear interrupt 754 if (ctrl) 755 ctrl->intrClear(); 756} 757 758//// 759// Manage the device internal state machine 760//// 761 762void 763IdeDisk::updateState(DevAction_t action) 764{ 765 switch (devState) { 766 case Device_Srst: 767 if (action == ACT_SRST_SET) { 768 // set the BSY bit 769 status |= STATUS_BSY_BIT; 770 } else if (action == ACT_SRST_CLEAR) { 771 // clear the BSY bit 772 status &= ~STATUS_BSY_BIT; 773 774 // reset the device state 775 reset(devID); 776 } 777 break; 778 779 case Device_Idle_S: 780 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 781 devState = Device_Idle_NS; 782 } else if (action == ACT_CMD_WRITE) { 783 startCommand(); 784 } 785 786 break; 787 788 case Device_Idle_SI: 789 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 790 devState = Device_Idle_NS; 791 intrClear(); 792 } else if (action == ACT_STAT_READ || isIENSet()) { 793 devState = Device_Idle_S; 794 intrClear(); 795 } else if (action == ACT_CMD_WRITE) { 796 intrClear(); 797 startCommand(); 798 } 799 800 break; 801 802 case Device_Idle_NS: 803 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 804 if (!isIENSet() && intrPending) { 805 devState = Device_Idle_SI; 806 intrPost(); 807 } 808 if (isIENSet() || !intrPending) { 809 devState = Device_Idle_S; 810 } 811 } 812 break; 813 814 case Command_Execution: 815 if (action == ACT_CMD_COMPLETE) { 816 // clear the BSY bit 817 setComplete(); 818 819 if (!isIENSet()) { 820 devState = Device_Idle_SI; 821 intrPost(); 822 } else { 823 devState = Device_Idle_S; 824 } 825 } 826 break; 827 828 case Prepare_Data_In: 829 if (action == ACT_CMD_ERROR) { 830 // clear the BSY bit 831 setComplete(); 832 833 if (!isIENSet()) { 834 devState = Device_Idle_SI; 835 intrPost(); 836 } else { 837 devState = Device_Idle_S; 838 } 839 } else if (action == ACT_DATA_READY) { 840 // clear the BSY bit 841 status &= ~STATUS_BSY_BIT; 842 // set the DRQ bit 843 status |= STATUS_DRQ_BIT; 844 845 // copy the data into the data buffer 846 if (cmdReg.command == WIN_IDENTIFY) { 847 // Reset the drqBytes for this block 848 drqBytesLeft = sizeof(struct hd_driveid); 849 850 memcpy((void *)dataBuffer, (void *)&driveID, 851 sizeof(struct hd_driveid)); 852 } else { 853 // Reset the drqBytes for this block 854 drqBytesLeft = SectorSize; 855 856 readDisk(curSector++, dataBuffer); 857 } 858 859 // put the first two bytes into the data register 860 memcpy((void *)&cmdReg.data0, (void *)dataBuffer, 861 sizeof(uint16_t)); 862 863 if (!isIENSet()) { 864 devState = Data_Ready_INTRQ_In; 865 intrPost(); 866 } else { 867 devState = Transfer_Data_In; 868 } 869 } 870 break; 871 872 case Data_Ready_INTRQ_In: 873 if (action == ACT_STAT_READ) { 874 devState = Transfer_Data_In; 875 intrClear(); 876 } 877 break; 878 879 case Transfer_Data_In: 880 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 881 if (action == ACT_DATA_READ_BYTE) { 882 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 883 } else { 884 drqBytesLeft -= 2; 885 cmdBytesLeft -= 2; 886 887 // copy next short into data registers 888 if (drqBytesLeft) 889 memcpy((void *)&cmdReg.data0, 890 (void *)&dataBuffer[SectorSize - drqBytesLeft], 891 sizeof(uint16_t)); 892 } 893 894 if (drqBytesLeft == 0) { 895 if (cmdBytesLeft == 0) { 896 // Clear the BSY bit 897 setComplete(); 898 devState = Device_Idle_S; 899 } else { 900 devState = Prepare_Data_In; 901 // set the BSY_BIT 902 status |= STATUS_BSY_BIT; 903 // clear the DRQ_BIT 904 status &= ~STATUS_DRQ_BIT; 905 906 /** @todo change this to a scheduled event to simulate 907 disk delay */ 908 updateState(ACT_DATA_READY); 909 } 910 } 911 } 912 break; 913 914 case Prepare_Data_Out: 915 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 916 // clear the BSY bit 917 setComplete(); 918 919 if (!isIENSet()) { 920 devState = Device_Idle_SI; 921 intrPost(); 922 } else { 923 devState = Device_Idle_S; 924 } 925 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 926 // clear the BSY bit 927 status &= ~STATUS_BSY_BIT; 928 // set the DRQ bit 929 status |= STATUS_DRQ_BIT; 930 931 // clear the data buffer to get it ready for writes 932 memset(dataBuffer, 0, MAX_DMA_SIZE); 933 934 // reset the drqBytes for this block 935 drqBytesLeft = SectorSize; 936 937 if (cmdBytesLeft == cmdBytes || isIENSet()) { 938 devState = Transfer_Data_Out; 939 } else { 940 devState = Data_Ready_INTRQ_Out; 941 intrPost(); 942 } 943 } 944 break; 945 946 case Data_Ready_INTRQ_Out: 947 if (action == ACT_STAT_READ) { 948 devState = Transfer_Data_Out; 949 intrClear(); 950 } 951 break; 952 953 case Transfer_Data_Out: 954 if (action == ACT_DATA_WRITE_BYTE || 955 action == ACT_DATA_WRITE_SHORT) { 956 957 if (action == ACT_DATA_READ_BYTE) { 958 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 959 } else { 960 // copy the latest short into the data buffer 961 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 962 (void *)&cmdReg.data0, 963 sizeof(uint16_t)); 964 965 drqBytesLeft -= 2; 966 cmdBytesLeft -= 2; 967 } 968 969 if (drqBytesLeft == 0) { 970 // copy the block to the disk 971 writeDisk(curSector++, dataBuffer); 972 973 // set the BSY bit 974 status |= STATUS_BSY_BIT; 975 // set the seek bit 976 status |= STATUS_SEEK_BIT; 977 // clear the DRQ bit 978 status &= ~STATUS_DRQ_BIT; 979 980 devState = Prepare_Data_Out; 981 982 /** @todo change this to a scheduled event to simulate 983 disk delay */ 984 updateState(ACT_DATA_READY); 985 } 986 } 987 break; 988 989 case Prepare_Data_Dma: 990 if (action == ACT_CMD_ERROR) { 991 // clear the BSY bit 992 setComplete(); 993 994 if (!isIENSet()) { 995 devState = Device_Idle_SI; 996 intrPost(); 997 } else { 998 devState = Device_Idle_S; 999 } 1000 } else if (action == ACT_DMA_READY) { 1001 // clear the BSY bit 1002 status &= ~STATUS_BSY_BIT; 1003 // set the DRQ bit 1004 status |= STATUS_DRQ_BIT; 1005 1006 devState = Transfer_Data_Dma; 1007 1008 if (dmaState != Dma_Idle) 1009 panic("Inconsistent DMA state, should be Dma_Idle\n"); 1010 1011 dmaState = Dma_Start; 1012 // wait for the write to the DMA start bit 1013 } 1014 break; 1015 1016 case Transfer_Data_Dma: 1017 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 1018 // clear the BSY bit 1019 setComplete(); 1020 // set the seek bit 1021 status |= STATUS_SEEK_BIT; 1022 // clear the controller state for DMA transfer 1023 ctrl->setDmaComplete(this); 1024 1025 if (!isIENSet()) { 1026 devState = Device_Idle_SI; 1027 intrPost(); 1028 } else { 1029 devState = Device_Idle_S; 1030 } 1031 } 1032 break; 1033 1034 default: 1035 panic("Unknown IDE device state: %#x\n", devState); 1036 } 1037} 1038 1039void 1040IdeDisk::serialize(ostream &os) 1041{ 1042 // Check all outstanding events to see if they are scheduled 1043 // these are all mutually exclusive 1044 Tick reschedule = 0; 1045 Events_t event = None; 1046 1047 int eventCount = 0; 1048 1049 if (dmaTransferEvent.scheduled()) { 1050 reschedule = dmaTransferEvent.when(); 1051 event = Transfer; 1052 eventCount++; 1053 } 1054 if (dmaReadWaitEvent.scheduled()) { 1055 reschedule = dmaReadWaitEvent.when(); 1056 event = ReadWait; 1057 eventCount++; 1058 } 1059 if (dmaWriteWaitEvent.scheduled()) { 1060 reschedule = dmaWriteWaitEvent.when(); 1061 event = WriteWait; 1062 eventCount++; 1063 } 1064 if (dmaPrdReadEvent.scheduled()) { 1065 reschedule = dmaPrdReadEvent.when(); 1066 event = PrdRead; 1067 eventCount++; 1068 } 1069 if (dmaReadEvent.scheduled()) { 1070 reschedule = dmaReadEvent.when(); 1071 event = DmaRead; 1072 eventCount++; 1073 } 1074 if (dmaWriteEvent.scheduled()) { 1075 reschedule = dmaWriteEvent.when(); 1076 event = DmaWrite; 1077 eventCount++; 1078 } 1079 1080 assert(eventCount <= 1); 1081 1082 SERIALIZE_SCALAR(reschedule); 1083 SERIALIZE_ENUM(event); 1084 1085 // Serialize device registers 1086 SERIALIZE_SCALAR(cmdReg.data0); 1087 SERIALIZE_SCALAR(cmdReg.data1); 1088 SERIALIZE_SCALAR(cmdReg.sec_count); 1089 SERIALIZE_SCALAR(cmdReg.sec_num); 1090 SERIALIZE_SCALAR(cmdReg.cyl_low); 1091 SERIALIZE_SCALAR(cmdReg.cyl_high); 1092 SERIALIZE_SCALAR(cmdReg.drive); 1093 SERIALIZE_SCALAR(cmdReg.command); 1094 SERIALIZE_SCALAR(status); 1095 SERIALIZE_SCALAR(nIENBit); 1096 SERIALIZE_SCALAR(devID); 1097 1098 // Serialize the PRD related information 1099 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1100 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1101 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1102 SERIALIZE_SCALAR(curPrdAddr); 1103 1104 // Serialize current transfer related information 1105 SERIALIZE_SCALAR(cmdBytesLeft); 1106 SERIALIZE_SCALAR(cmdBytes); 1107 SERIALIZE_SCALAR(drqBytesLeft); 1108 SERIALIZE_SCALAR(curSector); 1109 SERIALIZE_SCALAR(dmaRead); 1110 SERIALIZE_SCALAR(dmaInterfaceBytes); 1111 SERIALIZE_SCALAR(intrPending); 1112 SERIALIZE_ENUM(devState); 1113 SERIALIZE_ENUM(dmaState); 1114 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1115} 1116 1117void 1118IdeDisk::unserialize(Checkpoint *cp, const string §ion) 1119{ 1120 // Reschedule events that were outstanding 1121 // these are all mutually exclusive 1122 Tick reschedule = 0; 1123 Events_t event = None; 1124 1125 UNSERIALIZE_SCALAR(reschedule); 1126 UNSERIALIZE_ENUM(event); 1127 1128 switch (event) { 1129 case None : break; 1130 case Transfer : dmaTransferEvent.schedule(reschedule); break; 1131 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; 1132 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; 1133 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; 1134 case DmaRead : dmaReadEvent.schedule(reschedule); break; 1135 case DmaWrite : dmaWriteEvent.schedule(reschedule); break; 1136 } 1137 1138 // Unserialize device registers 1139 UNSERIALIZE_SCALAR(cmdReg.data0); 1140 UNSERIALIZE_SCALAR(cmdReg.data1); 1141 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1142 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1143 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1144 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1145 UNSERIALIZE_SCALAR(cmdReg.drive); 1146 UNSERIALIZE_SCALAR(cmdReg.command); 1147 UNSERIALIZE_SCALAR(status); 1148 UNSERIALIZE_SCALAR(nIENBit); 1149 UNSERIALIZE_SCALAR(devID); 1150 1151 // Unserialize the PRD related information 1152 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1153 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1154 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1155 UNSERIALIZE_SCALAR(curPrdAddr); 1156 1157 // Unserialize current transfer related information 1158 UNSERIALIZE_SCALAR(cmdBytes); 1159 UNSERIALIZE_SCALAR(cmdBytesLeft); 1160 UNSERIALIZE_SCALAR(drqBytesLeft); 1161 UNSERIALIZE_SCALAR(curSector); 1162 UNSERIALIZE_SCALAR(dmaRead); 1163 UNSERIALIZE_SCALAR(dmaInterfaceBytes); 1164 UNSERIALIZE_SCALAR(intrPending); 1165 UNSERIALIZE_ENUM(devState); 1166 UNSERIALIZE_ENUM(dmaState); 1167 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1168} 1169 1170#ifndef DOXYGEN_SHOULD_SKIP_THIS 1171 1172BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1173 1174 SimObjectParam<DiskImage *> image; 1175 SimObjectParam<PhysicalMemory *> physmem; 1176 Param<int> driveID; 1177 Param<int> disk_delay; 1178 1179END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1180 1181BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1182 1183 INIT_PARAM(image, "Disk image"), 1184 INIT_PARAM(physmem, "Physical memory"), 1185 INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"), 1186 INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in microseconds", 1) 1187 1188END_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1189 1190 1191CREATE_SIM_OBJECT(IdeDisk) 1192{ 1193 return new IdeDisk(getInstanceName(), image, physmem, driveID, 1194 disk_delay); 1195} 1196 1197REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 1198 1199#endif //DOXYGEN_SHOULD_SKIP_THIS 1200