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