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