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

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

unix.superglobalmegacorp.com

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