|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
1.1.1.4 root 7: //
8: // 割り込みコントローラ
9: //
10:
1.1 root 11: #pragma once
12:
13: #include "device.h"
1.1.1.2 root 14: #include "monitor.h"
1.1.1.6 ! root 15: #include <array>
1.1 root 16:
1.1.1.5 root 17: // XP からの割り込み用。
18: // これだけ1デバイスで2本あるので、仕方なく識別子を用意。
19: #define DEVICE_XPINT_HIGH ((Device *)(intptr_t)1)
20: #define DEVICE_XPINT_LOW ((Device *)(intptr_t)2)
21:
22: class DMACDevice;
23: class LanceDevice;
24: class MFPDevice;
25: class NewsCtlrDevice;
26: class NMIDevice;
27: class PEDECDevice;
1.1.1.6 ! root 28: class RTL8019ASDevice;
1.1.1.5 root 29: class SCCDevice;
30: class SIODevice;
31: class SPCDevice;
32: class SysClkDevice;
33:
1.1.1.4 root 34: // 割り込みを受け付けるデバイス。
1.1 root 35: // これ自体は IODevice である必要はないが、PEDEC や SysCtlr がこれを
36: // 継承するため。
37: class InterruptDevice : public IODevice
38: {
39: using inherited = IODevice;
40: public:
41: InterruptDevice();
1.1.1.5 root 42: InterruptDevice(int objid_);
1.1 root 43: virtual ~InterruptDevice() override;
44:
45: // 継承クラスの ResetHard() は保持している割り込み情報を全てキャンセルする。
46: // 各子デバイスはその ResetHard() で NegateINT() を明示的に呼び出して
47: // 割り込みをキャンセルする必要はなく、もし自身で独自に割り込み信号線の
48: // 状態に関する変数を持っていればそれをクリアするだけでよい。
1.1.1.4 root 49: void ResetHard(bool poweron) override;
1.1 root 50:
51: // AssertINT()、NegateINT()、ChangeINT() の呼び出し側は、
52: // (アサート中に AssertINT() を呼ぶというような) 現在の状態が
53: // 変わらないような呼び出しをしても構わない。特に副作用はない。
54:
55: // 子デバイスが割り込み信号線をアサートした
1.1.1.3 root 56: void AssertINT(Device *source);
1.1 root 57: // 子デバイスが割り込み信号線をネゲートした
1.1.1.3 root 58: void NegateINT(Device *source);
1.1 root 59:
60: // 子デバイスが割り込み信号線を val の状態に変えた。
61: // true ならアサート、false ならネゲート。
62: void ChangeINT(Device *source, bool val) {
63: if (val) {
64: AssertINT(source);
65: } else {
66: NegateINT(source);
67: }
68: }
69:
70: // MPU からの割り込みアクノリッジに応答する
71: virtual int InterruptAcknowledge(int lv) = 0;
1.1.1.3 root 72:
1.1.1.6 ! root 73: // 割り込み信号線の状態を取得する
! 74: bool GetINT(const Device *source) const;
! 75:
1.1.1.3 root 76: protected:
77: // 割り込みを上位デバイス(MPUなど)に伝達する。
78: // 子デバイスが割り込み信号線の状態を変えたときに呼び出される。
79: virtual void ChangeInterrupt() = 0;
80:
81: // Intmap について
82: //
83: // Intmap は 32bit のビットマップ値で、最大 31 個(といいつつ今の所 28 個)
84: // の割り込み発生の有無を個別に管理できる。
85: // 発生している割り込みのうち最も優先度が高い 1つを高速に検索するため、
86: // MSB 側を最も優先度が高い割り込みとして、Count-Leading-Zero で検索
87: // することにする。
88: // __builtin_clz(0) は動作未定義になるので、最下位ビットを常に立てて
89: // おくことで、割り込みなし(上位31bitがすべて0)の場合でもこの式が使える
90: // ようにしておく。
91: //
92: // 具体的にどの割り込みをどのビットに割り当てるかは継承先の実装によるが、
93: // m680x0 の場合、以下のように 1レベル 4つずつ割り当てることにする。
94: //
95: // 3 2 1 0
96: // 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
97: // +-------+-------+-------+-------+-------+-------+-------+-------+
98: // |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 |
99: // +-------+-------+-------+-------+-------+-------+-------+-------+
100: //
101: // これにより同一レベルのデバイス 4 つまでの割り込み信号線の状態を独立
102: // して保持しつつ、アサートされている信号線のうち最もレベルの高いものは
103: // 以下だけで求めることが出来る。
104: //
105: // ipl = (31 - __builtin_clz(intmap)) / 4;
106: //
1.1.1.5 root 107: // LUNA-88K の外部割り込みコントローラであるシステムコントローラも
1.1.1.3 root 108: // 概ねこれに近いので、sysctlr もこの構造を使う。
109: //
110: // PEDEC は 7レベル分けする必要ないので、適当に割り当ててある。
111:
112: static const uint32 IntmapSentinel = 0x00000001;
113:
114: // デバイスから Intmap 値を引く。
1.1.1.6 ! root 115: virtual uint32 GetIntmap(const Device *source) const = 0;
1.1.1.3 root 116:
117: // 割り込みマップ
118: uint32 intmap {};
119:
120: // 割り込み回数 (アサートのエッジでカウントアップする)
121: // [0] が Intmap の bit31 割り込みのカウント。
122: // [27] が Intmap の bit 4 割り込みのカウント。
123: uint64 counter[28] {};
1.1 root 124: };
125:
126: // m680x0 仮想割り込みコントローラ (共通部)
127: class M680x0Interrupt : public InterruptDevice
128: {
129: using inherited = InterruptDevice;
130: public:
131: static const int AutoVector = -1; // オートベクタ
132:
133: public:
134: M680x0Interrupt();
135: virtual ~M680x0Interrupt() override;
136:
1.1.1.5 root 137: bool Init() override;
1.1.1.4 root 138: void ResetHard(bool poweron) override;
1.1 root 139:
140: protected:
1.1.1.3 root 141: void ChangeInterrupt() override;
1.1 root 142:
143: // 現在の割り込みレベル
144: int ipl {};
145: };
146:
147: // X68k 仮想割り込みコントローラ
148: //
149: // Level
150: // 7 INTERRUPT スイッチ
151: // 6 MFP
152: // 5 SCC
153: // 4 (拡張ボード)
154: // 3 DMAC
155: // 2 (拡張ボード)
156: // 1 PEDEC <--+-- SPC
157: // +-- HDD (SASI)
158: // +-- FDC
159: // +-- FDD
160: // +-- PRN
161: //
162: class X68030Interrupt : public M680x0Interrupt
163: {
164: using inherited = M680x0Interrupt;
165:
166: // 割り込みマップ 76543210
167: static const uint32 IntmapNMI = 0x80000000;
168: static const uint32 IntmapMFP = 0x08000000;
169: static const uint32 IntmapSCC = 0x00800000;
1.1.1.6 ! root 170: static const uint32 IntmapNereid0 = 0x00080000;
! 171: static const uint32 IntmapNereid1 = 0x00040000;
1.1 root 172: static const uint32 IntmapDMAC = 0x00008000;
173: static const uint32 IntmapPEDEC = 0x00000080;
174:
175: public:
176: X68030Interrupt();
177: virtual ~X68030Interrupt() override;
178:
1.1.1.5 root 179: bool Init() override;
1.1 root 180: int InterruptAcknowledge(int lv) override;
181:
182: private:
1.1.1.6 ! root 183: uint32 GetIntmap(const Device *soruce) const override;
1.1.1.2 root 184:
185: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
186:
1.1.1.5 root 187: DMACDevice *dmac {};
188: MFPDevice *mfp {};
189: NMIDevice *nmi {};
190: PEDECDevice *pedec {};
1.1.1.6 ! root 191: std::array<RTL8019ASDevice *, 2> net {};
1.1.1.5 root 192: SCCDevice *scc {};
193:
1.1.1.2 root 194: Monitor monitor { this };
1.1 root 195: };
196:
197: // LUNA-I 仮想割り込みコントローラ
198: //
199: // Level
200: // 7
201: // 6 SIO
202: // 5 SystemClock
203: // 4 (XP high)
204: // 3 Lance
205: // 2 SPC
206: // 1 (XP low)
207: //
208: class LunaInterrupt : public M680x0Interrupt
209: {
210: using inherited = M680x0Interrupt;
211:
212: // 割り込みマップ 76543210
1.1.1.4 root 213: static const uint32 IntmapNMI = 0x80000000;
1.1 root 214: static const uint32 IntmapSIO = 0x08000000;
215: static const uint32 IntmapSysClk = 0x00800000;
1.1.1.5 root 216: static const uint32 IntmapXPHigh = 0x00400000;
1.1 root 217: static const uint32 IntmapLance = 0x00008000;
218: static const uint32 IntmapSPC = 0x00000800;
1.1.1.5 root 219: static const uint32 IntmapXPLow = 0x00000080;
1.1 root 220:
221: public:
222: LunaInterrupt();
223: virtual ~LunaInterrupt() override;
224:
1.1.1.5 root 225: bool Init() override;
226: int InterruptAcknowledge(int lv) override;
227:
228: private:
1.1.1.6 ! root 229: uint32 GetIntmap(const Device *source) const override;
1.1.1.5 root 230:
231: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
232:
233: LanceDevice *lance {};
234: NMIDevice *nmi {};
235: SIODevice *sio {};
236: SPCDevice *spc {};
237: SysClkDevice *sysclk {};
238:
239: Monitor monitor { this };
240: };
241:
242: // NEWS 仮想割り込みコントローラ
243: //
244: // Level
245: // 7
246: // 6 Timer
247: // 5 SCC(vectored)
248: // 4 SIC, Lance
249: // 3
250: // 2
251: // 1
252: //
253: class NewsInterrupt : public M680x0Interrupt
254: {
255: using inherited = M680x0Interrupt;
256:
257: // 割り込みマップ 76543210
258: static const uint32 IntmapNMI = 0x80000000;
259: static const uint32 IntmapTimer = 0x08000000;
260: static const uint32 IntmapSCC = 0x00800000;
261: static const uint32 IntmapSIC = 0x00080000;
262: static const uint32 IntmapLance = 0x00040000;
263:
264: public:
265: NewsInterrupt();
266: virtual ~NewsInterrupt() override;
267:
268: bool Init() override;
1.1 root 269: int InterruptAcknowledge(int lv) override;
270:
1.1.1.5 root 271: // 割り込みステータスを返す (NewsCtlr から呼ばれる)
272: uint8 PeekStatus() const;
273:
1.1 root 274: private:
1.1.1.6 ! root 275: uint32 GetIntmap(const Device *source) const override;
1.1.1.2 root 276:
277: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
278:
1.1.1.5 root 279: LanceDevice *lance {};
280: NewsCtlrDevice *newsctlr {};
281: SCCDevice *scc {};
282:
1.1.1.2 root 283: Monitor monitor { this };
1.1 root 284: };
285:
1.1.1.5 root 286: // LUNA-88K は sysctlr.cpp 参照。
1.1 root 287:
1.1.1.5 root 288: static inline InterruptDevice *GetInterruptDevice() {
289: return Object::GetObject<InterruptDevice>(OBJ_INTERRUPT);
290: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.