Merge from head.
[gem5.git] / src / dev / ide_ctrl.cc
1 /*
2 * Copyright (c) 2004-2005 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 * Authors: Andrew Schultz
29 * Ali Saidi
30 * Miguel Serrano
31 */
32
33 #include <cstddef>
34 #include <cstdlib>
35 #include <string>
36 #include <vector>
37
38 #include "base/trace.hh"
39 #include "cpu/intr_control.hh"
40 #include "dev/ide_ctrl.hh"
41 #include "dev/ide_disk.hh"
42 #include "dev/pciconfigall.hh"
43 #include "dev/pcireg.h"
44 #include "dev/platform.hh"
45 #include "mem/packet.hh"
46 #include "mem/packet_access.hh"
47 #include "sim/builder.hh"
48 #include "sim/sim_object.hh"
49 #include "sim/byteswap.hh"
50
51 using namespace std;
52
53 ////
54 // Initialization and destruction
55 ////
56
57 IdeController::IdeController(Params *p)
58 : PciDev(p)
59 {
60 // initialize the PIO interface addresses
61 pri_cmd_addr = 0;
62 pri_cmd_size = BARSize[0];
63
64 pri_ctrl_addr = 0;
65 pri_ctrl_size = BARSize[1];
66
67 sec_cmd_addr = 0;
68 sec_cmd_size = BARSize[2];
69
70 sec_ctrl_addr = 0;
71 sec_ctrl_size = BARSize[3];
72
73 // initialize the bus master interface (BMI) address to be configured
74 // via PCI
75 bmi_addr = 0;
76 bmi_size = BARSize[4];
77
78 // zero out all of the registers
79 memset(bmi_regs.data, 0, sizeof(bmi_regs));
80 memset(config_regs.data, 0, sizeof(config_regs.data));
81
82 // setup initial values
83 // enable both channels
84 config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
85 config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
86 bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
87 bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
88
89 // reset all internal variables
90 io_enabled = false;
91 bm_enabled = false;
92 memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
93
94 // setup the disks attached to controller
95 memset(disks, 0, sizeof(disks));
96 dev[0] = 0;
97 dev[1] = 0;
98
99 if (params()->disks.size() > 3)
100 panic("IDE controllers support a maximum of 4 devices attached!\n");
101
102 for (int i = 0; i < params()->disks.size(); i++) {
103 disks[i] = params()->disks[i];
104 disks[i]->setController(this);
105 }
106 }
107
108 IdeController::~IdeController()
109 {
110 for (int i = 0; i < 4; i++)
111 if (disks[i])
112 delete disks[i];
113 }
114
115 ////
116 // Utility functions
117 ///
118
119 void
120 IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
121 IdeRegType &reg_type)
122 {
123 offset = addr;
124
125 if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
126 offset -= pri_cmd_addr;
127 reg_type = COMMAND_BLOCK;
128 channel = PRIMARY;
129 } else if (addr >= pri_ctrl_addr &&
130 addr < (pri_ctrl_addr + pri_ctrl_size)) {
131 offset -= pri_ctrl_addr;
132 reg_type = CONTROL_BLOCK;
133 channel = PRIMARY;
134 } else if (addr >= sec_cmd_addr &&
135 addr < (sec_cmd_addr + sec_cmd_size)) {
136 offset -= sec_cmd_addr;
137 reg_type = COMMAND_BLOCK;
138 channel = SECONDARY;
139 } else if (addr >= sec_ctrl_addr &&
140 addr < (sec_ctrl_addr + sec_ctrl_size)) {
141 offset -= sec_ctrl_addr;
142 reg_type = CONTROL_BLOCK;
143 channel = SECONDARY;
144 } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
145 offset -= bmi_addr;
146 reg_type = BMI_BLOCK;
147 channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
148 } else {
149 panic("IDE controller access to invalid address: %#x\n", addr);
150 }
151 }
152
153 int
154 IdeController::getDisk(IdeChannel channel)
155 {
156 int disk = 0;
157 uint8_t *devBit = &dev[0];
158
159 if (channel == SECONDARY) {
160 disk += 2;
161 devBit = &dev[1];
162 }
163
164 disk += *devBit;
165
166 assert(*devBit == 0 || *devBit == 1);
167
168 return disk;
169 }
170
171 int
172 IdeController::getDisk(IdeDisk *diskPtr)
173 {
174 for (int i = 0; i < 4; i++) {
175 if ((long)diskPtr == (long)disks[i])
176 return i;
177 }
178 return -1;
179 }
180
181 bool
182 IdeController::isDiskSelected(IdeDisk *diskPtr)
183 {
184 for (int i = 0; i < 4; i++) {
185 if ((long)diskPtr == (long)disks[i]) {
186 // is disk is on primary or secondary channel
187 int channel = i/2;
188 // is disk the master or slave
189 int devID = i%2;
190
191 return (dev[channel] == devID);
192 }
193 }
194 panic("Unable to find disk by pointer!!\n");
195 }
196
197 ////
198 // Command completion
199 ////
200
201 void
202 IdeController::setDmaComplete(IdeDisk *disk)
203 {
204 int diskNum = getDisk(disk);
205
206 if (diskNum < 0)
207 panic("Unable to find disk based on pointer %#x\n", disk);
208
209 if (diskNum < 2) {
210 // clear the start/stop bit in the command register
211 bmi_regs.bmic0 &= ~SSBM;
212 // clear the bus master active bit in the status register
213 bmi_regs.bmis0 &= ~BMIDEA;
214 // set the interrupt bit
215 bmi_regs.bmis0 |= IDEINTS;
216 } else {
217 // clear the start/stop bit in the command register
218 bmi_regs.bmic1 &= ~SSBM;
219 // clear the bus master active bit in the status register
220 bmi_regs.bmis1 &= ~BMIDEA;
221 // set the interrupt bit
222 bmi_regs.bmis1 |= IDEINTS;
223 }
224 }
225
226
227 ////
228 // Read and write handling
229 ////
230
231 Tick
232 IdeController::readConfig(PacketPtr pkt)
233 {
234 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
235 if (offset < PCI_DEVICE_SPECIFIC) {
236 return PciDev::readConfig(pkt);
237 }
238
239 assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
240
241 pkt->allocate();
242
243 switch (pkt->getSize()) {
244 case sizeof(uint8_t):
245 switch (offset) {
246 case IDE_CTRL_CONF_DEV_TIMING:
247 pkt->set<uint8_t>(config_regs.sidetim);
248 break;
249 case IDE_CTRL_CONF_UDMA_CNTRL:
250 pkt->set<uint8_t>(config_regs.udmactl);
251 break;
252 case IDE_CTRL_CONF_PRIM_TIMING+1:
253 pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
254 break;
255 case IDE_CTRL_CONF_SEC_TIMING+1:
256 pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
257 break;
258 case IDE_CTRL_CONF_IDE_CONFIG:
259 pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
260 break;
261 case IDE_CTRL_CONF_IDE_CONFIG+1:
262 pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
263 break;
264 default:
265 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
266 offset);
267 }
268 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
269 (uint32_t)pkt->get<uint8_t>());
270 break;
271 case sizeof(uint16_t):
272 switch (offset) {
273 case IDE_CTRL_CONF_PRIM_TIMING:
274 pkt->set<uint16_t>(config_regs.idetim0);
275 break;
276 case IDE_CTRL_CONF_SEC_TIMING:
277 pkt->set<uint16_t>(config_regs.idetim1);
278 break;
279 case IDE_CTRL_CONF_UDMA_TIMING:
280 pkt->set<uint16_t>(config_regs.udmatim);
281 break;
282 case IDE_CTRL_CONF_IDE_CONFIG:
283 pkt->set<uint16_t>(config_regs.ideconfig);
284 break;
285 default:
286 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
287 offset);
288 }
289 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
290 (uint32_t)pkt->get<uint16_t>());
291 break;
292 case sizeof(uint32_t):
293 panic("No 32bit reads implemented for this device.");
294 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
295 (uint32_t)pkt->get<uint32_t>());
296 break;
297 default:
298 panic("invalid access size(?) for PCI configspace!\n");
299 }
300 pkt->makeAtomicResponse();
301 return configDelay;
302 }
303
304
305 Tick
306 IdeController::writeConfig(PacketPtr pkt)
307 {
308 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
309 if (offset < PCI_DEVICE_SPECIFIC) {
310 PciDev::writeConfig(pkt);
311 } else {
312 assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
313
314 switch (pkt->getSize()) {
315 case sizeof(uint8_t):
316 switch (offset) {
317 case IDE_CTRL_CONF_DEV_TIMING:
318 config_regs.sidetim = pkt->get<uint8_t>();
319 break;
320 case IDE_CTRL_CONF_UDMA_CNTRL:
321 config_regs.udmactl = pkt->get<uint8_t>();
322 break;
323 case IDE_CTRL_CONF_IDE_CONFIG:
324 config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
325 (pkt->get<uint8_t>());
326 break;
327 case IDE_CTRL_CONF_IDE_CONFIG+1:
328 config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
329 pkt->get<uint8_t>() << 8;
330 break;
331 default:
332 panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
333 offset);
334 }
335 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
336 offset, (uint32_t)pkt->get<uint8_t>());
337 break;
338 case sizeof(uint16_t):
339 switch (offset) {
340 case IDE_CTRL_CONF_PRIM_TIMING:
341 config_regs.idetim0 = pkt->get<uint16_t>();
342 break;
343 case IDE_CTRL_CONF_SEC_TIMING:
344 config_regs.idetim1 = pkt->get<uint16_t>();
345 break;
346 case IDE_CTRL_CONF_UDMA_TIMING:
347 config_regs.udmatim = pkt->get<uint16_t>();
348 break;
349 case IDE_CTRL_CONF_IDE_CONFIG:
350 config_regs.ideconfig = pkt->get<uint16_t>();
351 break;
352 default:
353 panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
354 offset);
355 }
356 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
357 offset, (uint32_t)pkt->get<uint16_t>());
358 break;
359 case sizeof(uint32_t):
360 panic("Write of unimplemented PCI config. register: %x\n", offset);
361 break;
362 default:
363 panic("invalid access size(?) for PCI configspace!\n");
364 }
365 pkt->makeAtomicResponse();
366 }
367
368 /* Trap command register writes and enable IO/BM as appropriate as well as
369 * BARs. */
370 switch(offset) {
371 case PCI0_BASE_ADDR0:
372 if (BARAddrs[0] != 0)
373 pri_cmd_addr = BARAddrs[0];
374 break;
375
376 case PCI0_BASE_ADDR1:
377 if (BARAddrs[1] != 0)
378 pri_ctrl_addr = BARAddrs[1];
379 break;
380
381 case PCI0_BASE_ADDR2:
382 if (BARAddrs[2] != 0)
383 sec_cmd_addr = BARAddrs[2];
384 break;
385
386 case PCI0_BASE_ADDR3:
387 if (BARAddrs[3] != 0)
388 sec_ctrl_addr = BARAddrs[3];
389 break;
390
391 case PCI0_BASE_ADDR4:
392 if (BARAddrs[4] != 0)
393 bmi_addr = BARAddrs[4];
394 break;
395
396 case PCI_COMMAND:
397 if (letoh(config.command) & PCI_CMD_IOSE)
398 io_enabled = true;
399 else
400 io_enabled = false;
401
402 if (letoh(config.command) & PCI_CMD_BME)
403 bm_enabled = true;
404 else
405 bm_enabled = false;
406 break;
407 }
408 return configDelay;
409 }
410
411
412 Tick
413 IdeController::read(PacketPtr pkt)
414 {
415 Addr offset;
416 IdeChannel channel;
417 IdeRegType reg_type;
418 int disk;
419
420 pkt->allocate();
421 if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
422 panic("Bad IDE read size: %d\n", pkt->getSize());
423
424 parseAddr(pkt->getAddr(), offset, channel, reg_type);
425
426 if (!io_enabled) {
427 pkt->makeAtomicResponse();
428 return pioDelay;
429 }
430
431 switch (reg_type) {
432 case BMI_BLOCK:
433 switch (pkt->getSize()) {
434 case sizeof(uint8_t):
435 pkt->set(bmi_regs.data[offset]);
436 break;
437 case sizeof(uint16_t):
438 pkt->set(*(uint16_t*)&bmi_regs.data[offset]);
439 break;
440 case sizeof(uint32_t):
441 pkt->set(*(uint32_t*)&bmi_regs.data[offset]);
442 break;
443 default:
444 panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize());
445 }
446 break;
447
448 case COMMAND_BLOCK:
449 case CONTROL_BLOCK:
450 disk = getDisk(channel);
451
452 if (disks[disk] == NULL) {
453 pkt->set<uint8_t>(0);
454 break;
455 }
456
457 switch (offset) {
458 case DATA_OFFSET:
459 switch (pkt->getSize()) {
460 case sizeof(uint16_t):
461 disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
462 break;
463
464 case sizeof(uint32_t):
465 disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
466 disks[disk]->read(offset, reg_type,
467 pkt->getPtr<uint8_t>() + sizeof(uint16_t));
468 break;
469
470 default:
471 panic("IDE read of data reg invalid size: %#x\n", pkt->getSize());
472 }
473 break;
474 default:
475 if (pkt->getSize() == sizeof(uint8_t)) {
476 disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
477 } else
478 panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize());
479 }
480 break;
481 default:
482 panic("IDE controller read of unknown register block type!\n");
483 }
484 if (pkt->getSize() == 1)
485 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
486 offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
487 else if (pkt->getSize() == 2)
488 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
489 offset, pkt->getSize(), pkt->get<uint16_t>());
490 else
491 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
492 offset, pkt->getSize(), pkt->get<uint32_t>());
493
494 pkt->makeAtomicResponse();
495 return pioDelay;
496 }
497
498 Tick
499 IdeController::write(PacketPtr pkt)
500 {
501 Addr offset;
502 IdeChannel channel;
503 IdeRegType reg_type;
504 int disk;
505 uint8_t oldVal, newVal;
506
507 parseAddr(pkt->getAddr(), offset, channel, reg_type);
508
509 if (!io_enabled) {
510 pkt->makeAtomicResponse();
511 DPRINTF(IdeCtrl, "io not enabled\n");
512 return pioDelay;
513 }
514
515 switch (reg_type) {
516 case BMI_BLOCK:
517 if (!bm_enabled) {
518 pkt->makeAtomicResponse();
519 return pioDelay;
520 }
521
522 switch (offset) {
523 // Bus master IDE command register
524 case BMIC1:
525 case BMIC0:
526 if (pkt->getSize() != sizeof(uint8_t))
527 panic("Invalid BMIC write size: %x\n", pkt->getSize());
528
529 // select the current disk based on DEV bit
530 disk = getDisk(channel);
531
532 oldVal = bmi_regs.chan[channel].bmic;
533 newVal = pkt->get<uint8_t>();
534
535 // if a DMA transfer is in progress, R/W control cannot change
536 if (oldVal & SSBM) {
537 if ((oldVal & RWCON) ^ (newVal & RWCON)) {
538 (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
539 }
540 }
541
542 // see if the start/stop bit is being changed
543 if ((oldVal & SSBM) ^ (newVal & SSBM)) {
544 if (oldVal & SSBM) {
545 // stopping DMA transfer
546 DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
547
548 // clear the BMIDEA bit
549 bmi_regs.chan[channel].bmis =
550 bmi_regs.chan[channel].bmis & ~BMIDEA;
551
552 if (disks[disk] == NULL)
553 panic("DMA stop for disk %d which does not exist\n",
554 disk);
555
556 // inform the disk of the DMA transfer abort
557 disks[disk]->abortDma();
558 } else {
559 // starting DMA transfer
560 DPRINTF(IdeCtrl, "Starting DMA transfer\n");
561
562 // set the BMIDEA bit
563 bmi_regs.chan[channel].bmis =
564 bmi_regs.chan[channel].bmis | BMIDEA;
565
566 if (disks[disk] == NULL)
567 panic("DMA start for disk %d which does not exist\n",
568 disk);
569
570 // inform the disk of the DMA transfer start
571 disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
572 }
573 }
574
575 // update the register value
576 bmi_regs.chan[channel].bmic = newVal;
577 break;
578
579 // Bus master IDE status register
580 case BMIS0:
581 case BMIS1:
582 if (pkt->getSize() != sizeof(uint8_t))
583 panic("Invalid BMIS write size: %x\n", pkt->getSize());
584
585 oldVal = bmi_regs.chan[channel].bmis;
586 newVal = pkt->get<uint8_t>();
587
588 // the BMIDEA bit is RO
589 newVal |= (oldVal & BMIDEA);
590
591 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
592 if ((oldVal & IDEINTS) && (newVal & IDEINTS))
593 newVal &= ~IDEINTS; // clear the interrupt?
594 else
595 (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
596
597 if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
598 newVal &= ~IDEDMAE;
599 else
600 (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
601
602 bmi_regs.chan[channel].bmis = newVal;
603 break;
604
605 // Bus master IDE descriptor table pointer register
606 case BMIDTP0:
607 case BMIDTP1:
608 {
609 if (pkt->getSize() != sizeof(uint32_t))
610 panic("Invalid BMIDTP write size: %x\n", pkt->getSize());
611
612 bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3);
613 }
614 break;
615
616 default:
617 if (pkt->getSize() != sizeof(uint8_t) &&
618 pkt->getSize() != sizeof(uint16_t) &&
619 pkt->getSize() != sizeof(uint32_t))
620 panic("IDE controller write of invalid write size: %x\n",
621 pkt->getSize());
622
623 // do a default copy of data into the registers
624 memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize());
625 }
626 break;
627 case COMMAND_BLOCK:
628 if (offset == IDE_SELECT_OFFSET) {
629 uint8_t *devBit = &dev[channel];
630 *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0;
631 }
632 // fall-through ok!
633 case CONTROL_BLOCK:
634 disk = getDisk(channel);
635
636 if (disks[disk] == NULL)
637 break;
638
639 switch (offset) {
640 case DATA_OFFSET:
641 switch (pkt->getSize()) {
642 case sizeof(uint16_t):
643 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
644 break;
645
646 case sizeof(uint32_t):
647 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
648 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() +
649 sizeof(uint16_t));
650 break;
651 default:
652 panic("IDE write of data reg invalid size: %#x\n", pkt->getSize());
653 }
654 break;
655 default:
656 if (pkt->getSize() == sizeof(uint8_t)) {
657 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
658 } else
659 panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize());
660 }
661 break;
662 default:
663 panic("IDE controller write of unknown register block type!\n");
664 }
665
666 if (pkt->getSize() == 1)
667 DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
668 offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
669 else if (pkt->getSize() == 2)
670 DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
671 offset, pkt->getSize(), pkt->get<uint16_t>());
672 else
673 DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
674 offset, pkt->getSize(), pkt->get<uint32_t>());
675
676
677 pkt->makeAtomicResponse();
678 return pioDelay;
679 }
680
681 ////
682 // Serialization
683 ////
684
685 void
686 IdeController::serialize(std::ostream &os)
687 {
688 // Serialize the PciDev base class
689 PciDev::serialize(os);
690
691 // Serialize register addresses and sizes
692 SERIALIZE_SCALAR(pri_cmd_addr);
693 SERIALIZE_SCALAR(pri_cmd_size);
694 SERIALIZE_SCALAR(pri_ctrl_addr);
695 SERIALIZE_SCALAR(pri_ctrl_size);
696 SERIALIZE_SCALAR(sec_cmd_addr);
697 SERIALIZE_SCALAR(sec_cmd_size);
698 SERIALIZE_SCALAR(sec_ctrl_addr);
699 SERIALIZE_SCALAR(sec_ctrl_size);
700 SERIALIZE_SCALAR(bmi_addr);
701 SERIALIZE_SCALAR(bmi_size);
702
703 // Serialize registers
704 SERIALIZE_ARRAY(bmi_regs.data,
705 sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
706 SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
707 SERIALIZE_ARRAY(config_regs.data,
708 sizeof(config_regs.data) / sizeof(config_regs.data[0]));
709
710 // Serialize internal state
711 SERIALIZE_SCALAR(io_enabled);
712 SERIALIZE_SCALAR(bm_enabled);
713 SERIALIZE_ARRAY(cmd_in_progress,
714 sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
715 }
716
717 void
718 IdeController::unserialize(Checkpoint *cp, const std::string &section)
719 {
720 // Unserialize the PciDev base class
721 PciDev::unserialize(cp, section);
722
723 // Unserialize register addresses and sizes
724 UNSERIALIZE_SCALAR(pri_cmd_addr);
725 UNSERIALIZE_SCALAR(pri_cmd_size);
726 UNSERIALIZE_SCALAR(pri_ctrl_addr);
727 UNSERIALIZE_SCALAR(pri_ctrl_size);
728 UNSERIALIZE_SCALAR(sec_cmd_addr);
729 UNSERIALIZE_SCALAR(sec_cmd_size);
730 UNSERIALIZE_SCALAR(sec_ctrl_addr);
731 UNSERIALIZE_SCALAR(sec_ctrl_size);
732 UNSERIALIZE_SCALAR(bmi_addr);
733 UNSERIALIZE_SCALAR(bmi_size);
734
735 // Unserialize registers
736 UNSERIALIZE_ARRAY(bmi_regs.data,
737 sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
738 UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
739 UNSERIALIZE_ARRAY(config_regs.data,
740 sizeof(config_regs.data) / sizeof(config_regs.data[0]));
741
742 // Unserialize internal state
743 UNSERIALIZE_SCALAR(io_enabled);
744 UNSERIALIZE_SCALAR(bm_enabled);
745 UNSERIALIZE_ARRAY(cmd_in_progress,
746 sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
747 }
748
749 #ifndef DOXYGEN_SHOULD_SKIP_THIS
750
751 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
752
753 SimObjectParam<System *> system;
754 SimObjectParam<Platform *> platform;
755 Param<Tick> min_backoff_delay;
756 Param<Tick> max_backoff_delay;
757 SimObjectParam<PciConfigData *> configdata;
758 Param<uint32_t> pci_bus;
759 Param<uint32_t> pci_dev;
760 Param<uint32_t> pci_func;
761 Param<Tick> pio_latency;
762 Param<Tick> config_latency;
763 SimObjectVectorParam<IdeDisk *> disks;
764
765 END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
766
767 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
768
769 INIT_PARAM(system, "System pointer"),
770 INIT_PARAM(platform, "Platform pointer"),
771 INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"),
772 INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"),
773 INIT_PARAM(configdata, "PCI Config data"),
774 INIT_PARAM(pci_bus, "PCI bus ID"),
775 INIT_PARAM(pci_dev, "PCI device number"),
776 INIT_PARAM(pci_func, "PCI function code"),
777 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
778 INIT_PARAM(config_latency, "Number of cycles for a config read or write"),
779 INIT_PARAM(disks, "IDE disks attached to this controller")
780
781 END_INIT_SIM_OBJECT_PARAMS(IdeController)
782
783 CREATE_SIM_OBJECT(IdeController)
784 {
785 IdeController::Params *params = new IdeController::Params;
786 params->name = getInstanceName();
787 params->platform = platform;
788 params->system = system;
789 params->min_backoff_delay = min_backoff_delay;
790 params->max_backoff_delay = max_backoff_delay;
791 params->configData = configdata;
792 params->busNum = pci_bus;
793 params->deviceNum = pci_dev;
794 params->functionNum = pci_func;
795 params->pio_delay = pio_latency;
796 params->config_delay = config_latency;
797 params->disks = disks;
798 return new IdeController(params);
799 }
800
801 REGISTER_SIM_OBJECT("IdeController", IdeController)
802
803 #endif //DOXYGEN_SHOULD_SKIP_THIS