i8259.cc revision 5688:e18928b6b108
12810SN/A/*
22810SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32810SN/A * All rights reserved.
42810SN/A *
52810SN/A * Redistribution and use in source and binary forms, with or without
62810SN/A * modification, are permitted provided that the following conditions are
72810SN/A * met: redistributions of source code must retain the above copyright
82810SN/A * notice, this list of conditions and the following disclaimer;
92810SN/A * redistributions in binary form must reproduce the above copyright
102810SN/A * notice, this list of conditions and the following disclaimer in the
112810SN/A * documentation and/or other materials provided with the distribution;
122810SN/A * neither the name of the copyright holders nor the names of its
132810SN/A * contributors may be used to endorse or promote products derived from
142810SN/A * this software without specific prior written permission.
152810SN/A *
162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272810SN/A *
282810SN/A * Authors: Gabe Black
292810SN/A */
302810SN/A
312810SN/A#include "base/bitfield.hh"
322810SN/A#include "dev/x86/i82094aa.hh"
332810SN/A#include "dev/x86/i8259.hh"
342810SN/A
352810SN/AX86ISA::I8259::I8259(Params * p) : BasicPioDevice(p), IntDev(this),
362810SN/A                    latency(p->pio_latency), output(p->output),
372810SN/A                    mode(p->mode), slave(NULL),
382810SN/A                    IRR(0), ISR(0), IMR(0),
394626SN/A                    readIRR(true), initControlWord(0), autoEOI(false)
404626SN/A{
415314SN/A    if (output) {
422810SN/A        I8259 * master;
432810SN/A        master = dynamic_cast<I8259 *>(output->getDevice());
444626SN/A        if (master)
454626SN/A            master->setSlave(this);
462810SN/A        I82094AA * ioApic;
472810SN/A        ioApic = dynamic_cast<I82094AA *>(output->getDevice());
482810SN/A        if (ioApic)
493374SN/A            ioApic->setExtIntPic(this);
509264Sdjordje.kovacevic@arm.com    }
512810SN/A    pioSize = 2;
525314SN/A}
534626SN/A
544626SN/ATick
552810SN/AX86ISA::I8259::read(PacketPtr pkt)
564626SN/A{
574626SN/A    assert(pkt->getSize() == 1);
584626SN/A    switch(pkt->getAddr() - pioAddr)
595875Ssteve.reinhardt@amd.com    {
605875Ssteve.reinhardt@amd.com      case 0x0:
615875Ssteve.reinhardt@amd.com        if (readIRR) {
625875Ssteve.reinhardt@amd.com            DPRINTF(I8259, "Reading IRR as %#x.\n", IRR);
635875Ssteve.reinhardt@amd.com            pkt->set(IRR);
645875Ssteve.reinhardt@amd.com        } else {
655875Ssteve.reinhardt@amd.com            DPRINTF(I8259, "Reading ISR as %#x.\n", ISR);
664871SN/A            pkt->set(ISR);
674871SN/A        }
684666SN/A        break;
694626SN/A      case 0x1:
705875Ssteve.reinhardt@amd.com        DPRINTF(I8259, "Reading IMR as %#x.\n", IMR);
715318SN/A        pkt->set(IMR);
725318SN/A        break;
734626SN/A    }
745318SN/A    return latency;
755875Ssteve.reinhardt@amd.com}
767823Ssteve.reinhardt@amd.com
775875Ssteve.reinhardt@amd.comTick
784626SN/AX86ISA::I8259::write(PacketPtr pkt)
794626SN/A{
804626SN/A    assert(pkt->getSize() == 1);
814903SN/A    uint8_t val = pkt->get<uint8_t>();
824903SN/A    switch (pkt->getAddr() - pioAddr) {
834903SN/A      case 0x0:
845314SN/A        if (bits(val, 4)) {
854903SN/A            DPRINTF(I8259, "Received initialization command word 1.\n");
864903SN/A            IMR = 0;
874903SN/A            edgeTriggered = bits(val, 3);
884903SN/A            DPRINTF(I8259, "%s triggered mode.\n",
894903SN/A                    edgeTriggered ? "Edge" : "Level");
904903SN/A            cascadeMode = !bits(val, 1);
914903SN/A            DPRINTF(I8259, "%s mode.\n",
924903SN/A                    cascadeMode ? "Cascade" : "Single");
935318SN/A            expectICW4 = bits(val, 0);
945875Ssteve.reinhardt@amd.com            if (!expectICW4) {
954903SN/A                autoEOI = false;
964908SN/A            }
974920SN/A            initControlWord = 1;
985314SN/A            DPRINTF(I8259, "Expecting %d more bytes.\n", expectICW4 ? 3 : 2);
995314SN/A        } else if (bits(val, 4, 3) == 0) {
1004903SN/A            DPRINTF(I8259, "Received operation command word 2.\n");
1014903SN/A            switch (bits(val, 7, 5)) {
1022810SN/A              case 0x0:
1032810SN/A                DPRINTF(I8259,
1042810SN/A                        "Subcommand: Rotate in auto-EOI mode (clear).\n");
1052810SN/A                break;
1062810SN/A              case 0x1:
1072810SN/A                {
1082810SN/A                    int line = findMsbSet(ISR);
1094626SN/A                    DPRINTF(I8259, "Subcommand: Nonspecific EOI on line %d.\n",
1104626SN/A                            line);
1114626SN/A                    handleEOI(line);
1124666SN/A                }
1134871SN/A                break;
1144666SN/A              case 0x2:
1154666SN/A                DPRINTF(I8259, "Subcommand: No operation.\n");
1164666SN/A                break;
1174666SN/A              case 0x3:
1184626SN/A                {
1192810SN/A                    int line = bits(val, 2, 0);
1204626SN/A                    DPRINTF(I8259, "Subcommand: Specific EIO on line %d.\n",
1214626SN/A                            line);
1224626SN/A                    handleEOI(line);
1234626SN/A                }
1243374SN/A                break;
1252810SN/A              case 0x4:
1264626SN/A                DPRINTF(I8259, "Subcommand: Rotate in auto-EOI mode (set).\n");
1275730SSteve.Reinhardt@amd.com                break;
1285730SSteve.Reinhardt@amd.com              case 0x5:
1294903SN/A                DPRINTF(I8259, "Subcommand: Rotate on nonspecific EOI.\n");
1304626SN/A                break;
1315314SN/A              case 0x6:
1324665SN/A                DPRINTF(I8259, "Subcommand: Set priority command.\n");
1334626SN/A                DPRINTF(I8259, "Lowest: IRQ%d   Highest IRQ%d.\n",
1344626SN/A                        bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
1354626SN/A                break;
1364908SN/A              case 0x7:
1374908SN/A                DPRINTF(I8259, "Subcommand: Rotate on specific EOI.\n");
1387667Ssteve.reinhardt@amd.com                DPRINTF(I8259, "Lowest: IRQ%d   Highest IRQ%d.\n",
1397667Ssteve.reinhardt@amd.com                        bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
1407667Ssteve.reinhardt@amd.com                break;
1417667Ssteve.reinhardt@amd.com            }
1427667Ssteve.reinhardt@amd.com        } else if (bits(val, 4, 3) == 1) {
1437667Ssteve.reinhardt@amd.com            DPRINTF(I8259, "Received operation command word 3.\n");
1447667Ssteve.reinhardt@amd.com            if (bits(val, 7)) {
1457667Ssteve.reinhardt@amd.com                DPRINTF(I8259, "%s special mask mode.\n",
1467667Ssteve.reinhardt@amd.com                        bits(val, 6) ? "Set" : "Clear");
1477667Ssteve.reinhardt@amd.com            }
1487667Ssteve.reinhardt@amd.com            if (bits(val, 1)) {
1497667Ssteve.reinhardt@amd.com                readIRR = bits(val, 0);
1507667Ssteve.reinhardt@amd.com                DPRINTF(I8259, "Read %s.\n", readIRR ? "IRR" : "ISR");
1517667Ssteve.reinhardt@amd.com            }
1527667Ssteve.reinhardt@amd.com        }
1537667Ssteve.reinhardt@amd.com        break;
1547667Ssteve.reinhardt@amd.com      case 0x1:
1557667Ssteve.reinhardt@amd.com        switch (initControlWord) {
1567667Ssteve.reinhardt@amd.com          case 0x0:
1577667Ssteve.reinhardt@amd.com            DPRINTF(I8259, "Received operation command word 1.\n");
1587667Ssteve.reinhardt@amd.com            DPRINTF(I8259, "Wrote IMR value %#x.\n", val);
1597667Ssteve.reinhardt@amd.com            IMR = val;
1604665SN/A            break;
1612810SN/A          case 0x1:
1626221Snate@binkert.org            DPRINTF(I8259, "Received initialization command word 2.\n");
1632810SN/A            vectorOffset = val & ~mask(3);
1646227Snate@binkert.org            DPRINTF(I8259, "Responsible for vectors %#x-%#x.\n",
1652810SN/A                    vectorOffset, vectorOffset | mask(3));
1664668SN/A            if (cascadeMode) {
1674668SN/A                initControlWord++;
1684668SN/A            } else {
1694668SN/A                cascadeBits = 0;
1704668SN/A                initControlWord = 0;
1712810SN/A            }
1722810SN/A            break;
1732810SN/A          case 0x2:
1742810SN/A            DPRINTF(I8259, "Received initialization command word 3.\n");
1752810SN/A            if (mode == Enums::I8259Master) {
1764626SN/A                DPRINTF(I8259, "Slaves attached to IRQs:%s%s%s%s%s%s%s%s\n",
1772810SN/A                        bits(val, 0) ? " 0" : "",
1782810SN/A                        bits(val, 1) ? " 1" : "",
1792810SN/A                        bits(val, 2) ? " 2" : "",
1802810SN/A                        bits(val, 3) ? " 3" : "",
1812810SN/A                        bits(val, 4) ? " 4" : "",
1822810SN/A                        bits(val, 5) ? " 5" : "",
1832810SN/A                        bits(val, 6) ? " 6" : "",
1843374SN/A                        bits(val, 7) ? " 7" : "");
1854903SN/A                cascadeBits = val;
1862810SN/A            } else {
1874903SN/A                DPRINTF(I8259, "Slave ID is %d.\n", val & mask(3));
1884665SN/A                cascadeBits = val & mask(3);
1892810SN/A            }
1904626SN/A            if (expectICW4)
1914626SN/A                initControlWord++;
1924626SN/A            else
1932810SN/A                initControlWord = 0;
1942810SN/A            break;
1953374SN/A          case 0x3:
1962810SN/A            DPRINTF(I8259, "Received initialization command word 4.\n");
1972810SN/A            if (bits(val, 4)) {
1983374SN/A                DPRINTF(I8259, "Special fully nested mode.\n");
1992982SN/A            } else {
2002810SN/A                DPRINTF(I8259, "Not special fully nested mode.\n");
2014666SN/A            }
2024666SN/A            if (bits(val, 3) == 0) {
2032810SN/A                DPRINTF(I8259, "Nonbuffered.\n");
2047667Ssteve.reinhardt@amd.com            } else if (bits(val, 2) == 0) {
2054908SN/A                DPRINTF(I8259, "Buffered.\n");
2065318SN/A            } else {
2075318SN/A                DPRINTF(I8259, "Unrecognized buffer mode.\n");
2082810SN/A            }
2092810SN/A            autoEOI = bits(val, 1);
2102810SN/A            DPRINTF(I8259, "%s End Of Interrupt.\n",
2112810SN/A                    autoEOI ? "Automatic" : "Normal");
2122810SN/A
2132810SN/A            DPRINTF(I8259, "%s mode.\n", bits(val, 0) ? "80x86" : "MCX-80/85");
2143374SN/A            initControlWord = 0;
2152810SN/A            break;
2162810SN/A        }
2174666SN/A        break;
2184902SN/A    }
2192810SN/A    return latency;
2202810SN/A}
2212810SN/A
2222810SN/Avoid
2232810SN/AX86ISA::I8259::handleEOI(int line)
2242810SN/A{
2252810SN/A    ISR &= ~(1 << line);
2262810SN/A    // There may be an interrupt that was waiting which can
2272810SN/A    // now be sent.
2282810SN/A    if (IRR)
2295730SSteve.Reinhardt@amd.com        requestInterrupt(findMsbSet(IRR));
2302810SN/A}
2312810SN/A
2322810SN/Avoid
2332810SN/AX86ISA::I8259::requestInterrupt(int line)
2342810SN/A{
2354903SN/A    if (bits(ISR, 7, line) == 0) {
2362810SN/A        if (output) {
2372810SN/A            DPRINTF(I8259, "Propogating interrupt.\n");
2384899SN/A            output->signalInterrupt();
2394899SN/A        } else {
2404899SN/A            warn("Received interrupt but didn't have "
2415730SSteve.Reinhardt@amd.com                    "anyone to tell about it.\n");
2424899SN/A        }
2434899SN/A    }
2442810SN/A}
2452810SN/A
2462810SN/Avoid
2475730SSteve.Reinhardt@amd.comX86ISA::I8259::signalInterrupt(int line)
2485730SSteve.Reinhardt@amd.com{
2495730SSteve.Reinhardt@amd.com    DPRINTF(I8259, "Interrupt raised on line %d.\n", line);
2505730SSteve.Reinhardt@amd.com    if (line >= NumLines)
2515730SSteve.Reinhardt@amd.com        fatal("Line number %d doesn't exist. The max is %d.\n",
2522810SN/A                line, NumLines - 1);
2532810SN/A    if (bits(IMR, line)) {
2542810SN/A        DPRINTF(I8259, "Interrupt %d was masked.\n", line);
2552810SN/A    } else {
2562810SN/A        IRR |= 1 << line;
2572810SN/A        requestInterrupt(line);
2582810SN/A    }
2594903SN/A}
2602810SN/A
2612810SN/Aint
2625730SSteve.Reinhardt@amd.comX86ISA::I8259::getVector()
2632810SN/A{
2644630SN/A    /*
2654630SN/A     * This code only handles one slave. Since that's how the PC platform
2664630SN/A     * always uses the 8259 PIC, there shouldn't be any need for more. If
2675875Ssteve.reinhardt@amd.com     * there -is- a need for more for some reason, "slave" can become a
2682810SN/A     * vector of slaves.
2692810SN/A     */
2704665SN/A    int line = findMsbSet(IRR);
2714665SN/A    IRR &= ~(1 << line);
2724671SN/A    DPRINTF(I8259, "Interrupt %d was accepted.\n", line);
2734668SN/A    if (autoEOI) {
2745314SN/A        handleEOI(line);
2754920SN/A    } else {
2762810SN/A        ISR |= 1 << line;
2775314SN/A    }
2782810SN/A    if (slave && bits(cascadeBits, line)) {
2795314SN/A        DPRINTF(I8259, "Interrupt was from slave who will "
2805314SN/A                "provide the vector.\n");
2815314SN/A        return slave->getVector();
2822810SN/A    }
2832810SN/A    return line | vectorOffset;
2842810SN/A}
285
286X86ISA::I8259 *
287I8259Params::create()
288{
289    return new X86ISA::I8259(this);
290}
291