|
|
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: {
137: monitor_size = nnSize(24, 6);
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 },
204: };
205:
206: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
207: uint intr_level = gMPU680x0->GetCPU()->reg.intr_level;
208:
209: monitor.Clear();
210:
211: y = 0;
212: monitor.Print(0, y++, "Lv Device Count IM=%d", intr_level);
213: for (int i = 0; i < countof(table); i++) {
214: uint32 map = table[i].map;
215: int clz = __builtin_clz(map);
216: int lv = (31 - clz) / 4;
217: monitor.Print(0, y, "%d", lv);
218: monitor.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
219: monitor.Print(8, y, "%10u", counter[clz]);
220: if (lv <= intr_level) {
221: monitor.Puts(20, y, "Mask");
222: }
223: y++;
224: }
225: // XXX PEDEC 分もここに表示したい
226: }
227:
228: //
229: // LUNA-I 仮想割り込みコントローラ
230: //
231:
232: // コンストラクタ
233: LunaInterrupt::LunaInterrupt()
234: {
235: monitor_size = nnSize(24, 5);
236: }
237:
238: // デストラクタ
239: LunaInterrupt::~LunaInterrupt()
240: {
241: }
242:
243:
244: // デバイスから Intmap 値を引く
245: uint32
246: LunaInterrupt::GetIntmap(Device *source) const
247: {
248: if (__predict_true(source == gSIO.get())) {
249: return IntmapSIO;
250: }
251: if (__predict_true(source == gSysClk.get())) {
252: return IntmapSysClk;
253: }
254: if (__predict_true(source == gEthernet.get())) {
255: return IntmapLance;
256: }
257: if (__predict_true(source == gSPC.get())) {
258: return IntmapSPC;
259: }
260: PANIC("Unknown interrupt source?");
261: }
262:
263: // 割り込みアクノリッジに応答する
264: int
265: LunaInterrupt::InterruptAcknowledge(int lv)
266: {
267: // LUNA は全てオートベクタ
268: return AutoVector;
269: }
270:
271: void
272: LunaInterrupt::MonitorUpdate(TextScreen& monitor)
273: {
274: int y;
275: struct {
276: const char *name;
277: uint32 map;
278: } table[] = {
279: { "SIO", IntmapSIO },
280: { "Clock", IntmapSysClk },
281: { "Lance", IntmapLance },
282: { "SPC", IntmapSPC },
283: };
284:
285: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
286: uint intr_level = gMPU680x0->GetCPU()->reg.intr_level;
287:
288: monitor.Clear();
289:
290: y = 0;
291: monitor.Print(0, y++, "Lv Device Count IM=%d", intr_level);
292: for (int i = 0; i < countof(table); i++) {
293: uint32 map = table[i].map;
294: int clz = __builtin_clz(map);
295: int lv = (31 - clz) / 4;
296: monitor.Print(0, y, "%d", lv);
297: monitor.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
298: monitor.Print(8, y, "%10u", counter[clz]);
299: if (lv <= intr_level) {
300: monitor.Puts(20, y, "Mask");
301: }
302: y++;
303: }
304: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.