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

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

unix.superglobalmegacorp.com

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