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