Annotation of nono/vm/interrupt.cpp, revision 1.1.1.6

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.6 ! root        7: //
        !             8: // 割り込みコントローラ
        !             9: //
        !            10: 
        !            11: // IODevice
        !            12: //    |
        !            13: //    |  +-----------------+
        !            14: //    +--| InterruptDevice | (割り込みコントローラの共通部)
        !            15: //       +-----------------+
        !            16: //          |  +-----------------+
        !            17: //          +--| M680x0Interrupt | (m68k 割り込みコントローラの共通部)
        !            18: //          |  +-----------------+
        !            19: //          |     |
        !            20: //          |     |  +-----------------+
        !            21: //          |     +--| X68030Interrupt | (X68030 の割り込みコントローラ)
        !            22: //          |     |  +-----------------+
        !            23: //          |     |
        !            24: //          |     |  +---------------+
        !            25: //          |     +--| LunaInterrupt |   (LUNA-I の割り込みコントローラ)
        !            26: //          |        +---------------+
        !            27: //          |
        !            28: //          +-- PEDECDevice   (X68030 の Lv1 担当コントローラ)
        !            29: //          +-- SysCtlrDevice (LUNA88K の割り込みコントローラ)
        !            30: 
1.1       root       31: #include "interrupt.h"
                     32: #include "dmac.h"
                     33: #include "lance.h"
                     34: #include "pedec.h"
                     35: #include "m68030.h"
                     36: #include "mfp.h"
                     37: #include "mpu680x0.h"
1.1.1.6 ! root       38: #include "nmi.h"
1.1       root       39: #include "scc.h"
                     40: #include "sio.h"
                     41: #include "spc.h"
                     42: #include "sysclk.h"
                     43: 
1.1.1.6 ! root       44: // グローバル参照用
        !            45: InterruptDevice *gInterrupt;
1.1       root       46: 
                     47: //
                     48: // 仮想割り込みコントローラ (共通部)
                     49: //
                     50: 
1.1.1.4   root       51: // コンストラクタ(オブジェクト名指定あり)
                     52: InterruptDevice::InterruptDevice(const std::string& objname_)
                     53:        : inherited(objname_)
                     54: {
                     55: }
                     56: 
                     57: // コンストラクタ(オブジェクト名指定なし)
1.1       root       58: InterruptDevice::InterruptDevice()
1.1.1.4   root       59:        : InterruptDevice("Interrupt")
1.1       root       60: {
                     61: }
                     62: 
                     63: // デストラクタ
                     64: InterruptDevice::~InterruptDevice()
                     65: {
1.1.1.6 ! root       66:        gInterrupt = NULL;
1.1       root       67: }
                     68: 
1.1.1.5   root       69: // リセット
                     70: void
1.1.1.6 ! root       71: InterruptDevice::ResetHard(bool poweron)
1.1.1.5   root       72: {
                     73:        intmap = IntmapSentinel;
                     74:        memset(&counter, 0, sizeof(counter));
                     75: }
                     76: 
                     77: // 子デバイスが割り込み信号線をアサートした
                     78: void
                     79: InterruptDevice::AssertINT(Device *source)
                     80: {
                     81:        uint32 oldmap;
                     82:        uint32 srcmap;
                     83: 
                     84:        oldmap = intmap;
                     85:        srcmap = GetIntmap(source);
                     86:        intmap |= srcmap;
                     87: 
                     88:        if ((oldmap ^ intmap) != 0) {
                     89:                // 立ち上がりエッジでカウント
                     90:                counter[__builtin_clz(srcmap)]++;
                     91:                ChangeInterrupt();
                     92:        }
                     93: }
                     94: 
                     95: // 子デバイスが割り込み信号線をネゲートした
                     96: void
                     97: InterruptDevice::NegateINT(Device *source)
                     98: {
                     99:        uint32 oldmap;
                    100:        uint32 srcmap;
                    101: 
                    102:        oldmap = intmap;
                    103:        srcmap = GetIntmap(source);
                    104:        intmap &= ~srcmap;
                    105: 
                    106:        if ((oldmap ^ intmap) != 0) {
                    107:                ChangeInterrupt();
                    108:        }
                    109: }
1.1       root      110: 
                    111: //
                    112: // 仮想割り込みコントローラ (m680x0 共通部)
                    113: //
                    114: 
                    115: // CPU コアからの割り込みアクノリッジを受け付けるグローバル関数
                    116: int
                    117: m68030_interrupt_acknowledge(int lv)
                    118: {
                    119:        return gInterrupt->InterruptAcknowledge(lv);
                    120: }
                    121: 
                    122: // コンストラクタ
                    123: M680x0Interrupt::M680x0Interrupt()
                    124: {
                    125: }
                    126: 
                    127: // デストラクタ
                    128: M680x0Interrupt::~M680x0Interrupt()
                    129: {
                    130: }
                    131: 
                    132: // リセット
                    133: void
1.1.1.6 ! root      134: M680x0Interrupt::ResetHard(bool poweron)
1.1       root      135: {
1.1.1.6 ! root      136:        inherited::ResetHard(poweron);
1.1       root      137:        ipl = 0;
                    138: }
                    139: 
                    140: void
1.1.1.5   root      141: M680x0Interrupt::ChangeInterrupt()
1.1       root      142: {
                    143:        int newipl;
                    144: 
1.1.1.6 ! root      145:        // intmap は最下位ビットを常に立ててあるので 0 にならない
1.1       root      146:        newipl = (uint)(31 - __builtin_clz(intmap)) / 4;
                    147: 
1.1.1.5   root      148:        // 割り込みレベルが変わったら、新しいレベルを通知
                    149:        if (newipl != ipl) {
1.1       root      150:                ipl = newipl;
                    151:                gMPU->Interrupt(ipl);
                    152:        }
                    153: }
                    154: 
                    155: 
                    156: //
                    157: // X68030 仮想割り込みコントローラ
                    158: //
                    159: 
                    160: // コンストラクタ
                    161: X68030Interrupt::X68030Interrupt()
                    162: {
1.1.1.6 ! root      163:        monitor.func = ToMonitorCallback(&X68030Interrupt::MonitorUpdate);
1.1.1.5   root      164:        monitor.SetSize(25, 11);
1.1.1.4   root      165:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      166: }
                    167: 
                    168: // デストラクタ
                    169: X68030Interrupt::~X68030Interrupt()
                    170: {
                    171: }
                    172: 
                    173: // デバイスから Intmap 値を引く
                    174: uint32
                    175: X68030Interrupt::GetIntmap(Device *source) const
                    176: {
1.1.1.6 ! root      177:        if (__predict_true(source == gMFP)) {
1.1       root      178:                return IntmapMFP;
                    179:        }
1.1.1.6 ! root      180:        if (__predict_true(source == gSCC)) {
1.1       root      181:                return IntmapSCC;
                    182:        }
1.1.1.6 ! root      183:        if (__predict_true(source == gDMAC)) {
1.1       root      184:                return IntmapDMAC;
                    185:        }
1.1.1.6 ! root      186:        if (__predict_true(source == gPEDEC)) {
1.1       root      187:                return IntmapPEDEC;
                    188:        }
1.1.1.6 ! root      189:        if (source == gNMI) {
1.1       root      190:                return IntmapNMI;
                    191:        }
1.1.1.6 ! root      192:        VMPANIC("Unknown interrupt source?");
1.1       root      193: }
                    194: 
                    195: // 割り込みアクノリッジに応答する
                    196: int
                    197: X68030Interrupt::InterruptAcknowledge(int lv)
                    198: {
                    199:        switch (lv) {
1.1.1.6 ! root      200:         case 7:
        !           201:                return AutoVector;
        !           202: 
1.1       root      203:         case 6:
                    204:                return gMFP->InterruptAcknowledge();
                    205: 
                    206:         case 5:
                    207:                return gSCC->InterruptAcknowledge();
                    208: 
                    209:         case 3:
                    210:                return gDMAC->InterruptAcknowledge();
                    211: 
                    212:         case 1:
                    213:                return gPEDEC->InterruptAcknowledge(lv);
                    214: 
                    215:         default:
                    216:                break;
                    217:        }
1.1.1.6 ! root      218:        VMPANIC("Unknown interrupt acknowledge lv=%d", lv);
1.1       root      219: }
                    220: 
                    221: void
1.1.1.4   root      222: X68030Interrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      223: {
                    224:        int y;
                    225:        struct {
                    226:                const char *name;
                    227:                uint32 map;
                    228:        } table[] = {
                    229:                { "NMI",        IntmapNMI },
                    230:                { "MFP",        IntmapMFP },
                    231:                { "SCC",        IntmapSCC },
                    232:                { "DMAC",       IntmapDMAC },
                    233:                { "PEDEC",      IntmapPEDEC },
                    234:        };
                    235: 
                    236:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.6 ! root      237:        uint intr_mask = gMPU680x0->GetCPU()->reg.intr_mask;
1.1       root      238: 
1.1.1.4   root      239:        screen.Clear();
1.1       root      240: 
                    241:        y = 0;
1.1.1.6 ! root      242:        screen.Print(0, y++, "Lv Device     Count  IM=%d", intr_mask);
1.1       root      243:        for (int i = 0; i < countof(table); i++) {
                    244:                uint32 map = table[i].map;
                    245:                int clz = __builtin_clz(map);
                    246:                int lv = (31 - clz) / 4;
1.1.1.4   root      247:                screen.Print(0, y, "%d", lv);
                    248:                screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.5   root      249:                screen.Print(8, y, "%11" PRIu64, counter[clz]);
1.1.1.6 ! root      250:                if (lv <= intr_mask) {
1.1.1.5   root      251:                        screen.Puts(21, y, "Mask");
1.1       root      252:                }
                    253:                y++;
                    254:        }
1.1.1.2   root      255: 
1.1.1.5   root      256:        // PEDEC 分も一緒に表示したい
1.1.1.6 ! root      257:        gPEDEC->MonitorUpdate(screen, intr_mask, y);
1.1       root      258: }
                    259: 
1.1.1.6 ! root      260: 
1.1       root      261: //
                    262: // LUNA-I 仮想割り込みコントローラ
                    263: //
                    264: 
                    265: // コンストラクタ
                    266: LunaInterrupt::LunaInterrupt()
                    267: {
1.1.1.6 ! root      268:        monitor.func = ToMonitorCallback(&LunaInterrupt::MonitorUpdate);
        !           269:        monitor.SetSize(25, 6);
1.1.1.4   root      270:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      271: }
                    272: 
                    273: // デストラクタ
                    274: LunaInterrupt::~LunaInterrupt()
                    275: {
                    276: }
                    277: 
                    278: // デバイスから Intmap 値を引く
                    279: uint32
                    280: LunaInterrupt::GetIntmap(Device *source) const
                    281: {
1.1.1.6 ! root      282:        if (__predict_true(source == gSIO)) {
1.1       root      283:                return IntmapSIO;
                    284:        }
1.1.1.6 ! root      285:        if (__predict_true(source == gSysClk)) {
1.1       root      286:                return IntmapSysClk;
                    287:        }
1.1.1.6 ! root      288:        if (__predict_true(source == gEthernet)) {
1.1       root      289:                return IntmapLance;
                    290:        }
1.1.1.6 ! root      291:        if (__predict_true(source == gSPC)) {
1.1       root      292:                return IntmapSPC;
                    293:        }
1.1.1.6 ! root      294:        if (source == gNMI) {
        !           295:                return IntmapNMI;
        !           296:        }
        !           297:        VMPANIC("Unknown interrupt source?");
1.1       root      298: }
                    299: 
                    300: // 割り込みアクノリッジに応答する
                    301: int
                    302: LunaInterrupt::InterruptAcknowledge(int lv)
                    303: {
                    304:        // LUNA は全てオートベクタ
                    305:        return AutoVector;
                    306: }
                    307: 
                    308: void
1.1.1.4   root      309: LunaInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      310: {
                    311:        int y;
                    312:        struct {
                    313:                const char *name;
                    314:                uint32 map;
                    315:        } table[] = {
1.1.1.6 ! root      316:                { "NMI",        IntmapNMI },
1.1       root      317:                { "SIO",        IntmapSIO },
                    318:                { "Clock",      IntmapSysClk },
                    319:                { "Lance",      IntmapLance },
                    320:                { "SPC",        IntmapSPC },
                    321:        };
                    322: 
                    323:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.6 ! root      324:        uint intr_mask = gMPU680x0->GetCPU()->reg.intr_mask;
1.1       root      325: 
1.1.1.4   root      326:        screen.Clear();
1.1       root      327: 
                    328:        y = 0;
1.1.1.6 ! root      329:        screen.Print(0, y++, "Lv Device     Count  IM=%d", intr_mask);
1.1       root      330:        for (int i = 0; i < countof(table); i++) {
                    331:                uint32 map = table[i].map;
                    332:                int clz = __builtin_clz(map);
                    333:                int lv = (31 - clz) / 4;
1.1.1.4   root      334:                screen.Print(0, y, "%d", lv);
                    335:                screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.5   root      336:                screen.Print(8, y, "%11" PRIu64, counter[clz]);
1.1.1.6 ! root      337:                if (lv <= intr_mask) {
1.1.1.5   root      338:                        screen.Puts(21, y, "Mask");
1.1       root      339:                }
                    340:                y++;
                    341:        }
                    342: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.