|
|
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_32(uint32 addr, uint32 data)
978: {
979: return xmem<32>(addr, data);
980: }
981:
982: //
983: // アドレス変換
984: //
985:
986: // デバッグ用
987: /*static*/ std::string
988: m88200::stat2str(uint32 stat)
989: {
990: std::string buf;
991:
992: if ((stat & m88200::DESC_WT))
993: buf += ",WT";
994: if ((stat & m88200::DESC_G))
995: buf += ",G";
996: if ((stat & m88200::DESC_CI))
997: buf += ",CI";
998: if ((stat & m88200::DESC_M))
999: buf += ",M";
1000: if ((stat & m88200::DESC_U))
1001: buf += ",U";
1002: if ((stat & m88200::DESC_WP))
1003: buf += ",WP";
1004:
1005: if (buf.empty()) {
1006: buf = ",0";
1007: }
1008: return buf.substr(1);
1009: }
1010:
1011: // アドレス変換。
1012: // 事前に acc_laddr, acc_super, acc_read を設定しておくこと。
1013: // 成功すれば acc_paddrH, acc_paddrL をセットして true を返す。
1014: // 失敗ならいろいろセットして(?) false を返す。
1015: // p2-3, Figure2-1
1016: bool
1017: m88200::Translate()
1018: {
1019: uint32 la;
1020:
1021: // Logical address(LA) presented on PBus
1022:
1023: putlog(3, "Translate %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
1024:
1025: // 下位2ビットは常にこうなる。
1026: acc_paddrL = acc_laddr & 3;
1027:
1028: // 2回しかループしないはず
1029: for (int loop = 0; loop < 3; loop++) {
1030: // Select Area Descriptor
1031: if (SelectAreaDesc() == false) {
1.1.1.3 root 1032: // XXX 図のこれはたぶん間違いだよなあ…
1033: // 誤: Physical Address <= LA[18-2] :: 00
1034: // 正: Physical Address <= LA[31-2] :: 00
1.1 root 1035: acc_paddrH = acc_laddr - acc_paddrL;
1.1.1.3 root 1036:
1037: parent->AddCycle(1);
1.1 root 1038: return true;
1039: }
1040:
1041: // type == Valid ここから
1042:
1043: // Search BATC first
1044: la = acc_laddr & 0xfff80000;
1045: la |= acc_super ? BATC_S : 0;
1046: for (int i = 0; i < batc.size(); i++) {
1047: m88200BATC& b = batc[i];
1048: if (b.lba == la) {
1049: // BATC hit
1050: putlog(4, " BATC[%d] hit", i);
1051: if (acc_IsWrite() && b.wp) {
1052: goto write_violation;
1053: }
1054:
1055: // Physical Address <= PBA :: LA[18-2] :: 00
1056: acc_paddrH = b.pba | (acc_laddr & 0x0007fffc);
1057: acc_stat |= b.stat;
1058: putlog(4, " BATC hit acc=%s paddr=$%08x",
1059: stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.3 root 1060:
1061: parent->AddCycle(1);
1.1 root 1062: return true;
1063: }
1064: }
1065:
1066: // BATC miss, search PATC then
1067: la = acc_laddr & 0xfffff000;
1068: la |= acc_super ? PATC_S : 0;
1069: acc_patc = NULL;
1070: for (int i = 0; i < patc.size(); i++) {
1071: m88200PATC& p = patc[i];
1072: if (p.lpa == la) {
1073: // PATC hit
1074: if (acc_IsWrite() && p.wp) {
1075: putlog(4, " PATC[%d] hit; stat=%s m=%d wp=%d", i,
1076: stat2str(p.stat).c_str(), p.m, p.wp);
1077: goto write_violation;
1078: }
1079: if (acc_IsWrite() && p.m == false) {
1080: // Update M bit
1081: // フローチャートでは PATC[M] はこの後のテーブルサーチ中
1082: // の Update Page Descriptor 処理中で更新するように書いて
1083: // あるように読めるのだが、その通りに実装すると、メモリ
1084: // 上の Page Descriptor に最初から M ビットが立っていると
1085: // (というか OpenBSD カーネルが用意した Page Descriptor
1086: // には立っているので) PATC[M] の更新も行われず、PATC[M]
1087: // が立っていないので再びここに来てしまい無限ループになる。
1088: // 誰が間違ってるのか分からないけど、とりあえずここで
1089: // PATC[M] を立てれば問題は起きない。
1090: putlog(4, " PATC[%d] hit; Need to update M bit", i);
1091: p.m = true;
1092:
1093: // この下の PATC miss に合流する
1094: acc_patc = &p;
1095: break;
1096: }
1097:
1098: // Physical Address <= PFA :: LA[11-2] :: 00
1099: acc_paddrH = p.pfa | (acc_laddr & 0x00000ffc);
1100: acc_stat |= p.stat;
1101: putlog(4, " PATC[%d] hit acc=%s paddr=$%08x", i,
1102: stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.3 root 1103:
1104: parent->AddCycle(1);
1.1 root 1105: return true;
1106: }
1107: }
1.1.1.2 root 1108: putlog(4, " BATC/PATC miss");
1.1 root 1109:
1110: // PATC miss
1111:
1112: // フローチャートでは PATC miss というラベルが付いてるが、コード
1113: // では acc_patc は PATC ループ前に NULL にしてあり(=miss)、
1114: // ループで PATC エントリが見付かれば acc_patc に代入してから
1115: // break してここに来るので、ちょっとだけ見た目と違うが意図してる
1116: // 動作は同じはず。
1117:
1118: // Table search operation
1119: if (TableSearch() == true) {
1120: continue;
1121: }
1122:
1123: // Invalid
1124: // Reply with fault (Figure2-10 だがここではすべて不要)
1125: return false;
1126: }
1127: PANIC("loop detected");
1128:
1129: write_violation:
1130: fault_code = FAULT_CODE_WRITE;
1131: //fault_addr UNKNOWN?
1132: // Reply with fault (Figure2-10 だがここではすべて不要)
1133: return false;
1134: }
1135:
1136:
1137: // Select Area Descriptor.
1138: // 結果が Type=Valid なら true、Type=Untranslated なら false を返す。
1139: // Probe Command からも呼ばれる。
1140: // p2-21, Figure2-5
1141: bool
1142: m88200::SelectAreaDesc()
1143: {
1144: const m88200APR *xapr;
1145:
1146: if (acc_super) {
1147: xapr = &sapr;
1148: } else {
1149: xapr = &uapr;
1150: }
1151:
1152: acc_stat = xapr->stat & ACC_STAT_MASK;
1153: if (xapr->enable) {
1154: // セグメントディスクリプタのアドレスはここで決まるが、
1155: // 次に行う BATC、PATC サーチでは使わず、それらが全部ミスして
1156: // テーブルサーチまで来た所で初めて使うので、ここでは表示しない。
1157: acc_sdaddr = xapr->addr | ((acc_laddr >> 20) & ~3U);
1158: putlog(4, " %s acc=%s", xapr->name, stat2str(acc_stat).c_str());
1159: return true;
1160: } else {
1161: putlog(3, " %s acc=%s Untranslated",
1162: xapr->name, stat2str(acc_stat).c_str());
1163: return false;
1164: }
1165: }
1166:
1167: // Table Search
1168: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1169: // p2-20, Figure2-4
1170: bool
1171: m88200::TableSearch()
1172: {
1173: putlog(4, " %s $%08x/%s acc=%s", __func__, acc_laddr,
1174: (acc_read ? "Read" : "Write"), stat2str(acc_stat).c_str());
1175:
1176: // XXX フローチャートを厳密に追っかけると MBus の Acquire/Release が
1177: // 対応していないので(orz)、ここでは
1178: // TableSearch() に入ったところで Acquire、
1179: // TableSearch() から出るところで Release だけに統一する。
1180:
1181: MBusAcquire();
1182:
1183: if (FetchSegmentDesc() == false) {
1184: MBusRelease();
1.1.1.3 root 1185:
1186: parent->AddCycle(7); // Table.6-2
1.1 root 1187: return false;
1188: }
1189:
1190: if (FetchPageDesc() == false) {
1191: MBusRelease();
1.1.1.3 root 1192:
1193: parent->AddCycle(11); // Table.6-2
1.1 root 1194: return false;
1195: }
1196:
1197: // 中央の TYPE = VALID のところ
1198: // ( )
1199: // +----------+ +----------+
1200: // | |
1201: // DESC[U]=0 || Otherwise
1202: // DESC[M]=0 && WRITE |
1203: // | |
1204: // UpdatePageDesc |
1205: // | |
1206: // <- RETRY -( )-- INVALID ---------- | -->
1207: // | |
1208: // VALID |
1209: // | |
1210: // ( ) <--------------------+
1211: // | |
1212: // +---+ +------------+
1213: // Otherwise TableSearch due to PATC miss
1214: // | |
1215: // (Only U/M bits CreatePATCEntry
1216: // Updated) |
1217: // | v
1218: // +---------------> ( )
1219:
1220: if ((tmp_desc & DESC_U) == 0 ||
1221: ((tmp_desc & DESC_M) == 0 && acc_IsWrite()))
1222: {
1.1.1.3 root 1223: parent->AddCycle(15); // Table.6-2
1224:
1.1 root 1225: if (UpdatePageDesc() == false) {
1226: MBusRelease();
1227: return false;
1228: }
1.1.1.3 root 1229: } else {
1230: parent->AddCycle(11); // Table.6-2
1.1 root 1231: }
1232:
1233: if (acc_patc == NULL) {
1234: // Table search due to PATC miss
1235: CreatePATCEntry();
1236: }
1237:
1238: MBusRelease();
1239: return true;
1240: }
1241:
1242: // Fetch Segment Descriptor
1243: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1244: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1245: // p2-22, Figure2-6
1246: bool
1247: m88200::FetchSegmentDesc()
1248: {
1249: uint64 data;
1250:
1251: data = MBusRead(acc_sdaddr, 4);
1252: if ((int64)data < 0) {
1253: return false;
1254: }
1255: tmp_desc = (uint32)data;
1256: tmp_desc &= (0xfffff000 |
1257: DESC_WT | DESC_SP | DESC_G | DESC_CI | DESC_WP | DESC_V);
1258:
1259: if ((tmp_desc & DESC_V) == 0) {
1260: fault_code = FAULT_CODE_SEGMENT;
1261: fault_addr = acc_sdaddr;
1262: putlog(4, " SD $%08x desc=$%08x SegFault", acc_sdaddr, tmp_desc);
1263: return false;
1264: } else {
1265: // Descriptor is valid
1266:
1267: if ((tmp_desc & DESC_SP) && acc_super == 0) {
1268: fault_code = FAULT_CODE_SUPERVISOR;
1269: fault_addr = acc_sdaddr;
1270: putlog(4, " SD $%08x desc=$%08x SupervisorFault",
1271: acc_sdaddr, tmp_desc);
1272: return false;
1273: }
1274:
1275: acc_pdaddr = (tmp_desc & 0xfffff000) | ((acc_laddr >> 10) & 0xffc);
1276: acc_stat |= tmp_desc & ACC_STAT_MASK;
1277: putlog(4, " SD $%08x pdaddr=$%08x stat=%s acc=%s",
1278: acc_sdaddr, acc_pdaddr,
1279: stat2str(tmp_desc).c_str(),
1280: stat2str(acc_stat).c_str());
1281: return true;
1282: }
1283: }
1284:
1285: // Fetch Page Descriptor
1286: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1287: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1288: // p2-23, Figure2-7
1289: bool
1290: m88200::FetchPageDesc()
1291: {
1292: uint64 data;
1293:
1294: data = MBusRead(acc_pdaddr, 4);
1295: if ((int64)data < 0) {
1296: return false;
1297: }
1298: tmp_desc = (uint32)data;
1299: tmp_desc &= (0xfffff000 | DESC_WT | DESC_SP | DESC_G | DESC_CI |
1300: DESC_M | DESC_U | DESC_WP | DESC_V);
1301:
1302: if ((tmp_desc & DESC_V) == 0) {
1303: fault_code = FAULT_CODE_PAGE;
1304: fault_addr = acc_pdaddr;
1305: putlog(4, " PD $%08x desc=$%08x PageFault", acc_pdaddr, tmp_desc);
1306: return false;
1307: } else {
1308: // Descriptor is valid
1309:
1310: if ((tmp_desc & DESC_SP) && acc_super == 0) {
1311: fault_code = FAULT_CODE_SUPERVISOR;
1312: fault_addr = acc_pdaddr;
1313: putlog(4, " PD $%08x desc=$%08x SupervisorFault",
1314: acc_pdaddr, tmp_desc);
1315: return false;
1316: }
1317:
1318: acc_stat |= tmp_desc & ACC_STAT_MASK;
1319:
1320: if ((acc_stat & DESC_WP) && acc_IsWrite()) {
1321: fault_code = FAULT_CODE_WRITE;
1322: // fault_addr は invalid data
1323: fault_addr = 0xdeadbeef;
1324: putlog(4, " PD $%08x desc=$%08x WriteFault", acc_pdaddr, tmp_desc);
1325: return false;
1326: } else {
1327: putlog(4, " PD $%08x stat=%s acc=%s", acc_pdaddr,
1328: stat2str(tmp_desc).c_str(),
1329: stat2str(acc_stat).c_str());
1330: return true;
1331: }
1332: }
1333: }
1334:
1335: // Update Page Descriptor
1336: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1337: // p2-24, Figure2-8
1338: bool
1339: m88200::UpdatePageDesc()
1340: {
1341: uint64 rv;
1342:
1343: if ((tmp_desc & DESC_M) == 0 && acc_IsWrite()) {
1344: // Update Modified bit and accrue status
1345:
1346: // XXX 図中 PATC[M] をセットするとあるが、ここでは遅い気がする。
1347: // Translate() 中の Update M bit のところのコメントも参照。
1348:
1349: // XXX 図中 ACC_STATUS[M] は TEMP_DESCR[M] じゃないの?
1350: tmp_desc |= DESC_M;
1351: }
1352:
1353: // Update Used bit
1354: tmp_desc |= DESC_U;
1355:
1356: rv = MBusWrite(acc_pdaddr, tmp_desc, 4);
1357: if ((int64)rv < 0) {
1358: return false;
1359: }
1360: putlog(4, " Update PD $%08x desc=$%08x stat=%s",
1361: acc_pdaddr, tmp_desc, stat2str(tmp_desc).c_str());
1362:
1363: return true;
1364: }
1365:
1366: // Create PATC Entry
1367: // 公式フローチャートと違って MBus Acquire したまま戻ること。
1368: // p2-25, Figure2-9
1369: void
1370: m88200::CreatePATCEntry()
1371: {
1372: // とりあえず線形探索で memcpy しとくべ
1373: memmove(&patc[1], &patc[0], sizeof(patc[0]) * (patc.size() - 1));
1374: // で、先頭に追加
1375: m88200PATC& p = patc[0];
1376:
1377: memset(&p, 0, sizeof(p));
1378: p.lpa = acc_laddr & 0xfffff000;
1379: p.pfa = tmp_desc & 0xfffff000;
1380: if (acc_super) {
1381: p.lpa |= PATC_S;
1382: }
1383: p.stat = acc_stat;
1384: putlog(4, " %s %c:$%08x:$%08x stat=%s", __func__,
1385: (p.lpa & PATC_S) ? 'S' : 'U', (p.lpa & 0xfffff000), p.pfa,
1386: stat2str(p.stat).c_str());
1387: }
1388:
1389: // アドレス変換 (デバッガ用)
1390: uint64
1391: m88200::TranslatePeek(uint32 laddr, bool issuper, bool do_search) const
1392: {
1393: const m88200APR *xapr;
1394: uint32 la;
1395:
1396: // Select Area Descriptor
1397: if (issuper) {
1398: xapr = &sapr;
1399: } else {
1400: xapr = &uapr;
1401: }
1402: if (xapr->enable == 0) {
1403: return laddr;
1404: }
1405:
1406: // Search BATC first
1407: la = laddr & 0xfff80000;
1408: la |= issuper ? BATC_S : 0;
1409: for (const auto& b : batc) {
1410: if (b.lba == la) {
1411: // BATC hit
1412: return b.pba | (laddr & 0x0007ffff);
1413: }
1414: }
1415:
1416: // BATC miss, search PATC then
1417: la = laddr & 0xfffff000;
1418: la |= issuper ? PATC_S : 0;
1419: for (const auto& p : patc) {
1420: if (p.lpa == la) {
1421: // PATC hit
1422: return p.pfa | (laddr & 0x00000fff);
1423: }
1424: }
1425:
1426: if (do_search == false) {
1427: return (uint64)-1;
1428: }
1429:
1430: // ここからテーブルサーチ
1431: uint64 data;
1432: uint32 desc_addr;
1433: uint32 desc;
1434:
1435: // Peek Segment Descriptor
1436: desc_addr = xapr->addr | ((laddr >> 20) & ~3U);
1437: data = vm_phys_peek_32(desc_addr);
1438: if ((int64)data < 0) {
1439: return data;
1440: }
1441: desc = (uint32)data;
1442: if ((desc & DESC_V) == 0) {
1443: return (uint64)-1;
1444: }
1445: if ((desc & DESC_SP) && issuper == false) {
1446: return (uint64)-1;
1447: }
1448:
1449: // Peek Page Descriptor
1450: desc_addr = (desc & 0xfffff000) | ((laddr >> 10) & 0xffc);
1451: data = vm_phys_peek_32(desc_addr);
1452: if ((int64)data < 0) {
1453: return data;
1454: }
1455: desc = (uint32)data;
1456: if ((desc & DESC_V) == 0) {
1457: return (uint64)-1;
1458: }
1459: if ((desc & DESC_SP) && issuper == false) {
1460: return (uint64)-1;
1461: }
1462:
1463: return (desc & 0xfffff000) | (laddr & 0x00000fff);
1464: }
1465:
1466:
1467: //
1468: // キャッシュ
1469: //
1470:
1471: // このラインの状態を更新
1472: void
1473: m88200CacheSet::Update(int line, m88200CacheSet::Status status)
1474: {
1475: vv[line] = status;
1476: if (status == IV) {
1477: // 無効なら
1478: tag[line] |= TAG_INVALID;
1479: L = TryUnuseLine(L, line);
1480: }
1481: }
1482:
1483: // CSSP L5-L0 の処理。
1484: // 引数 tmpL の状態から line を最新にしたらどうなるか、を返す。
1485: // 表示処理で一時変数に対して処理が必要なため分離してある。
1486: int
1487: m88200CacheSet::TryUseLine(int tmpL, int line)
1488: {
1489: // L フィールドは 3bit, 2bit, 1bit で構成され、
1490: // 他のラインの対応ビットを落として、
1491: // 自分のラインの対応ビットを全部立てれば、
1492: // 他のラインの順序を保存した状態で、自分が最新になるように
1493: // 順序をつけられる。
1494:
1495: if (line == 3) {
1496: tmpL |= 0b111'00'0;
1497: } else if (line == 2) {
1498: tmpL &= 0b011'11'1;
1499: tmpL |= 0b000'11'0;
1500: } else if (line == 1) {
1501: tmpL &= 0b101'01'1;
1502: tmpL |= 0b000'00'1;
1503: } else {
1504: tmpL &= 0b110'10'0;
1505: }
1506: return tmpL;
1507: }
1508:
1509: // CSSP L5-L0 の処理。
1510: // 引数 tmpL の状態から line を最古にしたらどうなるか、を返す。
1511: int
1512: m88200CacheSet::TryUnuseLine(int tmpL, int line)
1513: {
1514: // Use のちょうど反転論理
1515: if (line == 3) {
1516: tmpL &= 0b000'11'1;
1517: } else if (line == 2) {
1518: tmpL |= 0b100'00'0;
1519: tmpL &= 0b111'00'1;
1520: } else if (line == 1) {
1521: tmpL |= 0b010'10'0;
1522: tmpL &= 0b111'11'0;
1523: } else {
1524: tmpL |= 0b001'01'1;
1525: }
1526: return tmpL;
1527: }
1528:
1529: // CSSP L5-L0 の処理。
1530: // 引数 tmpL の状態で、最新の line を返す。
1531: // 表示処理で一時変数に対して処理が必要なため分離してある。
1532: int
1533: m88200CacheSet::TryGetOldestLine(int tmpL)
1534: {
1535: if (tmpL < 8) {
1536: return 3;
1537: }
1538: tmpL &= 7;
1539: if (tmpL < 2) {
1540: return 2;
1541: }
1542: tmpL &= 1;
1543: if (tmpL == 0) {
1544: return 1;
1545: } else {
1546: return 0;
1547: }
1548: }
1549:
1550: // 更新用に最も古いラインを選んで差し出す
1551: int
1552: m88200CacheSet::SelectOldestLine() const
1553: {
1554: // なければ、最も古いラインを差し出す
1555: return TryGetOldestLine(L);
1556: }
1557:
1558: // キャッシュの指定の line, word に data を書き込む。
1559: // size は 1, 2, 4 バイト。
1560: void
1561: m88200CacheSet::Write(int line, uint32 paddr, uint32 data, int size)
1562: {
1563: uint32 wordidx = (paddr >> 2) & 0x03;
1564: uint32 data32;
1565:
1566: if (__predict_true(size == 4)) {
1567: word[line * 4 + wordidx] = data;
1568: return;
1569: }
1570:
1571: data32 = word[line * 4 + wordidx];
1572: if (size == 2) {
1573: if ((paddr & 2) == 0) {
1574: data32 = (data32 & 0x0000ffff) | (data << 16);
1575: } else {
1576: data32 = (data32 & 0xffff0000) | data;
1577: }
1578: } else {
1579: switch (paddr & 3) {
1580: case 0:
1581: data32 = (data32 & 0x00ffffff) | (data << 24);
1582: break;
1583: case 1:
1584: data32 = (data32 & 0xff00ffff) | (data << 16);
1585: break;
1586: case 2:
1587: data32 = (data32 & 0xffff00ff) | (data << 8);
1588: break;
1589: case 3:
1590: data32 = (data32 & 0xffffff00) | data;
1591: break;
1592: default:
1593: __unreachable();
1594: }
1595: }
1596: word[line * 4 + wordidx] = data32;
1597: }
1598:
1.1.1.3 root 1599: // キャッシュを検索。
1600: // ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。
1601: int
1602: m88200CacheSet::Lookup(uint32 tagaddr) const
1603: {
1604: for (int line = 0; line < 4; line++) {
1605: if (tag[line] == tagaddr) {
1606: return line;
1607: }
1608: }
1609: return -1;
1610: }
1611:
1612:
1613: // キャッシュの指定の set, line にメモリから 1 ライン(4word) 読み込む。
1.1 root 1614: // 成功すれば 0 を返す。
1.1.1.3 root 1615: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1.1 root 1616: uint64
1.1.1.3 root 1617: m88200::ReadLine(m88200CacheSet& set, int line, uint32 tagaddr)
1.1 root 1618: {
1619: uint32 addr;
1.1.1.3 root 1620: uint64 data;
1621:
1622: // キャッシュラインの充填は実機では Burst Read されているらしいが
1623: // nono では Burst Read 用のメソッドは用意しておらず通常の 32bit
1624: // アクセスをしているため、このままでは所要ウェイト数が正しくない。
1625: // そこでここで差を調整することにする。
1626: // vm_phys_read_32() 4回なのでこれによって 12 wait が加算される。一方
1627: // 実機の Burst Read は取扱説明書によると 320ns (8 サイクル) で完了
1628: // するようなので、その差 4 をあらかじめ引いておく。
1629: // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.4 root 1630: AddCycle(-4);
1.1.1.3 root 1631:
1632: // タグを更新
1633: set.tag[line] = tagaddr;
1.1 root 1634:
1.1.1.3 root 1635: addr = set.tag[line] | (set.setidx << 4);
1.1 root 1636: for (int i = 0; i < 4; i++) {
1.1.1.3 root 1637: data = vm_phys_read_32(addr);
1638: if ((int64)data < 0) {
1639: fault_code = FAULT_CODE_BUSERR;
1640: fault_addr = addr;
1641: return data;
1.1 root 1642: }
1.1.1.3 root 1643: set.word[line * 4 + i] = data;
1.1 root 1644: addr += 4;
1645: }
1646: return 0;
1647: }
1648:
1.1.1.3 root 1649: // キャッシュの指定の set, line を1ライン、メモリに書き出す(コピーバック)。
1650: // 成功すれば 0 を返す。
1651: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1652: uint64
1653: m88200::CopyBackLine(m88200CacheSet& set, int line)
1.1 root 1654: {
1.1.1.3 root 1655: uint32 addr;
1656:
1657: // キャッシュラインの書き出しは実機では Burst Write されているらしいが
1658: // nono では Burst Write 用のメソッドは用意しておらず通常の 32bit
1659: // アクセスをしているため、このままでは所要ウェイト数が正しくない。
1660: // そこでここで差を調整することにする。
1661: // vm_phys_write_32() 4回なのでこれによって 8 wait が加算される。一方
1662: // 実機の Burst Write は取扱説明書によると 280ns (7サイクル) で完了する
1663: // ようなので、その差 1 をあらかじめて引いておく。
1664: // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.4 root 1665: AddCycle(-1);
1.1.1.3 root 1666:
1667: addr = set.tag[line] | (set.setidx << 4);
1668: for (int i = 0; i < 4; i++) {
1669: uint64 rv = vm_phys_write_32(addr, set.word[line * 4 + i]);
1670: if ((int64)rv < 0) {
1671: fault_code = FAULT_CODE_BUSERR;
1672: fault_addr = addr;
1673: return rv;
1.1 root 1674: }
1.1.1.3 root 1675: addr += 4;
1.1 root 1676: }
1.1.1.3 root 1677: return 0;
1.1 root 1678: }
1679:
1680: // キャッシュに対して paddr の読み込みを行う。
1681: // paddr は 32bit 境界のアドレスであること。
1682: // 読み込めれば該当の32bitワードを返す。
1683: // 何らかエラーが起きれば (uint64)-1 を返す。エラー要因は fault_code とか参照。
1684: // p.3-8 Figure 3-3
1685: uint64
1686: m88200::CacheRead(uint32 paddr)
1687: {
1688: int line;
1689: uint64 rv;
1690:
1691: assert((paddr & 3) == 0);
1692:
1693: // タグとセット番号
1694: uint32 tagaddr = (paddr & 0xfffff000);
1695: uint32 setidx = (paddr >> 4) & 0xff;
1696: uint32 wordidx = (paddr >> 2) & 0x03;
1697:
1698: m88200CacheSet& set = setarray[setidx];
1699: putlog(3, "CacheRead paddr=$%08x (set=$%02x)", paddr, setidx);
1700:
1701: line = set.Lookup(tagaddr);
1702: if (line >= 0) {
1703: // Cache Hit
1704: putlog(4, " CacheRead hit (line=%d,word=%d)", line, wordidx);
1.1.1.3 root 1705: parent->AddCycle(1);
1.1 root 1706: goto success;
1707: }
1708:
1709: // Cache Miss
1710:
1.1.1.3 root 1711: parent->AddCycle(10); // Table.6-2
1712:
1.1 root 1713: // reply <- Wait
1714: MBusAcquire();
1715:
1716: // Select cache line for replacement
1717: line = set.SelectOldestLine();
1718: putlog(4, " CacheRead miss (replace line=%d)", line);
1719:
1720: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 1721: parent->AddCycle(7); // Table.6-2
1722: rv = CopyBackLine(set, line);
1.1 root 1723: if ((int64)rv < 0) {
1724: goto error;
1725: }
1726: }
1727:
1728: // Mark cache line invalid
1729: set.Update(line, m88200CacheSet::IV);
1730:
1731: // Read line from memory
1.1.1.3 root 1732: rv = ReadLine(set, line, tagaddr);
1.1 root 1733: if ((int64)rv < 0) {
1734: goto error;
1735: }
1736:
1737: MBusRelease();
1738:
1739: // Update cache line
1740: set.Update(line, m88200CacheSet::SU);
1741:
1742: putlog(4, " CacheRead updated (line=%d,word=%d)", line, wordidx);
1743: success:
1744: set.Use(line);
1745: return set.word[line * 4 + wordidx];
1746:
1747: error:
1748: MBusRelease();
1749: return (uint64)-1;
1750: }
1751:
1752: // キャッシュに対して paddr への data の書き込みを行う。size は 1, 2, 4 バイト。
1753: // paddr は size に応じた境界にあること。
1754: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
1755: // エラー要因は fault_code とか参照。
1756: // p.3-10 Figure 3-5
1757: uint64
1758: m88200::CacheWrite(uint32 paddr, uint32 data, int size)
1759: {
1760: int line;
1761: uint64 rv;
1762:
1763: assert((paddr & (size - 1)) == 0);
1764:
1765: // タグとセット番号
1766: uint32 tagaddr = (paddr & 0xfffff000);
1767: uint32 setidx = (paddr >> 4) & 0xff;
1768:
1769: m88200CacheSet& set = setarray[setidx];
1770: putlog(3, "CacheWrite paddr=$%08x (set=$%02x)", paddr, setidx);
1771:
1772: line = set.Lookup(tagaddr);
1773: if (line >= 0) {
1774: // Cache Hit
1.1.1.3 root 1775: parent->AddCycle(1);
1.1 root 1776: return CacheWriteHit(set, line, paddr, data, size);
1777: }
1778:
1779: // Cache Miss
1780:
1.1.1.3 root 1781: parent->AddCycle(14); // Table.6-2
1782:
1.1 root 1783: // reply <- Wait
1784: MBusAcquire();
1785:
1786: // Select cache line for replacement
1787: line = set.SelectOldestLine();
1788: putlog(4, " CacheWrite miss (replace line=%d)", line);
1789:
1790: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 1791: parent->AddCycle(7); // Table.6-2
1792: rv = CopyBackLine(set, line);
1.1 root 1793: if ((int64)rv < 0) {
1794: goto error;
1795: }
1796: }
1797:
1798: // Mark line invalid
1799: set.Update(line, m88200CacheSet::IV);
1800:
1801: // Read line with intent to modify
1.1.1.3 root 1802: rv = ReadLine(set, line, tagaddr);
1.1 root 1803: if ((int64)rv < 0) {
1804: goto error;
1805: }
1806:
1807: // Write data to memory
1808: rv = MBusWrite(paddr, data, size);
1809: if ((int64)rv < 0) {
1.1.1.3 root 1810: goto error;
1.1 root 1811: }
1812:
1813: // Write data into cache
1814: set.Write(line, paddr, data, size);
1815:
1816: // Mark line exclusive unmodified
1817: set.Update(line, m88200CacheSet::EU);
1818: set.Use(line);
1819:
1820: MBusRelease();
1821: return 0;
1822:
1823: error:
1824: MBusRelease();
1825: return (uint64)-1;
1826: }
1827:
1828: // キャッシュがヒットした場合。
1829: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
1830: // p3-11 Figure 3-6
1831: uint64
1832: m88200::CacheWriteHit(m88200CacheSet& set, int line,
1833: uint32 paddr, uint32 data, int size)
1834: {
1835: uint64 rv;
1836:
1837: if (set.vv[line] == m88200CacheSet::SU) {
1838: // Line Shared Unmodified の場合
1839:
1840: putlog(4, " CacheWrite hit shared unmodified (line=%d)", line);
1841:
1842: // WriteThrough と Global は最後の状態変化だけが違う
1843: if ((acc_stat & (DESC_WT | DESC_G))) {
1844: // reply = Wait;
1845: MBusAcquire();
1846:
1847: // Write data to cache
1848: set.Write(line, paddr, data, size);
1849:
1850: // Write data to memory
1851: rv = MBusWrite(paddr, data, size);
1852: if ((int64)rv < 0) {
1853: MBusRelease();
1854: return rv;
1855: }
1856:
1857: if ((acc_stat & DESC_WT)) {
1858: // Mark line shared unmodified
1859: set.Update(line, m88200CacheSet::SU);
1860: } else {
1861: // Mark line exclusive unmodified
1862: set.Update(line, m88200CacheSet::EU);
1863: }
1864: set.Use(line);
1865:
1866: MBusRelease();
1867: return 0;
1868: }
1869:
1870: // どちらでもない場合は Line Exclusive と同じ処理に落ちる
1871: }
1872:
1873: // Line Exclusive の場合
1874:
1875: putlog(4, " CacheWrite hit exclusive (line=%d)", line);
1876:
1877: // Write data into cache
1878: putlog(4, " CacheWrite line=%d $%08x sz=%d", line, paddr, size);
1879: set.Write(line, paddr, data, size);
1880:
1881: // Mark line exclusive modified
1882: set.Update(line, m88200CacheSet::EM);
1883: set.Use(line);
1884: return 0;
1885: }
1886:
1887: // paddr への xmem を行う。size は 1, 2, 4 バイト。
1888: // 成功すれば読み出した値、エラーが起きれば (uint64)-1 を返す。
1889: // p3-13, Figure3-7
1890: uint64
1891: m88200::CacheXmem(uint32 paddr, uint32 data, int size)
1892: {
1893: int line;
1894: uint64 rv;
1895:
1896: assert((paddr & (size - 1)) == 0);
1897:
1898: // タグとセット番号
1899: uint32 tagaddr = (paddr & 0xfffff000);
1900: uint32 setidx = (paddr >> 4) & 0xff;
1901:
1902: m88200CacheSet& set = setarray[setidx];
1903: putlog(3, "CacheXmem paddr=$%08x (set=$%02x)", paddr, setidx);
1904:
1905: line = set.Lookup(tagaddr);
1906: if (line >= 0 && set.vv[line] == m88200CacheSet::EM) {
1907: // Cache Hit (and Line exclusive modified)
1908: putlog(4, " CacheXmem hit and EM (line=%d)", line);
1909:
1910: MBusAcquire();
1911:
1.1.1.3 root 1912: parent->AddCycle(7); // Table.6-2
1913: rv = CopyBackLine(set, line);
1.1 root 1914: if ((int64)rv < 0) {
1915: goto error;
1916: }
1917:
1918: set.Update(line, m88200CacheSet::IV);
1919: } else {
1920: // Cache Miss or (Cache Hit but other than exclusive modified)
1921:
1922: if (line >= 0) {
1923: // Cache Hit and Otherwise (= !EM)
1924: putlog(4, " CacheXmem hit but !EM (line=%d)", line);
1925: set.Update(line, m88200CacheSet::IV);
1926: } else {
1927: putlog(4, " CacheXmem miss");
1928: }
1929:
1930: MBusAcquire();
1931: }
1932:
1933: rv = MBusXmem(paddr, data, size);
1934: MBusRelease();
1935: return rv;
1936:
1937: error:
1938: MBusRelease();
1939: return rv;
1940: }
1.1.1.3 root 1941:
1942: // サイクルを加算する (VM から使う)
1943: void
1.1.1.4 root 1944: m88200::AddCycle(int32 cycle)
1.1.1.3 root 1945: {
1946: parent->AddCycle(cycle);
1947: }
1948:
1949: // MBus 使用権を取得する
1950: void
1951: m88200::MBusAcquire()
1952: {
1953: // アービトレーションのたびに1クロックかかる(?)
1954: // よく分からんけど、とりあえず、CMMU は一度所有権を持ったら放さない、
1955: // 別の CMMU がバスリクエストすると所有権はその CMMU に移る、とする。
1956: if (mbus_master != this) {
1957: mbus_master = this;
1958: parent->AddCycle(1);
1959: }
1960: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.