|
|
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()
149: {
150: logname = "sysctlr";
151: devname = "SysCtlr";
152:
1.1.1.3 root 153: monitor_size = nnSize(24, 10);
1.1 root 154: }
155:
156: // デストラクタ
157: SysCtlrDevice::~SysCtlrDevice()
158: {
159: }
160:
1.1.1.3 root 161: void
162: SysCtlrDevice::ResetHard()
163: {
164: // さすがにリセットくらいはされるだろう…
165: intmap = 0x00000001;
166: memset(&counter, 0, sizeof(counter));
167: for (int i = 0; i < 4; i++) {
168: // XXX 初期値は分からないがとりあえず割り込み禁止にしておく
169: cpu[i].maskval = 0xfc000000;
170: cpu[i].intmask = MakeIntMask(cpu[i].maskval, i);
171: cpu[i].ipl = 0;
172: }
173: }
174:
1.1 root 175: uint64
176: SysCtlrDevice::Read32(uint32 addr)
177: {
1.1.1.3 root 178: int n = (addr >> 2) & 3;
1.1 root 179:
180: if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3 root 181: // bit31-29 に発生している最上位の割り込みレベル
182: // bit23-18 に設定したレベル 6-1 の割り込みマスク
183: uint32 data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8);
1.1 root 184: putlog(2, "割り込み保持読み出し(CPU#%d) -> $%08x", n, data);
185: return data;
186: }
187:
188: if (0x69000000 <= addr && addr < 0x69000010) {
1.1.1.3 root 189: // 読み出しで SOFTINT ネゲート (値は関係ない)
190: putlog(1, "Softint(CPU#%d) Negate", n);
191: intmap &= ~(IntmapSoft0 << n);
192: ChangeInterrupt();
1.1 root 193: return 0xffffffff;
194: }
195:
196: if (0x6d000000 <= addr && addr < 0x6d000010) {
1.1.1.3 root 197: putlog(0, "CPU%d リセット 未実装読み込み", n);
1.1 root 198: return 0xffffffff;
199: }
200: if (addr == 0x6d000010) {
1.1.1.3 root 201: putlog(0, "CPU ALL リセット 未実装読み込み");
1.1 root 202: return 0xffffffff;
203: }
204:
205: putlog(0, "未実装読み込み $%08x", addr);
206: return 0xffffffff;
207: }
208:
209: uint64
210: SysCtlrDevice::Write32(uint32 addr, uint32 data)
211: {
212: int n = (addr & 15) >> 2;
213:
214: if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3 root 215: data &= 0xfc000000;
216: // 割り込みレベル変えるたびに表示されるのですごく多い。
217: // さらに同レベルが書き込まれることも多い…。
218: if (cpu[n].maskval != data) {
219: putlog(2, "割り込みマスク(CPU#%d) <- $%08x", n, data);
220: } else {
221: putlog(3, "割り込みマスク(CPU#%d) <- $%08x", n, data);
222: }
1.1 root 223:
1.1.1.3 root 224: // 設定値を保存
225: cpu[n].maskval = data;
226: // 内部マスクを書き換えて割り込み状態を更新
227: cpu[n].intmask = MakeIntMask(data, n);
228: ChangeInterrupt();
1.1 root 229: return 0;
230: }
231: if (0x69000000 <= addr && addr < 0x69000010) {
1.1.1.3 root 232: // 書き込みで SOFTINT アサート (値は関係ない)
233: putlog(1, "Softint(CPU#%d) Assert 0x%x", n, data);
234: counter[__builtin_clz(intmap)]++;
235: intmap |= IntmapSoft0 << n;
236: ChangeInterrupt();
1.1 root 237: return 0;
238: }
239: if (0x6d000000 <= addr && addr < 0x6d000010) {
240: putlog(0, "CPU%d リセット 未実装書き込み", n);
241: return 0;
242: }
243: if (addr == 0x6d000010) {
1.1.1.4 ! root 244: putlog(1, "Reset All CPUs");
! 245: gMPU->ResetHard();
1.1 root 246: return 0;
247: }
248:
249: putlog(0, "未実装書き込み $%08x <- $%08x", addr, data);
250: return 0;
251: }
252:
253: uint64
254: SysCtlrDevice::Peek8(uint32 addr)
255: {
1.1.1.3 root 256: int n = (addr >> 2) & 3;
1.1 root 257: uint32 data;
258:
259: if (0x65000000 <= addr && addr < 0x65000010) {
1.1.1.3 root 260: data = (cpu[n].ipl << 29) | (cpu[n].maskval >> 8);
1.1 root 261: } else {
262: data = 0xffffffff;
263: }
264: switch (addr & 3) {
265: case 0:
266: return data >> 24;
267: case 1:
268: return (data >> 16) & 0xff;
269: case 2:
270: return (data >> 8) & 0xff;
271: case 3:
272: return data & 0xff;
273: default:
274: break;
275: }
276: __unreachable();
277: }
278:
1.1.1.2 root 279: void
280: SysCtlrDevice::MonitorUpdate(TextScreen& monitor)
1.1 root 281: {
1.1.1.3 root 282: int y;
283: struct {
284: const char *name;
285: uint32 map;
286: } table[] = {
287: { "NMI", IntmapNMI },
288: { "Clock", IntmapSysClk },
289: { "SIO", IntmapSIO },
290: { "Lance", IntmapLance },
291: { "SPC", IntmapSPC },
292: { "Soft#0", IntmapSoft0 },
293: { "Soft#1", IntmapSoft1 },
294: { "Soft#2", IntmapSoft2 },
295: { "Soft#3", IntmapSoft3 },
296: };
297:
298: // CPU の割り込み可否は本当は関係ないけど、便宜的に一緒に表示したい
299: bool ei = gMPU88xx0->GetCPU()->IsIntrEnable();
300:
1.1 root 301: monitor.Clear();
1.1.1.3 root 302: y = 0;
303: // XXX CPU の実装数によってウィンドウ幅を変える。
304: // はみ出したところは描画されないのでヘッダは4つ分出力しておく
305: monitor.Print(0, y++, "Lv Device Count CPU0 CPU1 CPU2 CPU3");
306: for (int i = 0; i < countof(table); i++) {
307: uint32 map = table[i].map;
308: int clz = __builtin_clz(map);
309: int lv = (31 - clz) / 4;
310: monitor.Print(0, y, "%d", lv);
311: monitor.Print(2, y, TA::OnOff(intmap & map), "%s", table[i].name);
312: monitor.Print(8, y, "%10u", counter[clz]);
313:
314: // CPU ごとのマスク
315: // XXX 今は CPU は1つしかない
316: for (int n = 0; n < 1; n++) {
317: // Softint の他 CPU 分は
318: // 動作としては常にマスクされてて通過しないから問題ないが、
319: // 見せる分にはマスクされているではなく無効と見せたほうがいい。
320: if (lv == 1 && map != (IntmapSoft0 << n)) {
321: monitor.Puts(20 + n * 5, y, "----");
322: } else if ((cpu[n].intmask & map) == 0) {
323: monitor.Puts(20 + n * 5, y, "Mask");
324: } else if (!ei) {
325: monitor.Puts(20 + n * 5, y, "IND");
326: }
327: }
328:
329: y++;
330: }
331: }
332:
333: // デバイスから Intmap 値を引く
334: uint32
335: SysCtlrDevice::GetIntmap(Device *source) const
336: {
337: if (__predict_true(source == gSysClk.get())) {
338: return IntmapSysClk;
339: }
340: if (__predict_true(source == gSIO.get())) {
341: return IntmapSIO;
342: }
343: if (__predict_true(source == gEthernet.get())) {
344: return IntmapLance;
345: }
346: if (__predict_true(source == gSPC.get())) {
347: return IntmapSPC;
348: }
349: PANIC("Unknown interrupt source?");
350: }
351:
352: // 外部デバイスが割り込み信号線をアサートした
353: void
354: SysCtlrDevice::AssertINT(Device *source)
355: {
356: uint32 oldmap;
357: uint32 srcmap;
358:
359: oldmap = intmap;
360: srcmap = GetIntmap(source);
361: intmap |= srcmap;
362:
363: if ((oldmap ^ intmap) != 0) {
364: // 立ち上がりエッジでカウント
365: counter[__builtin_clz(srcmap)]++;
366: }
367:
368: ChangeInterrupt();
369: }
370:
371: // 外部デバイスが割り込み信号線をネゲートした
372: void
373: SysCtlrDevice::NegateINT(Device *source)
374: {
375: intmap &= ~GetIntmap(source);
376:
377: ChangeInterrupt();
378: }
379:
380: // 割り込みアクノリッジはない
381: int
382: SysCtlrDevice::InterruptAcknowledge(int lv)
383: {
384: return 0;
385: }
386:
387: // 割り込み状態を更新
388: void
389: SysCtlrDevice::ChangeInterrupt()
390: {
391: // XXX MPU 側がまだマルチプロセッサに対応してないので CPU#0 だけ
392: for (int i = 0; i < 1; i++) {
393: uint32 localmap = intmap & cpu[i].intmask;
394:
395: // intmap の最下位ビットは常に立ててあり localmap は 0 にならない
396: int newipl = (uint)(31 - __builtin_clz(localmap)) / 4;
397:
398: // アサートによって割り込みレベルが変わったら、新しいレベルを通知
399: if (newipl != cpu[i].ipl) {
400: cpu[i].ipl = newipl;
401: // MPU 側は 1 レベルしかない
402: gMPU->Interrupt(cpu[i].ipl ? 1 : 0);
403: }
1.1 root 404: }
405: }
1.1.1.3 root 406:
407: // 割り込みマスク設定レジスタの書き込み値から内部用のマスクを作成
408: // data は bit31-26 のみ使用。他のビットは不問。
409: // n は CPU# (Softint 用)。
410: /*static*/ uint32
411: SysCtlrDevice::MakeIntMask(uint32 data, int n)
412: {
413: uint32 val = 0xf0000001; // Lv7 は NMI、最下位は番兵用
414:
415: uint32 mask = 0x0f000000;
416: for (int i = 6; i >= 1; i--) {
417: if ((int32)data < 0) {
418: val |= mask;
419: }
420: mask >>= 4;
421: data <<= 1;
422: }
423:
424: // Softint は他 CPU 分のビットを下ろす
425: val &= (0xffffff0f | (IntmapSoft0 << n));
426:
427: return val;
428: }
429:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.