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