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

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 担当コントローラ)
1.1.1.7   root       29: //          +-- SysCtlrDevice (LUNA-88K の割り込みコントローラ)
1.1.1.6   root       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.7   root       38: #include "newsctlr.h"
1.1.1.6   root       39: #include "nmi.h"
1.1.1.8 ! root       40: #include "rtl8019as.h"
1.1       root       41: #include "scc.h"
                     42: #include "sio.h"
                     43: #include "spc.h"
                     44: #include "sysclk.h"
                     45: 
                     46: //
                     47: // 仮想割り込みコントローラ (共通部)
                     48: //
                     49: 
1.1.1.7   root       50: // コンストラクタ(オブジェクト名指定なし)
                     51: InterruptDevice::InterruptDevice()
                     52:        : InterruptDevice(OBJ_INTERRUPT)        // 移譲
1.1.1.4   root       53: {
                     54: }
                     55: 
1.1.1.7   root       56: // コンストラクタ(オブジェクト名指定あり)
                     57: InterruptDevice::InterruptDevice(int objid_)
                     58:        : inherited(objid_)
1.1       root       59: {
                     60: }
                     61: 
                     62: // デストラクタ
                     63: InterruptDevice::~InterruptDevice()
                     64: {
                     65: }
                     66: 
1.1.1.5   root       67: // リセット
                     68: void
1.1.1.6   root       69: InterruptDevice::ResetHard(bool poweron)
1.1.1.5   root       70: {
                     71:        intmap = IntmapSentinel;
                     72:        memset(&counter, 0, sizeof(counter));
                     73: }
                     74: 
                     75: // 子デバイスが割り込み信号線をアサートした
                     76: void
                     77: InterruptDevice::AssertINT(Device *source)
                     78: {
                     79:        uint32 oldmap;
                     80:        uint32 srcmap;
                     81: 
                     82:        oldmap = intmap;
                     83:        srcmap = GetIntmap(source);
                     84:        intmap |= srcmap;
                     85: 
                     86:        if ((oldmap ^ intmap) != 0) {
                     87:                // 立ち上がりエッジでカウント
                     88:                counter[__builtin_clz(srcmap)]++;
                     89:                ChangeInterrupt();
                     90:        }
                     91: }
                     92: 
                     93: // 子デバイスが割り込み信号線をネゲートした
                     94: void
                     95: InterruptDevice::NegateINT(Device *source)
                     96: {
                     97:        uint32 oldmap;
                     98:        uint32 srcmap;
                     99: 
                    100:        oldmap = intmap;
                    101:        srcmap = GetIntmap(source);
                    102:        intmap &= ~srcmap;
                    103: 
                    104:        if ((oldmap ^ intmap) != 0) {
                    105:                ChangeInterrupt();
                    106:        }
                    107: }
1.1       root      108: 
1.1.1.8 ! root      109: // 割り込み信号線の状態を取得
        !           110: bool
        !           111: InterruptDevice::GetINT(const Device *source) const
        !           112: {
        !           113:        uint32 srcmap;
        !           114: 
        !           115:        srcmap = GetIntmap(source);
        !           116: 
        !           117:        return (intmap & srcmap);
        !           118: }
        !           119: 
        !           120: 
1.1       root      121: //
                    122: // 仮想割り込みコントローラ (m680x0 共通部)
                    123: //
                    124: 
                    125: // コンストラクタ
                    126: M680x0Interrupt::M680x0Interrupt()
                    127: {
                    128: }
                    129: 
                    130: // デストラクタ
                    131: M680x0Interrupt::~M680x0Interrupt()
                    132: {
                    133: }
                    134: 
1.1.1.7   root      135: // 初期化
                    136: bool
                    137: M680x0Interrupt::Init()
                    138: {
                    139:        if (inherited::Init() == false) {
                    140:                return false;
                    141:        }
                    142: 
                    143:        return true;
                    144: }
                    145: 
1.1       root      146: // リセット
                    147: void
1.1.1.6   root      148: M680x0Interrupt::ResetHard(bool poweron)
1.1       root      149: {
1.1.1.6   root      150:        inherited::ResetHard(poweron);
1.1       root      151:        ipl = 0;
                    152: }
                    153: 
                    154: void
1.1.1.5   root      155: M680x0Interrupt::ChangeInterrupt()
1.1       root      156: {
                    157:        int newipl;
                    158: 
1.1.1.6   root      159:        // intmap は最下位ビットを常に立ててあるので 0 にならない
1.1       root      160:        newipl = (uint)(31 - __builtin_clz(intmap)) / 4;
                    161: 
1.1.1.5   root      162:        // 割り込みレベルが変わったら、新しいレベルを通知
                    163:        if (newipl != ipl) {
1.1       root      164:                ipl = newipl;
1.1.1.7   root      165:                mpu->Interrupt(ipl);
1.1       root      166:        }
                    167: }
                    168: 
                    169: 
                    170: //
                    171: // X68030 仮想割り込みコントローラ
                    172: //
                    173: 
                    174: // コンストラクタ
                    175: X68030Interrupt::X68030Interrupt()
                    176: {
1.1.1.6   root      177:        monitor.func = ToMonitorCallback(&X68030Interrupt::MonitorUpdate);
1.1.1.8 ! root      178:        monitor.SetSize(41, 13);
1.1.1.4   root      179:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      180: }
                    181: 
                    182: // デストラクタ
                    183: X68030Interrupt::~X68030Interrupt()
                    184: {
                    185: }
                    186: 
1.1.1.7   root      187: // 初期化
                    188: bool
                    189: X68030Interrupt::Init()
                    190: {
                    191:        if (inherited::Init() == false) {
                    192:                return false;
                    193:        }
                    194: 
                    195:        dmac = GetDMACDevice();
                    196:        mfp = GetMFPDevice();
1.1.1.8 ! root      197:        // Nereid は拡張ボードなので存在しない可能性がある
        !           198:        for (int i = 0; i < 2; i++) {
        !           199:                net[i] = gMainApp.FindObject<RTL8019ASDevice>(OBJ_ETHERNET(i));
        !           200:        }
1.1.1.7   root      201:        nmi = GetNMIDevice();
                    202:        pedec = GetPEDECDevice();
                    203:        scc = GetSCCDevice();
                    204: 
                    205:        return true;
                    206: }
                    207: 
1.1       root      208: // デバイスから Intmap 値を引く
                    209: uint32
1.1.1.8 ! root      210: X68030Interrupt::GetIntmap(const Device *source) const
1.1       root      211: {
1.1.1.7   root      212:        if (__predict_true(source == mfp)) {
1.1       root      213:                return IntmapMFP;
                    214:        }
1.1.1.7   root      215:        if (__predict_true(source == scc)) {
1.1       root      216:                return IntmapSCC;
                    217:        }
1.1.1.8 ! root      218:        if (__predict_true(source == net[0])) {
        !           219:                return IntmapNereid0;
        !           220:        }
        !           221:        if (__predict_true(source == net[1])) {
        !           222:                return IntmapNereid1;
        !           223:        }
1.1.1.7   root      224:        if (__predict_true(source == dmac)) {
1.1       root      225:                return IntmapDMAC;
                    226:        }
1.1.1.7   root      227:        if (__predict_true(source == pedec)) {
1.1       root      228:                return IntmapPEDEC;
                    229:        }
1.1.1.7   root      230:        if (source == nmi) {
1.1       root      231:                return IntmapNMI;
                    232:        }
1.1.1.6   root      233:        VMPANIC("Unknown interrupt source?");
1.1       root      234: }
                    235: 
                    236: // 割り込みアクノリッジに応答する
                    237: int
                    238: X68030Interrupt::InterruptAcknowledge(int lv)
                    239: {
                    240:        switch (lv) {
1.1.1.6   root      241:         case 7:
                    242:                return AutoVector;
                    243: 
1.1       root      244:         case 6:
1.1.1.7   root      245:                return mfp->InterruptAcknowledge();
1.1       root      246: 
                    247:         case 5:
1.1.1.7   root      248:                return scc->InterruptAcknowledge();
1.1       root      249: 
1.1.1.8 ! root      250:         case 4:
        !           251:                for (int i = 0; i < 2; i++) {
        !           252:                        if (net[i]) {
        !           253:                                return net[i]->InterruptAcknowledge();
        !           254:                        }
        !           255:                }
        !           256:                break;
        !           257: 
1.1       root      258:         case 3:
1.1.1.7   root      259:                return dmac->InterruptAcknowledge();
1.1       root      260: 
                    261:         case 1:
1.1.1.7   root      262:                return pedec->InterruptAcknowledge(lv);
1.1       root      263: 
                    264:         default:
                    265:                break;
                    266:        }
1.1.1.6   root      267:        VMPANIC("Unknown interrupt acknowledge lv=%d", lv);
1.1       root      268: }
                    269: 
                    270: void
1.1.1.4   root      271: X68030Interrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      272: {
                    273:        int y;
                    274:        struct {
                    275:                const char *name;
                    276:                uint32 map;
                    277:        } table[] = {
1.1.1.8 ! root      278:                { "NMI",                IntmapNMI },
        !           279:                { "MFP",                IntmapMFP },
        !           280:                { "SCC",                IntmapSCC },
        !           281:                { "Nereid0",    IntmapNereid0 },
        !           282:                { "Nereid1",    IntmapNereid1 },
        !           283:                { "DMAC",               IntmapDMAC },
        !           284:                { "PEDEC",              IntmapPEDEC },
1.1       root      285:        };
                    286: 
                    287:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.7   root      288:        auto mpu680x0 = dynamic_cast<MPU680x0Device*>(mpu);
                    289:        uint intr_mask = mpu680x0->reg.intr_mask;
1.1       root      290: 
1.1.1.4   root      291:        screen.Clear();
1.1       root      292: 
1.1.1.7   root      293:        // 0         1         2         3         4
                    294:        // 01234567890123456789012345678901234567890
1.1.1.8 ! root      295:        // Lv Device  IM=7                     Count
        !           296:        // 1  Nereid0     01234567890123456789012345
        !           297:        //     SPC    Mask
1.1.1.7   root      298: 
1.1       root      299:        y = 0;
1.1.1.8 ! root      300:        screen.Print(0, y, "Lv Device  IM=%d", intr_mask);
        !           301:        screen.Puts(36, y, "Count");
1.1.1.7   root      302:        y++;
1.1       root      303:        for (int i = 0; i < countof(table); i++) {
                    304:                uint32 map = table[i].map;
                    305:                int clz = __builtin_clz(map);
                    306:                int lv = (31 - clz) / 4;
1.1.1.4   root      307:                screen.Print(0, y, "%d", lv);
1.1.1.8 ! root      308:                if ((map == IntmapNereid0 && net[0] == NULL) ||
        !           309:                    (map == IntmapNereid1 && net[1] == NULL))
        !           310:                {
        !           311:                        screen.Puts(3, y, TA::Disable, table[i].name);
        !           312:                } else {
        !           313:                        screen.Puts(3, y, TA::OnOff(intmap & map), table[i].name);
        !           314:                }
1.1.1.6   root      315:                if (lv <= intr_mask) {
1.1.1.8 ! root      316:                        screen.Puts(11, y, "Mask");
1.1       root      317:                }
1.1.1.8 ! root      318:                screen.Print(15, y, "%26s", format_number(counter[clz]).c_str());
1.1       root      319:                y++;
                    320:        }
1.1.1.2   root      321: 
1.1.1.5   root      322:        // PEDEC 分も一緒に表示したい
1.1.1.7   root      323:        pedec->MonitorUpdate(screen, intr_mask, y);
1.1       root      324: }
                    325: 
1.1.1.6   root      326: 
1.1       root      327: //
                    328: // LUNA-I 仮想割り込みコントローラ
                    329: //
                    330: 
                    331: // コンストラクタ
                    332: LunaInterrupt::LunaInterrupt()
                    333: {
1.1.1.6   root      334:        monitor.func = ToMonitorCallback(&LunaInterrupt::MonitorUpdate);
1.1.1.7   root      335:        monitor.SetSize(40, 8);
1.1.1.4   root      336:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      337: }
                    338: 
                    339: // デストラクタ
                    340: LunaInterrupt::~LunaInterrupt()
                    341: {
                    342: }
                    343: 
1.1.1.7   root      344: // 初期化
                    345: bool
                    346: LunaInterrupt::Init()
                    347: {
                    348:        if (inherited::Init() == false) {
                    349:                return false;
                    350:        }
                    351: 
                    352:        lance = GetLanceDevice();
                    353:        nmi = GetNMIDevice();
                    354:        sio = GetSIODevice();
                    355:        spc = GetSPCDevice();
                    356:        sysclk = GetSysClkDevice();
                    357: 
                    358:        return true;
                    359: }
                    360: 
1.1       root      361: // デバイスから Intmap 値を引く
                    362: uint32
1.1.1.8 ! root      363: LunaInterrupt::GetIntmap(const Device *source) const
1.1       root      364: {
1.1.1.7   root      365:        if (__predict_true(source == sio)) {
1.1       root      366:                return IntmapSIO;
                    367:        }
1.1.1.7   root      368:        if (__predict_true(source == sysclk)) {
1.1       root      369:                return IntmapSysClk;
                    370:        }
1.1.1.7   root      371:        if (__predict_true(source == lance)) {
1.1       root      372:                return IntmapLance;
                    373:        }
1.1.1.7   root      374:        if (__predict_true(source == spc)) {
1.1       root      375:                return IntmapSPC;
                    376:        }
1.1.1.7   root      377:        if (__predict_true(source == DEVICE_XPINT_HIGH)) {
                    378:                return IntmapXPHigh;
                    379:        }
                    380:        if (__predict_true(source == DEVICE_XPINT_LOW)) {
                    381:                return IntmapXPLow;
                    382:        }
                    383:        if (source == nmi) {
1.1.1.6   root      384:                return IntmapNMI;
                    385:        }
                    386:        VMPANIC("Unknown interrupt source?");
1.1       root      387: }
                    388: 
                    389: // 割り込みアクノリッジに応答する
                    390: int
                    391: LunaInterrupt::InterruptAcknowledge(int lv)
                    392: {
                    393:        // LUNA は全てオートベクタ
                    394:        return AutoVector;
                    395: }
                    396: 
                    397: void
1.1.1.4   root      398: LunaInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      399: {
                    400:        int y;
                    401:        struct {
                    402:                const char *name;
                    403:                uint32 map;
                    404:        } table[] = {
1.1.1.6   root      405:                { "NMI",        IntmapNMI },
1.1       root      406:                { "SIO",        IntmapSIO },
                    407:                { "Clock",      IntmapSysClk },
1.1.1.7   root      408:                { "XP(Hi)",     IntmapXPHigh },
1.1       root      409:                { "Lance",      IntmapLance },
                    410:                { "SPC",        IntmapSPC },
1.1.1.7   root      411:                { "XP(Lo)",     IntmapXPLow },
                    412:        };
                    413: 
                    414:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
                    415:        auto mpu680x0 = dynamic_cast<MPU680x0Device*>(mpu);
                    416:        uint intr_mask = mpu680x0->reg.intr_mask;
                    417: 
                    418:        screen.Clear();
                    419: 
                    420:        // 0         1         2         3         4
                    421:        // 01234567890123456789012345678901234567890
                    422:        // Lv Device IM=7                     Count
                    423:        // 1  XP(Hi) Mask01234567890123456789012345
                    424: 
                    425:        y = 0;
                    426:        screen.Print(0, y, "Lv Device IM=%d", intr_mask);
                    427:        screen.Puts(35, y, "Count");
                    428:        y++;
                    429:        for (int i = 0; i < countof(table); i++) {
                    430:                uint32 map = table[i].map;
                    431:                int clz = __builtin_clz(map);
                    432:                int lv = (31 - clz) / 4;
                    433:                screen.Print(0, y, "%d", lv);
                    434:                screen.Print(3, y, TA::OnOff(intmap & map), "%s", table[i].name);
                    435:                if (lv <= intr_mask) {
                    436:                        screen.Puts(10, y, "Mask");
                    437:                }
                    438:                screen.Print(14, y, "%26s", format_number(counter[clz]).c_str());
                    439:                y++;
                    440:        }
                    441: }
                    442: 
                    443: 
                    444: //
                    445: // NEWS 仮想割り込みコントローラ
                    446: //
                    447: 
                    448: // コンストラクタ
                    449: NewsInterrupt::NewsInterrupt()
                    450: {
                    451:        monitor.func = ToMonitorCallback(&NewsInterrupt::MonitorUpdate);
                    452:        monitor.SetSize(40, 5);
                    453:        monitor.Regist(ID_MONITOR_INTERRUPT);
                    454: }
                    455: 
                    456: // デストラクタ
                    457: NewsInterrupt::~NewsInterrupt()
                    458: {
                    459: }
                    460: 
                    461: // 初期化
                    462: bool
                    463: NewsInterrupt::Init()
                    464: {
                    465:        if (inherited::Init() == false) {
                    466:                return false;
                    467:        }
                    468: 
                    469:        lance = GetLanceDevice();
                    470:        newsctlr = GetNewsCtlrDevice();
                    471:        scc = GetSCCDevice();
                    472: 
                    473:        return true;
                    474: }
                    475: 
                    476: // デバイスから Intmap 値を引く
                    477: uint32
1.1.1.8 ! root      478: NewsInterrupt::GetIntmap(const Device *source) const
1.1.1.7   root      479: {
                    480:        if (__predict_true(source == newsctlr)) {
                    481:                return IntmapTimer;
                    482:        }
                    483:        if (__predict_true(source == scc)) {
                    484:                return IntmapSCC;
                    485:        }
                    486:        if (__predict_true(source == lance)) {
                    487:                return IntmapLance;
                    488:        }
                    489:        VMPANIC("Unknown interrupt source?");
                    490: }
                    491: 
                    492: // 割り込みアクノリッジに応答する
                    493: int
                    494: NewsInterrupt::InterruptAcknowledge(int lv)
                    495: {
                    496:        // NEWS では 5 の SCC だけベクタで、他はオートベクタ?
                    497:        switch (lv) {
                    498:         case 5:
                    499:                return scc->InterruptAcknowledge();
                    500: 
                    501:         default:
                    502:                return AutoVector;
                    503:        }
                    504: }
                    505: 
                    506: // ステータスバイトを読み出す。NewsCtlr から呼ばれる。
                    507: uint8
                    508: NewsInterrupt::PeekStatus() const
                    509: {
                    510:        uint8 data = 0;
                    511: 
                    512:        if ((intmap & IntmapSIC)) {
                    513:                data |= 0x80;
                    514:        }
                    515:        if ((intmap & IntmapLance)) {
                    516:                data |= 0x04;
                    517:        }
                    518: 
                    519:        return data;
                    520: }
                    521: 
                    522: void
                    523: NewsInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
                    524: {
                    525:        int y;
                    526:        struct {
                    527:                const char *name;
                    528:                uint32 map;
                    529:        } table[] = {
                    530:                { "Timer",      IntmapTimer },
                    531:                { "SCC",        IntmapSCC },
                    532:                { "Lance",      IntmapLance },
1.1       root      533:        };
                    534: 
                    535:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.7   root      536:        auto mpu680x0 = dynamic_cast<MPU680x0Device*>(mpu);
                    537:        uint intr_mask = mpu680x0->reg.intr_mask;
1.1       root      538: 
1.1.1.4   root      539:        screen.Clear();
1.1       root      540: 
1.1.1.7   root      541:        // 0         1         2         3         4
                    542:        // 01234567890123456789012345678901234567890
                    543:        // Lv Device IM=7                     Count
                    544:        // 1  XP(Hi) Mask01234567890123456789012345
                    545: 
1.1       root      546:        y = 0;
1.1.1.7   root      547:        screen.Print(0, y, "Lv Device IM=%d", intr_mask);
                    548:        screen.Puts(35, y, "Count");
                    549:        y++;
1.1       root      550:        for (int i = 0; i < countof(table); i++) {
                    551:                uint32 map = table[i].map;
                    552:                int clz = __builtin_clz(map);
                    553:                int lv = (31 - clz) / 4;
1.1.1.4   root      554:                screen.Print(0, y, "%d", lv);
1.1.1.7   root      555:                screen.Print(3, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.6   root      556:                if (lv <= intr_mask) {
1.1.1.7   root      557:                        screen.Puts(10, y, "Mask");
1.1       root      558:                }
1.1.1.7   root      559:                screen.Print(14, y, "%26s", format_number(counter[clz]).c_str());
1.1       root      560:                y++;
                    561:        }
                    562: }

unix.superglobalmegacorp.com

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