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