--- nono/vm/sysctlr.cpp 2026/04/29 17:05:14 1.1.1.9 +++ nono/vm/sysctlr.cpp 2026/04/29 17:05:24 1.1.1.12 @@ -5,7 +5,7 @@ // // -// LUNA88K のシステムコントローラのような何か +// LUNA-88K のシステムコントローラのような何か // // IODevice @@ -20,7 +20,7 @@ // +-- PEDECDevice (X68030 の Lv1 担当コントローラ) // | // | +---------------+ -// +--| SysCtlrDevice | (LUNA88K の割り込みコントローラ) +// +--| SysCtlrDevice | (LUNA-88K の割り込みコントローラ) // +---------------+ // この辺を全部一つのデバイスで受け付けておくか。BusIO はまた後で考える。 @@ -33,7 +33,7 @@ // $6d00000n CPU#n をリセット(?) // $6d000010 全 CPU をリセット -// LUNA88K +// LUNA-88K // 割り込みコントロールレジスタ // $6500_000n // n: CPU ID * 4 (0,4,8,c) @@ -84,12 +84,12 @@ // 想定される回路 // // [割り込みソース] -// 1:SOFTINT レジスタ $6900000n -// | 2:(XP 低レベル?) +// 1:(XP低レベル|SOFTINT レジスタ $6900000n) +// | 2: // | | 3:SPC // | | | 4:(LANCE|拡張スロット?) -// | | | | 5:(拡張PC98?|シリアル?) -// | | | | | 6:(XP 高レベル?|システムクロック?) +// | | | | 5:(XP高レベル|拡張PC98?|シリアル?) +// | | | | | 6:システムクロック // | | | | | | 7:ABRTスイッチ // V V V V V V | // +---------------------+ | @@ -111,27 +111,22 @@ // 割り込みソース調査状況 // 1:SOFTINT レジスタ $6900000n // ROM のメモリコマンドで確認。OpenBSD machdep.c の記述の通り。 -// 2:XP 低レベル -// LUNA-I からの類推及び、OpenBSD mainbus.c に記述あり。OpenBSD のほうは -// 低レベルかどうかは不明。 +// 1:XP 低レベル +// OpenBSD mainbus.c および Issue#131 より。 // 3:SPC -// ROM1.2, OpenBSD ともに使用。 +// PROM 1.20, OpenBSD ともに使用。 // 4:LANCE // ROM はまだ不明。OpenBSD は使用。 // 4:拡張スロット // LUNA-I からの類推のみ。不明。 // 5:拡張PC98 -// LUNA-I からの類推のみ。LUNA88K にはスロットがないようなので、 -// LUNA88K2 が必要。 +// LUNA-I からの類推のみ。LUNA-88K にはスロットがないようなので、 +// LUNA-88K2 が必要。 // OpenBSD mainbus.c に記述あり。 // 5:シリアル(7201) // OpenBSD mainbus.c に記述。 -// 6:XP 高レベル -// LUNA-I からの類推。存在するかどうかも不明。 -// ただ、これをなくすと XP ファームウェアまで作り直しなので、 -// なくさないんじゃないかなあ。OMRON ファームで使ってなければ -// さっくり廃止されているかもしれない(PSGPAM が使用...レベル1 に -// 変えればいいだけだが) +// 5:XP 高レベル +// Issue#131 より。 // 6:システムクロック // ROM のメモリコマンドではレベル6割り込みが常時上がっているように観測 // できるので、おそらくシステムクロック割り込みが上がっている。 @@ -154,7 +149,7 @@ // 要はアドレスバスとR/W信号線しか見ていない。 #include "sysctlr.h" -#include "ethernet.h" +#include "lance.h" #include "mpu88xx0.h" #include "nmi.h" #include "prom.h" @@ -164,12 +159,15 @@ // コンストラクタ SysCtlrDevice::SysCtlrDevice() - : inherited("SystemCtlr") + : inherited(OBJ_INTERRUPT) { + SetName("SysCtlr"); AddAlias("SysCtlr"); + AddAlias("SystemCtlr"); + + intmap_status = IntmapSentinel; monitor.func = ToMonitorCallback(&SysCtlrDevice::MonitorUpdate); - monitor.SetSize(25, 10); monitor.Regist(ID_MONITOR_INTERRUPT); } @@ -178,6 +176,44 @@ SysCtlrDevice::~SysCtlrDevice() { } +// 初期化 +bool +SysCtlrDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + mpu88xx0 = GetMPU88xx0Device(mpu); + + // 検索順 + RegistINT(IntmapSysClk, "Clock", GetSysClkDevice()); + RegistINT(IntmapSIO, "SIO", GetSIODevice()); + RegistINT(IntmapLance, "Lance", GetLanceDevice()); + RegistINT(IntmapSPC, "SPC", GetSPCDevice()); + RegistINT(IntmapXPHigh, "XP(Hi)", DEVICE_XPINT_HIGH); + RegistINT(IntmapXPLow, "XP(Lo)", DEVICE_XPINT_LOW); + RegistINT(IntmapSoft, "SoftInt", mpu88xx0); // ? + RegistINT(IntmapNMI, "NMI", GetNMIDevice()); + + // 表示順 + disp_list = { + IntmapNMI, + IntmapSysClk, + IntmapSIO, + IntmapXPHigh, + IntmapLance, + IntmapSPC, + IntmapXPLow, + IntmapSoft, + }; + + // 行数が確定したのでサイズ設定 + monitor.SetSize(41, 1 + disp_list.size()); + + return true; +} + // リセット void SysCtlrDevice::ResetHard(bool poweron) @@ -190,10 +226,13 @@ SysCtlrDevice::ResetHard(bool poweron) cpu[i].maskval = 0xfc000000; cpu[i].intmask = MakeIntMask(cpu[i].maskval, i); cpu[i].ipl = 0; + cpu[i].softint = 0; + cpu[i].softint_count = 0; } + ChangeInterrupt(); } -uint64 +busdata SysCtlrDevice::Read32(uint32 addr) { int n = (addr >> 2) & 3; @@ -208,9 +247,11 @@ SysCtlrDevice::Read32(uint32 addr) if (0x69000000 <= addr && addr < 0x69000010) { // 読み出しで SOFTINT ネゲート (値は関係ない) - putlog(1, "Softint(CPU#%d) Negate", n); - intmap &= ~(IntmapSoft0 << n); - ChangeInterrupt(); + if (cpu[n].softint) { + putlog(1, "Softint(CPU#%d) Negate", n); + cpu[n].softint = 0; + ChangeInterrupt(); + } return 0xffffffff; } @@ -227,7 +268,7 @@ SysCtlrDevice::Read32(uint32 addr) return 0xffffffff; } -uint64 +busdata SysCtlrDevice::Write32(uint32 addr, uint32 data) { int n = (addr & 15) >> 2; @@ -251,10 +292,15 @@ SysCtlrDevice::Write32(uint32 addr, uint } if (0x69000000 <= addr && addr < 0x69000010) { // 書き込みで SOFTINT アサート (値は関係ない) - putlog(1, "Softint(CPU#%d) Assert 0x%x", n, data); - counter[__builtin_clz(intmap)]++; - intmap |= IntmapSoft0 << n; - ChangeInterrupt(); + if (cpu[n].softint == false) { + putlog(1, "Softint(CPU#%d) Assert", n); + cpu[n].softint = IntmapSoft; + cpu[n].softint_count++; + // 親クラスのカウンタも上げる (4つの和になる) + int clz = __builtin_clz(IntmapSoft); + counter[clz]++; + ChangeInterrupt(); + } return 0; } if (0x6d000000 <= addr && addr < 0x6d000010) { @@ -268,8 +314,8 @@ SysCtlrDevice::Write32(uint32 addr, uint // 間隔に書き換えて Start() した後、この書き込み命令から戻ったところの // ExecCallback が time だけ所要サイクルに書き換えて再度 Start() する // ため、時間はともかく幸い ResetCallback() が呼ばれることで動いている。 - gPROM0->ResetHard(false); - gMPU->ResetHard(false); + GetPROM0Device()->ResetHard(false); + mpu->ResetHard(false); ResetHard(false); return 0; } @@ -278,7 +324,7 @@ SysCtlrDevice::Write32(uint32 addr, uint return 0; } -uint64 +busdata SysCtlrDevice::Peek8(uint32 addr) { int n = (addr >> 2) & 3; @@ -299,45 +345,35 @@ SysCtlrDevice::Peek8(uint32 addr) case 3: return data & 0xff; default: - break; + __unreachable(); } - __unreachable(); } void SysCtlrDevice::MonitorUpdate(Monitor *, TextScreen& screen) { int y; - struct { - const char *name; - uint32 map; - } table[] = { - { "NMI", IntmapNMI }, - { "Clock", IntmapSysClk }, - { "SIO", IntmapSIO }, - { "Lance", IntmapLance }, - { "SPC", IntmapSPC }, - { "Soft#0", IntmapSoft0 }, - { "Soft#1", IntmapSoft1 }, - { "Soft#2", IntmapSoft2 }, - { "Soft#3", IntmapSoft3 }, - }; // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい - bool ei = gMPU88xx0->GetCPU()->IsIntrEnable(); + bool ei = mpu88xx0->IsIntrEnable(); screen.Clear(); + + // 0 1 2 3 4 + // 01234567890123456789012345678901234567890 + // Lv Device CPU0 Count + y = 0; - // XXX CPU の実装数によってウィンドウ幅を変える。 - // はみ出したところは描画されないのでヘッダは4つ分出力しておく - screen.Print(0, y++, "Lv Device Count CPU0 CPU1 CPU2 CPU3"); - for (int i = 0; i < countof(table); i++) { - uint32 map = table[i].map; + // XXX CPU の実装数によってウィンドウ幅を変えること。 + screen.Print(0, y, "Lv Device CPU0"); + screen.Puts(36, y, "Count"); + y++; + for (uint32 map : disp_list) { int clz = __builtin_clz(map); int lv = (31 - clz) / 4; screen.Print(0, y, "%d", lv); - screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name); - screen.Print(8, y, "%11" PRIu64, counter[clz]); + screen.Puts(3, y, TA::OnOff(intmap_status & map), GetIntName(map)); + screen.Print(15, y, "%26s", format_number(counter[clz]).c_str()); // CPU ごとのマスク // XXX 今は CPU は1つしかない @@ -345,43 +381,21 @@ SysCtlrDevice::MonitorUpdate(Monitor *, // Softint の他 CPU 分は // 動作としては常にマスクされてて通過しないから問題ないが、 // 見せる分にはマスクされているではなく無効と見せたほうがいい。 - if (lv == 1 && map != (IntmapSoft0 << n)) { - screen.Puts(21 + n * 5, y, "----"); - } else if ((cpu[n].intmask & map) == 0) { - screen.Puts(21 + n * 5, y, "Mask"); + if ((cpu[n].intmask & map) == 0) { + screen.Puts(11 + n * 5, y, "Mask"); } else if (!ei) { - screen.Puts(21 + n * 5, y, "IND"); + screen.Puts(11 + n * 5, y, "IND"); } } y++; } -} -// デバイスから Intmap 値を引く -uint32 -SysCtlrDevice::GetIntmap(Device *source) const -{ - if (__predict_true(source == gSysClk)) { - return IntmapSysClk; - } - if (__predict_true(source == gSIO)) { - return IntmapSIO; - } - if (__predict_true(source == gEthernet)) { - return IntmapLance; - } - if (__predict_true(source == gSPC)) { - return IntmapSPC; - } - if (source == gNMI) { - return IntmapNMI; - } - PANIC("Unknown interrupt source?"); + // ソフトウェア割り込みの CPU ごとのカウンタいる? } // 割り込みアクノリッジはない -int +busdata SysCtlrDevice::InterruptAcknowledge(int lv) { return 0; @@ -393,16 +407,16 @@ SysCtlrDevice::ChangeInterrupt() { // XXX MPU 側がまだマルチプロセッサに対応してないので CPU#0 だけ for (int i = 0; i < 1; i++) { - uint32 localmap = intmap & cpu[i].intmask; + uint32 localmap = (intmap_status | cpu[i].softint) & cpu[i].intmask; - // intmap の最下位ビットは常に立ててあり localmap は 0 にならない + // intmap_status の最下位ビットは常に立ててあり localmap は 0 にならない int newipl = (uint)(31 - __builtin_clz(localmap)) / 4; // 割り込みレベルが変わったら、新しいレベルを通知 if (newipl != cpu[i].ipl) { cpu[i].ipl = newipl; // MPU 側は 1 レベルしかない - gMPU->Interrupt(cpu[i].ipl ? 1 : 0); + mpu->Interrupt(cpu[i].ipl ? 1 : 0); } } } @@ -424,8 +438,5 @@ SysCtlrDevice::MakeIntMask(uint32 data, data <<= 1; } - // Softint は他 CPU 分のビットを下ろす - val &= (0xffffff0f | (IntmapSoft0 << n)); - return val; }