|
|
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 担当コントローラ)
1.1.1.7 root 29: // +-- SysCtlrDevice (LUNA-88K の割り込みコントローラ)
1.1.1.6 root 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.7 root 38: #include "newsctlr.h"
1.1.1.6 root 39: #include "nmi.h"
1.1.1.8 ! root 40: #include "rtl8019as.h"
1.1 root 41: #include "scc.h"
42: #include "sio.h"
43: #include "spc.h"
44: #include "sysclk.h"
45:
46: //
47: // 仮想割り込みコントローラ (共通部)
48: //
49:
1.1.1.7 root 50: // コンストラクタ(オブジェクト名指定なし)
51: InterruptDevice::InterruptDevice()
52: : InterruptDevice(OBJ_INTERRUPT) // 移譲
1.1.1.4 root 53: {
54: }
55:
1.1.1.7 root 56: // コンストラクタ(オブジェクト名指定あり)
57: InterruptDevice::InterruptDevice(int objid_)
58: : inherited(objid_)
1.1 root 59: {
60: }
61:
62: // デストラクタ
63: InterruptDevice::~InterruptDevice()
64: {
65: }
66:
1.1.1.5 root 67: // リセット
68: void
1.1.1.6 root 69: InterruptDevice::ResetHard(bool poweron)
1.1.1.5 root 70: {
71: intmap = IntmapSentinel;
72: memset(&counter, 0, sizeof(counter));
73: }
74:
75: // 子デバイスが割り込み信号線をアサートした
76: void
77: InterruptDevice::AssertINT(Device *source)
78: {
79: uint32 oldmap;
80: uint32 srcmap;
81:
82: oldmap = intmap;
83: srcmap = GetIntmap(source);
84: intmap |= srcmap;
85:
86: if ((oldmap ^ intmap) != 0) {
87: // 立ち上がりエッジでカウント
88: counter[__builtin_clz(srcmap)]++;
89: ChangeInterrupt();
90: }
91: }
92:
93: // 子デバイスが割り込み信号線をネゲートした
94: void
95: InterruptDevice::NegateINT(Device *source)
96: {
97: uint32 oldmap;
98: uint32 srcmap;
99:
100: oldmap = intmap;
101: srcmap = GetIntmap(source);
102: intmap &= ~srcmap;
103:
104: if ((oldmap ^ intmap) != 0) {
105: ChangeInterrupt();
106: }
107: }
1.1 root 108:
1.1.1.8 ! root 109: // 割り込み信号線の状態を取得
! 110: bool
! 111: InterruptDevice::GetINT(const Device *source) const
! 112: {
! 113: uint32 srcmap;
! 114:
! 115: srcmap = GetIntmap(source);
! 116:
! 117: return (intmap & srcmap);
! 118: }
! 119:
! 120:
1.1 root 121: //
122: // 仮想割り込みコントローラ (m680x0 共通部)
123: //
124:
125: // コンストラクタ
126: M680x0Interrupt::M680x0Interrupt()
127: {
128: }
129:
130: // デストラクタ
131: M680x0Interrupt::~M680x0Interrupt()
132: {
133: }
134:
1.1.1.7 root 135: // 初期化
136: bool
137: M680x0Interrupt::Init()
138: {
139: if (inherited::Init() == false) {
140: return false;
141: }
142:
143: return true;
144: }
145:
1.1 root 146: // リセット
147: void
1.1.1.6 root 148: M680x0Interrupt::ResetHard(bool poweron)
1.1 root 149: {
1.1.1.6 root 150: inherited::ResetHard(poweron);
1.1 root 151: ipl = 0;
152: }
153:
154: void
1.1.1.5 root 155: M680x0Interrupt::ChangeInterrupt()
1.1 root 156: {
157: int newipl;
158:
1.1.1.6 root 159: // intmap は最下位ビットを常に立ててあるので 0 にならない
1.1 root 160: newipl = (uint)(31 - __builtin_clz(intmap)) / 4;
161:
1.1.1.5 root 162: // 割り込みレベルが変わったら、新しいレベルを通知
163: if (newipl != ipl) {
1.1 root 164: ipl = newipl;
1.1.1.7 root 165: mpu->Interrupt(ipl);
1.1 root 166: }
167: }
168:
169:
170: //
171: // X68030 仮想割り込みコントローラ
172: //
173:
174: // コンストラクタ
175: X68030Interrupt::X68030Interrupt()
176: {
1.1.1.6 root 177: monitor.func = ToMonitorCallback(&X68030Interrupt::MonitorUpdate);
1.1.1.8 ! root 178: monitor.SetSize(41, 13);
1.1.1.4 root 179: monitor.Regist(ID_MONITOR_INTERRUPT);
1.1 root 180: }
181:
182: // デストラクタ
183: X68030Interrupt::~X68030Interrupt()
184: {
185: }
186:
1.1.1.7 root 187: // 初期化
188: bool
189: X68030Interrupt::Init()
190: {
191: if (inherited::Init() == false) {
192: return false;
193: }
194:
195: dmac = GetDMACDevice();
196: mfp = GetMFPDevice();
1.1.1.8 ! root 197: // Nereid は拡張ボードなので存在しない可能性がある
! 198: for (int i = 0; i < 2; i++) {
! 199: net[i] = gMainApp.FindObject<RTL8019ASDevice>(OBJ_ETHERNET(i));
! 200: }
1.1.1.7 root 201: nmi = GetNMIDevice();
202: pedec = GetPEDECDevice();
203: scc = GetSCCDevice();
204:
205: return true;
206: }
207:
1.1 root 208: // デバイスから Intmap 値を引く
209: uint32
1.1.1.8 ! root 210: X68030Interrupt::GetIntmap(const Device *source) const
1.1 root 211: {
1.1.1.7 root 212: if (__predict_true(source == mfp)) {
1.1 root 213: return IntmapMFP;
214: }
1.1.1.7 root 215: if (__predict_true(source == scc)) {
1.1 root 216: return IntmapSCC;
217: }
1.1.1.8 ! root 218: if (__predict_true(source == net[0])) {
! 219: return IntmapNereid0;
! 220: }
! 221: if (__predict_true(source == net[1])) {
! 222: return IntmapNereid1;
! 223: }
1.1.1.7 root 224: if (__predict_true(source == dmac)) {
1.1 root 225: return IntmapDMAC;
226: }
1.1.1.7 root 227: if (__predict_true(source == pedec)) {
1.1 root 228: return IntmapPEDEC;
229: }
1.1.1.7 root 230: if (source == nmi) {
1.1 root 231: return IntmapNMI;
232: }
1.1.1.6 root 233: VMPANIC("Unknown interrupt source?");
1.1 root 234: }
235:
236: // 割り込みアクノリッジに応答する
237: int
238: X68030Interrupt::InterruptAcknowledge(int lv)
239: {
240: switch (lv) {
1.1.1.6 root 241: case 7:
242: return AutoVector;
243:
1.1 root 244: case 6:
1.1.1.7 root 245: return mfp->InterruptAcknowledge();
1.1 root 246:
247: case 5:
1.1.1.7 root 248: return scc->InterruptAcknowledge();
1.1 root 249:
1.1.1.8 ! root 250: case 4:
! 251: for (int i = 0; i < 2; i++) {
! 252: if (net[i]) {
! 253: return net[i]->InterruptAcknowledge();
! 254: }
! 255: }
! 256: break;
! 257:
1.1 root 258: case 3:
1.1.1.7 root 259: return dmac->InterruptAcknowledge();
1.1 root 260:
261: case 1:
1.1.1.7 root 262: return pedec->InterruptAcknowledge(lv);
1.1 root 263:
264: default:
265: break;
266: }
1.1.1.6 root 267: VMPANIC("Unknown interrupt acknowledge lv=%d", lv);
1.1 root 268: }
269:
270: void
1.1.1.4 root 271: X68030Interrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 272: {
273: int y;
274: struct {
275: const char *name;
276: uint32 map;
277: } table[] = {
1.1.1.8 ! root 278: { "NMI", IntmapNMI },
! 279: { "MFP", IntmapMFP },
! 280: { "SCC", IntmapSCC },
! 281: { "Nereid0", IntmapNereid0 },
! 282: { "Nereid1", IntmapNereid1 },
! 283: { "DMAC", IntmapDMAC },
! 284: { "PEDEC", IntmapPEDEC },
1.1 root 285: };
286:
287: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.7 root 288: auto mpu680x0 = dynamic_cast<MPU680x0Device*>(mpu);
289: uint intr_mask = mpu680x0->reg.intr_mask;
1.1 root 290:
1.1.1.4 root 291: screen.Clear();
1.1 root 292:
1.1.1.7 root 293: // 0 1 2 3 4
294: // 01234567890123456789012345678901234567890
1.1.1.8 ! root 295: // Lv Device IM=7 Count
! 296: // 1 Nereid0 01234567890123456789012345
! 297: // SPC Mask
1.1.1.7 root 298:
1.1 root 299: y = 0;
1.1.1.8 ! root 300: screen.Print(0, y, "Lv Device IM=%d", intr_mask);
! 301: screen.Puts(36, y, "Count");
1.1.1.7 root 302: y++;
1.1 root 303: for (int i = 0; i < countof(table); i++) {
304: uint32 map = table[i].map;
305: int clz = __builtin_clz(map);
306: int lv = (31 - clz) / 4;
1.1.1.4 root 307: screen.Print(0, y, "%d", lv);
1.1.1.8 ! root 308: if ((map == IntmapNereid0 && net[0] == NULL) ||
! 309: (map == IntmapNereid1 && net[1] == NULL))
! 310: {
! 311: screen.Puts(3, y, TA::Disable, table[i].name);
! 312: } else {
! 313: screen.Puts(3, y, TA::OnOff(intmap & map), table[i].name);
! 314: }
1.1.1.6 root 315: if (lv <= intr_mask) {
1.1.1.8 ! root 316: screen.Puts(11, y, "Mask");
1.1 root 317: }
1.1.1.8 ! root 318: screen.Print(15, y, "%26s", format_number(counter[clz]).c_str());
1.1 root 319: y++;
320: }
1.1.1.2 root 321:
1.1.1.5 root 322: // PEDEC 分も一緒に表示したい
1.1.1.7 root 323: pedec->MonitorUpdate(screen, intr_mask, y);
1.1 root 324: }
325:
1.1.1.6 root 326:
1.1 root 327: //
328: // LUNA-I 仮想割り込みコントローラ
329: //
330:
331: // コンストラクタ
332: LunaInterrupt::LunaInterrupt()
333: {
1.1.1.6 root 334: monitor.func = ToMonitorCallback(&LunaInterrupt::MonitorUpdate);
1.1.1.7 root 335: monitor.SetSize(40, 8);
1.1.1.4 root 336: monitor.Regist(ID_MONITOR_INTERRUPT);
1.1 root 337: }
338:
339: // デストラクタ
340: LunaInterrupt::~LunaInterrupt()
341: {
342: }
343:
1.1.1.7 root 344: // 初期化
345: bool
346: LunaInterrupt::Init()
347: {
348: if (inherited::Init() == false) {
349: return false;
350: }
351:
352: lance = GetLanceDevice();
353: nmi = GetNMIDevice();
354: sio = GetSIODevice();
355: spc = GetSPCDevice();
356: sysclk = GetSysClkDevice();
357:
358: return true;
359: }
360:
1.1 root 361: // デバイスから Intmap 値を引く
362: uint32
1.1.1.8 ! root 363: LunaInterrupt::GetIntmap(const Device *source) const
1.1 root 364: {
1.1.1.7 root 365: if (__predict_true(source == sio)) {
1.1 root 366: return IntmapSIO;
367: }
1.1.1.7 root 368: if (__predict_true(source == sysclk)) {
1.1 root 369: return IntmapSysClk;
370: }
1.1.1.7 root 371: if (__predict_true(source == lance)) {
1.1 root 372: return IntmapLance;
373: }
1.1.1.7 root 374: if (__predict_true(source == spc)) {
1.1 root 375: return IntmapSPC;
376: }
1.1.1.7 root 377: if (__predict_true(source == DEVICE_XPINT_HIGH)) {
378: return IntmapXPHigh;
379: }
380: if (__predict_true(source == DEVICE_XPINT_LOW)) {
381: return IntmapXPLow;
382: }
383: if (source == nmi) {
1.1.1.6 root 384: return IntmapNMI;
385: }
386: VMPANIC("Unknown interrupt source?");
1.1 root 387: }
388:
389: // 割り込みアクノリッジに応答する
390: int
391: LunaInterrupt::InterruptAcknowledge(int lv)
392: {
393: // LUNA は全てオートベクタ
394: return AutoVector;
395: }
396:
397: void
1.1.1.4 root 398: LunaInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 399: {
400: int y;
401: struct {
402: const char *name;
403: uint32 map;
404: } table[] = {
1.1.1.6 root 405: { "NMI", IntmapNMI },
1.1 root 406: { "SIO", IntmapSIO },
407: { "Clock", IntmapSysClk },
1.1.1.7 root 408: { "XP(Hi)", IntmapXPHigh },
1.1 root 409: { "Lance", IntmapLance },
410: { "SPC", IntmapSPC },
1.1.1.7 root 411: { "XP(Lo)", IntmapXPLow },
412: };
413:
414: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
415: auto mpu680x0 = dynamic_cast<MPU680x0Device*>(mpu);
416: uint intr_mask = mpu680x0->reg.intr_mask;
417:
418: screen.Clear();
419:
420: // 0 1 2 3 4
421: // 01234567890123456789012345678901234567890
422: // Lv Device IM=7 Count
423: // 1 XP(Hi) Mask01234567890123456789012345
424:
425: y = 0;
426: screen.Print(0, y, "Lv Device IM=%d", intr_mask);
427: screen.Puts(35, y, "Count");
428: y++;
429: for (int i = 0; i < countof(table); i++) {
430: uint32 map = table[i].map;
431: int clz = __builtin_clz(map);
432: int lv = (31 - clz) / 4;
433: screen.Print(0, y, "%d", lv);
434: screen.Print(3, y, TA::OnOff(intmap & map), "%s", table[i].name);
435: if (lv <= intr_mask) {
436: screen.Puts(10, y, "Mask");
437: }
438: screen.Print(14, y, "%26s", format_number(counter[clz]).c_str());
439: y++;
440: }
441: }
442:
443:
444: //
445: // NEWS 仮想割り込みコントローラ
446: //
447:
448: // コンストラクタ
449: NewsInterrupt::NewsInterrupt()
450: {
451: monitor.func = ToMonitorCallback(&NewsInterrupt::MonitorUpdate);
452: monitor.SetSize(40, 5);
453: monitor.Regist(ID_MONITOR_INTERRUPT);
454: }
455:
456: // デストラクタ
457: NewsInterrupt::~NewsInterrupt()
458: {
459: }
460:
461: // 初期化
462: bool
463: NewsInterrupt::Init()
464: {
465: if (inherited::Init() == false) {
466: return false;
467: }
468:
469: lance = GetLanceDevice();
470: newsctlr = GetNewsCtlrDevice();
471: scc = GetSCCDevice();
472:
473: return true;
474: }
475:
476: // デバイスから Intmap 値を引く
477: uint32
1.1.1.8 ! root 478: NewsInterrupt::GetIntmap(const Device *source) const
1.1.1.7 root 479: {
480: if (__predict_true(source == newsctlr)) {
481: return IntmapTimer;
482: }
483: if (__predict_true(source == scc)) {
484: return IntmapSCC;
485: }
486: if (__predict_true(source == lance)) {
487: return IntmapLance;
488: }
489: VMPANIC("Unknown interrupt source?");
490: }
491:
492: // 割り込みアクノリッジに応答する
493: int
494: NewsInterrupt::InterruptAcknowledge(int lv)
495: {
496: // NEWS では 5 の SCC だけベクタで、他はオートベクタ?
497: switch (lv) {
498: case 5:
499: return scc->InterruptAcknowledge();
500:
501: default:
502: return AutoVector;
503: }
504: }
505:
506: // ステータスバイトを読み出す。NewsCtlr から呼ばれる。
507: uint8
508: NewsInterrupt::PeekStatus() const
509: {
510: uint8 data = 0;
511:
512: if ((intmap & IntmapSIC)) {
513: data |= 0x80;
514: }
515: if ((intmap & IntmapLance)) {
516: data |= 0x04;
517: }
518:
519: return data;
520: }
521:
522: void
523: NewsInterrupt::MonitorUpdate(Monitor *, TextScreen& screen)
524: {
525: int y;
526: struct {
527: const char *name;
528: uint32 map;
529: } table[] = {
530: { "Timer", IntmapTimer },
531: { "SCC", IntmapSCC },
532: { "Lance", IntmapLance },
1.1 root 533: };
534:
535: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
1.1.1.7 root 536: auto mpu680x0 = dynamic_cast<MPU680x0Device*>(mpu);
537: uint intr_mask = mpu680x0->reg.intr_mask;
1.1 root 538:
1.1.1.4 root 539: screen.Clear();
1.1 root 540:
1.1.1.7 root 541: // 0 1 2 3 4
542: // 01234567890123456789012345678901234567890
543: // Lv Device IM=7 Count
544: // 1 XP(Hi) Mask01234567890123456789012345
545:
1.1 root 546: y = 0;
1.1.1.7 root 547: screen.Print(0, y, "Lv Device IM=%d", intr_mask);
548: screen.Puts(35, y, "Count");
549: y++;
1.1 root 550: for (int i = 0; i < countof(table); i++) {
551: uint32 map = table[i].map;
552: int clz = __builtin_clz(map);
553: int lv = (31 - clz) / 4;
1.1.1.4 root 554: screen.Print(0, y, "%d", lv);
1.1.1.7 root 555: screen.Print(3, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.6 root 556: if (lv <= intr_mask) {
1.1.1.7 root 557: screen.Puts(10, y, "Mask");
1.1 root 558: }
1.1.1.7 root 559: screen.Print(14, y, "%26s", format_number(counter[clz]).c_str());
1.1 root 560: y++;
561: }
562: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.