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

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

unix.superglobalmegacorp.com

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