--- nono/vm/sysctlr.cpp 2026/04/29 17:04:36 1.1 +++ nono/vm/sysctlr.cpp 2026/04/29 17:05:59 1.1.1.17 @@ -4,158 +4,174 @@ // Licensed under nono-license.txt // -// LUNA88K のシステムコントローラのような何か - -#include "sysctlr.h" - -// この辺を全部一つのデバイスで受け付けておくか。BusIO はまた後で考える。 -// $6500000n.b HW 割り込みレベル (n*4 = CPU#n) -// $65000000.b CPU#0 -// $65000004.b CPU#1 -// $65000008.b CPU#2 -// $6500000c.b CPU#3 -// $6900000n ソフトウェア割り込み(?) -// $6d00000n CPU#n をリセット(?) -// $6d000010 全 CPU をリセット - -// intmask[] について: -// I/O ポート 0x6500_00xx での設定値は、 -// bit 31 30 29 28 27 26 25... -// lvl 6 5 4 3 2 1 (not used) -// の対応になっている。intmask では 25bit 右シフトして、 -// ビット番号が割り込みレベルに対応するようにマップした。 - - -// LUNA88K -// 割り込みコントロールレジスタ -// $6500_000n -// n: CPU ID * 4 (0,4,8,c) -// この16Mページ内はミラーされている模様。 -// 下位2bitしかデコードしていない? -// 書き込み時: -// 3 2 1 -// 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 -// +-+-+-+-+-+-+---------------------------------------------------+ -// |6|5|4|3|2|1| | -// +-+-+-+-+-+-+---------------------------------------------------+ -// bit31: 1=割り込み 6 イネーブル -// bit30: 1=割り込み 5 イネーブル -// bit29: 1=割り込み 4 イネーブル -// bit28: 1=割り込み 3 イネーブル -// bit27: 1=割り込み 2 イネーブル -// bit26: 1=割り込み 1 イネーブル -// m68k と異なり、個別の割り込みごとに許可/禁止できる。 -// 該当ビットに 1 を書き込むと許可。 -// 空欄部分は無視される模様。 -// -// 読み込み時 -// 3 2 1 -// 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 -// +-----+---------+-+-+-+-+-+-+-----------------------------------+ -// |Level| |6|5|4|3|2|1| | -// +-----+---------+-+-+-+-+-+-+-----------------------------------+ -// bit31-29: 発生している最上位レベルの割り込み。範囲は7-0 -// bit23-18: 書き込んだ割り込みマスク。 -// 空欄部分は「不定」の模様。 -// -// bit31-29 のレベルは、割り込みコントローラに入力 -// されている割り込み信号線6本を、マスク処理した後、 -// プライオリティバイナリエンコーダの値がそのまま出力されている模様。 -// ラッチ機構は無いようだ。 -// したがってマスクされている割り込み(マスクビットが 0) の -// 値が出力されることはない。 -// 同時に入力があった場合は、数字の大きいほうが出力される。 -// レベル7 はマスクなしでプライオリティエンコーダに入力されているようだ。 -// -// 割り込み入力がないときは 0 になる模様。 -// 本体 ABRT スイッチを押すと、押している間、すべての CPU の -// level が 111(=7) になる。離すと戻る。 -// 88100 には NMI が無いので、通常の割り込みと同じように処理している? -// (なので IND 状態だとABRT できない。いいのかそれで) -// (OpenBSD6.7 の割り込みハンドラはABRTには対応していないように読める) -// -// 想定される回路 -// -// [割り込みソース] -// 1:SOFTINT レジスタ $6900000n -// | 2:(XP 低レベル?) -// | | 3:SPC -// | | | 4:(LANCE|拡張スロット?) -// | | | | 5:(拡張PC98?|シリアル?) -// | | | | | 6:(XP 高レベル?|システムクロック?) -// | | | | | | 7:ABRTスイッチ -// V V V V V V | -// +---------------------+ | -// | 割り込みマスク | | (R:bit23-18, W:bit31-26) -// +---------------------+ | -// | | | | | | | -// V V V V V V V -// +-------------------------+ -// |プライオリティエンコーダ |-> (R:bit31-29) -// +-------------------------+ -// (入力のWired-OR) -// | -// [M88K INT] -// -// LUNA-I とはレベル配置が違う。1 レベルのズレに加え、シリアルが -// 6 -> 5 に変更されているようだ? -// -// 割り込みソース調査状況 -// 1:SOFTINT レジスタ $6900000n -// ROM のメモリコマンドで確認。OpenBSD machdep.c の記述の通り。 -// 2:XP 低レベル -// LUNA-I からの類推及び、OpenBSD mainbus.c に記述あり。OpenBSD のほうは -// 低レベルかどうかは不明。 -// 3:SPC -// ROM1.2, OpenBSD ともに使用。 -// 4:LANCE -// ROM はまだ不明。OpenBSD は使用。 -// 4:拡張スロット -// LUNA-I からの類推のみ。不明。 -// 5:拡張PC98 -// LUNA-I からの類推のみ。LUNA88K にはスロットがないようなので、 -// LUNA88K2 が必要。 -// OpenBSD mainbus.c に記述あり。 -// 5:シリアル(7201) -// OpenBSD mainbus.c に記述。 -// 6:XP 高レベル -// LUNA-I からの類推。存在するかどうかも不明。 -// ただ、これをなくすと XP ファームウェアまで作り直しなので、 -// なくさないんじゃないかなあ。OMRON ファームで使ってなければ -// さっくり廃止されているかもしれない(PSGPAM が使用...レベル1 に -// 変えればいいだけだが) -// 6:システムクロック -// ROM のメモリコマンドではレベル6割り込みが常時上がっているように観測 -// できるので、おそらくシステムクロック割り込みが上がっている。 -// OpenBSD maibus.c にも記述。 -// 7:ABRTスイッチ -// ROM のメモリコマンドで確認。 -// -// -// SOFTINT レジスタ $6900000n -// $69000000: CPU0 -// $69000004: CPU1 -// $69000008: CPU2 -// $6900000c: CPU3 -// 挙動: -// この32ビットのどこかにライトアクセスすると、INT1 をアサートする。 -// この32ビットのどこかをリードアクセスすると、INT1 をネゲートする。 -// データバスは無視される。 -// 0x00 を書いても、アサートされることに注意。 -// リードアクセスで読み込まれる値も不定のようだ。 -// 要はアドレスバスとR/W信号線しか見ていない。 +// +// LUNA-88K のシステムコントローラのような何か +// +// IODevice +// | +// +-- InterruptDevice (割り込みコントローラの共通部) +// | +// +-- M680x0Interrupt (m68k 割り込みコントローラの共通部) +// | | +// | +-- X68030Interrupt (X68030 の割り込みコントローラ) +// | +-- LunaInterrupt (LUNA-I の割り込みコントローラ) +// | +// +-- PEDECDevice (X68030 の Lv1 担当コントローラ) +// | +// | +---------------+ +// +--| SysCtlrDevice | (LUNA-88K の割り込みコントローラ) +// +---------------+ -std::unique_ptr gSysCtlr; +// この辺を全部このデバイスで受け付けてある。 +// +// 公称アドレス 実態範囲 +// $6500'000n $64'〜$67' 割り込み制御 +// $6900'000n $68'〜$6b' ソフトウェア割り込み設定 +// $6d00'00nn $6c'〜$6d' CPUリセット(?) +// ($6e'〜$6f' は不明、$ffffffff が読める) + +// $6500'000n: 割り込み制御レジスタ(?) +// アドレスは +// $6500'0000: CPU0 +// $6500'0004: CPU1 +// $6500'0008: CPU2 +// $6500'000c: CPU3 +// $64..$67 から始まるこの 64MB は 16バイトでミラーされている模様。 +// +// 書き込み時は +// 3 2 1 +// 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 +// +-+-+-+-+-+-+---------------------------------------------------+ +// |6|5|4|3|2|1| | +// +-+-+-+-+-+-+---------------------------------------------------+ +// bit31: %1 = 割り込み 6 イネーブル +// bit30: %1 = 割り込み 5 イネーブル +// bit29: %1 = 割り込み 4 イネーブル +// bit28: %1 = 割り込み 3 イネーブル +// bit27: %1 = 割り込み 2 イネーブル +// bit26: %1 = 割り込み 1 イネーブル +// +// m68k と異なり、個別の割り込みごとに許可/禁止できる。 +// 該当ビットに 1 を書き込むと許可。空欄部分は無視される模様。 +// +// 読み込み時は +// 3 2 1 +// 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 +// +-----+---------+-+-+-+-+-+-+-----------------------------------+ +// |Level| |6|5|4|3|2|1| | +// +-----+---------+-+-+-+-+-+-+-----------------------------------+ +// bit31-29: 発生している最上位レベルの割り込み。範囲は7-0。 +// bit23-18: 書き込んだ割り込みマスク。 +// +// 空欄部分は「不定」の模様。 +// +// bit31-29 のレベルは、割り込みコントローラに入力されている割り込み +// 信号線6本をマスク処理した後の、プライオリティバイナリエンコーダの値が +// そのまま出力されている模様。ラッチ機構は無いようだ。 +// 従ってマスクされている割り込み(ビットが 0) の値が出力されることはない。 +// 同時に入力があった場合は、数字の大きいほうが出力される。 +// レベル7 はマスクなしでプライオリティエンコーダに入力されているようだ。 +// 割り込み入力がないときは 0 になる模様。 +// +// 本体 ABRT スイッチを押している間、すべての CPU の Level が %111 (=7) +// になる。離すと戻る。 +// m88100 には NMI が無いので、通常の割り込みと同じように処理している? +// (なので IND 状態だとABRT できない。いいのかそれで) +// (OpenBSD6.7 の割り込みハンドラはABRTには対応していないように読める) +// +// 想定される回路 +// +// [割り込みソース] +// 7:ABRT スイッチ +// | 6:システムクロック +// | | 5:(シリアル | XP 高レベル | 拡張 PC-98?) +// | | | 4:(LANCE | 拡張スロット?) +// | | | | 3:SPC +// | | | | | 2:(未使用?) +// | | | | | | 1:(XP 低レベル | SOFTINT レジスタ $6900'000n) +// | | | | | | | +// | V V V V V V +// | +---------------------+ +// | | 割り込みマスク | (R:bit23-18, W:bit31-26) +// | +---------------------+ +// | | | | | | | +// V V V V V V V +// +-------------------------+ +// |プライオリティエンコーダ |-> (R:bit31-29) +// +-------------------------+ +// | | | +// V V V +// (Wired-OR) +// | +// [M88K INT] +// +// 割り込みソース調査状況。(LUNA-I とはレベル配置が違う) +// +// 1:SOFTINT レジスタ $6900'000n +// ROM のメモリコマンドで確認。OpenBSD machdep.c の記述の通り。 +// 1:XP 低レベル +// OpenBSD mainbus.c および Issue#131 より。 +// 3:SPC +// PROM 1.20, OpenBSD ともに使用。 +// 4:LANCE +// ROM はまだ不明。OpenBSD は使用。 +// 4:拡張スロット +// LUNA-I からの類推のみ。不明。 +// 5:拡張PC98 +// LUNA-I からの類推のみ。 +// LUNA-88K にはスロットがないようなので LUNA-88K2 が必要。 +// OpenBSD mainbus.c に記述あり。 +// 5:シリアル(uPD7201) +// OpenBSD mainbus.c に記述。 +// 5:XP 高レベル +// Issue#131 より。 +// 6:システムクロック +// ROM のメモリコマンドではレベル6割り込みが常時上がっているように +// 観測できるので、おそらくシステムクロック割り込みが上がっている。 +// OpenBSD maibus.c にも記述。 +// 7:ABRTスイッチ +// ROM のメモリコマンドで確認。 +// +// $6900'000n: ソフトウェア割り込み設定レジスタ(?) +// アドレスは +// $6900'0000: CPU0 +// $6900'0004: CPU1 +// $6900'0008: CPU2 +// $6900'000c: CPU3 +// +// この32ビットのどこかにライトアクセスすると、INT1 をアサートする。 +// この32ビットのどこかをリードアクセスすると、INT1 をネゲートする。 +// この時のデータバスは無視される。0x00 を書いてもアサートされることに注意。 +// リードアクセスで読み込める値も不定のようだ。 +// 要はアドレスバスと R/W 信号線しか見ていない。 +// +// $6d00'000n: CPU 個別リセットレジスタ(?) +// このへん触ると CPU がリセットされるというかだんまりになるので調査困難。 +// +// $6d00'0010: 全 CPU リセットレジスタ(?) +#include "sysctlr.h" +#include "lance.h" +#include "mpu88xx0.h" +#include "nmi.h" +#include "prom.h" +#include "sio.h" +#include "spc.h" +#include "sysclk.h" // コンストラクタ SysCtlrDevice::SysCtlrDevice() + : inherited(OBJ_INTERRUPT) { - logname = "sysctlr"; - devname = "SysCtlr"; + SetName("SysCtlr"); + AddAlias("SysCtlr"); + AddAlias("SystemCtlr"); - monitor.Init(60, 5); + intmap_status = IntmapSentinel; + + monitor = gMonitorManager->Regist(ID_MONITOR_INTERRUPT, this); + monitor->SetCallback(&SysCtlrDevice::MonitorScreen); } // デストラクタ @@ -163,99 +179,172 @@ SysCtlrDevice::~SysCtlrDevice() { } -uint64 -SysCtlrDevice::Read32(uint32 addr) +// 初期化 +bool +SysCtlrDevice::Init() { - int n = (addr & 15) >> 2; + mpu88xx0 = GetMPU88xx0Device(mpu); - // 読み込みでは割り込みレベルを返すようだ - // bit 31..29: アクティブな割り込みのレベル - // 24 level7 割り込みが発生したら 1 - // 23 level6 .. - // 22 level5 - // 21 level4 - // 20 level3 - // 19 level2 - // 18 level1 - // XXX: もう資料がないとわからない - if (0x65000000 <= addr && addr < 0x65000010) { - int maxlev = 0; - // 7 to 1 - for (int i = 7; i > 0; i--) { - if (intlevel[n] & (1 << i)) { - maxlev = i; - break; - } - } + // 検索順 + 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, + }; - uint32 data = (maxlev << 29) | (intlevel[n] << 17); - putlog(2, "割り込み保持読み出し(CPU#%d) -> $%08x", n, data); - return data; - } + // 行数が確定したのでサイズ設定 + monitor->SetSize(41, 1 + disp_list.size()); - if (0x69000000 <= addr && addr < 0x69000010) { - putlog(1, "ソフトウェア割り込み(CPU#%d)クリア(未実装)", n); - return 0xffffffff; - } + return true; +} - if (0x6d000000 <= addr && addr < 0x6d000010) { - putlog(1, "CPU%d リセット 未実装読み込み", n); - return 0xffffffff; +// リセット +void +SysCtlrDevice::ResetHard(bool poweron) +{ + // さすがにリセットくらいはされるだろう… + inherited::ResetHard(poweron); + + for (int i = 0; i < 4; i++) { + // XXX 初期値は分からないがとりあえず割り込み禁止にしておく + cpu[i].maskval = 0x00000000; + cpu[i].intmask = MakeIntMask(cpu[i].maskval, i); + cpu[i].ipl = 0; + cpu[i].softint = 0; + cpu[i].softint_count = 0; } - if (addr == 0x6d000010) { - putlog(1, "CPU ALL リセット 未実装読み込み"); - return 0xffffffff; + ChangeInterrupt(); +} + +busdata +SysCtlrDevice::Read(busaddr addr) +{ + uint32 paddr = addr.Addr(); + uint n = (paddr >> 2) & 3; + busdata data; + + // XXX バイト/ワードアクセスは未対応 + if (addr.GetSize() < 4) { + putlog(0, "Read $%08x size=%u (NOT IMPLEMENTED)", + paddr, addr.GetSize()); + } + + if (0x64000000 <= paddr && paddr < 0x68000000) { + data = Peek4(paddr); + putlog(2, "Read INT_CTRL(CPU#%u) -> $%08x", n, data.Data()); + + } else if (0x69000000 <= paddr && paddr < 0x69000010) { + // 読み出しで SOFTINT ネゲート (値は関係ない) + if (cpu[n].softint) { + putlog(1, "Softint(CPU#%u) Negate", n); + cpu[n].softint = 0; + ChangeInterrupt(); + } + data = 0xffffffff; + + } else if (0x6d000000 <= paddr && paddr < 0x6d000010) { + putlog(0, "Read CPU%u reset (NOT IMPLEMENTED)", n); + data = 0xffffffff; + + } else if (paddr == 0x6d000010) { + putlog(0, "Read All CPU reset (NOT IMPLEMENTED)"); + data = 0xffffffff; + + } else { + putlog(0, "Read $%08x (NOT IMPLEMENTED)", paddr); + data.SetBusErr(); } - putlog(0, "未実装読み込み $%08x", addr); - return 0xffffffff; + data |= BusData::Size4; + return data; } -uint64 -SysCtlrDevice::Write32(uint32 addr, uint32 data) +busdata +SysCtlrDevice::Write(busaddr addr, uint32 data) { - int n = (addr & 15) >> 2; + uint32 paddr = addr.Addr(); + uint n = (paddr >> 2) & 3U; - if (0x65000000 <= addr && addr < 0x65000010) { - intmask[n] = data >> 25; + // XXX バイト/ワードアクセスは未対応 + if (addr.GetSize() < 4) { + putlog(0, "Write $%08x size=%u (NOT IMPLEMENTED)", + paddr, addr.GetSize()); + } + + if (0x64000000 <= paddr && paddr < 0x68000000) { + // 割り込みマスクを設定。 + WriteIntMask(n, data); + + } else if (0x69000000 <= paddr && paddr < 0x69000010) { + // 書き込みで SOFTINT アサート (値は関係ない) + if (cpu[n].softint == false) { + putlog(1, "Softint(CPU#%u) Assert", n); + cpu[n].softint = IntmapSoft; + cpu[n].softint_count++; + // 親クラスのカウンタも上げる (4つの和になる) + int clz = __builtin_clz(IntmapSoft); + counter[clz]++; + ChangeInterrupt(); + } - // XXX: クリアしてみる - intlevel[n] = 0; + } else if (0x6d000000 <= paddr && paddr < 0x6d000010) { + putlog(0, "Write CPU%u reset (NOT IMPLEMENTED)", n); - putlog(1, "割り込みマスク(CPU#%d) <- $%08x", n, intmask[n] << 25); - return 0; - } - if (0x69000000 <= addr && addr < 0x69000010) { - // 詳細不明。0xFFFFFFFF が書き込まれている、ようだ。 - intlevel[n] &= ~data; - // bit 表示したい - putlog(0, "割り込み(CPU#%d)クリア 0x%x 残り=0x%x", n, data, intlevel[n]); - return 0; - } - if (0x6d000000 <= addr && addr < 0x6d000010) { - putlog(0, "CPU%d リセット 未実装書き込み", n); - return 0; - } - if (addr == 0x6d000010) { - putlog(0, "CPU ALL リセット 未実装書き込み"); - return 0; + } else if (paddr == 0x6d000010) { + putlog(1, "Reset All CPUs"); + // XXX このあたりもう少し整理する必要がある + // 今は MPU.ResetHard() が func を ResetCallback に、time をリセット + // 間隔に書き換えて Start() した後、この書き込み命令から戻ったところの + // ExecCallback が time だけ所要サイクルに書き換えて再度 Start() する + // ため、時間はともかく幸い ResetCallback() が呼ばれることで動いている。 + GetPROM0Device()->ResetHard(false); + mpu->ResetHard(false); + ResetHard(false); + + } else { + putlog(0, "Write $%08x <- $%08x (NOT IMPLEMENTED)", paddr, data); } - putlog(0, "未実装書き込み $%08x <- $%08x", addr, data); - return 0; + busdata r = BusData::Size4; + return r; } -uint64 -SysCtlrDevice::Peek8(uint32 addr) +// Peek1() の下請け。ロングワードで処理して後でバイトに分割するほうが楽。 +uint32 +SysCtlrDevice::Peek4(uint32 addr) const { + uint n = (addr >> 2) & 3; uint32 data; - int n = (addr & 15) >> 2; - if (0x65000000 <= addr && addr < 0x65000010) { - data = intmask[n] << 25; + if (0x64000000 <= addr && addr < 0x68000000) { + // bit31-29 に発生している最上位の割り込みレベル。 + // bit23-18 に設定したレベル 6-1 の割り込みマスク。 + data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8); } else { data = 0xffffffff; } + return data; +} + +busdata +SysCtlrDevice::Peek1(uint32 addr) +{ + uint32 data = Peek4(addr & ~3U); switch (addr & 3) { case 0: return data >> 24; @@ -266,19 +355,120 @@ SysCtlrDevice::Peek8(uint32 addr) case 3: return data & 0xff; default: - break; + __unreachable(); } - __unreachable(); } -bool -SysCtlrDevice::MonitorUpdate() +void +SysCtlrDevice::MonitorScreen(Monitor *, TextScreen& screen) { - monitor.Clear(); - monitor.Puts(6, 0, "IntrEnable SWIntr"); - for (int i = 0; i < countof(intmask); i++) { - monitor.Print(0, i + 1, "CPU#%d $%02x", i, intmask[i]); + int y; + + // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい + bool ei = mpu88xx0->IsIntrEnable(); + + screen.Clear(); + + // 0 1 2 3 4 + // 01234567890123456789012345678901234567890 + // Lv Device CPU0 Count + + y = 0; + // XXX CPU の実装数によってウィンドウ幅を変えること。 + screen.Print(0, y, "Lv Device CPU0"); + screen.Puts(36, y, "Count"); + y++; + for (uint32 map : disp_list) { + uint clz = __builtin_clz(map); + uint lv = (31 - clz) / 4; + screen.Print(0, y, "%u", lv); + 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つしかない + for (int n = 0; n < 1; n++) { + // Softint の他 CPU 分は + // 動作としては常にマスクされてて通過しないから問題ないが、 + // 見せる分にはマスクされているではなく無効と見せたほうがいい。 + if ((cpu[n].intmask & map) == 0) { + screen.Puts(11 + n * 5, y, "Mask"); + } else if (!ei) { + screen.Puts(11 + n * 5, y, "IND"); + } + } + + y++; } - return true; + // ソフトウェア割り込みの CPU ごとのカウンタいる? +} + +// 割り込みマスクを設定する。 +// data はロングワードレジスタの書き込み値 (bit31-26 のみ有効)。 +void +SysCtlrDevice::WriteIntMask(uint32 n, uint32 data) +{ + data &= 0xfc000000; + + // 割り込みレベル変えるたびに表示されるのですごく多い。 + // さらに同レベルが書き込まれることも多い…。 + if (cpu[n].maskval != data) { + putlog(2, "Interrupt Mask(CPU#%u) <- $%08x", n, data); + } else { + putlog(3, "Interrupt Mask(CPU#%u) <- $%08x", n, data); + } + + // 設定値を保存 + cpu[n].maskval = data; + // 内部マスクを書き換えて割り込み状態を更新 + cpu[n].intmask = MakeIntMask(data, n); + ChangeInterrupt(); +} + +// 割り込みアクノリッジはない +busdata +SysCtlrDevice::InterruptAcknowledge(int lv) +{ + return 0; +} + +// 割り込み状態を更新 +void +SysCtlrDevice::ChangeInterrupt() +{ + // XXX MPU 側がまだマルチプロセッサに対応してないので CPU#0 だけ + for (int i = 0; i < 1; i++) { + uint32 localmap = (intmap_status | cpu[i].softint) & cpu[i].intmask; + + // intmap_status の最下位ビットは常に立ててあり localmap は 0 にならない + uint newipl = (uint)(31 - __builtin_clz(localmap)) / 4; + + // 割り込みレベルが変わったら、新しいレベルを通知 + if (newipl != cpu[i].ipl) { + cpu[i].ipl = newipl; + // MPU 側は 1 レベルしかない + mpu->Interrupt(cpu[i].ipl ? 1 : 0); + } + } +} + +// 割り込みマスク設定レジスタの書き込み値から内部用のマスクを作成 +// data は bit31-26 のみ使用。他のビットは不問。 +// n は CPU# (Softint 用)。 +/*static*/ uint32 +SysCtlrDevice::MakeIntMask(uint32 data, uint n) +{ + uint32 val = 0xf0000001; // Lv7 は NMI、最下位は番兵用 + + uint32 mask = 0x0f000000; + for (int i = 6; i >= 1; i--) { + if ((int32)data < 0) { + val |= mask; + } + mask >>= 4; + data <<= 1; + } + + return val; }