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