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