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