--- nono/vm/interrupt.h 2026/04/29 17:04:45 1.1 +++ nono/vm/interrupt.h 2026/04/29 17:05:06 1.1.1.3 @@ -7,6 +7,7 @@ #pragma once #include "device.h" +#include "monitor.h" // // 割り込みを受け付けるデバイス @@ -18,8 +19,11 @@ class InterruptDevice : public IODevice using inherited = IODevice; public: InterruptDevice(); + InterruptDevice(const std::string& objname_); virtual ~InterruptDevice() override; + void ResetHard() override; + // 継承クラスの ResetHard() は保持している割り込み情報を全てキャンセルする。 // 各子デバイスはその ResetHard() で NegateINT() を明示的に呼び出して // 割り込みをキャンセルする必要はなく、もし自身で独自に割り込み信号線の @@ -30,9 +34,9 @@ class InterruptDevice : public IODevice // 変わらないような呼び出しをしても構わない。特に副作用はない。 // 子デバイスが割り込み信号線をアサートした - virtual void AssertINT(Device *source) = 0; + void AssertINT(Device *source); // 子デバイスが割り込み信号線をネゲートした - virtual void NegateINT(Device *source) = 0; + void NegateINT(Device *source); // 子デバイスが割り込み信号線を val の状態に変えた。 // true ならアサート、false ならネゲート。 @@ -46,6 +50,55 @@ class InterruptDevice : public IODevice // MPU からの割り込みアクノリッジに応答する virtual int InterruptAcknowledge(int lv) = 0; + + protected: + // 割り込みを上位デバイス(MPUなど)に伝達する。 + // 子デバイスが割り込み信号線の状態を変えたときに呼び出される。 + virtual void ChangeInterrupt() = 0; + + // Intmap について + // + // Intmap は 32bit のビットマップ値で、最大 31 個(といいつつ今の所 28 個) + // の割り込み発生の有無を個別に管理できる。 + // 発生している割り込みのうち最も優先度が高い 1つを高速に検索するため、 + // MSB 側を最も優先度が高い割り込みとして、Count-Leading-Zero で検索 + // することにする。 + // __builtin_clz(0) は動作未定義になるので、最下位ビットを常に立てて + // おくことで、割り込みなし(上位31bitがすべて0)の場合でもこの式が使える + // ようにしておく。 + // + // 具体的にどの割り込みをどのビットに割り当てるかは継承先の実装によるが、 + // m680x0 の場合、以下のように 1レベル 4つずつ割り当てることにする。 + // + // 3 2 1 0 + // 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 + // +-------+-------+-------+-------+-------+-------+-------+-------+ + // |7 7 7 7|6 6 6 6|5 5 5 5|4 4 4 4|3 3 3 3|2 2 2 2|1 1 1 1| %0001 | + // +-------+-------+-------+-------+-------+-------+-------+-------+ + // + // これにより同一レベルのデバイス 4 つまでの割り込み信号線の状態を独立 + // して保持しつつ、アサートされている信号線のうち最もレベルの高いものは + // 以下だけで求めることが出来る。 + // + // ipl = (31 - __builtin_clz(intmap)) / 4; + // + // LUNA88K の外部割り込みコントローラであるシステムコントローラも + // 概ねこれに近いので、sysctlr もこの構造を使う。 + // + // PEDEC は 7レベル分けする必要ないので、適当に割り当ててある。 + + static const uint32 IntmapSentinel = 0x00000001; + + // デバイスから Intmap 値を引く。 + virtual uint32 GetIntmap(Device *source) const = 0; + + // 割り込みマップ + uint32 intmap {}; + + // 割り込み回数 (アサートのエッジでカウントアップする) + // [0] が Intmap の bit31 割り込みのカウント。 + // [27] が Intmap の bit 4 割り込みのカウント。 + uint64 counter[28] {}; }; // @@ -63,42 +116,11 @@ class M680x0Interrupt : public Interrupt void ResetHard() override; - void AssertINT(Device *source) override; - void NegateINT(Device *source) override; - protected: - // Intmap は 32bit のビットマップ値で、値は機種ごとに定義する。 - // 1つの割り込みレベルにつき 4つまでデバイスをマッピングでき、また、 - // 同一レベル内での複数のデバイスの割り込み信号線の状態を独立して保持 - // できるようにするため。 - // - // 3 2 1 0 - // 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 - // +-------+-------+-------+-------+-------+-------+-------+-------+ - // |7 7 7 7|6 6 6 6|5 5 5 5|4 4 4 4|3 3 3 3|2 2 2 2|1 1 1 1| %0001 | - // +-------+-------+-------+-------+-------+-------+-------+-------+ - // - // bit31-4 でレベル 7-1 の割り込みを表す。 - // アサートされている信号線のうち最もレベルの高いものは以下で求まる。 - // ipl = (31 - clz(intmap)) / 4 - // 例えば bit30 と bit20 が立っている場合 (これは割り込みレベル 7 と 5 が - // 同時に要求されている状態)、最高レベルは (31 - 1) / 4 = 7 となる。 - // また __builtin_clz(0) は未定義なので使わない最下位ビットを常に立てて - // おくことで、割り込みなし(上位28bitがすべて0)の場合でもこの式が使える。 - - // デバイスから Intmap 値を引く。 - virtual uint32 GetIntmap(Device *source) const = 0; + void ChangeInterrupt() override; // 現在の割り込みレベル int ipl {}; - - // 割り込みマップ - uint32 intmap {}; - - // 割り込み回数 (アサートのエッジでカウントアップする) - // [0] が Intmap の bit31 割り込みのカウント。 - // [27] が Intmap の bit 4 割り込みのカウント。 - uint32 counter[28] {}; }; // @@ -132,12 +154,14 @@ class X68030Interrupt : public M680x0Int X68030Interrupt(); virtual ~X68030Interrupt() override; - void MonitorUpdate(TextScreen& monitor) override; - int InterruptAcknowledge(int lv) override; private: uint32 GetIntmap(Device *soruce) const override; + + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + Monitor monitor { this }; }; // @@ -166,12 +190,14 @@ class LunaInterrupt : public M680x0Inter LunaInterrupt(); virtual ~LunaInterrupt() override; - void MonitorUpdate(TextScreen& monitor) override; - int InterruptAcknowledge(int lv) override; private: uint32 GetIntmap(Device *source) const override; + + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + Monitor monitor { this }; }; // LUNA88K は sysctlr.cpp 参照。