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