|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // MC88200(CMMU)
8:
9: #include "m88100.h"
10: #include "m88200.h"
11: #include "mystring.h"
12:
1.1.1.3 root 13: // static 変数
14: m88200 *m88200::mbus_master = NULL;
15:
1.1 root 16: // m88200 コンストラクタ
17: m88200::m88200()
18: {
19: // logname, devname は Init() で確定する
20:
1.1.1.3 root 21: monitor_size = nnSize(52, 8);
1.1 root 22:
23: // ログ表示用の名前
24: sapr.name = "SAPR";
25: uapr.name = "UAPR";
26:
27: // 暗黙 BATC を初期化
28: SetBATC(8, 0xfff7ffb5); // $fff8xxxx,S,WT,CI,V
29: SetBATC(9, 0xfffffff5); // $ffffxxxx,S,WT,CI,V
30:
31: // セットインデックスを初期化
32: for (int i = 0; i < setarray.size(); i++) {
33: auto& set = setarray[i];
34: set.setidx = i;
35: }
36: }
37:
38: // m88200 デストラクタ
39: m88200::~m88200()
40: {
41: }
42:
43: // 本当はコンストラクタ渡ししたかったもの
44: void
45: m88200::Ctor(m88kcpu *parent_)
46: {
47: parent = parent_;
48: }
49:
50: // リセット
51: void
52: m88200::Reset()
53: {
1.1.1.3 root 54: const uint32 Undefined = 0xcccccccc;
55:
1.1 root 56: // レジスタ (p6-4, Table6-3)
1.1.1.3 root 57: // ID, version は別途 Set される。
1.1 root 58: command = 0;
59: ssr = 0;
1.1.1.3 root 60: sar = Undefined;
1.1 root 61: sctr = 0;
62: fault_code = 0;
1.1.1.3 root 63: fault_addr = Undefined;
1.1 root 64: sapr.enable = false;
65: sapr.stat = APR_CI;
66: uapr.enable = false;
67: uapr.stat = APR_CI;
68: }
69:
1.1.1.2 root 70: void
71: m88200::MonitorUpdate(TextScreen& monitor)
1.1 root 72: {
1.1.1.3 root 73: uint32 baseaddr;
1.1 root 74: uint32 reg;
75: int x;
76: int y;
77:
1.1.1.3 root 78: baseaddr = 0xfff00000 + (id << 12);
79:
1.1 root 80: monitor.Clear();
1.1.1.3 root 81: x = 24;
1.1 root 82:
83: y = 0;
1.1.1.3 root 84: monitor.Print(0, y++, "$%08x IDR:%08x ID=$%02x Type=5(88200) Ver=$%x",
85: baseaddr + 0, GetIDR(), id, version);
1.1 root 86:
87: reg = GetSSR();
1.1.1.3 root 88: monitor.Print(0, y, "$%08x SSR:%08x", baseaddr + 0x008, reg);
1.1 root 89: monitor.Puts(x, y, TA::OnOff(reg & SSR_CE), "CE");
90: monitor.Puts(x + 3, y, TA::OnOff(reg & SSR_BE), "BE");
91: monitor.Puts(x + 6, y, TA::OnOff(reg & SSR_WT), "WT");
92: monitor.Puts(x + 9, y, TA::OnOff(reg & SSR_SP), "SP");
93: monitor.Puts(x + 12, y, TA::OnOff(reg & SSR_G), "G");
94: monitor.Puts(x + 14, y, TA::OnOff(reg & SSR_CI), "CI");
95: monitor.Puts(x + 17, y, TA::OnOff(reg & SSR_M), "M");
96: monitor.Puts(x + 19, y, TA::OnOff(reg & SSR_U), "U");
97: monitor.Puts(x + 21, y, TA::OnOff(reg & SSR_WP), "WP");
98: monitor.Puts(x + 24, y, TA::OnOff(reg & SSR_BH), "BH");
99: monitor.Puts(x + 27, y, TA::OnOff(reg & SSR_V), "V");
100: y++;
101:
1.1.1.3 root 102: monitor.Print(0, y++, "$%08x SAR:%08x", baseaddr + 0x00c, GetSAR());
1.1 root 103:
104: reg = GetSCTR();
1.1.1.3 root 105: monitor.Print(0, y, "$%08x SCTR:%08x", baseaddr + 0x104, GetSCTR());
1.1 root 106: monitor.Puts(x, y, TA::OnOff(reg & SCTR_PE), "PE");
107: monitor.Puts(x + 3, y, TA::OnOff(reg & SCTR_SE), "SE");
108: monitor.Puts(x + 6, y, TA::OnOff(reg & SCTR_PR), "PR");
109: y++;
110:
111: reg = GetPFSR();
112: static const char * const codestr[] = {
113: "Success",
114: "1?",
115: "2?",
116: "Bus Error",
117: "Segment Fault",
118: "Page Fault",
119: "Supervisor Violation",
120: "Write Violation",
121: };
1.1.1.3 root 122: monitor.Print(0, y++, "$%08x PFSR:%08x %s", baseaddr + 0x108,
123: reg, codestr[fault_code]);
1.1 root 124:
1.1.1.3 root 125: monitor.Print(0, y++, "$%08x PFAR:%08x", baseaddr + 0x10c, GetPFAR());
1.1 root 126:
127: for (int i = 0; i < 2; i++) {
128: int s = 1 - i;
129: reg = GetAPR(s);
1.1.1.3 root 130: monitor.Print(0, y, "$%08x %cAPR:%08x", baseaddr + 0x200 + i * 4,
131: s ? 'S' : 'U', reg);
1.1 root 132: monitor.Print(x, y, "STBA=%05x'000 %c%c%c%c",
133: reg >> 12,
134: (reg & APR_WT) ? 'T' : '-',
135: (reg & APR_G) ? 'G' : '-',
136: (reg & APR_CI) ? 'C' : '-',
137: (reg & APR_TE) ? 'E' : '-');
138: y++;
139: }
140: }
141:
142: // データキャッシュの特定セットの詳細を TextScreen に出力する。
143: // y は開始オフセット。
144: // TextScreen は (70, 5) 必要。
145: void
146: m88200::MonitorCacheSet(TextScreen& s, int y, int setidx)
147: {
148: const m88200CacheSet& set = setarray[setidx];
149:
150: /*
151: 012345678901234567890123456789012345678901234567890123456789
152: L Tag Status
153: 0 $11223'344 VV 12345678 12345678 12345678 12345678
154: */
155: s.Puts(0, y, "L Tag Status Word");
156: s.Puts(58, y, "Order");
157: y++;
158:
159: // ラインの古い順に評価して順序を0-3でつける
160: int Lorder[4];
161: int tmpL = set.L;
162: for (int i = 0; i < 4; i++) {
163: int line = m88200CacheSet::TryGetOldestLine(tmpL);
164: Lorder[line] = 3 - i;
165: tmpL = m88200CacheSet::TryUseLine(tmpL, line);
166: }
167:
168: for (int line = 0; line < 4; line++, y++) {
169: TA attr;
170: // ステータスによって属性を選択
171: switch (set.vv[line]) {
172: case m88200CacheSet::Status::IV:
173: attr = TA::Disable;
174: break;
175: case m88200CacheSet::Status::EU:
176: case m88200CacheSet::Status::SU:
177: attr = TA::Off;
178: break;
179: case m88200CacheSet::Status::EM:
180: attr = TA::Em;
181: break;
182: }
183: s.Print(0, y, attr, "%d", line);
1.1.1.3 root 184: static const char statusstr[][4] = { "EU", "EM", "SU", "IV" };
1.1 root 185: s.Print(2, y, attr, "$%05x'%03x %s",
186: (set.tag[line] >> 12),
187: (setidx << 4),
188: statusstr[set.vv[line]]);
189:
190: if (set.vv[line] == m88200CacheSet::Status::EM) {
191: // メモリに対してダーティならボールドにする
192: for (int w = 0; w < 4; w++) {
193: uint32 addr;
194: uint32 m;
195: addr = (set.tag[line] & 0xfffff000) | (setidx << 4) | (w << 2);
196: m = (vm_phys_peek_8(addr) << 24)
197: | (vm_phys_peek_8(addr + 1) << 16)
198: | (vm_phys_peek_8(addr + 2) << 8)
199: | (vm_phys_peek_8(addr + 3));
200: if (set.word[line * 4 + w] != m) {
201: attr = TA::Em;
202: } else {
203: attr = TA::Off;
204: }
205: s.Print(20 + w * 9, y, attr, "%08x", set.word[line * 4 + w]);
206: }
207: } else {
208: // Unmodified (or Invalid) ならメモリとの比較は不要
209: for (int w = 0; w < 4; w++) {
210: s.Print(20 + w * 9, y, "%08x", set.word[line * 4 + w]);
211: }
212: }
213:
214: // 順序
215: s.Print(58, y, "%d", Lorder[line]);
216: }
217: }
218:
219: // データキャッシュの概要を指定の TextScreen に出力する。
220: // y は開始オフセット。CLI では単独コマンドとして、GUI ではページの一部と
221: // して描画するためこうなっている。
222: // cursor で指定された番号のセットは反転表示する。GUI でのカーソル用。
223: // 負数など範囲外の値を指定すればカーソルは表示されない。
224: // is_gui は GUI かどうか。CLI では80桁を微妙に越えるのは嫌だしどうせ表示
225: // だけなので間を詰めてあるが、GUI では 80桁制約はない代わりにマウス操作が
226: // あるので 1セットごとに間を空けて等間隔にしたい、という違いから。
227: // TextScreen は CLI なら (70, 17)、GUI なら (82, 17) 必要。
228: void
229: m88200::MonitorCacheOverview(TextScreen& s, int y, int cursor, bool is_gui)
230: {
231: // X ガイド
232: for (int i = 0; i < 16; i++) {
233: int x;
234: if (is_gui) {
235: x = 3 + i * 5;
236: } else {
237: x = 3 + i * 4 + (i / 4);
238: }
239: s.Print(x, y, "+0%x", i);
240: }
241: y++;
242:
243: // Y ガイド
244: for (int i = 0; i < 16; i++) {
245: s.Print(0, y + i, "%02x", i * 16);
246: }
247:
248: for (int i = 0; i < setarray.size(); i++) {
249: const auto& set = setarray[i];
1.1.1.3 root 250: const char str[] = "EMS-";
1.1 root 251: int col = i % 16;
252: int row = i / 16;
253: int x;
254: if (is_gui) {
255: x = 3 + col * 5;
256: } else {
257: x = 3 + col * 4 + col / 4;
258: }
259:
260: s.Print(x, y + row, TA::OnOff(i == cursor),
261: "%c%c%c%c",
262: str[set.vv[0]],
263: str[set.vv[1]],
264: str[set.vv[2]],
265: str[set.vv[3]]);
266: }
267: }
268:
269: // ID を設定する (IDR ではない)
270: void
271: m88200::SetID(uint id_)
272: {
273: id = id_;
274:
275: logname = string_format("cmmu%u", id);
276: devname = string_format("CMMU#%u", id);
277: }
278:
279: // IDR の Version フィールドを設定する
280: void
281: m88200::SetVersion(uint version_)
282: {
283: version = version_;
284: }
285:
286: // コマンド名
287: // (0-15 は全部 No Operation なので、16以降のみ)
288: /*static*/ const char * const
289: m88200::commandname[] = {
290: "No Operation", // $10
291: "No Operation", // $11
292: "No Operation", // $12
293: "No Operation", // $13
294: "DCache Invalidate, Line", // $14
295: "DCache Invalidate, Page", // $15
296: "DCache Invalidate, Segment", // $16
297: "DCache Invalidate, All", // $17
298:
299: "DCache Copyback, Line", // $18
300: "DCache Copyback, Page", // $19
301: "DCache Copyback, Segment", // $1a
302: "DCache Copyback, All", // $1b
303: "DCache Copy&Inv, Line", // $1c
304: "DCache Copy&Inv, Page", // $1d
305: "DCache Copy&Inv, Segment", // $1e
306: "DCache Copy&Inv, All", // $1f
307:
308: "Probe User Address", // $20
309: "Probe User Address", // $21
310: "Probe User Address", // $22
311: "Probe User Address", // $23
312: "Probe Supervisor Address", // $24
313: "Probe Supervisor Address", // $25
314: "Probe Supervisor Address", // $26
315: "Probe Supervisor Address", // $27
316:
317: "Probe User Address", // $28
318: "Probe User Address", // $29
319: "Probe User Address", // $2a
320: "Probe User Address", // $2b
321: "Probe Supervisor Address", // $2c
322: "Probe Supervisor Address", // $2d
323: "Probe Supervisor Address", // $2e
324: "Probe Supervisor Address", // $2f
325:
326: "Invalidate U PATC, Line", // $30
327: "Invalidate U PATC, Page", // $31
328: "Invalidate U PATC, Segment", // $32
329: "Invalidate U PATC, All", // $33
330: "Invalidate S PATC, Line", // $34
331: "Invalidate S PATC, Page", // $35
332: "Invalidate S PATC, Segment", // $36
333: "Invalidate S PATC, All", // $37
334:
335: "Invalidate U PATC, Line", // $38
336: "Invalidate U PATC, Page", // $39
337: "Invalidate U PATC, Segment", // $3a
338: "Invalidate U PATC, All", // $3b
339: "Invalidate S PATC, Line", // $3c
340: "Invalidate S PATC, Page", // $3d
341: "Invalidate S PATC, Segment", // $3e
342: "Invalidate S PATC, All", // $3f
343: };
344:
345: // SCR の読み出し
346: uint32
347: m88200::GetSCR() const
348: {
349: // b31-b6 (reserved) の読み出し値は未定義らしい。
350: // b5-b0 (Command Code) の読み出し値はマニュアルに記載がないけど
351: // たぶんそのまま読めるのかな。
352: return command;
353: }
354:
355: // SCR への書き込み
356: void
357: m88200::SetSCR(uint32 data)
358: {
359: command = data & 0x3f;
360:
361: // %00'XXXX No Operation
362: // %01'00XX No Operation
363: // %01'01gg Data Cache Invalidate
364: // %01'10gg Data Cache Copyback to Memory
365: // %01'11gg Data Cache Copyback and Invalidate
366: // %10'X0XX Probe User Address
367: // %10'X1XX Probe Supervisor Address
368: // %11'X0gg Invalidate User PATC Descriptors
369: // %11'X1gg Invalidate Supervisor PATC Descriptors
370:
371: const char *name;
372: if (command < 0x10) {
373: name = commandname[0];
374: } else {
375: name = commandname[command - 0x10];
376: }
377: putlog(1, "SCR <- $%08x (%s)", data, name);
378:
379: switch (command) {
380: case 0x00 ... 0x13: // No Operation
381: return;
382:
383: case 0x14 ... 0x1f: // Flush Data Cache
384: FlushCache();
385: return;
386:
387: case 0x20 ... 0x23: // Probe User Address
388: case 0x28 ... 0x2b:
389: putlog(0, "SCR Command: Probe User Address 未実装");
390: return;
391:
392: case 0x24 ... 0x27: // Probe Supervisor Address
393: case 0x2c ... 0x2f:
394: putlog(0, "SCR Command: Probe Supervisor Address 未実装");
395: return;
396:
397: case 0x30 ... 0x3f: // Invalidate {User,Supervisor} PATC Descriptors
398: InvalidatePATC();
399: return;
400: }
401: __unreachable();
402: }
403:
404: // command に応じてデータキャッシュをフラッシュする。SetSCR() の下請け。
405: // command が $14..$1f でのみ呼ぶこと。
406: // p3-18, Section 3.7
407: void
408: m88200::FlushCache()
409: {
410: uint32 op = command & 0x3c;
411: uint32 gg = command & 0x03;
412: uint32 addr = GetSAR();
413: bool copyback;
414: bool invalidate;
415:
416: // op CopyBack Invalidate
417: // %01'01gg false true | Data Cache Invalidate
418: // %01'10gg true false | Data Cache Copyback to Memory
419: // %01'11gg true true | Data Cache Copyback and invalidate
420:
421: // op によって書き戻しと無効化の組み合わせが異なる
422: if (op == 0x14) {
423: copyback = false;
424: invalidate = true;
425: } else if (op == 0x18) {
426: copyback = true;
427: invalidate = false;
428: } else if (op == 0x1c) {
429: copyback = true;
430: invalidate = true;
431: } else {
432: PANIC("unknown op = $%02x", op);
433: }
434:
435: // 影響範囲
436: switch (gg) {
437: case GG_LINE:
438: addr &= 0xfffffffc;
1.1.1.3 root 439: parent->AddCycle(1); // Table.6-1
1.1 root 440: break;
441: case GG_PAGE:
442: addr &= 0xfffff000;
1.1.1.3 root 443: parent->AddCycle(256); // Table.6-1
1.1 root 444: break;
445: case GG_SEG:
446: addr &= 0xffc00000;
1.1.1.3 root 447: parent->AddCycle(1024); // Table.6-1
1.1 root 448: break;
449: case GG_ALL:
1.1.1.3 root 450: parent->AddCycle(1024); // Table.6-1
1.1 root 451: break;
452: default:
453: __unreachable();
454: }
455:
1.1.1.3 root 456: // サイクル(基本部分) Table.6-1
457: uint32 cycle = 0;
458: if (invalidate) {
459: switch (gg) {
460: case GG_LINE: cycle = 1; break;
461: case GG_PAGE: cycle = 256; break;
462: case GG_SEG: cycle = 1024; break;
463: case GG_ALL: cycle = 256; break;
464: default: __unreachable();
465: }
466: }
467: if (copyback) {
468: switch (gg) {
469: case GG_LINE: cycle = 1; break;
470: case GG_PAGE: cycle = 256; break;
471: case GG_SEG: cycle = 1024; break;
472: case GG_ALL: cycle = 1024; break;
473: default: __unreachable();
474: }
475: }
476: // XXX ループ中のサイクル数は正しくないかも。よく分からん
477:
1.1 root 478: for (auto& set : setarray) {
479: for (int line = 0; line < 4; line++) {
480: // 条件にマッチするか
481: bool match;
482: switch (gg) {
483: case GG_LINE:
484: match = (addr == (set.tag[line] | (set.setidx << 4)));
485: break;
486: case GG_PAGE:
487: match = (addr == set.tag[line]);
488: break;
489: case GG_SEG:
490: match = (addr == (set.tag[line] & 0xffc00001));
491: break;
492: case GG_ALL:
493: match = true;
494: break;
495: default:
496: __unreachable();
497: }
498: if (!match)
499: continue;
500:
501: // Copyback ならまず EM なエントリを書き戻す。
502: if (copyback) {
503: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 504: cycle += 7; // Table.6-1
505: CopyBackLine(set, line);
1.1 root 506: }
507: }
508:
509: // Invalidate なら無効化する
510: if (invalidate) {
1.1.1.3 root 511: cycle += 1; // Table.6-1
1.1 root 512: set.Update(line, m88200CacheSet::IV);
513: }
514: }
515: }
1.1.1.3 root 516:
517: parent->AddCycle(cycle);
1.1 root 518: }
519:
520: // command に応じて PATC を無効化する。SetSCR() の下請け。
521: // command が $30..$3f で呼ぶこと。
522: // p2-9, Section 2.2.4
523: void
524: m88200::InvalidatePATC()
525: {
526: uint32 gg = command & 0x03;
527: uint32 addr = GetSAR();
528:
529: // ゲスト側が指定した端数部分は有効部分でマスクする。
530: // 内部では下位ビットはフラグ扱いなのでマスクしないと誤動作する。
531: if (gg == GG_SEG) {
532: addr &= 0xffc00000;
533: } else {
534: addr &= 0xfffff000;
535: }
536:
537: if ((command & 0x04)) {
538: addr |= PATC_S;
539: }
540:
541: for (auto& p : patc) {
542: bool match;
543: switch (command & 0x03) {
544: case GG_LINE:
545: match = false; // XXX 書いてないけどどうなる?
546: break;
547: case GG_PAGE:
548: match = (addr == p.lpa);
549: break;
550: case GG_SEG:
551: match = (addr == (p.lpa & 0xffc00fff));
552: break;
553: case GG_ALL:
554: match = true;
555: break;
556: default:
557: __unreachable();
558: }
559: if (match) {
560: // 無効化
561: p.lpa |= 0x01;
562: }
563: }
564: }
565:
566: // SCTR レジスタへの書き込み
567: void
568: m88200::SetSCTR(uint32 data)
569: {
570: sctr = data & (SCTR_PE | SCTR_SE | SCTR_PR);
571:
572: std::string msg;
573: if ((sctr & SCTR_PE))
574: msg += ",PE";
575: if ((sctr & SCTR_SE))
576: msg += ",SE";
577: if ((sctr & SCTR_PR))
578: msg += ",PR";
579: if (msg.length() > 0) {
580: putlog(0, "SCTR <- $%08x (%s 書き込み未実装)", data, msg.c_str() + 1);
581: }
582: }
583:
584: // SAPR, UAPR レジスタ値の読み出し (S/U ビット指定)
585: uint32
586: m88200::GetAPR(uint issuper) const
587: {
588: if (issuper) {
589: return GetAPR(sapr);
590: } else {
591: return GetAPR(uapr);
592: }
593: }
594:
595: // SAPR, UAPR レジスタ値の読み出し (実体指定)
596: uint32
597: m88200::GetAPR(const m88200APR& xapr) const
598: {
599: uint32 data;
600:
601: data = xapr.addr & APR_ADDR_MASK;
602: data |= xapr.stat & (APR_WT | APR_G | APR_CI);
603: if (xapr.enable) {
604: data |= APR_TE;
605: }
606: return data;
607: }
608:
609: // SAPR, UAPR レジスタへの書き込み (S/U ビット指定)
610: void
611: m88200::SetAPR(uint issuper, uint32 data)
612: {
613: if (issuper) {
614: return SetAPR(sapr, data);
615: } else {
616: return SetAPR(uapr, data);
617: }
618: }
619:
620: // SAPR, UAPR レジスタへの書き込み (実体指定)
621: void
622: m88200::SetAPR(m88200APR& xapr, uint32 data)
623: {
624: bool old_enable = xapr.enable;
625: xapr.addr = data & APR_ADDR_MASK;
626: xapr.stat = data & (APR_WT | APR_G | APR_CI);
627: xapr.enable = data & APR_TE;
628:
629: if (old_enable == false && xapr.enable == true) {
630: // 変換開始
631: putlog(1, "%s <- $%08x (Translation Enabled)", xapr.name, data);
632: } else if (old_enable == true && xapr.enable == false) {
633: // 変換停止
634: putlog(1, "%s <- $%08x (Translation Disabled)", xapr.name, data);
635: } else {
636: // 変化なし
637: putlog(1, "%s <- $%08x", xapr.name, data);
638: }
639: }
640:
641: // BATC(BWP) #n の読み出し
642: uint32
643: m88200::GetBATC(uint n) const
644: {
645: uint32 data;
646:
647: assert(n < 8);
648: const m88200BATC& b = batc[n];
649:
650: // 9 8 7 6 5 4 3 2 1 0
651: // BATC は S WT G CI WP V
652: // stat は WT SP G CI 0 M U WP 0 V
653:
654: data = b.lba & (BATC_LBA_MASK | BATC_S);
655: data |= (b.pba >> 13);
656: if ((b.stat & DESC_WT))
657: data |= BATC_WT;
658: if ((b.stat & DESC_G))
659: data |= BATC_G;
660: if ((b.stat & DESC_CI))
661: data |= BATC_CI;
662: if (b.wp)
663: data |= BATC_WP;
664: if ((b.lba & 1) == 0)
665: data |= BATC_V;
666: return data;
667: }
668:
669: // BATC (BWP) #n への書き込み
670: // (暗黙 BATC にも書き込めるよう n = 8,9 も受け付ける)
671: void
672: m88200::SetBATC(uint n, uint32 data)
673: {
674: assert(n < 10);
675: m88200BATC& b = batc[n];
676: putlog(1, "BWP%u <- $%08x", n, data);
677:
678: memset(&b, 0, sizeof(b));
679: b.lba = data & BATC_LBA_MASK;
680: b.lba |= (data & BATC_S);
681: if ((data & BATC_V) == 0) {
682: b.lba |= 1;
683: }
684: b.pba = (data & BATC_PBA_MASK) << 13;
685: // BATC と stat はビット順が違うので注意。すぐ上の GetBATC() 参照。
686: if ((data & BATC_WT))
687: b.stat = DESC_WT;
688: if ((data & BATC_G))
689: b.stat = DESC_G;
690: if ((data & BATC_CI))
691: b.stat = DESC_CI;
692: if ((data & BATC_WP)) {
693: b.stat = DESC_WP;
694: b.wp = true;
695: }
696: }
697:
698: // CSSP レジスタの読み出し
699: uint32
700: m88200::GetCSSP() const
701: {
702: uint32 setidx = (GetSAR() >> 4) & 0xff;
703: const m88200CacheSet& set = setarray[setidx];
704:
705: uint32 data = 0;
706: // L5-L0
707: data |= set.L << 24;
708:
709: // XXX D3-D0 未実装
710:
711: // VV3-VV0
712: data |= set.vv[3] << CSSP_VV3_OFFSET;
713: data |= set.vv[2] << CSSP_VV2_OFFSET;
714: data |= set.vv[1] << CSSP_VV1_OFFSET;
715: data |= set.vv[0] << CSSP_VV0_OFFSET;
716:
717: return data;
718: }
719:
720: // CSSP レジスタへの書き込み
721: void
722: m88200::SetCSSP(uint32 data)
723: {
724: uint32 setidx = (GetSAR() >> 4) & 0xff;
725: m88200CacheSet& set = setarray[setidx];
726:
727: putlog(1, "CSSP <- $%08x (set=$%02x)", data,setidx);
728:
729: // L5-L0 書き込み
730: set.L = (data >> 24) & 0x3f;
731:
732: // XXX D3-D0 未実装
733:
734: // VV3-VV0
735: set.vv[3] = (m88200CacheSet::Status)((data >> CSSP_VV3_OFFSET) & 3);
736: set.vv[2] = (m88200CacheSet::Status)((data >> CSSP_VV2_OFFSET) & 3);
737: set.vv[1] = (m88200CacheSet::Status)((data >> CSSP_VV1_OFFSET) & 3);
738: set.vv[0] = (m88200CacheSet::Status)((data >> CSSP_VV0_OFFSET) & 3);
739: }
740:
741:
742: //
743: // 物理バスアクセス
744: //
745:
746: // MBus から読み込みを行う。
747: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
748: // 成功すれば読み込めた値を返す。
749: // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。
750: uint64
751: m88200::MBusRead(uint32 paddr, int size)
752: {
753: uint64 data;
754:
755: if (size == 4) {
756: data = vm_phys_read_32(paddr);
757: } else if (size == 2) {
758: data = vm_phys_read_16(paddr);
759: } else {
760: data = vm_phys_read_8(paddr);
761: }
762: if ((int64)data < 0) {
763: fault_code = FAULT_CODE_BUSERR;
764: fault_addr = paddr;
765: }
766: return data;
767: }
768:
769: // MBus に書き込みを行う。
770: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
771: // 成功すれば 0 を返す。
772: // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。
773: uint64
774: m88200::MBusWrite(uint32 paddr, uint32 data, int size)
775: {
776: uint64 rv;
777:
778: if (size == 4) {
779: rv = vm_phys_write_32(paddr, data);
780: } else if (size == 2) {
781: rv = vm_phys_write_16(paddr, data);
782: } else {
783: rv = vm_phys_write_8(paddr, data);
784: }
785: if ((int64)rv < 0) {
786: fault_code = FAULT_CODE_BUSERR;
787: fault_addr = paddr;
788: }
789: return rv;
790: }
791:
792: // MBus に xmem トランザクションを行う。
793: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
794: // MBus Acquire された状態で呼び出すこと。
795: // 成功すれば読み込めた値を返す。
796: // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。
797: // read/write どちらでエラーが起きたかは acc_read で判別できる。
798: // p3-13, Figure3-7 の下半分のメインラインあたりに該当。
799: uint64
800: m88200::MBusXmem(uint32 paddr, uint32 data, int size)
801: {
802: uint64 fetched;
803: uint64 rv;
804:
805: // Read data with intent to modify
806: acc_read = true;
807: rv = MBusRead(paddr, size);
808: if ((int64)rv < 0) {
809: goto error;
810: }
811: fetched = (uint32)rv;
812:
813: // Supply data to PBus
814: // Reply = Success
815:
816: // Write data to memory
817: acc_read = false;
818: rv = MBusWrite(paddr, data, size);
819: if ((int64)rv < 0) {
820: goto error;
821: }
822:
823: rv = fetched;
824: error:
825: return rv;
826: }
827:
828: //
829: // アクセス関数
830: //
831:
832: template <int bits> uint64
833: m88200::load(uint32 addr)
834: {
835: uint64 data;
836:
837: acc_laddr = addr;
838: acc_read = true;
839: if (Translate() == false) {
1.1.1.4 ! root 840: putlog(2, "Translation BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
1.1 root 841: return (uint64)-1;
842: }
843: if ((acc_stat & DESC_CI)) {
1.1.1.3 root 844: parent->AddCycle(7); // Table.6-2
1.1 root 845: MBusAcquire();
846: data = MBusRead(acc_paddrH + acc_paddrL, bits / 8);
847: MBusRelease();
1.1.1.4 ! root 848: if ((int64)data < 0) {
! 849: putlog(2, "MBus BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
! 850: }
1.1 root 851: return data;
852: } else {
853: data = CacheRead(acc_paddrH);
854: if ((int64)data < 0) {
1.1.1.4 ! root 855: putlog(2, "Cache BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
1.1 root 856: return data;
857: }
858:
859: if (bits == 8) {
860: switch (acc_paddrL) {
861: case 0:
862: return (data >> 24);
863: case 1:
864: return (data >> 16) & 0xff;
865: case 2:
866: return (data >> 8) & 0xff;
867: case 3:
868: return data & 0xff;
869: }
870: }
871: if (bits == 16) {
872: if (acc_paddrL == 0) {
873: return data >> 16;
874: } else {
875: return data & 0xffff;
876: }
877: }
878: if (bits == 32) {
879: return data;
880: }
881: __unreachable();
882: }
883: }
884:
885: uint64
886: m88200::load_8(uint32 addr)
887: {
888: return load<8>(addr);
889: }
890:
891: uint64
892: m88200::load_16(uint32 addr)
893: {
894: return load<16>(addr);
895: }
896:
897: uint64
898: m88200::load_32(uint32 addr)
899: {
900: return load<32>(addr);
901: }
902:
903: #define DEBUG_WT 1
904:
905: template <int bits> uint64
906: m88200::store(uint32 addr, uint32 data)
907: {
908: uint64 rv;
909:
910: acc_laddr = addr;
911: acc_read = false;
912: if (Translate() == false) {
913: return (uint64)-1;
914: }
915: if ((acc_stat & DESC_CI)) {
1.1.1.3 root 916: parent->AddCycle(7); // Table.6-2
1.1 root 917: MBusAcquire();
918: rv = MBusWrite(acc_paddrH + acc_paddrL, data, bits / 8);
919: MBusRelease();
920: return rv;
921: } else {
1.1.1.3 root 922: if (DEBUG_WT) {
923: MBusAcquire();
1.1 root 924: MBusWrite(acc_paddrH + acc_paddrL, data, bits / 8);
1.1.1.3 root 925: MBusRelease();
926: }
1.1 root 927: return CacheWrite(acc_paddrH + acc_paddrL, data, bits / 8);
928: }
929: }
930:
931: uint64
932: m88200::store_8(uint32 addr, uint32 data)
933: {
934: return store<8>(addr, data);
935: }
936:
937: uint64
938: m88200::store_16(uint32 addr, uint32 data)
939: {
940: return store<16>(addr, data);
941: }
942:
943: uint64
944: m88200::store_32(uint32 addr, uint32 data)
945: {
946: return store<32>(addr, data);
947: }
948:
949: template <int bits> uint64
950: m88200::xmem(uint32 addr, uint32 data)
951: {
952: uint64 rv;
953:
954: acc_laddr = addr;
955: acc_read = false;
956: if (Translate() == false) {
957: return (uint64)-1;
958: }
959: if ((acc_stat & DESC_CI)) {
960: // XXX キャッシュ禁止領域だとどうなる?
961: MBusAcquire();
962: rv = MBusXmem(acc_paddrH + acc_paddrL, data, bits / 8);
963: MBusRelease();
964: return rv;
965: } else {
966: return CacheXmem(acc_paddrH + acc_paddrL, data, bits / 8);
967: }
968: }
969:
970: uint64
971: m88200::xmem_8(uint32 addr, uint32 data)
972: {
973: return xmem<8>(addr, data);
974: }
975:
976: uint64
977: m88200::xmem_16(uint32 addr, uint32 data)
978: {
979: return xmem<16>(addr, data);
980: }
981:
982: uint64
983: m88200::xmem_32(uint32 addr, uint32 data)
984: {
985: return xmem<32>(addr, data);
986: }
987:
988: //
989: // アドレス変換
990: //
991:
992: // デバッグ用
993: /*static*/ std::string
994: m88200::stat2str(uint32 stat)
995: {
996: std::string buf;
997:
998: if ((stat & m88200::DESC_WT))
999: buf += ",WT";
1000: if ((stat & m88200::DESC_G))
1001: buf += ",G";
1002: if ((stat & m88200::DESC_CI))
1003: buf += ",CI";
1004: if ((stat & m88200::DESC_M))
1005: buf += ",M";
1006: if ((stat & m88200::DESC_U))
1007: buf += ",U";
1008: if ((stat & m88200::DESC_WP))
1009: buf += ",WP";
1010:
1011: if (buf.empty()) {
1012: buf = ",0";
1013: }
1014: return buf.substr(1);
1015: }
1016:
1017: // アドレス変換。
1018: // 事前に acc_laddr, acc_super, acc_read を設定しておくこと。
1019: // 成功すれば acc_paddrH, acc_paddrL をセットして true を返す。
1020: // 失敗ならいろいろセットして(?) false を返す。
1021: // p2-3, Figure2-1
1022: bool
1023: m88200::Translate()
1024: {
1025: uint32 la;
1026:
1027: // Logical address(LA) presented on PBus
1028:
1029: putlog(3, "Translate %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
1030:
1031: // 下位2ビットは常にこうなる。
1032: acc_paddrL = acc_laddr & 3;
1033:
1034: // 2回しかループしないはず
1035: for (int loop = 0; loop < 3; loop++) {
1036: // Select Area Descriptor
1037: if (SelectAreaDesc() == false) {
1.1.1.3 root 1038: // XXX 図のこれはたぶん間違いだよなあ…
1039: // 誤: Physical Address <= LA[18-2] :: 00
1040: // 正: Physical Address <= LA[31-2] :: 00
1.1 root 1041: acc_paddrH = acc_laddr - acc_paddrL;
1.1.1.3 root 1042:
1043: parent->AddCycle(1);
1.1 root 1044: return true;
1045: }
1046:
1047: // type == Valid ここから
1048:
1049: // Search BATC first
1050: la = acc_laddr & 0xfff80000;
1051: la |= acc_super ? BATC_S : 0;
1052: for (int i = 0; i < batc.size(); i++) {
1053: m88200BATC& b = batc[i];
1054: if (b.lba == la) {
1055: // BATC hit
1056: putlog(4, " BATC[%d] hit", i);
1057: if (acc_IsWrite() && b.wp) {
1058: goto write_violation;
1059: }
1060:
1061: // Physical Address <= PBA :: LA[18-2] :: 00
1062: acc_paddrH = b.pba | (acc_laddr & 0x0007fffc);
1063: acc_stat |= b.stat;
1064: putlog(4, " BATC hit acc=%s paddr=$%08x",
1065: stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.3 root 1066:
1067: parent->AddCycle(1);
1.1 root 1068: return true;
1069: }
1070: }
1071:
1072: // BATC miss, search PATC then
1073: la = acc_laddr & 0xfffff000;
1074: la |= acc_super ? PATC_S : 0;
1075: acc_patc = NULL;
1076: for (int i = 0; i < patc.size(); i++) {
1077: m88200PATC& p = patc[i];
1078: if (p.lpa == la) {
1079: // PATC hit
1080: if (acc_IsWrite() && p.wp) {
1081: putlog(4, " PATC[%d] hit; stat=%s m=%d wp=%d", i,
1082: stat2str(p.stat).c_str(), p.m, p.wp);
1083: goto write_violation;
1084: }
1085: if (acc_IsWrite() && p.m == false) {
1086: // Update M bit
1087: // フローチャートでは PATC[M] はこの後のテーブルサーチ中
1088: // の Update Page Descriptor 処理中で更新するように書いて
1089: // あるように読めるのだが、その通りに実装すると、メモリ
1090: // 上の Page Descriptor に最初から M ビットが立っていると
1091: // (というか OpenBSD カーネルが用意した Page Descriptor
1092: // には立っているので) PATC[M] の更新も行われず、PATC[M]
1093: // が立っていないので再びここに来てしまい無限ループになる。
1094: // 誰が間違ってるのか分からないけど、とりあえずここで
1095: // PATC[M] を立てれば問題は起きない。
1096: putlog(4, " PATC[%d] hit; Need to update M bit", i);
1097: p.m = true;
1098:
1099: // この下の PATC miss に合流する
1100: acc_patc = &p;
1101: break;
1102: }
1103:
1104: // Physical Address <= PFA :: LA[11-2] :: 00
1105: acc_paddrH = p.pfa | (acc_laddr & 0x00000ffc);
1106: acc_stat |= p.stat;
1107: putlog(4, " PATC[%d] hit acc=%s paddr=$%08x", i,
1108: stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.3 root 1109:
1110: parent->AddCycle(1);
1.1 root 1111: return true;
1112: }
1113: }
1.1.1.2 root 1114: putlog(4, " BATC/PATC miss");
1.1 root 1115:
1116: // PATC miss
1117:
1118: // フローチャートでは PATC miss というラベルが付いてるが、コード
1119: // では acc_patc は PATC ループ前に NULL にしてあり(=miss)、
1120: // ループで PATC エントリが見付かれば acc_patc に代入してから
1121: // break してここに来るので、ちょっとだけ見た目と違うが意図してる
1122: // 動作は同じはず。
1123:
1124: // Table search operation
1125: if (TableSearch() == true) {
1126: continue;
1127: }
1128:
1129: // Invalid
1130: // Reply with fault (Figure2-10 だがここではすべて不要)
1131: return false;
1132: }
1133: PANIC("loop detected");
1134:
1135: write_violation:
1136: fault_code = FAULT_CODE_WRITE;
1137: //fault_addr UNKNOWN?
1138: // Reply with fault (Figure2-10 だがここではすべて不要)
1139: return false;
1140: }
1141:
1142:
1143: // Select Area Descriptor.
1144: // 結果が Type=Valid なら true、Type=Untranslated なら false を返す。
1145: // Probe Command からも呼ばれる。
1146: // p2-21, Figure2-5
1147: bool
1148: m88200::SelectAreaDesc()
1149: {
1150: const m88200APR *xapr;
1151:
1152: if (acc_super) {
1153: xapr = &sapr;
1154: } else {
1155: xapr = &uapr;
1156: }
1157:
1158: acc_stat = xapr->stat & ACC_STAT_MASK;
1159: if (xapr->enable) {
1160: // セグメントディスクリプタのアドレスはここで決まるが、
1161: // 次に行う BATC、PATC サーチでは使わず、それらが全部ミスして
1162: // テーブルサーチまで来た所で初めて使うので、ここでは表示しない。
1163: acc_sdaddr = xapr->addr | ((acc_laddr >> 20) & ~3U);
1164: putlog(4, " %s acc=%s", xapr->name, stat2str(acc_stat).c_str());
1165: return true;
1166: } else {
1167: putlog(3, " %s acc=%s Untranslated",
1168: xapr->name, stat2str(acc_stat).c_str());
1169: return false;
1170: }
1171: }
1172:
1173: // Table Search
1174: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1175: // p2-20, Figure2-4
1176: bool
1177: m88200::TableSearch()
1178: {
1179: putlog(4, " %s $%08x/%s acc=%s", __func__, acc_laddr,
1180: (acc_read ? "Read" : "Write"), stat2str(acc_stat).c_str());
1181:
1182: // XXX フローチャートを厳密に追っかけると MBus の Acquire/Release が
1183: // 対応していないので(orz)、ここでは
1184: // TableSearch() に入ったところで Acquire、
1185: // TableSearch() から出るところで Release だけに統一する。
1186:
1187: MBusAcquire();
1188:
1189: if (FetchSegmentDesc() == false) {
1190: MBusRelease();
1.1.1.3 root 1191:
1192: parent->AddCycle(7); // Table.6-2
1.1 root 1193: return false;
1194: }
1195:
1196: if (FetchPageDesc() == false) {
1197: MBusRelease();
1.1.1.3 root 1198:
1199: parent->AddCycle(11); // Table.6-2
1.1 root 1200: return false;
1201: }
1202:
1203: // 中央の TYPE = VALID のところ
1204: // ( )
1205: // +----------+ +----------+
1206: // | |
1207: // DESC[U]=0 || Otherwise
1208: // DESC[M]=0 && WRITE |
1209: // | |
1210: // UpdatePageDesc |
1211: // | |
1212: // <- RETRY -( )-- INVALID ---------- | -->
1213: // | |
1214: // VALID |
1215: // | |
1216: // ( ) <--------------------+
1217: // | |
1218: // +---+ +------------+
1219: // Otherwise TableSearch due to PATC miss
1220: // | |
1221: // (Only U/M bits CreatePATCEntry
1222: // Updated) |
1223: // | v
1224: // +---------------> ( )
1225:
1226: if ((tmp_desc & DESC_U) == 0 ||
1227: ((tmp_desc & DESC_M) == 0 && acc_IsWrite()))
1228: {
1.1.1.3 root 1229: parent->AddCycle(15); // Table.6-2
1230:
1.1 root 1231: if (UpdatePageDesc() == false) {
1232: MBusRelease();
1233: return false;
1234: }
1.1.1.3 root 1235: } else {
1236: parent->AddCycle(11); // Table.6-2
1.1 root 1237: }
1238:
1239: if (acc_patc == NULL) {
1240: // Table search due to PATC miss
1241: CreatePATCEntry();
1242: }
1243:
1244: MBusRelease();
1245: return true;
1246: }
1247:
1248: // Fetch Segment Descriptor
1249: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1250: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1251: // p2-22, Figure2-6
1252: bool
1253: m88200::FetchSegmentDesc()
1254: {
1255: uint64 data;
1256:
1257: data = MBusRead(acc_sdaddr, 4);
1258: if ((int64)data < 0) {
1259: return false;
1260: }
1261: tmp_desc = (uint32)data;
1262: tmp_desc &= (0xfffff000 |
1263: DESC_WT | DESC_SP | DESC_G | DESC_CI | DESC_WP | DESC_V);
1264:
1265: if ((tmp_desc & DESC_V) == 0) {
1266: fault_code = FAULT_CODE_SEGMENT;
1267: fault_addr = acc_sdaddr;
1268: putlog(4, " SD $%08x desc=$%08x SegFault", acc_sdaddr, tmp_desc);
1269: return false;
1270: } else {
1271: // Descriptor is valid
1272:
1273: if ((tmp_desc & DESC_SP) && acc_super == 0) {
1274: fault_code = FAULT_CODE_SUPERVISOR;
1275: fault_addr = acc_sdaddr;
1276: putlog(4, " SD $%08x desc=$%08x SupervisorFault",
1277: acc_sdaddr, tmp_desc);
1278: return false;
1279: }
1280:
1281: acc_pdaddr = (tmp_desc & 0xfffff000) | ((acc_laddr >> 10) & 0xffc);
1282: acc_stat |= tmp_desc & ACC_STAT_MASK;
1283: putlog(4, " SD $%08x pdaddr=$%08x stat=%s acc=%s",
1284: acc_sdaddr, acc_pdaddr,
1285: stat2str(tmp_desc).c_str(),
1286: stat2str(acc_stat).c_str());
1287: return true;
1288: }
1289: }
1290:
1291: // Fetch Page Descriptor
1292: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1293: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1294: // p2-23, Figure2-7
1295: bool
1296: m88200::FetchPageDesc()
1297: {
1298: uint64 data;
1299:
1300: data = MBusRead(acc_pdaddr, 4);
1301: if ((int64)data < 0) {
1302: return false;
1303: }
1304: tmp_desc = (uint32)data;
1305: tmp_desc &= (0xfffff000 | DESC_WT | DESC_SP | DESC_G | DESC_CI |
1306: DESC_M | DESC_U | DESC_WP | DESC_V);
1307:
1308: if ((tmp_desc & DESC_V) == 0) {
1309: fault_code = FAULT_CODE_PAGE;
1310: fault_addr = acc_pdaddr;
1311: putlog(4, " PD $%08x desc=$%08x PageFault", acc_pdaddr, tmp_desc);
1312: return false;
1313: } else {
1314: // Descriptor is valid
1315:
1316: if ((tmp_desc & DESC_SP) && acc_super == 0) {
1317: fault_code = FAULT_CODE_SUPERVISOR;
1318: fault_addr = acc_pdaddr;
1319: putlog(4, " PD $%08x desc=$%08x SupervisorFault",
1320: acc_pdaddr, tmp_desc);
1321: return false;
1322: }
1323:
1324: acc_stat |= tmp_desc & ACC_STAT_MASK;
1325:
1326: if ((acc_stat & DESC_WP) && acc_IsWrite()) {
1327: fault_code = FAULT_CODE_WRITE;
1328: // fault_addr は invalid data
1329: fault_addr = 0xdeadbeef;
1330: putlog(4, " PD $%08x desc=$%08x WriteFault", acc_pdaddr, tmp_desc);
1331: return false;
1332: } else {
1333: putlog(4, " PD $%08x stat=%s acc=%s", acc_pdaddr,
1334: stat2str(tmp_desc).c_str(),
1335: stat2str(acc_stat).c_str());
1336: return true;
1337: }
1338: }
1339: }
1340:
1341: // Update Page Descriptor
1342: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1343: // p2-24, Figure2-8
1344: bool
1345: m88200::UpdatePageDesc()
1346: {
1347: uint64 rv;
1348:
1349: if ((tmp_desc & DESC_M) == 0 && acc_IsWrite()) {
1350: // Update Modified bit and accrue status
1351:
1352: // XXX 図中 PATC[M] をセットするとあるが、ここでは遅い気がする。
1353: // Translate() 中の Update M bit のところのコメントも参照。
1354:
1355: // XXX 図中 ACC_STATUS[M] は TEMP_DESCR[M] じゃないの?
1356: tmp_desc |= DESC_M;
1357: }
1358:
1359: // Update Used bit
1360: tmp_desc |= DESC_U;
1361:
1362: rv = MBusWrite(acc_pdaddr, tmp_desc, 4);
1363: if ((int64)rv < 0) {
1364: return false;
1365: }
1366: putlog(4, " Update PD $%08x desc=$%08x stat=%s",
1367: acc_pdaddr, tmp_desc, stat2str(tmp_desc).c_str());
1368:
1369: return true;
1370: }
1371:
1372: // Create PATC Entry
1373: // 公式フローチャートと違って MBus Acquire したまま戻ること。
1374: // p2-25, Figure2-9
1375: void
1376: m88200::CreatePATCEntry()
1377: {
1378: // とりあえず線形探索で memcpy しとくべ
1379: memmove(&patc[1], &patc[0], sizeof(patc[0]) * (patc.size() - 1));
1380: // で、先頭に追加
1381: m88200PATC& p = patc[0];
1382:
1383: memset(&p, 0, sizeof(p));
1384: p.lpa = acc_laddr & 0xfffff000;
1385: p.pfa = tmp_desc & 0xfffff000;
1386: if (acc_super) {
1387: p.lpa |= PATC_S;
1388: }
1389: p.stat = acc_stat;
1390: putlog(4, " %s %c:$%08x:$%08x stat=%s", __func__,
1391: (p.lpa & PATC_S) ? 'S' : 'U', (p.lpa & 0xfffff000), p.pfa,
1392: stat2str(p.stat).c_str());
1393: }
1394:
1395: // アドレス変換 (デバッガ用)
1396: uint64
1397: m88200::TranslatePeek(uint32 laddr, bool issuper, bool do_search) const
1398: {
1399: const m88200APR *xapr;
1400: uint32 la;
1401:
1402: // Select Area Descriptor
1403: if (issuper) {
1404: xapr = &sapr;
1405: } else {
1406: xapr = &uapr;
1407: }
1408: if (xapr->enable == 0) {
1409: return laddr;
1410: }
1411:
1412: // Search BATC first
1413: la = laddr & 0xfff80000;
1414: la |= issuper ? BATC_S : 0;
1415: for (const auto& b : batc) {
1416: if (b.lba == la) {
1417: // BATC hit
1418: return b.pba | (laddr & 0x0007ffff);
1419: }
1420: }
1421:
1422: // BATC miss, search PATC then
1423: la = laddr & 0xfffff000;
1424: la |= issuper ? PATC_S : 0;
1425: for (const auto& p : patc) {
1426: if (p.lpa == la) {
1427: // PATC hit
1428: return p.pfa | (laddr & 0x00000fff);
1429: }
1430: }
1431:
1432: if (do_search == false) {
1433: return (uint64)-1;
1434: }
1435:
1436: // ここからテーブルサーチ
1437: uint64 data;
1438: uint32 desc_addr;
1439: uint32 desc;
1440:
1441: // Peek Segment Descriptor
1442: desc_addr = xapr->addr | ((laddr >> 20) & ~3U);
1443: data = vm_phys_peek_32(desc_addr);
1444: if ((int64)data < 0) {
1445: return data;
1446: }
1447: desc = (uint32)data;
1448: if ((desc & DESC_V) == 0) {
1449: return (uint64)-1;
1450: }
1451: if ((desc & DESC_SP) && issuper == false) {
1452: return (uint64)-1;
1453: }
1454:
1455: // Peek Page Descriptor
1456: desc_addr = (desc & 0xfffff000) | ((laddr >> 10) & 0xffc);
1457: data = vm_phys_peek_32(desc_addr);
1458: if ((int64)data < 0) {
1459: return data;
1460: }
1461: desc = (uint32)data;
1462: if ((desc & DESC_V) == 0) {
1463: return (uint64)-1;
1464: }
1465: if ((desc & DESC_SP) && issuper == false) {
1466: return (uint64)-1;
1467: }
1468:
1469: return (desc & 0xfffff000) | (laddr & 0x00000fff);
1470: }
1471:
1472:
1473: //
1474: // キャッシュ
1475: //
1476:
1477: // このラインの状態を更新
1478: void
1479: m88200CacheSet::Update(int line, m88200CacheSet::Status status)
1480: {
1481: vv[line] = status;
1482: if (status == IV) {
1483: // 無効なら
1484: tag[line] |= TAG_INVALID;
1485: L = TryUnuseLine(L, line);
1486: }
1487: }
1488:
1489: // CSSP L5-L0 の処理。
1490: // 引数 tmpL の状態から line を最新にしたらどうなるか、を返す。
1491: // 表示処理で一時変数に対して処理が必要なため分離してある。
1492: int
1493: m88200CacheSet::TryUseLine(int tmpL, int line)
1494: {
1495: // L フィールドは 3bit, 2bit, 1bit で構成され、
1496: // 他のラインの対応ビットを落として、
1497: // 自分のラインの対応ビットを全部立てれば、
1498: // 他のラインの順序を保存した状態で、自分が最新になるように
1499: // 順序をつけられる。
1500:
1501: if (line == 3) {
1502: tmpL |= 0b111'00'0;
1503: } else if (line == 2) {
1504: tmpL &= 0b011'11'1;
1505: tmpL |= 0b000'11'0;
1506: } else if (line == 1) {
1507: tmpL &= 0b101'01'1;
1508: tmpL |= 0b000'00'1;
1509: } else {
1510: tmpL &= 0b110'10'0;
1511: }
1512: return tmpL;
1513: }
1514:
1515: // CSSP L5-L0 の処理。
1516: // 引数 tmpL の状態から line を最古にしたらどうなるか、を返す。
1517: int
1518: m88200CacheSet::TryUnuseLine(int tmpL, int line)
1519: {
1520: // Use のちょうど反転論理
1521: if (line == 3) {
1522: tmpL &= 0b000'11'1;
1523: } else if (line == 2) {
1524: tmpL |= 0b100'00'0;
1525: tmpL &= 0b111'00'1;
1526: } else if (line == 1) {
1527: tmpL |= 0b010'10'0;
1528: tmpL &= 0b111'11'0;
1529: } else {
1530: tmpL |= 0b001'01'1;
1531: }
1532: return tmpL;
1533: }
1534:
1535: // CSSP L5-L0 の処理。
1536: // 引数 tmpL の状態で、最新の line を返す。
1537: // 表示処理で一時変数に対して処理が必要なため分離してある。
1538: int
1539: m88200CacheSet::TryGetOldestLine(int tmpL)
1540: {
1541: if (tmpL < 8) {
1542: return 3;
1543: }
1544: tmpL &= 7;
1545: if (tmpL < 2) {
1546: return 2;
1547: }
1548: tmpL &= 1;
1549: if (tmpL == 0) {
1550: return 1;
1551: } else {
1552: return 0;
1553: }
1554: }
1555:
1556: // 更新用に最も古いラインを選んで差し出す
1557: int
1558: m88200CacheSet::SelectOldestLine() const
1559: {
1560: // なければ、最も古いラインを差し出す
1561: return TryGetOldestLine(L);
1562: }
1563:
1564: // キャッシュの指定の line, word に data を書き込む。
1565: // size は 1, 2, 4 バイト。
1566: void
1567: m88200CacheSet::Write(int line, uint32 paddr, uint32 data, int size)
1568: {
1569: uint32 wordidx = (paddr >> 2) & 0x03;
1570: uint32 data32;
1571:
1572: if (__predict_true(size == 4)) {
1573: word[line * 4 + wordidx] = data;
1574: return;
1575: }
1576:
1577: data32 = word[line * 4 + wordidx];
1578: if (size == 2) {
1579: if ((paddr & 2) == 0) {
1580: data32 = (data32 & 0x0000ffff) | (data << 16);
1581: } else {
1582: data32 = (data32 & 0xffff0000) | data;
1583: }
1584: } else {
1585: switch (paddr & 3) {
1586: case 0:
1587: data32 = (data32 & 0x00ffffff) | (data << 24);
1588: break;
1589: case 1:
1590: data32 = (data32 & 0xff00ffff) | (data << 16);
1591: break;
1592: case 2:
1593: data32 = (data32 & 0xffff00ff) | (data << 8);
1594: break;
1595: case 3:
1596: data32 = (data32 & 0xffffff00) | data;
1597: break;
1598: default:
1599: __unreachable();
1600: }
1601: }
1602: word[line * 4 + wordidx] = data32;
1603: }
1604:
1.1.1.3 root 1605: // キャッシュを検索。
1606: // ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。
1607: int
1608: m88200CacheSet::Lookup(uint32 tagaddr) const
1609: {
1610: for (int line = 0; line < 4; line++) {
1611: if (tag[line] == tagaddr) {
1612: return line;
1613: }
1614: }
1615: return -1;
1616: }
1617:
1618:
1619: // キャッシュの指定の set, line にメモリから 1 ライン(4word) 読み込む。
1.1 root 1620: // 成功すれば 0 を返す。
1.1.1.3 root 1621: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1.1 root 1622: uint64
1.1.1.3 root 1623: m88200::ReadLine(m88200CacheSet& set, int line, uint32 tagaddr)
1.1 root 1624: {
1625: uint32 addr;
1.1.1.3 root 1626: uint64 data;
1627:
1628: // キャッシュラインの充填は実機では Burst Read されているらしいが
1629: // nono では Burst Read 用のメソッドは用意しておらず通常の 32bit
1630: // アクセスをしているため、このままでは所要ウェイト数が正しくない。
1631: // そこでここで差を調整することにする。
1632: // vm_phys_read_32() 4回なのでこれによって 12 wait が加算される。一方
1633: // 実機の Burst Read は取扱説明書によると 320ns (8 サイクル) で完了
1634: // するようなので、その差 4 をあらかじめ引いておく。
1635: // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.4 ! root 1636: AddCycle(-4);
1.1.1.3 root 1637:
1638: // タグを更新
1639: set.tag[line] = tagaddr;
1.1 root 1640:
1.1.1.3 root 1641: addr = set.tag[line] | (set.setidx << 4);
1.1 root 1642: for (int i = 0; i < 4; i++) {
1.1.1.3 root 1643: data = vm_phys_read_32(addr);
1644: if ((int64)data < 0) {
1645: fault_code = FAULT_CODE_BUSERR;
1646: fault_addr = addr;
1647: return data;
1.1 root 1648: }
1.1.1.3 root 1649: set.word[line * 4 + i] = data;
1.1 root 1650: addr += 4;
1651: }
1652: return 0;
1653: }
1654:
1.1.1.3 root 1655: // キャッシュの指定の set, line を1ライン、メモリに書き出す(コピーバック)。
1656: // 成功すれば 0 を返す。
1657: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1658: uint64
1659: m88200::CopyBackLine(m88200CacheSet& set, int line)
1.1 root 1660: {
1.1.1.3 root 1661: uint32 addr;
1662:
1663: // キャッシュラインの書き出しは実機では Burst Write されているらしいが
1664: // nono では Burst Write 用のメソッドは用意しておらず通常の 32bit
1665: // アクセスをしているため、このままでは所要ウェイト数が正しくない。
1666: // そこでここで差を調整することにする。
1667: // vm_phys_write_32() 4回なのでこれによって 8 wait が加算される。一方
1668: // 実機の Burst Write は取扱説明書によると 280ns (7サイクル) で完了する
1669: // ようなので、その差 1 をあらかじめて引いておく。
1670: // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.4 ! root 1671: AddCycle(-1);
1.1.1.3 root 1672:
1673: addr = set.tag[line] | (set.setidx << 4);
1674: for (int i = 0; i < 4; i++) {
1675: uint64 rv = vm_phys_write_32(addr, set.word[line * 4 + i]);
1676: if ((int64)rv < 0) {
1677: fault_code = FAULT_CODE_BUSERR;
1678: fault_addr = addr;
1679: return rv;
1.1 root 1680: }
1.1.1.3 root 1681: addr += 4;
1.1 root 1682: }
1.1.1.3 root 1683: return 0;
1.1 root 1684: }
1685:
1686: // キャッシュに対して paddr の読み込みを行う。
1687: // paddr は 32bit 境界のアドレスであること。
1688: // 読み込めれば該当の32bitワードを返す。
1689: // 何らかエラーが起きれば (uint64)-1 を返す。エラー要因は fault_code とか参照。
1690: // p.3-8 Figure 3-3
1691: uint64
1692: m88200::CacheRead(uint32 paddr)
1693: {
1694: int line;
1695: uint64 rv;
1696:
1697: assert((paddr & 3) == 0);
1698:
1699: // タグとセット番号
1700: uint32 tagaddr = (paddr & 0xfffff000);
1701: uint32 setidx = (paddr >> 4) & 0xff;
1702: uint32 wordidx = (paddr >> 2) & 0x03;
1703:
1704: m88200CacheSet& set = setarray[setidx];
1705: putlog(3, "CacheRead paddr=$%08x (set=$%02x)", paddr, setidx);
1706:
1707: line = set.Lookup(tagaddr);
1708: if (line >= 0) {
1709: // Cache Hit
1710: putlog(4, " CacheRead hit (line=%d,word=%d)", line, wordidx);
1.1.1.3 root 1711: parent->AddCycle(1);
1.1 root 1712: goto success;
1713: }
1714:
1715: // Cache Miss
1716:
1.1.1.3 root 1717: parent->AddCycle(10); // Table.6-2
1718:
1.1 root 1719: // reply <- Wait
1720: MBusAcquire();
1721:
1722: // Select cache line for replacement
1723: line = set.SelectOldestLine();
1724: putlog(4, " CacheRead miss (replace line=%d)", line);
1725:
1726: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 1727: parent->AddCycle(7); // Table.6-2
1728: rv = CopyBackLine(set, line);
1.1 root 1729: if ((int64)rv < 0) {
1730: goto error;
1731: }
1732: }
1733:
1734: // Mark cache line invalid
1735: set.Update(line, m88200CacheSet::IV);
1736:
1737: // Read line from memory
1.1.1.3 root 1738: rv = ReadLine(set, line, tagaddr);
1.1 root 1739: if ((int64)rv < 0) {
1740: goto error;
1741: }
1742:
1743: MBusRelease();
1744:
1745: // Update cache line
1746: set.Update(line, m88200CacheSet::SU);
1747:
1748: putlog(4, " CacheRead updated (line=%d,word=%d)", line, wordidx);
1749: success:
1750: set.Use(line);
1751: return set.word[line * 4 + wordidx];
1752:
1753: error:
1754: MBusRelease();
1755: return (uint64)-1;
1756: }
1757:
1758: // キャッシュに対して paddr への data の書き込みを行う。size は 1, 2, 4 バイト。
1759: // paddr は size に応じた境界にあること。
1760: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
1761: // エラー要因は fault_code とか参照。
1762: // p.3-10 Figure 3-5
1763: uint64
1764: m88200::CacheWrite(uint32 paddr, uint32 data, int size)
1765: {
1766: int line;
1767: uint64 rv;
1768:
1769: assert((paddr & (size - 1)) == 0);
1770:
1771: // タグとセット番号
1772: uint32 tagaddr = (paddr & 0xfffff000);
1773: uint32 setidx = (paddr >> 4) & 0xff;
1774:
1775: m88200CacheSet& set = setarray[setidx];
1776: putlog(3, "CacheWrite paddr=$%08x (set=$%02x)", paddr, setidx);
1777:
1778: line = set.Lookup(tagaddr);
1779: if (line >= 0) {
1780: // Cache Hit
1.1.1.3 root 1781: parent->AddCycle(1);
1.1 root 1782: return CacheWriteHit(set, line, paddr, data, size);
1783: }
1784:
1785: // Cache Miss
1786:
1.1.1.3 root 1787: parent->AddCycle(14); // Table.6-2
1788:
1.1 root 1789: // reply <- Wait
1790: MBusAcquire();
1791:
1792: // Select cache line for replacement
1793: line = set.SelectOldestLine();
1794: putlog(4, " CacheWrite miss (replace line=%d)", line);
1795:
1796: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 1797: parent->AddCycle(7); // Table.6-2
1798: rv = CopyBackLine(set, line);
1.1 root 1799: if ((int64)rv < 0) {
1800: goto error;
1801: }
1802: }
1803:
1804: // Mark line invalid
1805: set.Update(line, m88200CacheSet::IV);
1806:
1807: // Read line with intent to modify
1.1.1.3 root 1808: rv = ReadLine(set, line, tagaddr);
1.1 root 1809: if ((int64)rv < 0) {
1810: goto error;
1811: }
1812:
1813: // Write data to memory
1814: rv = MBusWrite(paddr, data, size);
1815: if ((int64)rv < 0) {
1.1.1.3 root 1816: goto error;
1.1 root 1817: }
1818:
1819: // Write data into cache
1820: set.Write(line, paddr, data, size);
1821:
1822: // Mark line exclusive unmodified
1823: set.Update(line, m88200CacheSet::EU);
1824: set.Use(line);
1825:
1826: MBusRelease();
1827: return 0;
1828:
1829: error:
1830: MBusRelease();
1831: return (uint64)-1;
1832: }
1833:
1834: // キャッシュがヒットした場合。
1835: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
1836: // p3-11 Figure 3-6
1837: uint64
1838: m88200::CacheWriteHit(m88200CacheSet& set, int line,
1839: uint32 paddr, uint32 data, int size)
1840: {
1841: uint64 rv;
1842:
1843: if (set.vv[line] == m88200CacheSet::SU) {
1844: // Line Shared Unmodified の場合
1845:
1846: putlog(4, " CacheWrite hit shared unmodified (line=%d)", line);
1847:
1848: // WriteThrough と Global は最後の状態変化だけが違う
1849: if ((acc_stat & (DESC_WT | DESC_G))) {
1850: // reply = Wait;
1851: MBusAcquire();
1852:
1853: // Write data to cache
1854: set.Write(line, paddr, data, size);
1855:
1856: // Write data to memory
1857: rv = MBusWrite(paddr, data, size);
1858: if ((int64)rv < 0) {
1859: MBusRelease();
1860: return rv;
1861: }
1862:
1863: if ((acc_stat & DESC_WT)) {
1864: // Mark line shared unmodified
1865: set.Update(line, m88200CacheSet::SU);
1866: } else {
1867: // Mark line exclusive unmodified
1868: set.Update(line, m88200CacheSet::EU);
1869: }
1870: set.Use(line);
1871:
1872: MBusRelease();
1873: return 0;
1874: }
1875:
1876: // どちらでもない場合は Line Exclusive と同じ処理に落ちる
1877: }
1878:
1879: // Line Exclusive の場合
1880:
1881: putlog(4, " CacheWrite hit exclusive (line=%d)", line);
1882:
1883: // Write data into cache
1884: putlog(4, " CacheWrite line=%d $%08x sz=%d", line, paddr, size);
1885: set.Write(line, paddr, data, size);
1886:
1887: // Mark line exclusive modified
1888: set.Update(line, m88200CacheSet::EM);
1889: set.Use(line);
1890: return 0;
1891: }
1892:
1893: // paddr への xmem を行う。size は 1, 2, 4 バイト。
1894: // 成功すれば読み出した値、エラーが起きれば (uint64)-1 を返す。
1895: // p3-13, Figure3-7
1896: uint64
1897: m88200::CacheXmem(uint32 paddr, uint32 data, int size)
1898: {
1899: int line;
1900: uint64 rv;
1901:
1902: assert((paddr & (size - 1)) == 0);
1903:
1904: // タグとセット番号
1905: uint32 tagaddr = (paddr & 0xfffff000);
1906: uint32 setidx = (paddr >> 4) & 0xff;
1907:
1908: m88200CacheSet& set = setarray[setidx];
1909: putlog(3, "CacheXmem paddr=$%08x (set=$%02x)", paddr, setidx);
1910:
1911: line = set.Lookup(tagaddr);
1912: if (line >= 0 && set.vv[line] == m88200CacheSet::EM) {
1913: // Cache Hit (and Line exclusive modified)
1914: putlog(4, " CacheXmem hit and EM (line=%d)", line);
1915:
1916: MBusAcquire();
1917:
1.1.1.3 root 1918: parent->AddCycle(7); // Table.6-2
1919: rv = CopyBackLine(set, line);
1.1 root 1920: if ((int64)rv < 0) {
1921: goto error;
1922: }
1923:
1924: set.Update(line, m88200CacheSet::IV);
1925: } else {
1926: // Cache Miss or (Cache Hit but other than exclusive modified)
1927:
1928: if (line >= 0) {
1929: // Cache Hit and Otherwise (= !EM)
1930: putlog(4, " CacheXmem hit but !EM (line=%d)", line);
1931: set.Update(line, m88200CacheSet::IV);
1932: } else {
1933: putlog(4, " CacheXmem miss");
1934: }
1935:
1936: MBusAcquire();
1937: }
1938:
1939: rv = MBusXmem(paddr, data, size);
1940: MBusRelease();
1941: return rv;
1942:
1943: error:
1944: MBusRelease();
1945: return rv;
1946: }
1.1.1.3 root 1947:
1948: // サイクルを加算する (VM から使う)
1949: void
1.1.1.4 ! root 1950: m88200::AddCycle(int32 cycle)
1.1.1.3 root 1951: {
1952: parent->AddCycle(cycle);
1953: }
1954:
1955: // MBus 使用権を取得する
1956: void
1957: m88200::MBusAcquire()
1958: {
1959: // アービトレーションのたびに1クロックかかる(?)
1960: // よく分からんけど、とりあえず、CMMU は一度所有権を持ったら放さない、
1961: // 別の CMMU がバスリクエストすると所有権はその CMMU に移る、とする。
1962: if (mbus_master != this) {
1963: mbus_master = this;
1964: parent->AddCycle(1);
1965: }
1966: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.