Annotation of nono/vm/sysctlr.cpp, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.8   root        7: //
1.1.1.10! root        8: // LUNA-88K のシステムコントローラのような何か
1.1.1.8   root        9: //
1.1       root       10: 
1.1.1.8   root       11: // IODevice
                     12: //    |
                     13: //    +-- InterruptDevice (割り込みコントローラの共通部)
                     14: //          |
                     15: //          +-- M680x0Interrupt (m68k 割り込みコントローラの共通部)
                     16: //          |     |
                     17: //          |     +-- X68030Interrupt  (X68030 の割り込みコントローラ)
                     18: //          |     +-- LunaInterrupt    (LUNA-I の割り込みコントローラ)
                     19: //          |
                     20: //          +-- PEDECDevice (X68030 の Lv1 担当コントローラ)
                     21: //          |
                     22: //          |  +---------------+
1.1.1.10! root       23: //          +--| SysCtlrDevice | (LUNA-88K の割り込みコントローラ)
1.1.1.8   root       24: //             +---------------+
1.1       root       25: 
                     26: // この辺を全部一つのデバイスで受け付けておくか。BusIO はまた後で考える。
                     27: // $6500000n.b HW 割り込みレベル (n*4 = CPU#n)
                     28: //   $65000000.b       CPU#0
                     29: //   $65000004.b       CPU#1
                     30: //   $65000008.b       CPU#2
                     31: //   $6500000c.b       CPU#3
                     32: // $6900000n   ソフトウェア割り込み(?)
                     33: // $6d00000n   CPU#n をリセット(?)
                     34: // $6d000010   全 CPU をリセット
                     35: 
1.1.1.10! root       36: // LUNA-88K
1.1       root       37: // 割り込みコントロールレジスタ
                     38: // $6500_000n
                     39: //  n: CPU ID * 4 (0,4,8,c)
                     40: //  この16Mページ内はミラーされている模様。
                     41: //  下位2bitしかデコードしていない?
                     42: // 書き込み時:
                     43: //    3                   2                   1
                     44: //  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
                     45: // +-+-+-+-+-+-+---------------------------------------------------+
                     46: // |6|5|4|3|2|1|                                                   |
                     47: // +-+-+-+-+-+-+---------------------------------------------------+
                     48: // bit31: 1=割り込み 6 イネーブル
                     49: // bit30: 1=割り込み 5 イネーブル
                     50: // bit29: 1=割り込み 4 イネーブル
                     51: // bit28: 1=割り込み 3 イネーブル
                     52: // bit27: 1=割り込み 2 イネーブル
                     53: // bit26: 1=割り込み 1 イネーブル
                     54: // m68k と異なり、個別の割り込みごとに許可/禁止できる。
                     55: // 該当ビットに 1 を書き込むと許可。
                     56: // 空欄部分は無視される模様。
                     57: //
                     58: // 読み込み時
                     59: //    3                   2                   1
                     60: //  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
                     61: // +-----+---------+-+-+-+-+-+-+-----------------------------------+
                     62: // |Level|         |6|5|4|3|2|1|                                   |
                     63: // +-----+---------+-+-+-+-+-+-+-----------------------------------+
                     64: // bit31-29: 発生している最上位レベルの割り込み。範囲は7-0
                     65: // bit23-18: 書き込んだ割り込みマスク。
                     66: // 空欄部分は「不定」の模様。
                     67: //
                     68: // bit31-29 のレベルは、割り込みコントローラに入力
                     69: // されている割り込み信号線6本を、マスク処理した後、
                     70: // プライオリティバイナリエンコーダの値がそのまま出力されている模様。
                     71: // ラッチ機構は無いようだ。
                     72: // したがってマスクされている割り込み(マスクビットが 0) の
                     73: // 値が出力されることはない。
                     74: // 同時に入力があった場合は、数字の大きいほうが出力される。
                     75: // レベル7 はマスクなしでプライオリティエンコーダに入力されているようだ。
                     76: //
                     77: // 割り込み入力がないときは 0 になる模様。
                     78: // 本体 ABRT スイッチを押すと、押している間、すべての CPU の
                     79: // level が 111(=7) になる。離すと戻る。
                     80: // 88100 には NMI が無いので、通常の割り込みと同じように処理している?
                     81: // (なので IND 状態だとABRT できない。いいのかそれで)
                     82: // (OpenBSD6.7 の割り込みハンドラはABRTには対応していないように読める)
                     83: //
                     84: // 想定される回路
                     85: //
                     86: // [割り込みソース]
                     87: //  1:SOFTINT レジスタ $6900000n
                     88: //  |   2:(XP 低レベル?)
                     89: //  |   |   3:SPC
                     90: //  |   |   |   4:(LANCE|拡張スロット?)
                     91: //  |   |   |   |   5:(拡張PC98?|シリアル?)
                     92: //  |   |   |   |   |   6:(XP 高レベル?|システムクロック?)
                     93: //  |   |   |   |   |   |   7:ABRTスイッチ
                     94: //  V   V   V   V   V   V   |
                     95: // +---------------------+  |
                     96: // |   割り込みマスク    |  |  (R:bit23-18, W:bit31-26)
                     97: // +---------------------+  |
                     98: //  |   |   |   |   |   |   |
                     99: //  V   V   V   V   V   V   V
                    100: // +-------------------------+
                    101: // |プライオリティエンコーダ |-> (R:bit31-29)
                    102: // +-------------------------+
1.1.1.3   root      103: //          | | |
                    104: //          V V V
                    105: //        (Wired-OR)
                    106: //            |
                    107: //        [M88K INT]
1.1       root      108: //
1.1.1.3   root      109: // LUNA-I とはレベル配置が違う。
1.1       root      110: //
                    111: // 割り込みソース調査状況
                    112: // 1:SOFTINT レジスタ $6900000n
                    113: //   ROM のメモリコマンドで確認。OpenBSD machdep.c の記述の通り。
                    114: // 2:XP 低レベル
                    115: //   LUNA-I からの類推及び、OpenBSD mainbus.c に記述あり。OpenBSD のほうは
                    116: //   低レベルかどうかは不明。
                    117: // 3:SPC
1.1.1.10! root      118: //   PROM 1.20, OpenBSD ともに使用。
1.1       root      119: // 4:LANCE
                    120: //   ROM はまだ不明。OpenBSD は使用。
                    121: // 4:拡張スロット
                    122: //   LUNA-I からの類推のみ。不明。
                    123: // 5:拡張PC98
1.1.1.10! root      124: //   LUNA-I からの類推のみ。LUNA-88K にはスロットがないようなので、
        !           125: //   LUNA-88K2 が必要。
1.1       root      126: //   OpenBSD mainbus.c に記述あり。
                    127: // 5:シリアル(7201)
                    128: //   OpenBSD mainbus.c に記述。
                    129: // 6:XP 高レベル
                    130: //   LUNA-I からの類推。存在するかどうかも不明。
                    131: //   ただ、これをなくすと XP ファームウェアまで作り直しなので、
                    132: //   なくさないんじゃないかなあ。OMRON ファームで使ってなければ
                    133: //   さっくり廃止されているかもしれない(PSGPAM が使用...レベル1 に
                    134: //   変えればいいだけだが)
                    135: // 6:システムクロック
                    136: //   ROM のメモリコマンドではレベル6割り込みが常時上がっているように観測
                    137: //   できるので、おそらくシステムクロック割り込みが上がっている。
                    138: //   OpenBSD maibus.c にも記述。
                    139: // 7:ABRTスイッチ
                    140: //   ROM のメモリコマンドで確認。
                    141: //
                    142: //
                    143: // SOFTINT レジスタ $6900000n
                    144: //  $69000000: CPU0
                    145: //  $69000004: CPU1
                    146: //  $69000008: CPU2
                    147: //  $6900000c: CPU3
                    148: // 挙動:
                    149: // この32ビットのどこかにライトアクセスすると、INT1 をアサートする。
                    150: // この32ビットのどこかをリードアクセスすると、INT1 をネゲートする。
                    151: // データバスは無視される。
                    152: // 0x00 を書いても、アサートされることに注意。
                    153: // リードアクセスで読み込まれる値も不定のようだ。
                    154: // 要はアドレスバスとR/W信号線しか見ていない。
                    155: 
1.1.1.8   root      156: #include "sysctlr.h"
1.1.1.10! root      157: #include "lance.h"
1.1.1.8   root      158: #include "mpu88xx0.h"
                    159: #include "nmi.h"
                    160: #include "prom.h"
                    161: #include "sio.h"
                    162: #include "spc.h"
                    163: #include "sysclk.h"
1.1       root      164: 
                    165: // コンストラクタ
                    166: SysCtlrDevice::SysCtlrDevice()
1.1.1.10! root      167:        : inherited(OBJ_INTERRUPT)
1.1       root      168: {
1.1.1.10! root      169:        SetName("SystemCtlr");
        !           170:        AddAlias("SystemCtlr");
1.1.1.5   root      171:        AddAlias("SysCtlr");
1.1       root      172: 
1.1.1.8   root      173:        monitor.func = ToMonitorCallback(&SysCtlrDevice::MonitorUpdate);
1.1.1.10! root      174:        monitor.SetSize(40, 12);
1.1.1.5   root      175:        monitor.Regist(ID_MONITOR_INTERRUPT);
1.1       root      176: }
                    177: 
                    178: // デストラクタ
                    179: SysCtlrDevice::~SysCtlrDevice()
                    180: {
                    181: }
                    182: 
1.1.1.10! root      183: // 初期化
        !           184: bool
        !           185: SysCtlrDevice::Init()
        !           186: {
        !           187:        if (inherited::Init() == false) {
        !           188:                return false;
        !           189:        }
        !           190: 
        !           191:        lance = GetLanceDevice();
        !           192:        mpu88xx0 = GetMPU88xx0Device();
        !           193:        nmi = GetNMIDevice();
        !           194:        sio = GetSIODevice();
        !           195:        spc = GetSPCDevice();
        !           196:        sysclk = GetSysClkDevice();
        !           197: 
        !           198:        return true;
        !           199: }
        !           200: 
1.1.1.8   root      201: // リセット
1.1.1.3   root      202: void
1.1.1.8   root      203: SysCtlrDevice::ResetHard(bool poweron)
1.1.1.3   root      204: {
                    205:        // さすがにリセットくらいはされるだろう…
1.1.1.8   root      206:        inherited::ResetHard(poweron);
1.1.1.7   root      207: 
1.1.1.3   root      208:        for (int i = 0; i < 4; i++) {
                    209:                // XXX 初期値は分からないがとりあえず割り込み禁止にしておく
                    210:                cpu[i].maskval = 0xfc000000;
                    211:                cpu[i].intmask = MakeIntMask(cpu[i].maskval, i);
                    212:                cpu[i].ipl = 0;
                    213:        }
                    214: }
                    215: 
1.1       root      216: uint64
                    217: SysCtlrDevice::Read32(uint32 addr)
                    218: {
1.1.1.3   root      219:        int n = (addr >> 2) & 3;
1.1       root      220: 
                    221:        if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3   root      222:                // bit31-29 に発生している最上位の割り込みレベル
                    223:                // bit23-18 に設定したレベル 6-1 の割り込みマスク
                    224:                uint32 data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8);
1.1       root      225:                putlog(2, "割り込み保持読み出し(CPU#%d) -> $%08x", n, data);
                    226:                return data;
                    227:        }
                    228: 
                    229:        if (0x69000000 <= addr && addr < 0x69000010) {
1.1.1.3   root      230:                // 読み出しで SOFTINT ネゲート (値は関係ない)
                    231:                putlog(1, "Softint(CPU#%d) Negate", n);
                    232:                intmap &= ~(IntmapSoft0 << n);
                    233:                ChangeInterrupt();
1.1       root      234:                return 0xffffffff;
                    235:        }
                    236: 
                    237:        if (0x6d000000 <= addr && addr < 0x6d000010) {
1.1.1.9   root      238:                putlog(0, "Read CPU%d reset (NOT IMPLEMENTED)", n);
1.1       root      239:                return 0xffffffff;
                    240:        }
                    241:        if (addr == 0x6d000010) {
1.1.1.9   root      242:                putlog(0, "Read All CPU reset (NOT IMPLEMENTED)");
1.1       root      243:                return 0xffffffff;
                    244:        }
                    245: 
1.1.1.9   root      246:        putlog(0, "Read $%08x (NOT IMPLEMENTED)", addr);
1.1       root      247:        return 0xffffffff;
                    248: }
                    249: 
                    250: uint64
                    251: SysCtlrDevice::Write32(uint32 addr, uint32 data)
                    252: {
                    253:        int n = (addr & 15) >> 2;
                    254: 
                    255:        if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3   root      256:                data &= 0xfc000000;
                    257:                // 割り込みレベル変えるたびに表示されるのですごく多い。
                    258:                // さらに同レベルが書き込まれることも多い…。
                    259:                if (cpu[n].maskval != data) {
1.1.1.9   root      260:                        putlog(2, "Interrupt Mask(CPU#%d) <- $%08x", n, data);
1.1.1.3   root      261:                } else {
1.1.1.9   root      262:                        putlog(3, "Interrupt Mask(CPU#%d) <- $%08x", n, data);
1.1.1.3   root      263:                }
1.1       root      264: 
1.1.1.3   root      265:                // 設定値を保存
                    266:                cpu[n].maskval = data;
                    267:                // 内部マスクを書き換えて割り込み状態を更新
                    268:                cpu[n].intmask = MakeIntMask(data, n);
                    269:                ChangeInterrupt();
1.1       root      270:                return 0;
                    271:        }
                    272:        if (0x69000000 <= addr && addr < 0x69000010) {
1.1.1.3   root      273:                // 書き込みで SOFTINT アサート (値は関係ない)
                    274:                putlog(1, "Softint(CPU#%d) Assert 0x%x", n, data);
                    275:                counter[__builtin_clz(intmap)]++;
                    276:                intmap |= IntmapSoft0 << n;
                    277:                ChangeInterrupt();
1.1       root      278:                return 0;
                    279:        }
                    280:        if (0x6d000000 <= addr && addr < 0x6d000010) {
1.1.1.9   root      281:                putlog(0, "Write CPU%d reset (NOT IMPLEMENTED)", n);
1.1       root      282:                return 0;
                    283:        }
                    284:        if (addr == 0x6d000010) {
1.1.1.4   root      285:                putlog(1, "Reset All CPUs");
1.1.1.8   root      286:                // XXX このあたりもう少し整理する必要がある
                    287:                // 今は MPU.ResetHard() が func を ResetCallback に、time をリセット
                    288:                // 間隔に書き換えて Start() した後、この書き込み命令から戻ったところの
                    289:                // ExecCallback が time だけ所要サイクルに書き換えて再度 Start() する
                    290:                // ため、時間はともかく幸い ResetCallback() が呼ばれることで動いている。
1.1.1.10! root      291:                GetPROM0Device()->ResetHard(false);
        !           292:                mpu->ResetHard(false);
1.1.1.8   root      293:                ResetHard(false);
1.1       root      294:                return 0;
                    295:        }
                    296: 
1.1.1.9   root      297:        putlog(0, "Write $%08x <- $%08x (NOT IMPLEMENTED)", addr, data);
1.1       root      298:        return 0;
                    299: }
                    300: 
                    301: uint64
                    302: SysCtlrDevice::Peek8(uint32 addr)
                    303: {
1.1.1.3   root      304:        int n = (addr >> 2) & 3;
1.1       root      305:        uint32 data;
                    306: 
                    307:        if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3   root      308:                data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8);
1.1       root      309:        } else {
                    310:                data = 0xffffffff;
                    311:        }
                    312:        switch (addr & 3) {
                    313:         case 0:
                    314:                return data >> 24;
                    315:         case 1:
                    316:                return (data >> 16) & 0xff;
                    317:         case 2:
                    318:                return (data >>  8) & 0xff;
                    319:         case 3:
                    320:                return data & 0xff;
                    321:         default:
1.1.1.10! root      322:                __unreachable();
1.1       root      323:        }
                    324: }
                    325: 
1.1.1.2   root      326: void
1.1.1.5   root      327: SysCtlrDevice::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      328: {
1.1.1.3   root      329:        int y;
                    330:        struct {
                    331:                const char *name;
                    332:                uint32 map;
                    333:        } table[] = {
                    334:                { "NMI",        IntmapNMI },
                    335:                { "Clock",      IntmapSysClk },
1.1.1.10! root      336:                { "XP(Hi)",     IntmapXPHigh },
1.1.1.3   root      337:                { "SIO",        IntmapSIO },
                    338:                { "Lance",      IntmapLance },
                    339:                { "SPC",        IntmapSPC },
1.1.1.10! root      340:                { "XP(Lo)",     IntmapXPLow },
1.1.1.3   root      341:                { "Soft#0",     IntmapSoft0 },
                    342:                { "Soft#1",     IntmapSoft1 },
                    343:                { "Soft#2",     IntmapSoft2 },
                    344:                { "Soft#3",     IntmapSoft3 },
                    345:        };
                    346: 
                    347:        // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.10! root      348:        bool ei = mpu88xx0->IsIntrEnable();
1.1.1.3   root      349: 
1.1.1.5   root      350:        screen.Clear();
1.1.1.10! root      351: 
        !           352:        // 0         1         2         3         4
        !           353:        // 01234567890123456789012345678901234567890
        !           354:        // Lv Device CPU0                     Count
        !           355: 
1.1.1.3   root      356:        y = 0;
1.1.1.10! root      357:        // XXX CPU の実装数によってウィンドウ幅を変えること。
        !           358:        screen.Print(0, y, "Lv Device CPU0");
        !           359:        screen.Puts(35, y, "Count");
        !           360:        y++;
1.1.1.3   root      361:        for (int i = 0; i < countof(table); i++) {
                    362:                uint32 map = table[i].map;
                    363:                int clz = __builtin_clz(map);
                    364:                int lv = (31 - clz) / 4;
1.1.1.5   root      365:                screen.Print(0, y, "%d", lv);
1.1.1.10! root      366:                screen.Print(3, y, TA::OnOff(intmap & map), "%s", table[i].name);
        !           367:                screen.Print(14, y, "%26s", format_number(counter[clz]).c_str());
1.1.1.3   root      368: 
                    369:                // CPU ごとのマスク
                    370:                // XXX 今は CPU は1つしかない
                    371:                for (int n = 0; n < 1; n++) {
                    372:                        // Softint の他 CPU 分は
                    373:                        // 動作としては常にマスクされてて通過しないから問題ないが、
                    374:                        // 見せる分にはマスクされているではなく無効と見せたほうがいい。
                    375:                        if (lv == 1 && map != (IntmapSoft0 << n)) {
1.1.1.10! root      376:                                screen.Puts(10 + n * 5, y, "----");
1.1.1.3   root      377:                        } else if ((cpu[n].intmask & map) == 0) {
1.1.1.10! root      378:                                screen.Puts(10 + n * 5, y, "Mask");
1.1.1.3   root      379:                        } else if (!ei) {
1.1.1.10! root      380:                                screen.Puts(10 + n * 5, y, "IND");
1.1.1.3   root      381:                        }
                    382:                }
                    383: 
                    384:                y++;
                    385:        }
                    386: }
                    387: 
                    388: // デバイスから Intmap 値を引く
                    389: uint32
                    390: SysCtlrDevice::GetIntmap(Device *source) const
                    391: {
1.1.1.10! root      392:        if (__predict_true(source == sysclk)) {
1.1.1.3   root      393:                return IntmapSysClk;
                    394:        }
1.1.1.10! root      395:        if (__predict_true(source == sio)) {
1.1.1.3   root      396:                return IntmapSIO;
                    397:        }
1.1.1.10! root      398:        if (__predict_true(source == lance)) {
1.1.1.3   root      399:                return IntmapLance;
                    400:        }
1.1.1.10! root      401:        if (__predict_true(source == spc)) {
1.1.1.3   root      402:                return IntmapSPC;
                    403:        }
1.1.1.10! root      404:        if (__predict_true(source == DEVICE_XPINT_HIGH)) {
        !           405:                return IntmapXPHigh;
        !           406:        }
        !           407:        if (__predict_true(source == DEVICE_XPINT_LOW)) {
        !           408:                return IntmapXPLow;
        !           409:        }
        !           410:        if (source == nmi) {
1.1.1.8   root      411:                return IntmapNMI;
                    412:        }
1.1.1.3   root      413:        PANIC("Unknown interrupt source?");
                    414: }
                    415: 
                    416: // 割り込みアクノリッジはない
                    417: int
                    418: SysCtlrDevice::InterruptAcknowledge(int lv)
                    419: {
                    420:        return 0;
                    421: }
                    422: 
                    423: // 割り込み状態を更新
                    424: void
                    425: SysCtlrDevice::ChangeInterrupt()
                    426: {
                    427:        // XXX MPU 側がまだマルチプロセッサに対応してないので CPU#0 だけ
                    428:        for (int i = 0; i < 1; i++) {
                    429:                uint32 localmap = intmap & cpu[i].intmask;
                    430: 
                    431:                // intmap の最下位ビットは常に立ててあり localmap は 0 にならない
                    432:                int newipl = (uint)(31 - __builtin_clz(localmap)) / 4;
                    433: 
1.1.1.7   root      434:                // 割り込みレベルが変わったら、新しいレベルを通知
1.1.1.3   root      435:                if (newipl != cpu[i].ipl) {
                    436:                        cpu[i].ipl = newipl;
                    437:                        // MPU 側は 1 レベルしかない
1.1.1.10! root      438:                        mpu->Interrupt(cpu[i].ipl ? 1 : 0);
1.1.1.3   root      439:                }
1.1       root      440:        }
                    441: }
1.1.1.3   root      442: 
                    443: // 割り込みマスク設定レジスタの書き込み値から内部用のマスクを作成
                    444: // data は bit31-26 のみ使用。他のビットは不問。
                    445: // n は CPU# (Softint 用)。
                    446: /*static*/ uint32
                    447: SysCtlrDevice::MakeIntMask(uint32 data, int n)
                    448: {
                    449:        uint32 val = 0xf0000001;        // Lv7 は NMI、最下位は番兵用
                    450: 
                    451:        uint32 mask = 0x0f000000;
                    452:        for (int i = 6; i >= 1; i--) {
                    453:                if ((int32)data < 0) {
                    454:                        val |= mask;
                    455:                }
                    456:                mask >>= 4;
                    457:                data <<= 1;
                    458:        }
                    459: 
                    460:        // Softint は他 CPU 分のビットを下ろす
                    461:        val &= (0xffffff0f | (IntmapSoft0 << n));
                    462: 
                    463:        return val;
                    464: }

unix.superglobalmegacorp.com

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