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

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: 
                     58: 
                     59: //
                     60: // 仮想割り込みコントローラ (m680x0 共通部)
                     61: //
                     62: 
                     63: // CPU コアからの割り込みアクノリッジを受け付けるグローバル関数
                     64: int
                     65: m68030_interrupt_acknowledge(int lv)
                     66: {
                     67:        return gInterrupt->InterruptAcknowledge(lv);
                     68: }
                     69: 
                     70: // コンストラクタ
                     71: M680x0Interrupt::M680x0Interrupt()
                     72: {
                     73: }
                     74: 
                     75: // デストラクタ
                     76: M680x0Interrupt::~M680x0Interrupt()
                     77: {
                     78: }
                     79: 
                     80: // リセット
                     81: void
                     82: M680x0Interrupt::ResetHard()
                     83: {
                     84:        ipl = 0;
                     85:        intmap = 0x00000001;
                     86:        memset(&counter, 0, sizeof(counter));
                     87: }
                     88: 
                     89: // 子デバイスが割り込み信号線をアサートした (m680x0 共通)
                     90: void
                     91: M680x0Interrupt::AssertINT(Device *source)
                     92: {
                     93:        uint32 oldmap;
                     94:        uint32 srcmap;
                     95:        int newipl;
                     96: 
                     97:        oldmap = intmap;
                     98:        srcmap = GetIntmap(source);
                     99:        intmap |= srcmap;
                    100: 
                    101:        if ((oldmap ^ intmap) != 0) {
                    102:                // 立ち上がりエッジでカウント
                    103:                counter[__builtin_clz(srcmap)]++;
                    104:        }
                    105: 
                    106:        newipl = (uint)(31 - __builtin_clz(intmap)) / 4;
                    107: 
                    108:        // アサートによって割り込みレベルが上がったら、新しいレベルを通知
                    109:        // (現在通知中より低い割り込みは受け付けただけでここで保留)
                    110:        if (newipl > ipl) {
                    111:                ipl = newipl;
                    112:                gMPU->Interrupt(ipl);
                    113:        }
                    114: }
                    115: 
1.1.1.3   root      116: // 子デバイスが割り込み信号線をネゲートした (m680x0 共通)
1.1       root      117: void
                    118: M680x0Interrupt::NegateINT(Device *source)
                    119: {
                    120:        int newipl;
                    121: 
                    122:        intmap &= ~GetIntmap(source);
                    123:        // intmap の最下位ビットは常に立ててあり intmap は 0 にならない
                    124:        newipl = (uint)(31 - __builtin_clz(intmap)) / 4;
                    125: 
                    126:        // ネゲートによって割り込みレベルが下がったら、新しいレベルを通知
                    127:        // (以前に保留されていた低いレベルがあればここで見えるようになる)
                    128:        if (newipl < ipl) {
                    129:                ipl = newipl;
                    130:                gMPU->Interrupt(ipl);
                    131:        }
                    132: }
                    133: 
                    134: 
                    135: //
                    136: // X68030 仮想割り込みコントローラ
                    137: //
                    138: 
                    139: // コンストラクタ
                    140: X68030Interrupt::X68030Interrupt()
                    141: {
1.1.1.4 ! root      142:        monitor.func = (MonitorCallback_t)&X68030Interrupt::MonitorUpdate;
        !           143:        monitor.SetSize(24, 11);
        !           144:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      145: }
                    146: 
                    147: // デストラクタ
                    148: X68030Interrupt::~X68030Interrupt()
                    149: {
                    150: }
                    151: 
                    152: // デバイスから Intmap 値を引く
                    153: uint32
                    154: X68030Interrupt::GetIntmap(Device *source) const
                    155: {
                    156:        if (__predict_true(source == gMFP.get())) {
                    157:                return IntmapMFP;
                    158:        }
                    159:        if (__predict_true(source == gSCC.get())) {
                    160:                return IntmapSCC;
                    161:        }
                    162:        if (__predict_true(source == gDMAC.get())) {
                    163:                return IntmapDMAC;
                    164:        }
                    165:        if (__predict_true(source == gPEDEC.get())) {
                    166:                return IntmapPEDEC;
                    167:        }
                    168:        if (source == NULL) {
                    169:                // XXX デバイスまだいないのでとりあえず
                    170:                return IntmapNMI;
                    171:        }
                    172:        PANIC("Unknown interrupt source?");
                    173: }
                    174: 
                    175: // 割り込みアクノリッジに応答する
                    176: int
                    177: X68030Interrupt::InterruptAcknowledge(int lv)
                    178: {
                    179:        switch (lv) {
                    180:         case 6:
                    181:                return gMFP->InterruptAcknowledge();
                    182: 
                    183:         case 5:
                    184:                return gSCC->InterruptAcknowledge();
                    185: 
                    186:         case 3:
                    187:                return gDMAC->InterruptAcknowledge();
                    188: 
                    189:         case 1:
                    190:                return gPEDEC->InterruptAcknowledge(lv);
                    191: 
                    192:         default:
                    193:                break;
                    194:        }
                    195:        PANIC("Unknown interrupt acknowledge lv=%d", lv);
                    196: }
                    197: 
                    198: void
1.1.1.4 ! root      199: X68030Interrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      200: {
                    201:        int y;
                    202:        struct {
                    203:                const char *name;
                    204:                uint32 map;
                    205:        } table[] = {
                    206:                { "NMI",        IntmapNMI },
                    207:                { "MFP",        IntmapMFP },
                    208:                { "SCC",        IntmapSCC },
                    209:                { "DMAC",       IntmapDMAC },
                    210:                { "PEDEC",      IntmapPEDEC },
1.1.1.2   root      211:        }, tablePEDEC[] = {
                    212:                { "SPC",        PEDECDevice::IntmapSPC },
                    213:                { "FDC",        PEDECDevice::IntmapFDC },
                    214:                { "FDD",        PEDECDevice::IntmapFDD },
                    215:                { "HDD",        PEDECDevice::IntmapHDD },
                    216:                { "PRT",        PEDECDevice::IntmapPRT },
1.1       root      217:        };
                    218: 
                    219:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
                    220:        uint intr_level = gMPU680x0->GetCPU()->reg.intr_level;
1.1.1.2   root      221:        // PEDEC 分も一緒に表示したい
                    222:        uint32 pintr = gPEDEC->GetInt();
1.1       root      223: 
1.1.1.4 ! root      224:        screen.Clear();
1.1       root      225: 
                    226:        y = 0;
1.1.1.4 ! root      227:        screen.Print(0, y++, "Lv Device    Count  IM=%d", intr_level);
1.1       root      228:        for (int i = 0; i < countof(table); i++) {
                    229:                uint32 map = table[i].map;
                    230:                int clz = __builtin_clz(map);
                    231:                int lv = (31 - clz) / 4;
1.1.1.4 ! root      232:                screen.Print(0, y, "%d", lv);
        !           233:                screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
        !           234:                screen.Print(8, y, "%10u", counter[clz]);
1.1       root      235:                if (lv <= intr_level) {
1.1.1.4 ! root      236:                        screen.Puts(20, y, "Mask");
1.1       root      237:                }
                    238:                y++;
                    239:        }
1.1.1.2   root      240: 
                    241:        // pintr は下位ワードが割り込み状態、上位ワードが許可状態。
                    242:        uint32 pmask = pintr >> 16;
                    243:        for (int i = 0; i < countof(tablePEDEC); i++) {
                    244:                uint32 map = tablePEDEC[i].map;
1.1.1.4 ! root      245:                screen.Puts(3, y, TA::OnOff(pintr & map), tablePEDEC[i].name);
1.1.1.2   root      246:                // XXX カウンタはまだない
                    247:                if (intr_level >= 1 || (pmask & map) == 0) {
1.1.1.4 ! root      248:                        screen.Puts(20, y, "Mask");
1.1.1.2   root      249:                }
                    250:                y++;
                    251:        }
1.1       root      252: }
                    253: 
                    254: //
                    255: // LUNA-I 仮想割り込みコントローラ
                    256: //
                    257: 
                    258: // コンストラクタ
                    259: LunaInterrupt::LunaInterrupt()
                    260: {
1.1.1.4 ! root      261:        monitor.func = (MonitorCallback_t)&LunaInterrupt::MonitorUpdate;
        !           262:        monitor.SetSize(24, 5);
        !           263:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      264: }
                    265: 
                    266: // デストラクタ
                    267: LunaInterrupt::~LunaInterrupt()
                    268: {
                    269: }
                    270: 
                    271: 
                    272: // デバイスから Intmap 値を引く
                    273: uint32
                    274: LunaInterrupt::GetIntmap(Device *source) const
                    275: {
                    276:        if (__predict_true(source == gSIO.get())) {
                    277:                return IntmapSIO;
                    278:        }
                    279:        if (__predict_true(source == gSysClk.get())) {
                    280:                return IntmapSysClk;
                    281:        }
                    282:        if (__predict_true(source == gEthernet.get())) {
                    283:                return IntmapLance;
                    284:        }
                    285:        if (__predict_true(source == gSPC.get())) {
                    286:                return IntmapSPC;
                    287:        }
                    288:        PANIC("Unknown interrupt source?");
                    289: }
                    290: 
                    291: // 割り込みアクノリッジに応答する
                    292: int
                    293: LunaInterrupt::InterruptAcknowledge(int lv)
                    294: {
                    295:        // LUNA は全てオートベクタ
                    296:        return AutoVector;
                    297: }
                    298: 
                    299: void
1.1.1.4 ! root      300: LunaInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      301: {
                    302:        int y;
                    303:        struct {
                    304:                const char *name;
                    305:                uint32 map;
                    306:        } table[] = {
                    307:                { "SIO",        IntmapSIO },
                    308:                { "Clock",      IntmapSysClk },
                    309:                { "Lance",      IntmapLance },
                    310:                { "SPC",        IntmapSPC },
                    311:        };
                    312: 
                    313:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
                    314:        uint intr_level = gMPU680x0->GetCPU()->reg.intr_level;
                    315: 
1.1.1.4 ! root      316:        screen.Clear();
1.1       root      317: 
                    318:        y = 0;
1.1.1.4 ! root      319:        screen.Print(0, y++, "Lv Device    Count  IM=%d", intr_level);
1.1       root      320:        for (int i = 0; i < countof(table); i++) {
                    321:                uint32 map = table[i].map;
                    322:                int clz = __builtin_clz(map);
                    323:                int lv = (31 - clz) / 4;
1.1.1.4 ! root      324:                screen.Print(0, y, "%d", lv);
        !           325:                screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
        !           326:                screen.Print(8, y, "%10u", counter[clz]);
1.1       root      327:                if (lv <= intr_level) {
1.1.1.4 ! root      328:                        screen.Puts(20, y, "Mask");
1.1       root      329:                }
                    330:                y++;
                    331:        }
                    332: }

unix.superglobalmegacorp.com

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