6636a5ff61f0d15b2f1cd27976c8538204994852
[gem5.git] / 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
29 #include <cstddef>
30 #include <cstdlib>
31 #include <string>
32 #include <vector>
33
34 #include "base/trace.hh"
35 #include "cpu/intr_control.hh"
36 #include "dev/ide_ctrl.hh"
37 #include "dev/ide_disk.hh"
38 #include "dev/pciconfigall.hh"
39 #include "dev/pcireg.h"
40 #include "dev/platform.hh"
41 #include "mem/bus/bus.hh"
42 #include "mem/bus/dma_interface.hh"
43 #include "mem/bus/pio_interface.hh"
44 #include "mem/bus/pio_interface_impl.hh"
45 #include "mem/functional/memory_control.hh"
46 #include "mem/functional/physical.hh"
47 #include "sim/builder.hh"
48 #include "sim/sim_object.hh"
49
50 using namespace std;
51
52 ////
53 // Initialization and destruction
54 ////
55
56 IdeController::IdeController(Params *p)
57 : PciDev(p)
58 {
59 // initialize the PIO interface addresses
60 pri_cmd_addr = 0;
61 pri_cmd_size = BARSize[0];
62
63 pri_ctrl_addr = 0;
64 pri_ctrl_size = BARSize[1];
65
66 sec_cmd_addr = 0;
67 sec_cmd_size = BARSize[2];
68
69 sec_ctrl_addr = 0;
70 sec_ctrl_size = BARSize[3];
71
72 // initialize the bus master interface (BMI) address to be configured
73 // via PCI
74 bmi_addr = 0;
75 bmi_size = BARSize[4];
76
77 // zero out all of the registers
78 memset(bmi_regs, 0, sizeof(bmi_regs));
79 memset(pci_config_regs.data, 0, sizeof(pci_config_regs.data));
80
81 // setup initial values
82 pci_config_regs.idetim = htoa((uint32_t)0x80008000); // enable both channels
83 *(uint8_t *)&bmi_regs[BMIS0] = 0x60;
84 *(uint8_t *)&bmi_regs[BMIS1] = 0x60;
85
86 // reset all internal variables
87 io_enabled = false;
88 bm_enabled = false;
89 memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
90
91 // create the PIO and DMA interfaces
92 if (params()->host_bus) {
93 pioInterface = newPioInterface(name(), params()->hier,
94 params()->host_bus, this,
95 &IdeController::cacheAccess);
96
97 dmaInterface = new DMAInterface<Bus>(name() + ".dma",
98 params()->host_bus,
99 params()->host_bus, 1,
100 true);
101 pioLatency = params()->pio_latency * params()->host_bus->clockRate;
102 }
103
104 // setup the disks attached to controller
105 memset(disks, 0, sizeof(IdeDisk *) * 4);
106 dev[0] = 0;
107 dev[1] = 0;
108
109 if (params()->disks.size() > 3)
110 panic("IDE controllers support a maximum of 4 devices attached!\n");
111
112 for (int i = 0; i < params()->disks.size(); i++) {
113 disks[i] = params()->disks[i];
114 disks[i]->setController(this, dmaInterface);
115 }
116 }
117
118 IdeController::~IdeController()
119 {
120 for (int i = 0; i < 4; i++)
121 if (disks[i])
122 delete disks[i];
123 }
124
125 ////
126 // Utility functions
127 ///
128
129 void
130 IdeController::parseAddr(const Addr &addr, Addr &offset, bool &primary,
131 RegType_t &type)
132 {
133 offset = addr;
134
135 if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
136 offset -= pri_cmd_addr;
137 type = COMMAND_BLOCK;
138 primary = true;
139 } else if (addr >= pri_ctrl_addr &&
140 addr < (pri_ctrl_addr + pri_ctrl_size)) {
141 offset -= pri_ctrl_addr;
142 type = CONTROL_BLOCK;
143 primary = true;
144 } else if (addr >= sec_cmd_addr &&
145 addr < (sec_cmd_addr + sec_cmd_size)) {
146 offset -= sec_cmd_addr;
147 type = COMMAND_BLOCK;
148 primary = false;
149 } else if (addr >= sec_ctrl_addr &&
150 addr < (sec_ctrl_addr + sec_ctrl_size)) {
151 offset -= sec_ctrl_addr;
152 type = CONTROL_BLOCK;
153 primary = false;
154 } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
155 offset -= bmi_addr;
156 type = BMI_BLOCK;
157 primary = (offset < BMIC1) ? true : false;
158 } else {
159 panic("IDE controller access to invalid address: %#x\n", addr);
160 }
161 }
162
163 int
164 IdeController::getDisk(bool primary)
165 {
166 int disk = 0;
167 uint8_t *devBit = &dev[0];
168
169 if (!primary) {
170 disk += 2;
171 devBit = &dev[1];
172 }
173
174 disk += *devBit;
175
176 assert(*devBit == 0 || *devBit == 1);
177
178 return disk;
179 }
180
181 int
182 IdeController::getDisk(IdeDisk *diskPtr)
183 {
184 for (int i = 0; i < 4; i++) {
185 if ((long)diskPtr == (long)disks[i])
186 return i;
187 }
188 return -1;
189 }
190
191 bool
192 IdeController::isDiskSelected(IdeDisk *diskPtr)
193 {
194 for (int i = 0; i < 4; i++) {
195 if ((long)diskPtr == (long)disks[i]) {
196 // is disk is on primary or secondary channel
197 int channel = i/2;
198 // is disk the master or slave
199 int devID = i%2;
200
201 return (dev[channel] == devID);
202 }
203 }
204 panic("Unable to find disk by pointer!!\n");
205 }
206
207 ////
208 // Command completion
209 ////
210
211 void
212 IdeController::setDmaComplete(IdeDisk *disk)
213 {
214 int diskNum = getDisk(disk);
215
216 if (diskNum < 0)
217 panic("Unable to find disk based on pointer %#x\n", disk);
218
219 if (diskNum < 2) {
220 // clear the start/stop bit in the command register
221 bmi_regs[BMIC0] &= ~SSBM;
222 // clear the bus master active bit in the status register
223 bmi_regs[BMIS0] &= ~BMIDEA;
224 // set the interrupt bit
225 bmi_regs[BMIS0] |= IDEINTS;
226 } else {
227 // clear the start/stop bit in the command register
228 bmi_regs[BMIC1] &= ~SSBM;
229 // clear the bus master active bit in the status register
230 bmi_regs[BMIS1] &= ~BMIDEA;
231 // set the interrupt bit
232 bmi_regs[BMIS1] |= IDEINTS;
233 }
234 }
235
236 ////
237 // Bus timing and bus access functions
238 ////
239
240 Tick
241 IdeController::cacheAccess(MemReqPtr &req)
242 {
243 // @todo Add more accurate timing to cache access
244 return curTick + pioLatency;
245 }
246
247 ////
248 // Read and write handling
249 ////
250
251 void
252 IdeController::ReadConfig(int offset, int size, uint8_t *data)
253 {
254 int config_offset;
255
256 #if TRACING_ON
257 Addr origOffset = offset;
258 #endif
259
260 if (offset < PCI_DEVICE_SPECIFIC) {
261 PciDev::ReadConfig(offset, size, data);
262 } else if (offset >= IDE_CTRL_CONFIG_START && (offset + size) <= IDE_CTRL_CONFIG_END) {
263
264 config_offset = offset - IDE_CTRL_CONFIG_START;
265
266 switch(size) {
267 case sizeof(uint32_t):
268 memcpy(data, &pci_config_regs.data[config_offset], sizeof(uint32_t));
269 *(uint32_t*)data = htoa(*(uint32_t*)data);
270 break;
271
272 case sizeof(uint16_t):
273 memcpy(data, &pci_config_regs.data[config_offset], sizeof(uint16_t));
274 *(uint16_t*)data = htoa(*(uint16_t*)data);
275 break;
276
277 case sizeof(uint8_t):
278 memcpy(data, &pci_config_regs.data[config_offset], sizeof(uint8_t));
279 break;
280
281 default:
282 panic("Invalid PCI configuration read size!\n");
283 }
284 } else {
285 panic("Read of unimplemented PCI config. register: %x\n", offset);
286 }
287
288 DPRINTF(IdeCtrl, "PCI read offset: %#x (%#x) size: %#x data: %#x\n",
289 origOffset, offset, size,
290 *(uint32_t *)data & (0xffffffff >> 8 * (4 - size)));
291 }
292
293 void
294 IdeController::WriteConfig(int offset, int size, uint32_t data)
295 {
296 int config_offset;
297
298 if (offset < PCI_DEVICE_SPECIFIC) {
299 PciDev::WriteConfig(offset, size, data);
300 } else if (offset >= IDE_CTRL_CONFIG_START && (offset + size) <= IDE_CTRL_CONFIG_END) {
301
302 config_offset = offset - IDE_CTRL_CONFIG_START;
303
304 switch(size) {
305 case sizeof(uint32_t):
306 case sizeof(uint16_t):
307 case sizeof(uint8_t):
308 memcpy(&pci_config_regs.data[config_offset], &data, size);
309 break;
310
311 default:
312 panic("Invalid PCI configuration write size!\n");
313 }
314
315 } else {
316 panic("Write of unimplemented PCI config. register: %x\n", offset);
317 }
318
319 DPRINTF(IdeCtrl, "PCI write offset: %#x size: %#x data: %#x\n",
320 offset, size, data & (0xffffffff >> 8 * (4 - size)));
321
322
323 // Catch the writes to specific PCI registers that have side affects
324 // (like updating the PIO ranges)
325 switch (offset) {
326 case PCI_COMMAND:
327 if (config.data[offset] & PCI_CMD_IOSE)
328 io_enabled = true;
329 else
330 io_enabled = false;
331
332 if (config.data[offset] & PCI_CMD_BME)
333 bm_enabled = true;
334 else
335 bm_enabled = false;
336 break;
337
338 case PCI0_BASE_ADDR0:
339 if (BARAddrs[0] != 0) {
340 pri_cmd_addr = BARAddrs[0];
341 if (pioInterface)
342 pioInterface->addAddrRange(RangeSize(pri_cmd_addr,
343 pri_cmd_size));
344
345 pri_cmd_addr &= EV5::PAddrUncachedMask;
346 }
347 break;
348
349 case PCI0_BASE_ADDR1:
350 if (BARAddrs[1] != 0) {
351 pri_ctrl_addr = BARAddrs[1];
352 if (pioInterface)
353 pioInterface->addAddrRange(RangeSize(pri_ctrl_addr,
354 pri_ctrl_size));
355
356 pri_ctrl_addr &= EV5::PAddrUncachedMask;
357 }
358 break;
359
360 case PCI0_BASE_ADDR2:
361 if (BARAddrs[2] != 0) {
362 sec_cmd_addr = BARAddrs[2];
363 if (pioInterface)
364 pioInterface->addAddrRange(RangeSize(sec_cmd_addr,
365 sec_cmd_size));
366
367 sec_cmd_addr &= EV5::PAddrUncachedMask;
368 }
369 break;
370
371 case PCI0_BASE_ADDR3:
372 if (BARAddrs[3] != 0) {
373 sec_ctrl_addr = BARAddrs[3];
374 if (pioInterface)
375 pioInterface->addAddrRange(RangeSize(sec_ctrl_addr,
376 sec_ctrl_size));
377
378 sec_ctrl_addr &= EV5::PAddrUncachedMask;
379 }
380 break;
381
382 case PCI0_BASE_ADDR4:
383 if (BARAddrs[4] != 0) {
384 bmi_addr = BARAddrs[4];
385 if (pioInterface)
386 pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size));
387
388 bmi_addr &= EV5::PAddrUncachedMask;
389 }
390 break;
391 }
392 }
393
394 Fault
395 IdeController::read(MemReqPtr &req, uint8_t *data)
396 {
397 Addr offset;
398 bool primary;
399 RegType_t type;
400 int disk;
401
402 parseAddr(req->paddr, offset, primary, type);
403
404 if (!io_enabled)
405 return No_Fault;
406
407 // sanity check the size (allows byte, word, or dword access)
408 switch (req->size) {
409 case sizeof(uint8_t):
410 case sizeof(uint16_t):
411 case sizeof(uint32_t):
412 break;
413 default:
414 panic("IDE controller read of invalid size: %#x\n", req->size);
415 }
416
417 if (type != BMI_BLOCK) {
418
419 disk = getDisk(primary);
420 if (disks[disk])
421 if (req->size == sizeof(uint32_t) && offset == DATA_OFFSET) {
422 ((uint16_t*)data)[0] = disks[disk]->read(offset, type);
423 ((uint16_t*)data)[1] = disks[disk]->read(offset, type);
424 }
425 else if (req->size == sizeof(uint8_t) && offset == DATA_OFFSET) {
426 panic("IDE read of data reg invalid size: %#x\n", req->size);
427 }
428 else {
429 *data = disks[disk]->read(offset, type);
430 }
431 } else {
432 memcpy((void *)data, &bmi_regs[offset], req->size);
433 }
434
435 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
436 offset, req->size,
437 (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - req->size)));
438
439 return No_Fault;
440 }
441
442 Fault
443 IdeController::write(MemReqPtr &req, const uint8_t *data)
444 {
445 Addr offset;
446 bool primary;
447 bool byte;
448 bool cmdBlk;
449 RegType_t type;
450 int disk;
451
452 parseAddr(req->paddr, offset, primary, type);
453 byte = (req->size == sizeof(uint8_t)) ? true : false;
454 cmdBlk = (type == COMMAND_BLOCK) ? true : false;
455
456 DPRINTF(IdeCtrl, "write from offset: %#x size: %#x data: %#x\n",
457 offset, req->size,
458 (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - req->size)));
459
460 uint8_t oldVal, newVal;
461
462 if (!io_enabled)
463 return No_Fault;
464
465 if (type == BMI_BLOCK && !bm_enabled)
466 return No_Fault;
467
468 if (type != BMI_BLOCK) {
469 // shadow the dev bit
470 if (type == COMMAND_BLOCK && offset == IDE_SELECT_OFFSET) {
471 uint8_t *devBit = (primary ? &dev[0] : &dev[1]);
472 *devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0);
473 }
474
475 assert(req->size != sizeof(uint32_t));
476
477 disk = getDisk(primary);
478 if (disks[disk])
479 disks[disk]->write(offset, byte, cmdBlk, data);
480 } else {
481 switch (offset) {
482 // Bus master IDE command register
483 case BMIC1:
484 case BMIC0:
485 if (req->size != sizeof(uint8_t))
486 panic("Invalid BMIC write size: %x\n", req->size);
487
488 // select the current disk based on DEV bit
489 disk = getDisk(primary);
490
491 oldVal = bmi_regs[offset];
492 newVal = *data;
493
494 // if a DMA transfer is in progress, R/W control cannot change
495 if (oldVal & SSBM) {
496 if ((oldVal & RWCON) ^ (newVal & RWCON)) {
497 (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
498 }
499 }
500
501 // see if the start/stop bit is being changed
502 if ((oldVal & SSBM) ^ (newVal & SSBM)) {
503 if (oldVal & SSBM) {
504 // stopping DMA transfer
505 DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
506
507 // clear the BMIDEA bit
508 bmi_regs[offset + 0x2] &= ~BMIDEA;
509
510 if (disks[disk] == NULL)
511 panic("DMA stop for disk %d which does not exist\n",
512 disk);
513
514 // inform the disk of the DMA transfer abort
515 disks[disk]->abortDma();
516 } else {
517 // starting DMA transfer
518 DPRINTF(IdeCtrl, "Starting DMA transfer\n");
519
520 // set the BMIDEA bit
521 bmi_regs[offset + 0x2] |= BMIDEA;
522
523 if (disks[disk] == NULL)
524 panic("DMA start for disk %d which does not exist\n",
525 disk);
526
527 // inform the disk of the DMA transfer start
528 if (primary)
529 disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP0]);
530 else
531 disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP1]);
532 }
533 }
534
535 // update the register value
536 bmi_regs[offset] = newVal;
537 break;
538
539 // Bus master IDE status register
540 case BMIS0:
541 case BMIS1:
542 if (req->size != sizeof(uint8_t))
543 panic("Invalid BMIS write size: %x\n", req->size);
544
545 oldVal = bmi_regs[offset];
546 newVal = *data;
547
548 // the BMIDEA bit is RO
549 newVal |= (oldVal & BMIDEA);
550
551 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
552 if ((oldVal & IDEINTS) && (newVal & IDEINTS))
553 newVal &= ~IDEINTS; // clear the interrupt?
554 else
555 (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
556
557 if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
558 newVal &= ~IDEDMAE;
559 else
560 (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
561
562 bmi_regs[offset] = newVal;
563 break;
564
565 // Bus master IDE descriptor table pointer register
566 case BMIDTP0:
567 case BMIDTP1:
568 if (req->size != sizeof(uint32_t))
569 panic("Invalid BMIDTP write size: %x\n", req->size);
570
571 *(uint32_t *)&bmi_regs[offset] = *(uint32_t *)data & ~0x3;
572 break;
573
574 default:
575 if (req->size != sizeof(uint8_t) &&
576 req->size != sizeof(uint16_t) &&
577 req->size != sizeof(uint32_t))
578 panic("IDE controller write of invalid write size: %x\n",
579 req->size);
580
581 // do a default copy of data into the registers
582 memcpy((void *)&bmi_regs[offset], data, req->size);
583 }
584 }
585
586 return No_Fault;
587 }
588
589 ////
590 // Serialization
591 ////
592
593 void
594 IdeController::serialize(std::ostream &os)
595 {
596 // Serialize the PciDev base class
597 PciDev::serialize(os);
598
599 // Serialize register addresses and sizes
600 SERIALIZE_SCALAR(pri_cmd_addr);
601 SERIALIZE_SCALAR(pri_cmd_size);
602 SERIALIZE_SCALAR(pri_ctrl_addr);
603 SERIALIZE_SCALAR(pri_ctrl_size);
604 SERIALIZE_SCALAR(sec_cmd_addr);
605 SERIALIZE_SCALAR(sec_cmd_size);
606 SERIALIZE_SCALAR(sec_ctrl_addr);
607 SERIALIZE_SCALAR(sec_ctrl_size);
608 SERIALIZE_SCALAR(bmi_addr);
609 SERIALIZE_SCALAR(bmi_size);
610
611 // Serialize registers
612 SERIALIZE_ARRAY(bmi_regs, 16);
613 SERIALIZE_ARRAY(dev, 2);
614 SERIALIZE_ARRAY(pci_config_regs.data, 22);
615
616 // Serialize internal state
617 SERIALIZE_SCALAR(io_enabled);
618 SERIALIZE_SCALAR(bm_enabled);
619 SERIALIZE_ARRAY(cmd_in_progress, 4);
620 }
621
622 void
623 IdeController::unserialize(Checkpoint *cp, const std::string &section)
624 {
625 // Unserialize the PciDev base class
626 PciDev::unserialize(cp, section);
627
628 // Unserialize register addresses and sizes
629 UNSERIALIZE_SCALAR(pri_cmd_addr);
630 UNSERIALIZE_SCALAR(pri_cmd_size);
631 UNSERIALIZE_SCALAR(pri_ctrl_addr);
632 UNSERIALIZE_SCALAR(pri_ctrl_size);
633 UNSERIALIZE_SCALAR(sec_cmd_addr);
634 UNSERIALIZE_SCALAR(sec_cmd_size);
635 UNSERIALIZE_SCALAR(sec_ctrl_addr);
636 UNSERIALIZE_SCALAR(sec_ctrl_size);
637 UNSERIALIZE_SCALAR(bmi_addr);
638 UNSERIALIZE_SCALAR(bmi_size);
639
640 // Unserialize registers
641 UNSERIALIZE_ARRAY(bmi_regs, 16);
642 UNSERIALIZE_ARRAY(dev, 2);
643 UNSERIALIZE_ARRAY(pci_config_regs.data, 22);
644
645 // Unserialize internal state
646 UNSERIALIZE_SCALAR(io_enabled);
647 UNSERIALIZE_SCALAR(bm_enabled);
648 UNSERIALIZE_ARRAY(cmd_in_progress, 4);
649
650 if (pioInterface) {
651 pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size));
652 pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size));
653 pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size));
654 pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size));
655 pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size));
656 }
657 }
658
659 #ifndef DOXYGEN_SHOULD_SKIP_THIS
660
661 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
662
663 Param<Addr> addr;
664 SimObjectVectorParam<IdeDisk *> disks;
665 SimObjectParam<MemoryController *> mmu;
666 SimObjectParam<PciConfigAll *> configspace;
667 SimObjectParam<PciConfigData *> configdata;
668 SimObjectParam<Platform *> platform;
669 Param<uint32_t> pci_bus;
670 Param<uint32_t> pci_dev;
671 Param<uint32_t> pci_func;
672 SimObjectParam<Bus *> io_bus;
673 Param<Tick> pio_latency;
674 SimObjectParam<HierParams *> hier;
675
676 END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
677
678 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
679
680 INIT_PARAM(addr, "Device Address"),
681 INIT_PARAM(disks, "IDE disks attached to this controller"),
682 INIT_PARAM(mmu, "Memory controller"),
683 INIT_PARAM(configspace, "PCI Configspace"),
684 INIT_PARAM(configdata, "PCI Config data"),
685 INIT_PARAM(platform, "Platform pointer"),
686 INIT_PARAM(pci_bus, "PCI bus ID"),
687 INIT_PARAM(pci_dev, "PCI device number"),
688 INIT_PARAM(pci_func, "PCI function code"),
689 INIT_PARAM_DFLT(io_bus, "Host bus to attach to", NULL),
690 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
691 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
692
693 END_INIT_SIM_OBJECT_PARAMS(IdeController)
694
695 CREATE_SIM_OBJECT(IdeController)
696 {
697 IdeController::Params *params = new IdeController::Params;
698 params->name = getInstanceName();
699 params->mmu = mmu;
700 params->configSpace = configspace;
701 params->configData = configdata;
702 params->plat = platform;
703 params->busNum = pci_bus;
704 params->deviceNum = pci_dev;
705 params->functionNum = pci_func;
706
707 params->disks = disks;
708 params->host_bus = io_bus;
709 params->pio_latency = pio_latency;
710 params->hier = hier;
711 return new IdeController(params);
712 }
713
714 REGISTER_SIM_OBJECT("IdeController", IdeController)
715
716 #endif //DOXYGEN_SHOULD_SKIP_THIS