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