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