|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
1.1.1.8 root 7: //
1.1 root 8: // LUNA88K のシステムコントローラのような何か
1.1.1.8 root 9: //
1.1 root 10:
1.1.1.8 root 11: // IODevice
12: // |
13: // +-- InterruptDevice (割り込みコントローラの共通部)
14: // |
15: // +-- M680x0Interrupt (m68k 割り込みコントローラの共通部)
16: // | |
17: // | +-- X68030Interrupt (X68030 の割り込みコントローラ)
18: // | +-- LunaInterrupt (LUNA-I の割り込みコントローラ)
19: // |
20: // +-- PEDECDevice (X68030 の Lv1 担当コントローラ)
21: // |
22: // | +---------------+
23: // +--| SysCtlrDevice | (LUNA88K の割り込みコントローラ)
24: // +---------------+
1.1 root 25:
26: // この辺を全部一つのデバイスで受け付けておくか。BusIO はまた後で考える。
27: // $6500000n.b HW 割り込みレベル (n*4 = CPU#n)
28: // $65000000.b CPU#0
29: // $65000004.b CPU#1
30: // $65000008.b CPU#2
31: // $6500000c.b CPU#3
32: // $6900000n ソフトウェア割り込み(?)
33: // $6d00000n CPU#n をリセット(?)
34: // $6d000010 全 CPU をリセット
35:
36: // LUNA88K
37: // 割り込みコントロールレジスタ
38: // $6500_000n
39: // n: CPU ID * 4 (0,4,8,c)
40: // この16Mページ内はミラーされている模様。
41: // 下位2bitしかデコードしていない?
42: // 書き込み時:
43: // 3 2 1
44: // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
45: // +-+-+-+-+-+-+---------------------------------------------------+
46: // |6|5|4|3|2|1| |
47: // +-+-+-+-+-+-+---------------------------------------------------+
48: // bit31: 1=割り込み 6 イネーブル
49: // bit30: 1=割り込み 5 イネーブル
50: // bit29: 1=割り込み 4 イネーブル
51: // bit28: 1=割り込み 3 イネーブル
52: // bit27: 1=割り込み 2 イネーブル
53: // bit26: 1=割り込み 1 イネーブル
54: // m68k と異なり、個別の割り込みごとに許可/禁止できる。
55: // 該当ビットに 1 を書き込むと許可。
56: // 空欄部分は無視される模様。
57: //
58: // 読み込み時
59: // 3 2 1
60: // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
61: // +-----+---------+-+-+-+-+-+-+-----------------------------------+
62: // |Level| |6|5|4|3|2|1| |
63: // +-----+---------+-+-+-+-+-+-+-----------------------------------+
64: // bit31-29: 発生している最上位レベルの割り込み。範囲は7-0
65: // bit23-18: 書き込んだ割り込みマスク。
66: // 空欄部分は「不定」の模様。
67: //
68: // bit31-29 のレベルは、割り込みコントローラに入力
69: // されている割り込み信号線6本を、マスク処理した後、
70: // プライオリティバイナリエンコーダの値がそのまま出力されている模様。
71: // ラッチ機構は無いようだ。
72: // したがってマスクされている割り込み(マスクビットが 0) の
73: // 値が出力されることはない。
74: // 同時に入力があった場合は、数字の大きいほうが出力される。
75: // レベル7 はマスクなしでプライオリティエンコーダに入力されているようだ。
76: //
77: // 割り込み入力がないときは 0 になる模様。
78: // 本体 ABRT スイッチを押すと、押している間、すべての CPU の
79: // level が 111(=7) になる。離すと戻る。
80: // 88100 には NMI が無いので、通常の割り込みと同じように処理している?
81: // (なので IND 状態だとABRT できない。いいのかそれで)
82: // (OpenBSD6.7 の割り込みハンドラはABRTには対応していないように読める)
83: //
84: // 想定される回路
85: //
86: // [割り込みソース]
87: // 1:SOFTINT レジスタ $6900000n
88: // | 2:(XP 低レベル?)
89: // | | 3:SPC
90: // | | | 4:(LANCE|拡張スロット?)
91: // | | | | 5:(拡張PC98?|シリアル?)
92: // | | | | | 6:(XP 高レベル?|システムクロック?)
93: // | | | | | | 7:ABRTスイッチ
94: // V V V V V V |
95: // +---------------------+ |
96: // | 割り込みマスク | | (R:bit23-18, W:bit31-26)
97: // +---------------------+ |
98: // | | | | | | |
99: // V V V V V V V
100: // +-------------------------+
101: // |プライオリティエンコーダ |-> (R:bit31-29)
102: // +-------------------------+
1.1.1.3 root 103: // | | |
104: // V V V
105: // (Wired-OR)
106: // |
107: // [M88K INT]
1.1 root 108: //
1.1.1.3 root 109: // LUNA-I とはレベル配置が違う。
1.1 root 110: //
111: // 割り込みソース調査状況
112: // 1:SOFTINT レジスタ $6900000n
113: // ROM のメモリコマンドで確認。OpenBSD machdep.c の記述の通り。
114: // 2:XP 低レベル
115: // LUNA-I からの類推及び、OpenBSD mainbus.c に記述あり。OpenBSD のほうは
116: // 低レベルかどうかは不明。
117: // 3:SPC
118: // ROM1.2, OpenBSD ともに使用。
119: // 4:LANCE
120: // ROM はまだ不明。OpenBSD は使用。
121: // 4:拡張スロット
122: // LUNA-I からの類推のみ。不明。
123: // 5:拡張PC98
124: // LUNA-I からの類推のみ。LUNA88K にはスロットがないようなので、
125: // LUNA88K2 が必要。
126: // OpenBSD mainbus.c に記述あり。
127: // 5:シリアル(7201)
128: // OpenBSD mainbus.c に記述。
129: // 6:XP 高レベル
130: // LUNA-I からの類推。存在するかどうかも不明。
131: // ただ、これをなくすと XP ファームウェアまで作り直しなので、
132: // なくさないんじゃないかなあ。OMRON ファームで使ってなければ
133: // さっくり廃止されているかもしれない(PSGPAM が使用...レベル1 に
134: // 変えればいいだけだが)
135: // 6:システムクロック
136: // ROM のメモリコマンドではレベル6割り込みが常時上がっているように観測
137: // できるので、おそらくシステムクロック割り込みが上がっている。
138: // OpenBSD maibus.c にも記述。
139: // 7:ABRTスイッチ
140: // ROM のメモリコマンドで確認。
141: //
142: //
143: // SOFTINT レジスタ $6900000n
144: // $69000000: CPU0
145: // $69000004: CPU1
146: // $69000008: CPU2
147: // $6900000c: CPU3
148: // 挙動:
149: // この32ビットのどこかにライトアクセスすると、INT1 をアサートする。
150: // この32ビットのどこかをリードアクセスすると、INT1 をネゲートする。
151: // データバスは無視される。
152: // 0x00 を書いても、アサートされることに注意。
153: // リードアクセスで読み込まれる値も不定のようだ。
154: // 要はアドレスバスとR/W信号線しか見ていない。
155:
1.1.1.8 root 156: #include "sysctlr.h"
157: #include "ethernet.h"
158: #include "mpu88xx0.h"
159: #include "nmi.h"
160: #include "prom.h"
161: #include "sio.h"
162: #include "spc.h"
163: #include "sysclk.h"
1.1 root 164:
165: // コンストラクタ
166: SysCtlrDevice::SysCtlrDevice()
1.1.1.5 root 167: : inherited("SystemCtlr")
1.1 root 168: {
1.1.1.5 root 169: AddAlias("SysCtlr");
1.1 root 170:
1.1.1.8 root 171: monitor.func = ToMonitorCallback(&SysCtlrDevice::MonitorUpdate);
1.1.1.7 root 172: monitor.SetSize(25, 10);
1.1.1.5 root 173: monitor.Regist(ID_MONITOR_INTERRUPT);
1.1 root 174: }
175:
176: // デストラクタ
177: SysCtlrDevice::~SysCtlrDevice()
178: {
179: }
180:
1.1.1.8 root 181: // リセット
1.1.1.3 root 182: void
1.1.1.8 root 183: SysCtlrDevice::ResetHard(bool poweron)
1.1.1.3 root 184: {
185: // さすがにリセットくらいはされるだろう…
1.1.1.8 root 186: inherited::ResetHard(poweron);
1.1.1.7 root 187:
1.1.1.3 root 188: for (int i = 0; i < 4; i++) {
189: // XXX 初期値は分からないがとりあえず割り込み禁止にしておく
190: cpu[i].maskval = 0xfc000000;
191: cpu[i].intmask = MakeIntMask(cpu[i].maskval, i);
192: cpu[i].ipl = 0;
193: }
194: }
195:
1.1 root 196: uint64
197: SysCtlrDevice::Read32(uint32 addr)
198: {
1.1.1.3 root 199: int n = (addr >> 2) & 3;
1.1 root 200:
201: if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3 root 202: // bit31-29 に発生している最上位の割り込みレベル
203: // bit23-18 に設定したレベル 6-1 の割り込みマスク
204: uint32 data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8);
1.1 root 205: putlog(2, "割り込み保持読み出し(CPU#%d) -> $%08x", n, data);
206: return data;
207: }
208:
209: if (0x69000000 <= addr && addr < 0x69000010) {
1.1.1.3 root 210: // 読み出しで SOFTINT ネゲート (値は関係ない)
211: putlog(1, "Softint(CPU#%d) Negate", n);
212: intmap &= ~(IntmapSoft0 << n);
213: ChangeInterrupt();
1.1 root 214: return 0xffffffff;
215: }
216:
217: if (0x6d000000 <= addr && addr < 0x6d000010) {
1.1.1.9 ! root 218: putlog(0, "Read CPU%d reset (NOT IMPLEMENTED)", n);
1.1 root 219: return 0xffffffff;
220: }
221: if (addr == 0x6d000010) {
1.1.1.9 ! root 222: putlog(0, "Read All CPU reset (NOT IMPLEMENTED)");
1.1 root 223: return 0xffffffff;
224: }
225:
1.1.1.9 ! root 226: putlog(0, "Read $%08x (NOT IMPLEMENTED)", addr);
1.1 root 227: return 0xffffffff;
228: }
229:
230: uint64
231: SysCtlrDevice::Write32(uint32 addr, uint32 data)
232: {
233: int n = (addr & 15) >> 2;
234:
235: if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3 root 236: data &= 0xfc000000;
237: // 割り込みレベル変えるたびに表示されるのですごく多い。
238: // さらに同レベルが書き込まれることも多い…。
239: if (cpu[n].maskval != data) {
1.1.1.9 ! root 240: putlog(2, "Interrupt Mask(CPU#%d) <- $%08x", n, data);
1.1.1.3 root 241: } else {
1.1.1.9 ! root 242: putlog(3, "Interrupt Mask(CPU#%d) <- $%08x", n, data);
1.1.1.3 root 243: }
1.1 root 244:
1.1.1.3 root 245: // 設定値を保存
246: cpu[n].maskval = data;
247: // 内部マスクを書き換えて割り込み状態を更新
248: cpu[n].intmask = MakeIntMask(data, n);
249: ChangeInterrupt();
1.1 root 250: return 0;
251: }
252: if (0x69000000 <= addr && addr < 0x69000010) {
1.1.1.3 root 253: // 書き込みで SOFTINT アサート (値は関係ない)
254: putlog(1, "Softint(CPU#%d) Assert 0x%x", n, data);
255: counter[__builtin_clz(intmap)]++;
256: intmap |= IntmapSoft0 << n;
257: ChangeInterrupt();
1.1 root 258: return 0;
259: }
260: if (0x6d000000 <= addr && addr < 0x6d000010) {
1.1.1.9 ! root 261: putlog(0, "Write CPU%d reset (NOT IMPLEMENTED)", n);
1.1 root 262: return 0;
263: }
264: if (addr == 0x6d000010) {
1.1.1.4 root 265: putlog(1, "Reset All CPUs");
1.1.1.8 root 266: // XXX このあたりもう少し整理する必要がある
267: // 今は MPU.ResetHard() が func を ResetCallback に、time をリセット
268: // 間隔に書き換えて Start() した後、この書き込み命令から戻ったところの
269: // ExecCallback が time だけ所要サイクルに書き換えて再度 Start() する
270: // ため、時間はともかく幸い ResetCallback() が呼ばれることで動いている。
271: gPROM0->ResetHard(false);
272: gMPU->ResetHard(false);
273: ResetHard(false);
1.1 root 274: return 0;
275: }
276:
1.1.1.9 ! root 277: putlog(0, "Write $%08x <- $%08x (NOT IMPLEMENTED)", addr, data);
1.1 root 278: return 0;
279: }
280:
281: uint64
282: SysCtlrDevice::Peek8(uint32 addr)
283: {
1.1.1.3 root 284: int n = (addr >> 2) & 3;
1.1 root 285: uint32 data;
286:
287: if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3 root 288: data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8);
1.1 root 289: } else {
290: data = 0xffffffff;
291: }
292: switch (addr & 3) {
293: case 0:
294: return data >> 24;
295: case 1:
296: return (data >> 16) & 0xff;
297: case 2:
298: return (data >> 8) & 0xff;
299: case 3:
300: return data & 0xff;
301: default:
302: break;
303: }
304: __unreachable();
305: }
306:
1.1.1.2 root 307: void
1.1.1.5 root 308: SysCtlrDevice::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 309: {
1.1.1.3 root 310: int y;
311: struct {
312: const char *name;
313: uint32 map;
314: } table[] = {
315: { "NMI", IntmapNMI },
316: { "Clock", IntmapSysClk },
317: { "SIO", IntmapSIO },
318: { "Lance", IntmapLance },
319: { "SPC", IntmapSPC },
320: { "Soft#0", IntmapSoft0 },
321: { "Soft#1", IntmapSoft1 },
322: { "Soft#2", IntmapSoft2 },
323: { "Soft#3", IntmapSoft3 },
324: };
325:
326: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
327: bool ei = gMPU88xx0->GetCPU()->IsIntrEnable();
328:
1.1.1.5 root 329: screen.Clear();
1.1.1.3 root 330: y = 0;
331: // XXX CPU の実装数によってウィンドウ幅を変える。
332: // はみ出したところは描画されないのでヘッダは4つ分出力しておく
1.1.1.7 root 333: screen.Print(0, y++, "Lv Device Count CPU0 CPU1 CPU2 CPU3");
1.1.1.3 root 334: for (int i = 0; i < countof(table); i++) {
335: uint32 map = table[i].map;
336: int clz = __builtin_clz(map);
337: int lv = (31 - clz) / 4;
1.1.1.5 root 338: screen.Print(0, y, "%d", lv);
339: screen.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
1.1.1.7 root 340: screen.Print(8, y, "%11" PRIu64, counter[clz]);
1.1.1.3 root 341:
342: // CPU ごとのマスク
343: // XXX 今は CPU は1つしかない
344: for (int n = 0; n < 1; n++) {
345: // Softint の他 CPU 分は
346: // 動作としては常にマスクされてて通過しないから問題ないが、
347: // 見せる分にはマスクされているではなく無効と見せたほうがいい。
348: if (lv == 1 && map != (IntmapSoft0 << n)) {
1.1.1.7 root 349: screen.Puts(21 + n * 5, y, "----");
1.1.1.3 root 350: } else if ((cpu[n].intmask & map) == 0) {
1.1.1.7 root 351: screen.Puts(21 + n * 5, y, "Mask");
1.1.1.3 root 352: } else if (!ei) {
1.1.1.7 root 353: screen.Puts(21 + n * 5, y, "IND");
1.1.1.3 root 354: }
355: }
356:
357: y++;
358: }
359: }
360:
361: // デバイスから Intmap 値を引く
362: uint32
363: SysCtlrDevice::GetIntmap(Device *source) const
364: {
1.1.1.8 root 365: if (__predict_true(source == gSysClk)) {
1.1.1.3 root 366: return IntmapSysClk;
367: }
1.1.1.8 root 368: if (__predict_true(source == gSIO)) {
1.1.1.3 root 369: return IntmapSIO;
370: }
1.1.1.8 root 371: if (__predict_true(source == gEthernet)) {
1.1.1.3 root 372: return IntmapLance;
373: }
1.1.1.8 root 374: if (__predict_true(source == gSPC)) {
1.1.1.3 root 375: return IntmapSPC;
376: }
1.1.1.8 root 377: if (source == gNMI) {
378: return IntmapNMI;
379: }
1.1.1.3 root 380: PANIC("Unknown interrupt source?");
381: }
382:
383: // 割り込みアクノリッジはない
384: int
385: SysCtlrDevice::InterruptAcknowledge(int lv)
386: {
387: return 0;
388: }
389:
390: // 割り込み状態を更新
391: void
392: SysCtlrDevice::ChangeInterrupt()
393: {
394: // XXX MPU 側がまだマルチプロセッサに対応してないので CPU#0 だけ
395: for (int i = 0; i < 1; i++) {
396: uint32 localmap = intmap & cpu[i].intmask;
397:
398: // intmap の最下位ビットは常に立ててあり localmap は 0 にならない
399: int newipl = (uint)(31 - __builtin_clz(localmap)) / 4;
400:
1.1.1.7 root 401: // 割り込みレベルが変わったら、新しいレベルを通知
1.1.1.3 root 402: if (newipl != cpu[i].ipl) {
403: cpu[i].ipl = newipl;
404: // MPU 側は 1 レベルしかない
405: gMPU->Interrupt(cpu[i].ipl ? 1 : 0);
406: }
1.1 root 407: }
408: }
1.1.1.3 root 409:
410: // 割り込みマスク設定レジスタの書き込み値から内部用のマスクを作成
411: // data は bit31-26 のみ使用。他のビットは不問。
412: // n は CPU# (Softint 用)。
413: /*static*/ uint32
414: SysCtlrDevice::MakeIntMask(uint32 data, int n)
415: {
416: uint32 val = 0xf0000001; // Lv7 は NMI、最下位は番兵用
417:
418: uint32 mask = 0x0f000000;
419: for (int i = 6; i >= 1; i--) {
420: if ((int32)data < 0) {
421: val |= mask;
422: }
423: mask >>= 4;
424: data <<= 1;
425: }
426:
427: // Softint は他 CPU 分のビットを下ろす
428: val &= (0xffffff0f | (IntmapSoft0 << n));
429:
430: return val;
431: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.