ide_disk.cc revision 849
1/* 2 * Copyright (c) 2003 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/** @file 30 * Device model implementation for an IDE disk 31 */ 32 33#include <cerrno> 34#include <cstring> 35#include <deque> 36#include <string> 37 38#include "base/cprintf.hh" // csprintf 39#include "base/trace.hh" 40#include "dev/disk_image.hh" 41#include "dev/ide_disk.hh" 42#include "dev/ide_ctrl.hh" 43#include "dev/tsunami.hh" 44#include "dev/tsunami_pchip.hh" 45#include "mem/functional_mem/physical_memory.hh" 46#include "mem/bus/bus.hh" 47#include "mem/bus/dma_interface.hh" 48#include "mem/bus/pio_interface.hh" 49#include "mem/bus/pio_interface_impl.hh" 50#include "sim/builder.hh" 51#include "sim/sim_object.hh" 52#include "sim/universe.hh" 53 54using namespace std; 55 56IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, 57 int id, int delay) 58 : SimObject(name), ctrl(NULL), image(img), physmem(phys), dmaTransferEvent(this), 59 dmaReadWaitEvent(this), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 60 dmaReadEvent(this), dmaWriteEvent(this) 61{ 62 diskDelay = (delay * ticksPerSecond / 1000) / image->size(); 63 64 // initialize the data buffer and shadow registers 65 dataBuffer = new uint8_t[MAX_DMA_SIZE]; 66 67 memset(dataBuffer, 0, MAX_DMA_SIZE); 68 memset(&cmdReg, 0, sizeof(CommandReg_t)); 69 memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 70 71 curPrdAddr = 0; 72 curSector = 0; 73 curCommand = 0; 74 cmdBytesLeft = 0; 75 drqBytesLeft = 0; 76 dmaRead = false; 77 intrPending = false; 78 79 // fill out the drive ID structure 80 memset(&driveID, 0, sizeof(struct hd_driveid)); 81 82 // Calculate LBA and C/H/S values 83 uint16_t cylinders; 84 uint8_t heads; 85 uint8_t sectors; 86 87 uint32_t lba_size = image->size(); 88 if (lba_size >= 16383*16*63) { 89 cylinders = 16383; 90 heads = 16; 91 sectors = 63; 92 } else { 93 if (lba_size >= 63) 94 sectors = 63; 95 else 96 sectors = lba_size; 97 98 if ((lba_size / sectors) >= 16) 99 heads = 16; 100 else 101 heads = (lba_size / sectors); 102 103 cylinders = lba_size / (heads * sectors); 104 } 105 106 // Setup the model name 107 sprintf((char *)driveID.model, "5MI EDD si k"); 108 // Set the maximum multisector transfer size 109 driveID.max_multsect = MAX_MULTSECT; 110 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 111 driveID.capability = 0x7; 112 // UDMA support, EIDE support 113 driveID.field_valid = 0x6; 114 // Setup default C/H/S settings 115 driveID.cyls = cylinders; 116 driveID.sectors = sectors; 117 driveID.heads = heads; 118 // Setup the current multisector transfer size 119 driveID.multsect = MAX_MULTSECT; 120 driveID.multsect_valid = 0x1; 121 // Number of sectors on disk 122 driveID.lba_capacity = lba_size; 123 // Multiword DMA mode 2 and below supported 124 driveID.dma_mword = 0x400; 125 // Set PIO mode 4 and 3 supported 126 driveID.eide_pio_modes = 0x3; 127 // Set DMA mode 4 and below supported 128 driveID.dma_ultra = 0x10; 129 // Statically set hardware config word 130 driveID.hw_config = 0x4001; 131 132 // set the device state to idle 133 dmaState = Dma_Idle; 134 135 if (id == DEV0) { 136 devState = Device_Idle_S; 137 devID = DEV0; 138 } else if (id == DEV1) { 139 devState = Device_Idle_NS; 140 devID = DEV1; 141 } else { 142 panic("Invalid device ID: %#x\n", id); 143 } 144 145 // set the device ready bit 146 cmdReg.status |= STATUS_DRDY_BIT; 147} 148 149IdeDisk::~IdeDisk() 150{ 151 // destroy the data buffer 152 delete [] dataBuffer; 153} 154 155//// 156// Device registers read/write 157//// 158 159void 160IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) 161{ 162 DevAction_t action = ACT_NONE; 163 164 if (cmdBlk) { 165 if (offset < 0 || offset > sizeof(CommandReg_t)) 166 panic("Invalid disk command register offset: %#x\n", offset); 167 168 if (!byte && offset != DATA_OFFSET) 169 panic("Invalid 16-bit read, only allowed on data reg\n"); 170 171 if (!byte) 172 *(uint16_t *)data = *(uint16_t *)&cmdReg.data0; 173 else 174 *data = ((uint8_t *)&cmdReg)[offset]; 175 176 // determine if an action needs to be taken on the state machine 177 if (offset == STATUS_OFFSET) { 178 action = ACT_STAT_READ; 179 } else if (offset == DATA_OFFSET) { 180 if (byte) 181 action = ACT_DATA_READ_BYTE; 182 else 183 action = ACT_DATA_READ_SHORT; 184 } 185 186 } else { 187 if (offset != ALTSTAT_OFFSET) 188 panic("Invalid disk control register offset: %#x\n", offset); 189 190 if (!byte) 191 panic("Invalid 16-bit read from control block\n"); 192 193 *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET]; 194 } 195 196 if (action != ACT_NONE) 197 updateState(action); 198} 199 200void 201IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) 202{ 203 DevAction_t action = ACT_NONE; 204 205 if (cmdBlk) { 206 if (offset < 0 || offset > sizeof(CommandReg_t)) 207 panic("Invalid disk command register offset: %#x\n", offset); 208 209 if (!byte && offset != DATA_OFFSET) 210 panic("Invalid 16-bit write, only allowed on data reg\n"); 211 212 if (!byte) 213 *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data; 214 else 215 ((uint8_t *)&cmdReg)[offset] = *data; 216 217 // determine if an action needs to be taken on the state machine 218 if (offset == COMMAND_OFFSET) { 219 action = ACT_CMD_WRITE; 220 } else if (offset == DATA_OFFSET) { 221 if (byte) 222 action = ACT_DATA_WRITE_BYTE; 223 else 224 action = ACT_DATA_WRITE_SHORT; 225 } 226 227 } else { 228 if (offset != CONTROL_OFFSET) 229 panic("Invalid disk control register offset: %#x\n", offset); 230 231 if (!byte) 232 panic("Invalid 16-bit write to control block\n"); 233 234 if (*data & CONTROL_RST_BIT) 235 panic("Software reset not supported!\n"); 236 237 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 238 } 239 240 if (action != ACT_NONE) 241 updateState(action); 242} 243 244//// 245// Perform DMA transactions 246//// 247 248void 249IdeDisk::doDmaTransfer() 250{ 251 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 252 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 253 dmaState, devState); 254 255 // first read the current PRD 256 if (dmaInterface) { 257 if (dmaInterface->busy()) { 258 // reschedule after waiting period 259 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 260 return; 261 } 262 263 dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, 264 &dmaPrdReadEvent); 265 } else { 266 dmaPrdReadDone(); 267 } 268} 269 270void 271IdeDisk::dmaPrdReadDone() 272{ 273 // actually copy the PRD from physical memory 274 memcpy((void *)&curPrd.entry, 275 physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), 276 sizeof(PrdEntry_t)); 277 278 curPrdAddr += sizeof(PrdEntry_t); 279 280 if (dmaRead) 281 doDmaRead(); 282 else 283 doDmaWrite(); 284} 285 286void 287IdeDisk::doDmaRead() 288{ 289 Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize); 290 291 if (dmaInterface) { 292 if (dmaInterface->busy()) { 293 // reschedule after waiting period 294 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 295 return; 296 } 297 298 Addr dmaAddr = 299 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 300 dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(), 301 curTick + totalDiskDelay, &dmaReadEvent); 302 } else { 303 // schedule dmaReadEvent with sectorDelay (dmaReadDone) 304 dmaReadEvent.schedule(curTick + totalDiskDelay); 305 } 306} 307 308void 309IdeDisk::dmaReadDone() 310{ 311 // actually copy the data from memory to data buffer 312 Addr dmaAddr = 313 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 314 memcpy((void *)dataBuffer, 315 physmem->dma_addr(dmaAddr, curPrd.getByteCount()), 316 curPrd.getByteCount()); 317 318 uint32_t bytesWritten = 0; 319 320 while (bytesWritten < curPrd.getByteCount()) { 321 if (cmdBytesLeft <= 0) 322 panic("DMA data is larger than # sectors specified\n"); 323 324 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 325 326 bytesWritten += SectorSize; 327 cmdBytesLeft -= SectorSize; 328 } 329 330 // check for the EOT 331 if (curPrd.getEOT()){ 332 assert(cmdBytesLeft == 0); 333 dmaState = Dma_Idle; 334 updateState(ACT_DMA_DONE); 335 } else { 336 doDmaTransfer(); 337 } 338} 339 340void 341IdeDisk::doDmaWrite() 342{ 343 Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize); 344 345 if (dmaInterface) { 346 if (dmaInterface->busy()) { 347 // reschedule after waiting period 348 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 349 return; 350 } 351 352 Addr dmaAddr = 353 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 354 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 355 curPrd.getByteCount(), curTick + totalDiskDelay, 356 &dmaWriteEvent); 357 } else { 358 // schedule event with disk delay (dmaWriteDone) 359 dmaWriteEvent.schedule(curTick + totalDiskDelay); 360 } 361} 362 363void 364IdeDisk::dmaWriteDone() 365{ 366 uint32_t bytesRead = 0; 367 368 // clear out the data buffer 369 memset(dataBuffer, 0, MAX_DMA_SIZE); 370 371 while (bytesRead < curPrd.getByteCount()) { 372 if (cmdBytesLeft <= 0) 373 panic("DMA requested data is larger than # sectors specified\n"); 374 375 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 376 377 bytesRead += SectorSize; 378 cmdBytesLeft -= SectorSize; 379 } 380 381 // copy the data to memory 382 Addr dmaAddr = 383 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 384 memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()), 385 (void *)dataBuffer, curPrd.getByteCount()); 386 387 // check for the EOT 388 if (curPrd.getEOT()) { 389 assert(cmdBytesLeft == 0); 390 dmaState = Dma_Idle; 391 updateState(ACT_DMA_DONE); 392 } else { 393 doDmaTransfer(); 394 } 395} 396 397//// 398// Disk utility routines 399/// 400 401void 402IdeDisk::readDisk(uint32_t sector, uint8_t *data) 403{ 404 uint32_t bytesRead = image->read(data, sector); 405 406 if (bytesRead != SectorSize) 407 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 408 name(), bytesRead, SectorSize, errno); 409} 410 411void 412IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 413{ 414 uint32_t bytesWritten = image->write(data, sector); 415 416 if (bytesWritten != SectorSize) 417 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 418 name(), bytesWritten, SectorSize, errno); 419} 420 421//// 422// Setup and handle commands 423//// 424 425void 426IdeDisk::startDma(const uint32_t &prdTableBase) 427{ 428 if (dmaState != Dma_Start) 429 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 430 431 if (devState != Transfer_Data_Dma) 432 panic("Inconsistent device state for DMA start!\n"); 433 434 curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase); 435 436 dmaState = Dma_Transfer; 437 438 // schedule dma transfer (doDmaTransfer) 439 dmaTransferEvent.schedule(curTick + 1); 440} 441 442void 443IdeDisk::abortDma() 444{ 445 if (dmaState == Dma_Idle) 446 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n"); 447 448 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 449 panic("Inconsistent device state, should be in Transfer or Prepare!\n"); 450 451 updateState(ACT_CMD_ERROR); 452} 453 454void 455IdeDisk::startCommand() 456{ 457 DevAction_t action = ACT_NONE; 458 uint32_t size = 0; 459 dmaRead = false; 460 461 // copy the command to the shadow 462 curCommand = cmdReg.command; 463 464 // Decode commands 465 switch (cmdReg.command) { 466 // Supported non-data commands 467 case WIN_READ_NATIVE_MAX: 468 size = image->size() - 1; 469 cmdReg.sec_num = (size & 0xff); 470 cmdReg.cyl_low = ((size & 0xff00) >> 8); 471 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 472 cmdReg.head = ((size & 0xf000000) >> 24); 473 474 devState = Command_Execution; 475 action = ACT_CMD_COMPLETE; 476 break; 477 478 case WIN_RECAL: 479 case WIN_SPECIFY: 480 case WIN_FLUSH_CACHE: 481 case WIN_VERIFY: 482 case WIN_SEEK: 483 case WIN_SETFEATURES: 484 case WIN_SETMULT: 485 devState = Command_Execution; 486 action = ACT_CMD_COMPLETE; 487 break; 488 489 // Supported PIO data-in commands 490 case WIN_IDENTIFY: 491 cmdBytesLeft = drqBytesLeft = sizeof(struct hd_driveid); 492 devState = Prepare_Data_In; 493 action = ACT_DATA_READY; 494 break; 495 496 case WIN_MULTREAD: 497 case WIN_READ: 498 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 499 panic("Attempt to perform CHS access, only supports LBA\n"); 500 501 if (cmdReg.sec_count == 0) 502 cmdBytesLeft = (256 * SectorSize); 503 else 504 cmdBytesLeft = (cmdReg.sec_count * SectorSize); 505 506 drqBytesLeft = SectorSize; 507 curSector = getLBABase(); 508 509 devState = Prepare_Data_In; 510 action = ACT_DATA_READY; 511 break; 512 513 // Supported PIO data-out commands 514 case WIN_MULTWRITE: 515 case WIN_WRITE: 516 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 517 panic("Attempt to perform CHS access, only supports LBA\n"); 518 519 if (cmdReg.sec_count == 0) 520 cmdBytesLeft = (256 * SectorSize); 521 else 522 cmdBytesLeft = (cmdReg.sec_count * SectorSize); 523 524 drqBytesLeft = SectorSize; 525 curSector = getLBABase(); 526 527 devState = Prepare_Data_Out; 528 action = ACT_DATA_READY; 529 break; 530 531 // Supported DMA commands 532 case WIN_WRITEDMA: 533 dmaRead = true; // a write to the disk is a DMA read from memory 534 case WIN_READDMA: 535 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 536 panic("Attempt to perform CHS access, only supports LBA\n"); 537 538 if (cmdReg.sec_count == 0) 539 cmdBytesLeft = (256 * SectorSize); 540 else 541 cmdBytesLeft = (cmdReg.sec_count * SectorSize); 542 543 drqBytesLeft = SectorSize; 544 curSector = getLBABase(); 545 546 devState = Prepare_Data_Dma; 547 action = ACT_DMA_READY; 548 break; 549 550 default: 551 panic("Unsupported ATA command: %#x\n", cmdReg.command); 552 } 553 554 if (action != ACT_NONE) { 555 // set the BSY bit 556 cmdReg.status |= STATUS_BSY_BIT; 557 // clear the DRQ bit 558 cmdReg.status &= ~STATUS_DRQ_BIT; 559 560 updateState(action); 561 } 562} 563 564//// 565// Handle setting and clearing interrupts 566//// 567 568void 569IdeDisk::intrPost() 570{ 571 if (intrPending) 572 panic("Attempt to post an interrupt with one pending\n"); 573 574 intrPending = true; 575 576 // talk to controller to set interrupt 577 if (ctrl) 578 ctrl->intrPost(); 579} 580 581void 582IdeDisk::intrClear() 583{ 584 if (!intrPending) 585 panic("Attempt to clear a non-pending interrupt\n"); 586 587 intrPending = false; 588 589 // talk to controller to clear interrupt 590 if (ctrl) 591 ctrl->intrClear(); 592} 593 594//// 595// Manage the device internal state machine 596//// 597 598void 599IdeDisk::updateState(DevAction_t action) 600{ 601 switch (devState) { 602 case Device_Idle_S: 603 if (!isDEVSelect()) 604 devState = Device_Idle_NS; 605 else if (action == ACT_CMD_WRITE) 606 startCommand(); 607 608 break; 609 610 case Device_Idle_SI: 611 if (!isDEVSelect()) { 612 devState = Device_Idle_NS; 613 intrClear(); 614 } else if (action == ACT_STAT_READ || isIENSet()) { 615 devState = Device_Idle_S; 616 intrClear(); 617 } else if (action == ACT_CMD_WRITE) { 618 intrClear(); 619 startCommand(); 620 } 621 622 break; 623 624 case Device_Idle_NS: 625 if (isDEVSelect()) { 626 if (!isIENSet() && intrPending) { 627 devState = Device_Idle_SI; 628 intrPost(); 629 } 630 if (isIENSet() || !intrPending) { 631 devState = Device_Idle_S; 632 } 633 } 634 break; 635 636 case Command_Execution: 637 if (action == ACT_CMD_COMPLETE) { 638 // clear the BSY bit 639 setComplete(); 640 641 if (!isIENSet()) { 642 devState = Device_Idle_SI; 643 intrPost(); 644 } else { 645 devState = Device_Idle_S; 646 } 647 } 648 break; 649 650 case Prepare_Data_In: 651 if (action == ACT_CMD_ERROR) { 652 // clear the BSY bit 653 setComplete(); 654 655 if (!isIENSet()) { 656 devState = Device_Idle_SI; 657 intrPost(); 658 } else { 659 devState = Device_Idle_S; 660 } 661 } else if (action == ACT_DATA_READY) { 662 // clear the BSY bit 663 cmdReg.status &= ~STATUS_BSY_BIT; 664 // set the DRQ bit 665 cmdReg.status |= STATUS_DRQ_BIT; 666 667 // put the first two bytes into the data register 668 memcpy((void *)&cmdReg.data0, (void *)dataBuffer, sizeof(uint16_t)); 669 // copy the data into the data buffer 670 if (curCommand == WIN_IDENTIFY) 671 memcpy((void *)dataBuffer, (void *)&driveID, 672 sizeof(struct hd_driveid)); 673 else 674 readDisk(curSector++, dataBuffer); 675 676 if (!isIENSet()) { 677 devState = Data_Ready_INTRQ_In; 678 intrPost(); 679 } else { 680 devState = Transfer_Data_In; 681 } 682 } 683 break; 684 685 case Data_Ready_INTRQ_In: 686 if (action == ACT_STAT_READ) { 687 devState = Transfer_Data_In; 688 intrClear(); 689 } 690 break; 691 692 case Transfer_Data_In: 693 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 694 if (action == ACT_DATA_READ_BYTE) { 695 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 696 } else { 697 drqBytesLeft -= 2; 698 cmdBytesLeft -= 2; 699 700 // copy next short into data registers 701 memcpy((void *)&cmdReg.data0, 702 (void *)&dataBuffer[SectorSize - drqBytesLeft], 703 sizeof(uint16_t)); 704 } 705 706 if (drqBytesLeft == 0) { 707 if (cmdBytesLeft == 0) { 708 // Clear the BSY bit 709 setComplete(); 710 devState = Device_Idle_S; 711 } else { 712 devState = Prepare_Data_In; 713 cmdReg.status |= STATUS_BSY_BIT; 714 } 715 } 716 } 717 break; 718 719 case Prepare_Data_Out: 720 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 721 // clear the BSY bit 722 setComplete(); 723 724 if (!isIENSet()) { 725 devState = Device_Idle_SI; 726 intrPost(); 727 } else { 728 devState = Device_Idle_S; 729 } 730 } else if (cmdBytesLeft != 0) { 731 // clear the BSY bit 732 cmdReg.status &= ~STATUS_BSY_BIT; 733 // set the DRQ bit 734 cmdReg.status |= STATUS_DRQ_BIT; 735 736 // clear the data buffer to get it ready for writes 737 memset(dataBuffer, 0, MAX_DMA_SIZE); 738 739 if (!isIENSet()) { 740 devState = Data_Ready_INTRQ_Out; 741 intrPost(); 742 } else { 743 devState = Transfer_Data_Out; 744 } 745 } 746 break; 747 748 case Data_Ready_INTRQ_Out: 749 if (action == ACT_STAT_READ) { 750 devState = Transfer_Data_Out; 751 intrClear(); 752 } 753 break; 754 755 case Transfer_Data_Out: 756 if (action == ACT_DATA_WRITE_BYTE || action == ACT_DATA_WRITE_SHORT) { 757 if (action == ACT_DATA_READ_BYTE) { 758 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 759 } else { 760 // copy the latest short into the data buffer 761 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 762 (void *)&cmdReg.data0, 763 sizeof(uint16_t)); 764 765 drqBytesLeft -= 2; 766 cmdBytesLeft -= 2; 767 } 768 769 if (drqBytesLeft == 0) { 770 // copy the block to the disk 771 writeDisk(curSector++, dataBuffer); 772 773 // set the BSY bit 774 cmdReg.status |= STATUS_BSY_BIT; 775 // clear the DRQ bit 776 cmdReg.status &= ~STATUS_DRQ_BIT; 777 778 devState = Prepare_Data_Out; 779 } 780 } 781 break; 782 783 case Prepare_Data_Dma: 784 if (action == ACT_CMD_ERROR) { 785 // clear the BSY bit 786 setComplete(); 787 788 if (!isIENSet()) { 789 devState = Device_Idle_SI; 790 intrPost(); 791 } else { 792 devState = Device_Idle_S; 793 } 794 } else if (action == ACT_DMA_READY) { 795 // clear the BSY bit 796 cmdReg.status &= ~STATUS_BSY_BIT; 797 // set the DRQ bit 798 cmdReg.status |= STATUS_DRQ_BIT; 799 800 devState = Transfer_Data_Dma; 801 802 if (dmaState != Dma_Idle) 803 panic("Inconsistent DMA state, should be Dma_Idle\n"); 804 805 dmaState = Dma_Start; 806 // wait for the write to the DMA start bit 807 } 808 break; 809 810 case Transfer_Data_Dma: 811 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 812 // clear the BSY bit 813 setComplete(); 814 // set the seek bit 815 cmdReg.status |= 0x10; 816 // clear the controller state for DMA transfer 817 ctrl->setDmaComplete(this); 818 819 if (!isIENSet()) { 820 devState = Device_Idle_SI; 821 intrPost(); 822 } else { 823 devState = Device_Idle_S; 824 } 825 } 826 break; 827 828 default: 829 panic("Unknown IDE device state: %#x\n", devState); 830 } 831} 832 833void 834IdeDisk::serialize(ostream &os) 835{ 836} 837 838void 839IdeDisk::unserialize(Checkpoint *cp, const string §ion) 840{ 841} 842 843#ifndef DOXYGEN_SHOULD_SKIP_THIS 844 845BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 846 847 SimObjectParam<DiskImage *> image; 848 SimObjectParam<PhysicalMemory *> physmem; 849 Param<int> driveID; 850 Param<int> disk_delay; 851 852END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 853 854BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 855 856 INIT_PARAM(image, "Disk image"), 857 INIT_PARAM(physmem, "Physical memory"), 858 INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"), 859 INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0) 860 861END_INIT_SIM_OBJECT_PARAMS(IdeDisk) 862 863 864CREATE_SIM_OBJECT(IdeDisk) 865{ 866 return new IdeDisk(getInstanceName(), image, physmem, driveID, disk_delay); 867} 868 869REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 870 871#endif //DOXYGEN_SHOULD_SKIP_THIS 872