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