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