|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
1.1.1.6 ! root 7: //
! 8: // 割り込みコントローラ
! 9: //
! 10:
! 11: // IODevice
! 12: // |
! 13: // | +-----------------+
! 14: // +--| InterruptDevice | (割り込みコントローラの共通部)
! 15: // +-----------------+
! 16: // | +-----------------+
! 17: // +--| M680x0Interrupt | (m68k 割り込みコントローラの共通部)
! 18: // | +-----------------+
! 19: // | |
! 20: // | | +-----------------+
! 21: // | +--| X68030Interrupt | (X68030 の割り込みコントローラ)
! 22: // | | +-----------------+
! 23: // | |
! 24: // | | +---------------+
! 25: // | +--| LunaInterrupt | (LUNA-I の割り込みコントローラ)
! 26: // | +---------------+
! 27: // |
! 28: // +-- PEDECDevice (X68030 の Lv1 担当コントローラ)
! 29: // +-- SysCtlrDevice (LUNA88K の割り込みコントローラ)
! 30:
1.1 root 31: #include "interrupt.h"
32: #include "dmac.h"
33: #include "lance.h"
34: #include "pedec.h"
35: #include "m68030.h"
36: #include "mfp.h"
37: #include "mpu680x0.h"
1.1.1.6 ! root 38: #include "nmi.h"
1.1 root 39: #include "scc.h"
40: #include "sio.h"
41: #include "spc.h"
42: #include "sysclk.h"
43:
1.1.1.6 ! root 44: // グローバル参照用
! 45: InterruptDevice *gInterrupt;
1.1 root 46:
47: //
48: // 仮想割り込みコントローラ (共通部)
49: //
50:
1.1.1.4 root 51: // コンストラクタ(オブジェクト名指定あり)
52: InterruptDevice::InterruptDevice(const std::string& objname_)
53: : inherited(objname_)
54: {
55: }
56:
57: // コンストラクタ(オブジェクト名指定なし)
1.1 root 58: InterruptDevice::InterruptDevice()
1.1.1.4 root 59: : InterruptDevice("Interrupt")
1.1 root 60: {
61: }
62:
63: // デストラクタ
64: InterruptDevice::~InterruptDevice()
65: {
1.1.1.6 ! root 66: gInterrupt = NULL;
1.1 root 67: }
68:
1.1.1.5 root 69: // リセット
70: void
1.1.1.6 ! root 71: InterruptDevice::ResetHard(bool poweron)
1.1.1.5 root 72: {
73: intmap = IntmapSentinel;
74: memset(&counter, 0, sizeof(counter));
75: }
76:
77: // 子デバイスが割り込み信号線をアサートした
78: void
79: InterruptDevice::AssertINT(Device *source)
80: {
81: uint32 oldmap;
82: uint32 srcmap;
83:
84: oldmap = intmap;
85: srcmap = GetIntmap(source);
86: intmap |= srcmap;
87:
88: if ((oldmap ^ intmap) != 0) {
89: // 立ち上がりエッジでカウント
90: counter[__builtin_clz(srcmap)]++;
91: ChangeInterrupt();
92: }
93: }
94:
95: // 子デバイスが割り込み信号線をネゲートした
96: void
97: InterruptDevice::NegateINT(Device *source)
98: {
99: uint32 oldmap;
100: uint32 srcmap;
101:
102: oldmap = intmap;
103: srcmap = GetIntmap(source);
104: intmap &= ~srcmap;
105:
106: if ((oldmap ^ intmap) != 0) {
107: ChangeInterrupt();
108: }
109: }
1.1 root 110:
111: //
112: // 仮想割り込みコントローラ (m680x0 共通部)
113: //
114:
115: // CPU コアからの割り込みアクノリッジを受け付けるグローバル関数
116: int
117: m68030_interrupt_acknowledge(int lv)
118: {
119: return gInterrupt->InterruptAcknowledge(lv);
120: }
121:
122: // コンストラクタ
123: M680x0Interrupt::M680x0Interrupt()
124: {
125: }
126:
127: // デストラクタ
128: M680x0Interrupt::~M680x0Interrupt()
129: {
130: }
131:
132: // リセット
133: void
1.1.1.6 ! root 134: M680x0Interrupt::ResetHard(bool poweron)
1.1 root 135: {
1.1.1.6 ! root 136: inherited::ResetHard(poweron);
1.1 root 137: ipl = 0;
138: }
139:
140: void
1.1.1.5 root 141: M680x0Interrupt::ChangeInterrupt()
1.1 root 142: {
143: int newipl;
144:
1.1.1.6 ! root 145: // intmap は最下位ビットを常に立ててあるので 0 にならない
1.1 root 146: newipl = (uint)(31 - __builtin_clz(intmap)) / 4;
147:
1.1.1.5 root 148: // 割り込みレベルが変わったら、新しいレベルを通知
149: if (newipl != ipl) {
1.1 root 150: ipl = newipl;
151: gMPU->Interrupt(ipl);
152: }
153: }
154:
155:
156: //
157: // X68030 仮想割り込みコントローラ
158: //
159:
160: // コンストラクタ
161: X68030Interrupt::X68030Interrupt()
162: {
1.1.1.6 ! root 163: monitor.func = ToMonitorCallback(&X68030Interrupt::MonitorUpdate);
1.1.1.5 root 164: monitor.SetSize(25, 11);
1.1.1.4 root 165: monitor.Regist(ID_MONITOR_INTERRUPT);
1.1 root 166: }
167:
168: // デストラクタ
169: X68030Interrupt::~X68030Interrupt()
170: {
171: }
172:
173: // デバイスから Intmap 値を引く
174: uint32
175: X68030Interrupt::GetIntmap(Device *source) const
176: {
1.1.1.6 ! root 177: if (__predict_true(source == gMFP)) {
1.1 root 178: return IntmapMFP;
179: }
1.1.1.6 ! root 180: if (__predict_true(source == gSCC)) {
1.1 root 181: return IntmapSCC;
182: }
1.1.1.6 ! root 183: if (__predict_true(source == gDMAC)) {
1.1 root 184: return IntmapDMAC;
185: }
1.1.1.6 ! root 186: if (__predict_true(source == gPEDEC)) {
1.1 root 187: return IntmapPEDEC;
188: }
1.1.1.6 ! root 189: if (source == gNMI) {
1.1 root 190: return IntmapNMI;
191: }
1.1.1.6 ! root 192: VMPANIC("Unknown interrupt source?");
1.1 root 193: }
194:
195: // 割り込みアクノリッジに応答する
196: int
197: X68030Interrupt::InterruptAcknowledge(int lv)
198: {
199: switch (lv) {
1.1.1.6 ! root 200: case 7:
! 201: return AutoVector;
! 202:
1.1 root 203: case 6:
204: return gMFP->InterruptAcknowledge();
205:
206: case 5:
207: return gSCC->InterruptAcknowledge();
208:
209: case 3:
210: return gDMAC->InterruptAcknowledge();
211:
212: case 1:
213: return gPEDEC->InterruptAcknowledge(lv);
214:
215: default:
216: break;
217: }
1.1.1.6 ! root 218: VMPANIC("Unknown interrupt acknowledge lv=%d", lv);
1.1 root 219: }
220:
221: void
1.1.1.4 root 222: X68030Interrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 223: {
224: int y;
225: struct {
226: const char *name;
227: uint32 map;
228: } table[] = {
229: { "NMI", IntmapNMI },
230: { "MFP", IntmapMFP },
231: { "SCC", IntmapSCC },
232: { "DMAC", IntmapDMAC },
233: { "PEDEC", IntmapPEDEC },
234: };
235:
236: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.6 ! root 237: uint intr_mask = gMPU680x0->GetCPU()->reg.intr_mask;
1.1 root 238:
1.1.1.4 root 239: screen.Clear();
1.1 root 240:
241: y = 0;
1.1.1.6 ! root 242: screen.Print(0, y++, "Lv Device Count IM=%d", intr_mask);
1.1 root 243: for (int i = 0; i < countof(table); i++) {
244: uint32 map = table[i].map;
245: int clz = __builtin_clz(map);
246: int lv = (31 - clz) / 4;
1.1.1.4 root 247: screen.Print(0, y, "%d", lv);
248: screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.5 root 249: screen.Print(8, y, "%11" PRIu64, counter[clz]);
1.1.1.6 ! root 250: if (lv <= intr_mask) {
1.1.1.5 root 251: screen.Puts(21, y, "Mask");
1.1 root 252: }
253: y++;
254: }
1.1.1.2 root 255:
1.1.1.5 root 256: // PEDEC 分も一緒に表示したい
1.1.1.6 ! root 257: gPEDEC->MonitorUpdate(screen, intr_mask, y);
1.1 root 258: }
259:
1.1.1.6 ! root 260:
1.1 root 261: //
262: // LUNA-I 仮想割り込みコントローラ
263: //
264:
265: // コンストラクタ
266: LunaInterrupt::LunaInterrupt()
267: {
1.1.1.6 ! root 268: monitor.func = ToMonitorCallback(&LunaInterrupt::MonitorUpdate);
! 269: monitor.SetSize(25, 6);
1.1.1.4 root 270: monitor.Regist(ID_MONITOR_INTERRUPT);
1.1 root 271: }
272:
273: // デストラクタ
274: LunaInterrupt::~LunaInterrupt()
275: {
276: }
277:
278: // デバイスから Intmap 値を引く
279: uint32
280: LunaInterrupt::GetIntmap(Device *source) const
281: {
1.1.1.6 ! root 282: if (__predict_true(source == gSIO)) {
1.1 root 283: return IntmapSIO;
284: }
1.1.1.6 ! root 285: if (__predict_true(source == gSysClk)) {
1.1 root 286: return IntmapSysClk;
287: }
1.1.1.6 ! root 288: if (__predict_true(source == gEthernet)) {
1.1 root 289: return IntmapLance;
290: }
1.1.1.6 ! root 291: if (__predict_true(source == gSPC)) {
1.1 root 292: return IntmapSPC;
293: }
1.1.1.6 ! root 294: if (source == gNMI) {
! 295: return IntmapNMI;
! 296: }
! 297: VMPANIC("Unknown interrupt source?");
1.1 root 298: }
299:
300: // 割り込みアクノリッジに応答する
301: int
302: LunaInterrupt::InterruptAcknowledge(int lv)
303: {
304: // LUNA は全てオートベクタ
305: return AutoVector;
306: }
307:
308: void
1.1.1.4 root 309: LunaInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 310: {
311: int y;
312: struct {
313: const char *name;
314: uint32 map;
315: } table[] = {
1.1.1.6 ! root 316: { "NMI", IntmapNMI },
1.1 root 317: { "SIO", IntmapSIO },
318: { "Clock", IntmapSysClk },
319: { "Lance", IntmapLance },
320: { "SPC", IntmapSPC },
321: };
322:
323: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.6 ! root 324: uint intr_mask = gMPU680x0->GetCPU()->reg.intr_mask;
1.1 root 325:
1.1.1.4 root 326: screen.Clear();
1.1 root 327:
328: y = 0;
1.1.1.6 ! root 329: screen.Print(0, y++, "Lv Device Count IM=%d", intr_mask);
1.1 root 330: for (int i = 0; i < countof(table); i++) {
331: uint32 map = table[i].map;
332: int clz = __builtin_clz(map);
333: int lv = (31 - clz) / 4;
1.1.1.4 root 334: screen.Print(0, y, "%d", lv);
335: screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.5 root 336: screen.Print(8, y, "%11" PRIu64, counter[clz]);
1.1.1.6 ! root 337: if (lv <= intr_mask) {
1.1.1.5 root 338: screen.Puts(21, y, "Mask");
1.1 root 339: }
340: y++;
341: }
342: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.