--- nono/vm/sysctlr.cpp 2026/04/29 17:04:45 1.1.1.3 +++ nono/vm/sysctlr.cpp 2026/04/29 17:05:10 1.1.1.8 @@ -4,14 +4,24 @@ // Licensed under nono-license.txt // +// // LUNA88K のシステムコントローラのような何か +// -#include "sysctlr.h" -#include "ethernet.h" -#include "mpu88xx0.h" -#include "sio.h" -#include "spc.h" -#include "sysclk.h" +// IODevice +// | +// +-- InterruptDevice (割り込みコントローラの共通部) +// | +// +-- M680x0Interrupt (m68k 割り込みコントローラの共通部) +// | | +// | +-- X68030Interrupt (X68030 の割り込みコントローラ) +// | +-- LunaInterrupt (LUNA-I の割り込みコントローラ) +// | +// +-- PEDECDevice (X68030 の Lv1 担当コントローラ) +// | +// | +---------------+ +// +--| SysCtlrDevice | (LUNA88K の割り込みコントローラ) +// +---------------+ // この辺を全部一つのデバイスで受け付けておくか。BusIO はまた後で考える。 // $6500000n.b HW 割り込みレベル (n*4 = CPU#n) @@ -143,14 +153,24 @@ // リードアクセスで読み込まれる値も不定のようだ。 // 要はアドレスバスとR/W信号線しか見ていない。 +#include "sysctlr.h" +#include "ethernet.h" +#include "mpu88xx0.h" +#include "nmi.h" +#include "prom.h" +#include "sio.h" +#include "spc.h" +#include "sysclk.h" // コンストラクタ SysCtlrDevice::SysCtlrDevice() + : inherited("SystemCtlr") { - logname = "sysctlr"; - devname = "SysCtlr"; + AddAlias("SysCtlr"); - monitor_size = nnSize(24, 10); + monitor.func = ToMonitorCallback(&SysCtlrDevice::MonitorUpdate); + monitor.SetSize(25, 10); + monitor.Regist(ID_MONITOR_INTERRUPT); } // デストラクタ @@ -158,12 +178,13 @@ SysCtlrDevice::~SysCtlrDevice() { } +// リセット void -SysCtlrDevice::ResetHard() +SysCtlrDevice::ResetHard(bool poweron) { // さすがにリセットくらいはされるだろう… - intmap = 0x00000001; - memset(&counter, 0, sizeof(counter)); + inherited::ResetHard(poweron); + for (int i = 0; i < 4; i++) { // XXX 初期値は分からないがとりあえず割り込み禁止にしておく cpu[i].maskval = 0xfc000000; @@ -241,7 +262,15 @@ SysCtlrDevice::Write32(uint32 addr, uint return 0; } if (addr == 0x6d000010) { - putlog(0, "CPU ALL リセット 未実装書き込み"); + putlog(1, "Reset All CPUs"); + // XXX このあたりもう少し整理する必要がある + // 今は MPU.ResetHard() が func を ResetCallback に、time をリセット + // 間隔に書き換えて Start() した後、この書き込み命令から戻ったところの + // ExecCallback が time だけ所要サイクルに書き換えて再度 Start() する + // ため、時間はともかく幸い ResetCallback() が呼ばれることで動いている。 + gPROM0->ResetHard(false); + gMPU->ResetHard(false); + ResetHard(false); return 0; } @@ -276,7 +305,7 @@ SysCtlrDevice::Peek8(uint32 addr) } void -SysCtlrDevice::MonitorUpdate(TextScreen& monitor) +SysCtlrDevice::MonitorUpdate(Monitor *, TextScreen& screen) { int y; struct { @@ -297,18 +326,18 @@ SysCtlrDevice::MonitorUpdate(TextScreen& // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい bool ei = gMPU88xx0->GetCPU()->IsIntrEnable(); - monitor.Clear(); + screen.Clear(); y = 0; // XXX CPU の実装数によってウィンドウ幅を変える。 // はみ出したところは描画されないのでヘッダは4つ分出力しておく - monitor.Print(0, y++, "Lv Device Count CPU0 CPU1 CPU2 CPU3"); + screen.Print(0, y++, "Lv Device Count CPU0 CPU1 CPU2 CPU3"); for (int i = 0; i < countof(table); i++) { uint32 map = table[i].map; int clz = __builtin_clz(map); int lv = (31 - clz) / 4; - monitor.Print(0, y, "%d", lv); - monitor.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name); - monitor.Print(8, y, "%10u", counter[clz]); + 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]); // CPU ごとのマスク // XXX 今は CPU は1つしかない @@ -317,11 +346,11 @@ SysCtlrDevice::MonitorUpdate(TextScreen& // 動作としては常にマスクされてて通過しないから問題ないが、 // 見せる分にはマスクされているではなく無効と見せたほうがいい。 if (lv == 1 && map != (IntmapSoft0 << n)) { - monitor.Puts(20 + n * 5, y, "----"); + screen.Puts(21 + n * 5, y, "----"); } else if ((cpu[n].intmask & map) == 0) { - monitor.Puts(20 + n * 5, y, "Mask"); + screen.Puts(21 + n * 5, y, "Mask"); } else if (!ei) { - monitor.Puts(20 + n * 5, y, "IND"); + screen.Puts(21 + n * 5, y, "IND"); } } @@ -333,47 +362,22 @@ SysCtlrDevice::MonitorUpdate(TextScreen& uint32 SysCtlrDevice::GetIntmap(Device *source) const { - if (__predict_true(source == gSysClk.get())) { + if (__predict_true(source == gSysClk)) { return IntmapSysClk; } - if (__predict_true(source == gSIO.get())) { + if (__predict_true(source == gSIO)) { return IntmapSIO; } - if (__predict_true(source == gEthernet.get())) { + if (__predict_true(source == gEthernet)) { return IntmapLance; } - if (__predict_true(source == gSPC.get())) { + if (__predict_true(source == gSPC)) { return IntmapSPC; } - PANIC("Unknown interrupt source?"); -} - -// 外部デバイスが割り込み信号線をアサートした -void -SysCtlrDevice::AssertINT(Device *source) -{ - uint32 oldmap; - uint32 srcmap; - - oldmap = intmap; - srcmap = GetIntmap(source); - intmap |= srcmap; - - if ((oldmap ^ intmap) != 0) { - // 立ち上がりエッジでカウント - counter[__builtin_clz(srcmap)]++; + if (source == gNMI) { + return IntmapNMI; } - - ChangeInterrupt(); -} - -// 外部デバイスが割り込み信号線をネゲートした -void -SysCtlrDevice::NegateINT(Device *source) -{ - intmap &= ~GetIntmap(source); - - ChangeInterrupt(); + PANIC("Unknown interrupt source?"); } // 割り込みアクノリッジはない @@ -394,7 +398,7 @@ SysCtlrDevice::ChangeInterrupt() // intmap の最下位ビットは常に立ててあり localmap は 0 にならない int newipl = (uint)(31 - __builtin_clz(localmap)) / 4; - // アサートによって割り込みレベルが変わったら、新しいレベルを通知 + // 割り込みレベルが変わったら、新しいレベルを通知 if (newipl != cpu[i].ipl) { cpu[i].ipl = newipl; // MPU 側は 1 レベルしかない @@ -425,4 +429,3 @@ SysCtlrDevice::MakeIntMask(uint32 data, return val; } -