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