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

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

unix.superglobalmegacorp.com

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