|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: #pragma once
8:
9: #include "device.h"
1.1.1.2 root 10: #include "monitor.h"
1.1 root 11:
12: //
13: // 割り込みを受け付けるデバイス
14: // これ自体は IODevice である必要はないが、PEDEC や SysCtlr がこれを
15: // 継承するため。
16: //
17: class InterruptDevice : public IODevice
18: {
19: using inherited = IODevice;
20: public:
21: InterruptDevice();
1.1.1.2 root 22: InterruptDevice(const std::string& objname_);
1.1 root 23: virtual ~InterruptDevice() override;
24:
1.1.1.3 ! root 25: void ResetHard() override;
! 26:
1.1 root 27: // 継承クラスの ResetHard() は保持している割り込み情報を全てキャンセルする。
28: // 各子デバイスはその ResetHard() で NegateINT() を明示的に呼び出して
29: // 割り込みをキャンセルする必要はなく、もし自身で独自に割り込み信号線の
30: // 状態に関する変数を持っていればそれをクリアするだけでよい。
31:
32: // AssertINT()、NegateINT()、ChangeINT() の呼び出し側は、
33: // (アサート中に AssertINT() を呼ぶというような) 現在の状態が
34: // 変わらないような呼び出しをしても構わない。特に副作用はない。
35:
36: // 子デバイスが割り込み信号線をアサートした
1.1.1.3 ! root 37: void AssertINT(Device *source);
1.1 root 38: // 子デバイスが割り込み信号線をネゲートした
1.1.1.3 ! root 39: void NegateINT(Device *source);
1.1 root 40:
41: // 子デバイスが割り込み信号線を val の状態に変えた。
42: // true ならアサート、false ならネゲート。
43: void ChangeINT(Device *source, bool val) {
44: if (val) {
45: AssertINT(source);
46: } else {
47: NegateINT(source);
48: }
49: }
50:
51: // MPU からの割り込みアクノリッジに応答する
52: virtual int InterruptAcknowledge(int lv) = 0;
1.1.1.3 ! root 53:
! 54: protected:
! 55: // 割り込みを上位デバイス(MPUなど)に伝達する。
! 56: // 子デバイスが割り込み信号線の状態を変えたときに呼び出される。
! 57: virtual void ChangeInterrupt() = 0;
! 58:
! 59: // Intmap について
! 60: //
! 61: // Intmap は 32bit のビットマップ値で、最大 31 個(といいつつ今の所 28 個)
! 62: // の割り込み発生の有無を個別に管理できる。
! 63: // 発生している割り込みのうち最も優先度が高い 1つを高速に検索するため、
! 64: // MSB 側を最も優先度が高い割り込みとして、Count-Leading-Zero で検索
! 65: // することにする。
! 66: // __builtin_clz(0) は動作未定義になるので、最下位ビットを常に立てて
! 67: // おくことで、割り込みなし(上位31bitがすべて0)の場合でもこの式が使える
! 68: // ようにしておく。
! 69: //
! 70: // 具体的にどの割り込みをどのビットに割り当てるかは継承先の実装によるが、
! 71: // m680x0 の場合、以下のように 1レベル 4つずつ割り当てることにする。
! 72: //
! 73: // 3 2 1 0
! 74: // 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
! 75: // +-------+-------+-------+-------+-------+-------+-------+-------+
! 76: // |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 |
! 77: // +-------+-------+-------+-------+-------+-------+-------+-------+
! 78: //
! 79: // これにより同一レベルのデバイス 4 つまでの割り込み信号線の状態を独立
! 80: // して保持しつつ、アサートされている信号線のうち最もレベルの高いものは
! 81: // 以下だけで求めることが出来る。
! 82: //
! 83: // ipl = (31 - __builtin_clz(intmap)) / 4;
! 84: //
! 85: // LUNA88K の外部割り込みコントローラであるシステムコントローラも
! 86: // 概ねこれに近いので、sysctlr もこの構造を使う。
! 87: //
! 88: // PEDEC は 7レベル分けする必要ないので、適当に割り当ててある。
! 89:
! 90: static const uint32 IntmapSentinel = 0x00000001;
! 91:
! 92: // デバイスから Intmap 値を引く。
! 93: virtual uint32 GetIntmap(Device *source) const = 0;
! 94:
! 95: // 割り込みマップ
! 96: uint32 intmap {};
! 97:
! 98: // 割り込み回数 (アサートのエッジでカウントアップする)
! 99: // [0] が Intmap の bit31 割り込みのカウント。
! 100: // [27] が Intmap の bit 4 割り込みのカウント。
! 101: uint64 counter[28] {};
1.1 root 102: };
103:
104: //
105: // m680x0 仮想割り込みコントローラ (共通部)
106: //
107: class M680x0Interrupt : public InterruptDevice
108: {
109: using inherited = InterruptDevice;
110: public:
111: static const int AutoVector = -1; // オートベクタ
112:
113: public:
114: M680x0Interrupt();
115: virtual ~M680x0Interrupt() override;
116:
117: void ResetHard() override;
118:
119: protected:
1.1.1.3 ! root 120: void ChangeInterrupt() override;
1.1 root 121:
122: // 現在の割り込みレベル
123: int ipl {};
124: };
125:
126: //
127: // X68k 仮想割り込みコントローラ
128: //
129: // Level
130: // 7 INTERRUPT スイッチ
131: // 6 MFP
132: // 5 SCC
133: // 4 (拡張ボード)
134: // 3 DMAC
135: // 2 (拡張ボード)
136: // 1 PEDEC <--+-- SPC
137: // +-- HDD (SASI)
138: // +-- FDC
139: // +-- FDD
140: // +-- PRN
141: //
142: class X68030Interrupt : public M680x0Interrupt
143: {
144: using inherited = M680x0Interrupt;
145:
146: // 割り込みマップ 76543210
147: static const uint32 IntmapNMI = 0x80000000;
148: static const uint32 IntmapMFP = 0x08000000;
149: static const uint32 IntmapSCC = 0x00800000;
150: static const uint32 IntmapDMAC = 0x00008000;
151: static const uint32 IntmapPEDEC = 0x00000080;
152:
153: public:
154: X68030Interrupt();
155: virtual ~X68030Interrupt() override;
156:
157: int InterruptAcknowledge(int lv) override;
158:
159: private:
160: uint32 GetIntmap(Device *soruce) const override;
1.1.1.2 root 161:
162: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
163:
164: Monitor monitor { this };
1.1 root 165: };
166:
167: //
168: // LUNA-I 仮想割り込みコントローラ
169: //
170: // Level
171: // 7
172: // 6 SIO
173: // 5 SystemClock
174: // 4 (XP high)
175: // 3 Lance
176: // 2 SPC
177: // 1 (XP low)
178: //
179: class LunaInterrupt : public M680x0Interrupt
180: {
181: using inherited = M680x0Interrupt;
182:
183: // 割り込みマップ 76543210
184: static const uint32 IntmapSIO = 0x08000000;
185: static const uint32 IntmapSysClk = 0x00800000;
186: static const uint32 IntmapLance = 0x00008000;
187: static const uint32 IntmapSPC = 0x00000800;
188:
189: public:
190: LunaInterrupt();
191: virtual ~LunaInterrupt() override;
192:
193: int InterruptAcknowledge(int lv) override;
194:
195: private:
196: uint32 GetIntmap(Device *source) const override;
1.1.1.2 root 197:
198: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
199:
200: Monitor monitor { this };
1.1 root 201: };
202:
203: // LUNA88K は sysctlr.cpp 参照。
204:
205: extern std::unique_ptr<InterruptDevice> gInterrupt;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.