|
|
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 "m88200.h"
1.1.1.11 root 10: #include "mainbus.h"
11: #include "mpu88xx0.h"
1.1 root 12:
1.1.1.3 root 13: // static 変数
14: m88200 *m88200::mbus_master = NULL;
15:
1.1 root 16: // m88200 コンストラクタ
1.1.1.11 root 17: m88200::m88200(MPU88xx0Device *parent_, uint id_)
18: : inherited(OBJ_M88200(id_))
1.1 root 19: {
1.1.1.11 root 20: parent = parent_;
21:
22: // ID は IDR レジスタへの書き込みで後から変更できるように読めるが、
23: // ハードウェアパラメータのはずだし変更する意味はないのと、仮に変更しても
24: // 実際訳の分からんことにしかならんと思う。
25: // そして PROM も OpenBSD/luna88k も IDR へ書き込んでいないので、やはり
26: // あらかじめ決まっているハードウェアパラメータだと思うことにする。
27: // それと、コンストラクタ時点で ID が決まってないのは何かと困るという
28: // こちらの都合もある。
29: id = id_;
30:
31: ClearAlias();
32: AddAlias(string_format("CMMU%u", id));
1.1 root 33:
1.1.1.9 root 34: reg_monitor.func = ToMonitorCallback(&m88200::MonitorUpdateReg);
1.1.1.7 root 35: reg_monitor.SetSize(52, 8);
1.1.1.11 root 36: reg_monitor.Regist(ID_MONITOR_CMMU(id));
37:
1.1.1.9 root 38: atc_monitor.func = ToMonitorCallback(&m88200::MonitorUpdateATC);
39: #if defined(M88200_STAT)
1.1.1.12! root 40: atc_monitor.SetSize(77, 44 + 5);
1.1.1.9 root 41: #else
1.1.1.12! root 42: atc_monitor.SetSize(77, 44);
1.1.1.9 root 43: #endif
1.1.1.11 root 44: atc_monitor.Regist(ID_MONITOR_ATC(id));
45:
1.1.1.9 root 46: cache_monitor.func = ToMonitorCallback(&m88200::MonitorUpdateCache);
1.1.1.7 root 47: cache_monitor.SetSize(82, 23);
1.1.1.11 root 48: cache_monitor.Regist(ID_SUBWIN_CACHE(id));
1.1 root 49:
50: // ログ表示用の名前
51: sapr.name = "SAPR";
52: uapr.name = "UAPR";
53: }
54:
55: // m88200 デストラクタ
56: m88200::~m88200()
57: {
58: }
59:
1.1.1.11 root 60: // 初期化
61: bool
62: m88200::Init()
1.1 root 63: {
1.1.1.11 root 64: if (inherited::Init() == false) {
65: return false;
66: }
67:
68: mainbus = GetMainbusDevice();
69:
1.1.1.12! root 70: memset(&atc_hash_all[0], 0, atc_hash_all.size());
! 71: for (auto& b : batc) {
! 72: b.lba |= BATC_INVALID;
! 73: }
! 74: for (auto& p : patc) {
! 75: p.lpa |= PATC_INVALID;
! 76: }
! 77:
! 78: // 暗黙 BATC を初期化
! 79: SetBATC(8, 0xfff00000, 0xfff00000, BWP_S | BWP_WT | BWP_CI | BWP_V);
! 80: SetBATC(9, 0xfff80000, 0xfff80000, BWP_S | BWP_WT | BWP_CI | BWP_V);
! 81:
! 82: // セットインデックスを初期化
! 83: for (int i = 0; i < setarray.size(); i++) {
! 84: auto& set = setarray[i];
! 85: set.setidx = i;
! 86: }
! 87:
1.1.1.11 root 88: return true;
1.1 root 89: }
90:
91: // リセット
92: void
93: m88200::Reset()
94: {
1.1.1.3 root 95: const uint32 Undefined = 0xcccccccc;
96:
1.1 root 97: // レジスタ (p6-4, Table6-3)
1.1.1.3 root 98: // ID, version は別途 Set される。
1.1 root 99: command = 0;
100: ssr = 0;
1.1.1.3 root 101: sar = Undefined;
1.1 root 102: sctr = 0;
103: fault_code = 0;
1.1.1.3 root 104: fault_addr = Undefined;
1.1 root 105: sapr.enable = false;
106: sapr.stat = APR_CI;
107: uapr.enable = false;
108: uapr.stat = APR_CI;
1.1.1.12! root 109:
! 110: // BATC, PATC はリセットで初期化されないようだが確認のしようがない。
1.1 root 111: }
112:
1.1.1.7 root 113: // モニター更新 (CMMU レジスタ)
1.1.1.2 root 114: void
1.1.1.7 root 115: m88200::MonitorUpdateReg(Monitor *, TextScreen& screen)
1.1 root 116: {
1.1.1.3 root 117: uint32 baseaddr;
1.1 root 118: uint32 reg;
119: int x;
120: int y;
121:
1.1.1.3 root 122: baseaddr = 0xfff00000 + (id << 12);
123:
1.1.1.7 root 124: screen.Clear();
1.1.1.3 root 125: x = 24;
1.1 root 126:
127: y = 0;
1.1.1.7 root 128: screen.Print(0, y++, "$%08x IDR:%08x ID=$%02x Type=5(88200) Ver=$%x",
1.1.1.3 root 129: baseaddr + 0, GetIDR(), id, version);
1.1 root 130:
131: reg = GetSSR();
1.1.1.7 root 132: screen.Print(0, y, "$%08x SSR:%08x", baseaddr + 0x008, reg);
133: screen.Puts(x, y, TA::OnOff(reg & SSR_CE), "CE");
134: screen.Puts(x + 3, y, TA::OnOff(reg & SSR_BE), "BE");
135: screen.Puts(x + 6, y, TA::OnOff(reg & SSR_WT), "WT");
136: screen.Puts(x + 9, y, TA::OnOff(reg & SSR_SP), "SP");
137: screen.Puts(x + 12, y, TA::OnOff(reg & SSR_G), "G");
138: screen.Puts(x + 14, y, TA::OnOff(reg & SSR_CI), "CI");
139: screen.Puts(x + 17, y, TA::OnOff(reg & SSR_M), "M");
140: screen.Puts(x + 19, y, TA::OnOff(reg & SSR_U), "U");
141: screen.Puts(x + 21, y, TA::OnOff(reg & SSR_WP), "WP");
142: screen.Puts(x + 24, y, TA::OnOff(reg & SSR_BH), "BH");
143: screen.Puts(x + 27, y, TA::OnOff(reg & SSR_V), "V");
1.1 root 144: y++;
145:
1.1.1.7 root 146: screen.Print(0, y++, "$%08x SAR:%08x", baseaddr + 0x00c, GetSAR());
1.1 root 147:
148: reg = GetSCTR();
1.1.1.7 root 149: screen.Print(0, y, "$%08x SCTR:%08x", baseaddr + 0x104, GetSCTR());
150: screen.Puts(x, y, TA::OnOff(reg & SCTR_PE), "PE");
151: screen.Puts(x + 3, y, TA::OnOff(reg & SCTR_SE), "SE");
152: screen.Puts(x + 6, y, TA::OnOff(reg & SCTR_PR), "PR");
1.1 root 153: y++;
154:
155: reg = GetPFSR();
156: static const char * const codestr[] = {
157: "Success",
158: "1?",
159: "2?",
160: "Bus Error",
161: "Segment Fault",
162: "Page Fault",
163: "Supervisor Violation",
164: "Write Violation",
165: };
1.1.1.7 root 166: screen.Print(0, y++, "$%08x PFSR:%08x %s", baseaddr + 0x108,
1.1.1.3 root 167: reg, codestr[fault_code]);
1.1 root 168:
1.1.1.7 root 169: screen.Print(0, y++, "$%08x PFAR:%08x", baseaddr + 0x10c, GetPFAR());
1.1 root 170:
171: for (int i = 0; i < 2; i++) {
172: int s = 1 - i;
173: reg = GetAPR(s);
1.1.1.7 root 174: screen.Print(0, y, "$%08x %cAPR:%08x", baseaddr + 0x200 + i * 4,
1.1.1.3 root 175: s ? 'S' : 'U', reg);
1.1.1.7 root 176: screen.Print(x, y, "STBA=%05x'000 %c%c%c%c",
1.1 root 177: reg >> 12,
178: (reg & APR_WT) ? 'T' : '-',
179: (reg & APR_G) ? 'G' : '-',
180: (reg & APR_CI) ? 'C' : '-',
181: (reg & APR_TE) ? 'E' : '-');
182: y++;
183: }
184: }
185:
1.1.1.7 root 186: // モニター更新 (ATC)
187: void
188: m88200::MonitorUpdateATC(Monitor *, TextScreen& screen)
189: {
190: int x;
191: int y;
192:
193: screen.Clear();
194:
195: screen.Print(0, 0, "SAPR %05x'000 TE=%d %c%c%c",
196: (sapr.addr >> 12) & 0xfffff,
197: sapr.enable ? 1 : 0,
1.1.1.9 root 198: (sapr.stat & APR_WT) ? 'T' : '-',
199: (sapr.stat & APR_G) ? 'G' : '-',
200: (sapr.stat & APR_CI) ? 'C' : '-');
1.1.1.7 root 201:
1.1.1.9 root 202: screen.Print(40, 0, "UAPR %05x'000 TE=%d %c%c%c",
1.1.1.7 root 203: (uapr.addr >> 12) & 0xfffff,
204: uapr.enable ? 1 : 0,
1.1.1.9 root 205: (uapr.stat & APR_WT) ? 'T' : '-',
206: (uapr.stat & APR_G) ? 'G' : '-',
207: (uapr.stat & APR_CI) ? 'C' : '-');
1.1.1.7 root 208:
209: screen.Puts(0, 1, "<BATC>");
1.1.1.9 root 210: screen.Puts(0, 2, "No. LBA PBA Stat Hit%");
211: screen.Puts(40, 2, "No. LBA PBA Stat Hit%");
1.1.1.7 root 212: x = 0;
213: y = 3;
1.1.1.9 root 214: uint64 batc_total = 0;
1.1.1.7 root 215: for (int i = 0; i < 10; i++) {
216: if (i == batc.size() / 2) {
1.1.1.9 root 217: x = 40;
1.1.1.7 root 218: y = 3;
219: }
220: if (i < 8) {
221: screen.Print(x, y, " %d:", i);
222: } else {
223: screen.Print(x, y, "(%d)", i);
224: }
225:
226: const m88200BATC& b = batc[i];
1.1.1.9 root 227: if (b.IsValid()) {
1.1.1.7 root 228: screen.Print(x + 4, y, "%c:%04x'0000 %04x'0000 %c%c%c%c",
1.1.1.9 root 229: b.IsS() ? 'S' : 'U',
1.1.1.7 root 230: b.lba >> 16, b.pba >> 16,
1.1.1.9 root 231: (b.stat & DESC_WT) ? 'T' : '-',
232: (b.stat & DESC_G) ? 'G' : '-',
233: (b.stat & DESC_CI) ? 'C' : '-',
234: (b.stat & DESC_WP) ? 'P' : '-');
235: }
236: if (batc_hit[i] == 0) {
237: screen.Puts(x + 32, y, "--.-%");
238: } else {
239: screen.Print(x + 32, y, "%4.1f%%",
240: (double)batc_hit[i] / translate_total * 100);
241: batc_total += batc_hit[i];
1.1.1.7 root 242: }
243: y++;
244: }
245:
246: screen.Puts(0, 8, "<PATC>");
247: screen.Puts(0, 9, "No. LPA PFA Stat");
1.1.1.9 root 248: screen.Puts(40, 9, "No. LPA PFA Stat");
1.1.1.7 root 249:
250: x = 0;
251: y = 10;
252: for (int i = 0; i < patc.size(); i++) {
253: if (i == patc.size() / 2) {
1.1.1.9 root 254: x = 40;
1.1.1.7 root 255: y = 10;
256: }
257: screen.Print(x, y, "%2d:", i);
258:
259: const m88200PATC& p = patc[i];
1.1.1.9 root 260: if (p.IsValid()) {
1.1.1.7 root 261: screen.Print(x + 4, y, "%c:%05x'000 %05x'000 %c%c%c%c%c",
1.1.1.9 root 262: p.IsS() ? 'S' : 'U',
1.1.1.7 root 263: p.lpa >> 12, p.pfa >> 12,
1.1.1.9 root 264: (p.stat & DESC_WT) ? 'T' : '-',
265: (p.stat & DESC_G) ? 'G' : '-',
266: (p.stat & DESC_CI) ? 'C' : '-',
267: (p.stat & DESC_WP) ? 'P' : '-',
268: p.m ? 'M' : '-');
1.1.1.7 root 269: }
270: y++;
271: }
1.1.1.9 root 272:
1.1.1.12! root 273: x = 49;
! 274: y++;
! 275: screen.Puts(0, y++, "<Statistics>");
! 276: screen.Print(0, y++, "Translate %26s",
! 277: format_number(translate_total).c_str());
! 278: screen.Print(0, y, " BATC hit %26s (",
! 279: format_number(batc_total).c_str());
! 280: if (__predict_false(batc_total == 0)) {
! 281: screen.Puts(x, y, "---.-%)");
1.1.1.9 root 282: } else {
1.1.1.12! root 283: screen.Print(x, y, "%5.1f%%)",
! 284: (double)batc_total / translate_total * 100);
1.1.1.9 root 285: }
286: y++;
1.1.1.12! root 287: screen.Print(0, y, " PATC hit %26s (",
! 288: format_number(patc_hit).c_str());
! 289: if (__predict_false(patc_hit == 0)) {
! 290: screen.Puts(x, y, "---.-%)");
1.1.1.9 root 291: } else {
1.1.1.12! root 292: screen.Print(x, y, "%5.1f%%)",
! 293: (double)patc_hit / translate_total * 100);
1.1.1.9 root 294: }
295: y++;
1.1.1.12! root 296: screen.Print(0, y, " BATC/PATC miss %26s (",
! 297: format_number(atc_miss).c_str());
! 298: if (__predict_false(atc_miss == 0)) {
! 299: screen.Puts(x, y, "---.-%)");
1.1.1.9 root 300: } else {
1.1.1.12! root 301: screen.Print(x, y, "%5.1f%%)",
! 302: (double)atc_miss / translate_total * 100);
1.1.1.9 root 303: }
1.1.1.12! root 304: #if defined(M88200_STAT)
1.1.1.9 root 305: y++;
306: screen.Print(0, y++, "PATC create %26s",
307: format_number(stat_patc_create).c_str());
308: screen.Print(0, y++, "PATC invalidate %26s",
309: format_number(stat_patc_invalidate).c_str());
310: screen.Print(0, y++, "PATC SCR InvAll %26s",
311: format_number(stat_patc_invcmd_all).c_str());
312: screen.Print(0, y++, "PATC SCR InvSegment %26s",
313: format_number(stat_patc_invcmd_seg).c_str());
314: screen.Print(0, y++, "PATC SCR InvPage %26s",
315: format_number(stat_patc_invcmd_page).c_str());
316: #endif
1.1.1.7 root 317: }
318:
319: // モニター更新 (キャッシュ、概要と詳細の両方、GUI から呼ばれる)
320: // screen.userdata は注目しているセット番号。
321: void
322: m88200::MonitorUpdateCache(Monitor *, TextScreen& screen)
323: {
324: int setidx = screen.userdata;
325:
326: // 上半分(概要)
327: MonitorCacheOverview(screen, 0, setidx, true);
328: // 下半分(セット詳細)
329: MonitorCacheSet(screen, 18, setidx);
330: }
331:
1.1 root 332: // データキャッシュの特定セットの詳細を TextScreen に出力する。
333: // y は開始オフセット。
334: // TextScreen は (70, 5) 必要。
335: void
336: m88200::MonitorCacheSet(TextScreen& s, int y, int setidx)
337: {
1.1.1.7 root 338: assertmsg(0 <= setidx && setidx < setarray.size(), "setidx=%d", setidx);
1.1 root 339: const m88200CacheSet& set = setarray[setidx];
340:
341: /*
342: 012345678901234567890123456789012345678901234567890123456789
343: L Tag Status
344: 0 $11223'344 VV 12345678 12345678 12345678 12345678
345: */
346: s.Puts(0, y, "L Tag Status Word");
347: s.Puts(58, y, "Order");
348: y++;
349:
350: // ラインの古い順に評価して順序を0-3でつける
351: int Lorder[4];
352: int tmpL = set.L;
353: for (int i = 0; i < 4; i++) {
354: int line = m88200CacheSet::TryGetOldestLine(tmpL);
355: Lorder[line] = 3 - i;
356: tmpL = m88200CacheSet::TryUseLine(tmpL, line);
357: }
358:
359: for (int line = 0; line < 4; line++, y++) {
360: TA attr;
361: // ステータスによって属性を選択
362: switch (set.vv[line]) {
363: case m88200CacheSet::Status::IV:
364: attr = TA::Disable;
365: break;
366: case m88200CacheSet::Status::EU:
367: case m88200CacheSet::Status::SU:
368: attr = TA::Off;
369: break;
370: case m88200CacheSet::Status::EM:
371: attr = TA::Em;
372: break;
373: }
374: s.Print(0, y, attr, "%d", line);
1.1.1.3 root 375: static const char statusstr[][4] = { "EU", "EM", "SU", "IV" };
1.1 root 376: s.Print(2, y, attr, "$%05x'%03x %s",
377: (set.tag[line] >> 12),
378: (setidx << 4),
379: statusstr[set.vv[line]]);
380:
381: if (set.vv[line] == m88200CacheSet::Status::EM) {
382: // メモリに対してダーティならボールドにする
383: for (int w = 0; w < 4; w++) {
384: uint32 addr;
385: uint32 m;
386: addr = (set.tag[line] & 0xfffff000) | (setidx << 4) | (w << 2);
1.1.1.11 root 387: m = (mainbus->Peek8(addr) << 24)
388: | (mainbus->Peek8(addr + 1) << 16)
389: | (mainbus->Peek8(addr + 2) << 8)
390: | (mainbus->Peek8(addr + 3));
1.1 root 391: if (set.word[line * 4 + w] != m) {
392: attr = TA::Em;
393: } else {
394: attr = TA::Off;
395: }
396: s.Print(20 + w * 9, y, attr, "%08x", set.word[line * 4 + w]);
397: }
398: } else {
399: // Unmodified (or Invalid) ならメモリとの比較は不要
400: for (int w = 0; w < 4; w++) {
401: s.Print(20 + w * 9, y, "%08x", set.word[line * 4 + w]);
402: }
403: }
404:
405: // 順序
406: s.Print(58, y, "%d", Lorder[line]);
407: }
408: }
409:
410: // データキャッシュの概要を指定の TextScreen に出力する。
411: // y は開始オフセット。CLI では単独コマンドとして、GUI ではページの一部と
412: // して描画するためこうなっている。
413: // cursor で指定された番号のセットは反転表示する。GUI でのカーソル用。
414: // 負数など範囲外の値を指定すればカーソルは表示されない。
415: // is_gui は GUI かどうか。CLI では80桁を微妙に越えるのは嫌だしどうせ表示
416: // だけなので間を詰めてあるが、GUI では 80桁制約はない代わりにマウス操作が
417: // あるので 1セットごとに間を空けて等間隔にしたい、という違いから。
418: // TextScreen は CLI なら (70, 17)、GUI なら (82, 17) 必要。
419: void
420: m88200::MonitorCacheOverview(TextScreen& s, int y, int cursor, bool is_gui)
421: {
422: // X ガイド
423: for (int i = 0; i < 16; i++) {
424: int x;
425: if (is_gui) {
426: x = 3 + i * 5;
427: } else {
428: x = 3 + i * 4 + (i / 4);
429: }
430: s.Print(x, y, "+0%x", i);
431: }
432: y++;
433:
434: // Y ガイド
435: for (int i = 0; i < 16; i++) {
436: s.Print(0, y + i, "%02x", i * 16);
437: }
438:
439: for (int i = 0; i < setarray.size(); i++) {
440: const auto& set = setarray[i];
1.1.1.3 root 441: const char str[] = "EMS-";
1.1 root 442: int col = i % 16;
443: int row = i / 16;
444: int x;
445: if (is_gui) {
446: x = 3 + col * 5;
447: } else {
448: x = 3 + col * 4 + col / 4;
449: }
450:
451: s.Print(x, y + row, TA::OnOff(i == cursor),
452: "%c%c%c%c",
453: str[set.vv[0]],
454: str[set.vv[1]],
455: str[set.vv[2]],
456: str[set.vv[3]]);
457: }
458: }
459:
460: // IDR の Version フィールドを設定する
461: void
462: m88200::SetVersion(uint version_)
463: {
464: version = version_;
465: }
466:
467: // コマンド名
468: // (0-15 は全部 No Operation なので、16以降のみ)
469: /*static*/ const char * const
470: m88200::commandname[] = {
471: "No Operation", // $10
472: "No Operation", // $11
473: "No Operation", // $12
474: "No Operation", // $13
475: "DCache Invalidate, Line", // $14
476: "DCache Invalidate, Page", // $15
477: "DCache Invalidate, Segment", // $16
478: "DCache Invalidate, All", // $17
479:
480: "DCache Copyback, Line", // $18
481: "DCache Copyback, Page", // $19
482: "DCache Copyback, Segment", // $1a
483: "DCache Copyback, All", // $1b
484: "DCache Copy&Inv, Line", // $1c
485: "DCache Copy&Inv, Page", // $1d
486: "DCache Copy&Inv, Segment", // $1e
487: "DCache Copy&Inv, All", // $1f
488:
489: "Probe User Address", // $20
490: "Probe User Address", // $21
491: "Probe User Address", // $22
492: "Probe User Address", // $23
493: "Probe Supervisor Address", // $24
494: "Probe Supervisor Address", // $25
495: "Probe Supervisor Address", // $26
496: "Probe Supervisor Address", // $27
497:
498: "Probe User Address", // $28
499: "Probe User Address", // $29
500: "Probe User Address", // $2a
501: "Probe User Address", // $2b
502: "Probe Supervisor Address", // $2c
503: "Probe Supervisor Address", // $2d
504: "Probe Supervisor Address", // $2e
505: "Probe Supervisor Address", // $2f
506:
507: "Invalidate U PATC, Line", // $30
508: "Invalidate U PATC, Page", // $31
509: "Invalidate U PATC, Segment", // $32
510: "Invalidate U PATC, All", // $33
511: "Invalidate S PATC, Line", // $34
512: "Invalidate S PATC, Page", // $35
513: "Invalidate S PATC, Segment", // $36
514: "Invalidate S PATC, All", // $37
515:
516: "Invalidate U PATC, Line", // $38
517: "Invalidate U PATC, Page", // $39
518: "Invalidate U PATC, Segment", // $3a
519: "Invalidate U PATC, All", // $3b
520: "Invalidate S PATC, Line", // $3c
521: "Invalidate S PATC, Page", // $3d
522: "Invalidate S PATC, Segment", // $3e
523: "Invalidate S PATC, All", // $3f
524: };
525:
526: // SCR の読み出し
527: uint32
528: m88200::GetSCR() const
529: {
530: // b31-b6 (reserved) の読み出し値は未定義らしい。
531: // b5-b0 (Command Code) の読み出し値はマニュアルに記載がないけど
532: // たぶんそのまま読めるのかな。
533: return command;
534: }
535:
536: // SCR への書き込み
537: void
538: m88200::SetSCR(uint32 data)
539: {
540: command = data & 0x3f;
541:
542: // %00'XXXX No Operation
543: // %01'00XX No Operation
544: // %01'01gg Data Cache Invalidate
545: // %01'10gg Data Cache Copyback to Memory
546: // %01'11gg Data Cache Copyback and Invalidate
547: // %10'X0XX Probe User Address
548: // %10'X1XX Probe Supervisor Address
549: // %11'X0gg Invalidate User PATC Descriptors
550: // %11'X1gg Invalidate Supervisor PATC Descriptors
551:
552: const char *name;
553: if (command < 0x10) {
554: name = commandname[0];
555: } else {
556: name = commandname[command - 0x10];
557: }
558: putlog(1, "SCR <- $%08x (%s)", data, name);
559:
560: switch (command) {
561: case 0x00 ... 0x13: // No Operation
562: return;
563:
564: case 0x14 ... 0x1f: // Flush Data Cache
565: FlushCache();
566: return;
567:
568: case 0x20 ... 0x23: // Probe User Address
569: case 0x28 ... 0x2b:
1.1.1.10 root 570: putlog(0, "SCR Command: Probe User Address (NOT IMPLEMENTED)");
1.1 root 571: return;
572:
573: case 0x24 ... 0x27: // Probe Supervisor Address
574: case 0x2c ... 0x2f:
1.1.1.10 root 575: putlog(0, "SCR Command: Probe Supervisor Address (NOT IMPLEMENTED)");
1.1 root 576: return;
577:
578: case 0x30 ... 0x3f: // Invalidate {User,Supervisor} PATC Descriptors
579: InvalidatePATC();
580: return;
581: }
1.1.1.11 root 582: PANIC("should not reach: command=$%02x", command);
1.1 root 583: }
584:
585: // command に応じてデータキャッシュをフラッシュする。SetSCR() の下請け。
586: // command が $14..$1f でのみ呼ぶこと。
587: // p3-18, Section 3.7
588: void
589: m88200::FlushCache()
590: {
591: uint32 op = command & 0x3c;
592: uint32 gg = command & 0x03;
593: uint32 addr = GetSAR();
594: bool copyback;
595: bool invalidate;
596:
1.1.1.11 root 597: assert(0x14 <= op && op <= 0x1f);
598:
1.1 root 599: // op CopyBack Invalidate
600: // %01'01gg false true | Data Cache Invalidate
601: // %01'10gg true false | Data Cache Copyback to Memory
602: // %01'11gg true true | Data Cache Copyback and invalidate
603:
604: // op によって書き戻しと無効化の組み合わせが異なる
605: if (op == 0x14) {
606: copyback = false;
607: invalidate = true;
608: } else if (op == 0x18) {
609: copyback = true;
610: invalidate = false;
1.1.1.11 root 611: } else {
1.1 root 612: copyback = true;
613: invalidate = true;
614: }
615:
616: // 影響範囲
617: switch (gg) {
618: case GG_LINE:
1.1.1.11 root 619: addr &= 0xfffffff0;
1.1.1.3 root 620: parent->AddCycle(1); // Table.6-1
1.1 root 621: break;
622: case GG_PAGE:
623: addr &= 0xfffff000;
1.1.1.3 root 624: parent->AddCycle(256); // Table.6-1
1.1 root 625: break;
626: case GG_SEG:
627: addr &= 0xffc00000;
1.1.1.3 root 628: parent->AddCycle(1024); // Table.6-1
1.1 root 629: break;
630: case GG_ALL:
1.1.1.3 root 631: parent->AddCycle(1024); // Table.6-1
1.1 root 632: break;
633: default:
634: __unreachable();
635: }
636:
1.1.1.3 root 637: // サイクル(基本部分) Table.6-1
638: uint32 cycle = 0;
639: if (invalidate) {
640: switch (gg) {
641: case GG_LINE: cycle = 1; break;
642: case GG_PAGE: cycle = 256; break;
643: case GG_SEG: cycle = 1024; break;
644: case GG_ALL: cycle = 256; break;
645: default: __unreachable();
646: }
647: }
648: if (copyback) {
649: switch (gg) {
650: case GG_LINE: cycle = 1; break;
651: case GG_PAGE: cycle = 256; break;
652: case GG_SEG: cycle = 1024; break;
653: case GG_ALL: cycle = 1024; break;
654: default: __unreachable();
655: }
656: }
657: // XXX ループ中のサイクル数は正しくないかも。よく分からん
658:
1.1 root 659: for (auto& set : setarray) {
660: for (int line = 0; line < 4; line++) {
661: // 条件にマッチするか
662: bool match;
663: switch (gg) {
664: case GG_LINE:
665: match = (addr == (set.tag[line] | (set.setidx << 4)));
666: break;
667: case GG_PAGE:
668: match = (addr == set.tag[line]);
669: break;
670: case GG_SEG:
671: match = (addr == (set.tag[line] & 0xffc00001));
672: break;
673: case GG_ALL:
674: match = true;
675: break;
676: default:
677: __unreachable();
678: }
679: if (!match)
680: continue;
681:
682: // Copyback ならまず EM なエントリを書き戻す。
683: if (copyback) {
684: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 685: cycle += 7; // Table.6-1
686: CopyBackLine(set, line);
1.1 root 687: }
688: }
689:
690: // Invalidate なら無効化する
691: if (invalidate) {
1.1.1.3 root 692: cycle += 1; // Table.6-1
1.1 root 693: set.Update(line, m88200CacheSet::IV);
694: }
695: }
696: }
1.1.1.3 root 697:
698: parent->AddCycle(cycle);
1.1 root 699: }
700:
1.1.1.12! root 701: // issuper, addr から atc_hash_all[] のインデックスを返す。
! 702: // (_all でないほうのインデックスは (laddr >> 12) だけなので用意しない)
! 703: inline uint32
! 704: m88200::addr2hash(bool issuper, uint32 addr) const
! 705: {
! 706: uint64 la = (issuper ? 0x1'00000000ULL : 0) | addr;
! 707: return la >> 12;
! 708: }
! 709:
1.1 root 710: // command に応じて PATC を無効化する。SetSCR() の下請け。
711: // command が $30..$3f で呼ぶこと。
712: // p2-9, Section 2.2.4
713: void
714: m88200::InvalidatePATC()
715: {
716: uint32 gg = command & 0x03;
1.1.1.9 root 717: bool s = (command & 0x04);
1.1 root 718:
1.1.1.9 root 719: if (__predict_true(gg == GG_PAGE)) {
720: // 指定の1本だけ無効にする。
721: // Page は呼び出し回数が多いのと1本だけならハッシュで引けるので別対応。
722: #if defined(M88200_STAT)
723: stat_patc_invcmd_page++;
724: #endif
725:
1.1.1.12! root 726: uint32 la = addr2hash(s, GetSAR());
! 727: uint8 n = atc_hash_all[la];
1.1 root 728:
1.1.1.12! root 729: if (__predict_true((int8)n > 0)) {
! 730: // PATC#(n-1)
! 731: n--;
! 732: putlog(4, "Invalidate PATCEntry from GG_PAGE n=%d", n);
! 733: InvalidatePATCEntry(patc[n]);
! 734: // 1本ヒットすればこれ以上一致することはないはず
1.1 root 735: }
1.1.1.9 root 736: } else {
737: // 指定範囲を無効にする。All と Segment はマスクが違うだけ。
1.1.1.12! root 738: uint32 addr;
! 739: uint32 mask;
1.1.1.9 root 740:
741: if (gg == GG_ALL) {
742: // S/U 指定したほう全体を無効にする
743: #if defined(M88200_STAT)
744: stat_patc_invcmd_all++;
745: #endif
746: mask = 0;
747: } else if (gg == GG_SEG) {
748: // S/U 指定したほうの指定セグメント範囲全部を無効にする
749: #if defined(M88200_STAT)
750: stat_patc_invcmd_seg++;
751: #endif
752: mask = 0xffc00000;
753: } else {
754: // GG_LINE はマニュアルにどうなるか書いてない
1.1.1.10 root 755: putlog(0, "Undefined Invalidate PATC Line");
1.1.1.9 root 756: return;
757: }
758:
759: addr = GetSAR() & mask;
760: addr |= (s) ? PATC_S : 0;
761:
762: mask |= PATC_S | PATC_INVALID;
763:
764: for (int i = 0; i < patc.size(); i++) {
765: m88200PATC& p = patc[i];
766: if ((p.lpa & mask) == addr) {
767: // 無効化
768: // XXX 削除した結果穴が空いても詰める処理は未実装
1.1.1.12! root 769: putlog(4, "Invalidate PATCEntry from GG_* n=%d", i);
! 770: InvalidatePATCEntry(p);
1.1.1.9 root 771: }
1.1 root 772: }
773: }
774: }
775:
776: // SCTR レジスタへの書き込み
777: void
778: m88200::SetSCTR(uint32 data)
779: {
780: sctr = data & (SCTR_PE | SCTR_SE | SCTR_PR);
781:
1.1.1.9 root 782: // 全 CMMU について、それぞれスヌープ相手になる CMMU リストを更新。
783: // どの CMMU の SCTR への書き込みでも毎回全ての CMMU を書き換える。
1.1.1.11 root 784: std::array<m88200*, 8> cmmu {};
785: int n = cmmu.size();
1.1.1.9 root 786: for (int i = 0; i < n; i++) {
1.1.1.11 root 787: cmmu[i] = gMainApp.FindObject<m88200>(OBJ_M88200(i));
788: }
789: for (int i = 0; i < n; i++) {
790: if (cmmu[i] == NULL)
791: continue;
792: cmmu[i]->other_cmmu.clear();
1.1.1.9 root 793: for (int j = 0; j < n; j++) {
1.1.1.11 root 794: if (cmmu[j] == NULL || i == j)
1.1.1.9 root 795: continue;
1.1.1.11 root 796: if ((cmmu[j]->sctr & SCTR_SE)) {
797: cmmu[i]->other_cmmu.push_back(cmmu[j]);
1.1.1.9 root 798: }
799: }
800: }
801:
1.1 root 802: std::string msg;
803: if ((sctr & SCTR_PE))
804: msg += ",PE";
805: if ((sctr & SCTR_PR))
806: msg += ",PR";
807: if (msg.length() > 0) {
1.1.1.10 root 808: putlog(0, "SCTR <- $%08x (%s NOT IMPLEMENTED)", data, msg.c_str() + 1);
1.1 root 809: }
810: }
811:
812: // SAPR, UAPR レジスタ値の読み出し (S/U ビット指定)
813: uint32
814: m88200::GetAPR(uint issuper) const
815: {
816: if (issuper) {
817: return GetAPR(sapr);
818: } else {
819: return GetAPR(uapr);
820: }
821: }
822:
823: // SAPR, UAPR レジスタ値の読み出し (実体指定)
824: uint32
825: m88200::GetAPR(const m88200APR& xapr) const
826: {
827: uint32 data;
828:
829: data = xapr.addr & APR_ADDR_MASK;
830: data |= xapr.stat & (APR_WT | APR_G | APR_CI);
831: if (xapr.enable) {
832: data |= APR_TE;
833: }
834: return data;
835: }
836:
837: // SAPR, UAPR レジスタへの書き込み (実体指定)
838: void
839: m88200::SetAPR(m88200APR& xapr, uint32 data)
840: {
841: bool old_enable = xapr.enable;
842: xapr.addr = data & APR_ADDR_MASK;
843: xapr.stat = data & (APR_WT | APR_G | APR_CI);
844: xapr.enable = data & APR_TE;
845:
846: if (old_enable == false && xapr.enable == true) {
847: // 変換開始
848: putlog(1, "%s <- $%08x (Translation Enabled)", xapr.name, data);
849: } else if (old_enable == true && xapr.enable == false) {
850: // 変換停止
851: putlog(1, "%s <- $%08x (Translation Disabled)", xapr.name, data);
852: } else {
853: // 変化なし
854: putlog(1, "%s <- $%08x", xapr.name, data);
855: }
856: }
857:
1.1.1.9 root 858: // BWP(BATC Write Port) #n への書き込み
1.1 root 859: void
1.1.1.12! root 860: m88200::SetBWP(uint bn, uint32 data)
! 861: {
! 862: assert(bn < 8);
! 863: putlog(1, "BWP%u <- $%08x", bn, data);
! 864:
! 865: uint32 laddr = data & BWP_LBA_MASK;
! 866: uint32 paddr = (data & BWP_PBA_MASK) << 13;
! 867: uint32 flags = data & BWP_FLAG_MASK;
! 868:
! 869: // BATC の LBA は衝突してはいけない (が、どうなるかは書いてない)。
! 870: // XXX 要実機検証…
! 871:
! 872: // とりあえず暗黙 BATC (#8, #9) と衝突する設定は無視しておく。
! 873: if (laddr >= 0xfff00000) {
! 874: return;
! 875: }
! 876:
! 877: // それ以外の BATC (#0-#7) と衝突する設定は先着優先としておく。
! 878: uint32 la = addr2hash((flags & BWP_S), laddr);
! 879: uint8 n = atc_hash_all[la];
! 880: if (n != 0 && ~n != bn) {
! 881: return;
! 882: }
! 883:
! 884: SetBATC(bn, laddr, paddr, flags);
! 885: }
! 886:
! 887: // BATC #n を更新する。
! 888: // n は 0-9 (暗黙 BATC も含む)。
! 889: // laddr の衝突は呼び出し側で回避してある。
! 890: void
! 891: m88200::SetBATC(uint n, uint32 laddr, uint32 paddr, uint32 flags)
1.1 root 892: {
893: m88200BATC& b = batc[n];
894:
1.1.1.9 root 895: // BWP レジスタへの書き込み値と内部データ構造(stat)ではビット位置が違う
896: // ことに注意。
897: //
898: // 31 10 9 8 7 6 5 4 3 2 1 0
899: // +----..-----+----+----+----+----+----+----+----+----+----+----+
900: // BWP |LBA PBA | S | WT | G | CI | WP | V |
901: // +----..-----+----+----+----+----+----+----+----+----+----+----+
902: //
903: // 31 10 9 8 7 6 5 4 3 2 1 0
904: // +----..-----+----+----+----+----+----+----+----+----+----+----+
905: // stat | 0 0 | WT | SP | G | CI | 0 | M | U | WP | 0 | V |
906: // +----..-----+----+----+----+----+----+----+----+----+----+----+
907:
1.1.1.12! root 908: // 更新前の BATC が有効なら、BATC を書き換える前にハッシュをクリア。
! 909: if (b.IsValid()) {
! 910: uint32 la = addr2hash(b.IsS(), b.lba);
! 911: memset(&atc_hash_all[la], 0, 128);
! 912:
! 913: // BATC が消えたことによってここを指していた PATC が見えるように
! 914: // なったら、復活させる。
! 915: for (int i = 0; i < patc.size(); i++) {
! 916: const auto& p = patc[i];
! 917: if (p.IsValid() &&
! 918: p.IsS() == b.IsS() &&
! 919: (p.lpa & m88200BATC::LBAMASK) == b.Laddr())
! 920: {
! 921: la = addr2hash(p.IsS(), p.lpa);
! 922: atc_hash_all[la] = i + 1;
! 923: }
! 924: }
! 925: }
! 926:
1.1 root 927: memset(&b, 0, sizeof(b));
1.1.1.12! root 928: b.lba = laddr;
! 929: b.lba |= (flags & BWP_S);
! 930: if ((flags & BWP_V) == 0) {
! 931: b.lba |= BATC_INVALID;
1.1.1.9 root 932: }
1.1.1.12! root 933: b.pba = paddr;
! 934: if ((flags & BWP_WT))
1.1.1.9 root 935: b.stat |= DESC_WT;
1.1.1.12! root 936: if ((flags & BWP_G))
1.1.1.9 root 937: b.stat |= DESC_G;
1.1.1.12! root 938: if ((flags & BWP_CI))
1.1.1.9 root 939: b.stat |= DESC_CI;
1.1.1.12! root 940: if ((flags & BWP_WP)) {
1.1.1.9 root 941: b.stat |= DESC_WP;
1.1 root 942: b.wp = true;
943: }
1.1.1.9 root 944:
1.1.1.12! root 945: // 更新後の BATC が有効なら、ハッシュもセット。
! 946: if (b.IsValid()) {
! 947: uint32 la = addr2hash(b.IsS(), b.lba);
! 948: // この領域に PATC があれば追い出す。
! 949: for (int i = la; i < la + 128; i++) {
! 950: uint8 pn = atc_hash_all[i];
! 951: if ((int8)pn > 0) {
! 952: pn--;
! 953: putlog(4, "Invalidate PATCEntry from SetBATC(%d) n=%d", n, pn);
! 954: InvalidatePATCEntry(patc[pn]);
1.1.1.9 root 955: }
956: }
1.1.1.12! root 957: memset(&atc_hash_all[la], ~n, 128);
1.1.1.9 root 958: }
1.1.1.12! root 959: //DumpATC();
1.1 root 960: }
961:
962: // CSSP レジスタの読み出し
963: uint32
964: m88200::GetCSSP() const
965: {
966: uint32 setidx = (GetSAR() >> 4) & 0xff;
967: const m88200CacheSet& set = setarray[setidx];
968:
969: uint32 data = 0;
970: // L5-L0
971: data |= set.L << 24;
972:
973: // XXX D3-D0 未実装
974:
975: // VV3-VV0
976: data |= set.vv[3] << CSSP_VV3_OFFSET;
977: data |= set.vv[2] << CSSP_VV2_OFFSET;
978: data |= set.vv[1] << CSSP_VV1_OFFSET;
979: data |= set.vv[0] << CSSP_VV0_OFFSET;
980:
981: return data;
982: }
983:
984: // CSSP レジスタへの書き込み
985: void
986: m88200::SetCSSP(uint32 data)
987: {
988: uint32 setidx = (GetSAR() >> 4) & 0xff;
989: m88200CacheSet& set = setarray[setidx];
990:
991: putlog(1, "CSSP <- $%08x (set=$%02x)", data,setidx);
992:
993: // L5-L0 書き込み
994: set.L = (data >> 24) & 0x3f;
995:
996: // XXX D3-D0 未実装
997:
998: // VV3-VV0
999: set.vv[3] = (m88200CacheSet::Status)((data >> CSSP_VV3_OFFSET) & 3);
1000: set.vv[2] = (m88200CacheSet::Status)((data >> CSSP_VV2_OFFSET) & 3);
1001: set.vv[1] = (m88200CacheSet::Status)((data >> CSSP_VV1_OFFSET) & 3);
1002: set.vv[0] = (m88200CacheSet::Status)((data >> CSSP_VV0_OFFSET) & 3);
1003: }
1004:
1.1.1.9 root 1005: // S/U 信号線を設定。true なら Super、false なら User。
1006: void
1007: m88200::SetSuper(bool super)
1008: {
1.1.1.12! root 1009: // acc_super は S/U ビットだけだと知っているので OR ではなく代入。
! 1010: if (super) {
! 1011: acc_super = busaddr::S;
1.1.1.9 root 1012: acc_apr = &sapr;
1.1.1.12! root 1013: atc_hash = &atc_hash_all[0x10'0000];
1.1.1.9 root 1014: } else {
1.1.1.12! root 1015: acc_super = busaddr::U;
1.1.1.9 root 1016: acc_apr = &uapr;
1.1.1.12! root 1017: atc_hash = &atc_hash_all[0];
1.1.1.9 root 1018: }
1019: }
1020:
1.1 root 1021:
1022: //
1023: // 物理バスアクセス
1024: //
1025:
1026: // MBus から読み込みを行う。
1027: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
1.1.1.12! root 1028: // バスエラーなら呼び出し側で SetFault(FAULT_CODE_BUSERR, paddr) を呼ぶこと。
! 1029: busdata
1.1 root 1030: m88200::MBusRead(uint32 paddr, int size)
1031: {
1.1.1.12! root 1032: busaddr baddr(paddr, acc_super);
! 1033: busdata bd;
1.1 root 1034:
1035: if (size == 4) {
1.1.1.12! root 1036: bd = mainbus->Read32(baddr);
1.1 root 1037: } else if (size == 2) {
1.1.1.12! root 1038: bd = mainbus->Read16(baddr);
1.1 root 1039: } else {
1.1.1.12! root 1040: bd = mainbus->Read8(baddr);
1.1 root 1041: }
1.1.1.12! root 1042: parent->AddWait(bd.GetWait());
! 1043: return bd;
1.1 root 1044: }
1045:
1046: // MBus に書き込みを行う。
1047: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
1.1.1.12! root 1048: // バスエラーなら呼び出し側で SetFault(FAULT_CODE_BUSERR, paddr) を呼ぶこと。
! 1049: busdata
1.1 root 1050: m88200::MBusWrite(uint32 paddr, uint32 data, int size)
1051: {
1.1.1.12! root 1052: busaddr baddr(paddr, acc_super);
! 1053: busdata bd;
1.1 root 1054:
1055: if (size == 4) {
1.1.1.12! root 1056: bd = mainbus->Write32(baddr, data);
1.1 root 1057: } else if (size == 2) {
1.1.1.12! root 1058: bd = mainbus->Write16(baddr, data);
1.1 root 1059: } else {
1.1.1.12! root 1060: bd = mainbus->Write8(baddr, data);
1.1 root 1061: }
1.1.1.12! root 1062: parent->AddWait(bd.GetWait());
! 1063: return bd;
1.1 root 1064: }
1065:
1066: // MBus に xmem トランザクションを行う。
1.1.1.6 root 1067: // paddr は size によって 1, 4 バイト境界に整列していること (2バイトはない)。
1.1 root 1068: // MBus Acquire された状態で呼び出すこと。
1069: // 成功すれば読み込めた値を返す。
1.1.1.12! root 1070: // バスエラーなら呼び出し側で SetFault(FAULT_CODE_BUSERR, paddr) を呼ぶこと。
1.1 root 1071: // read/write どちらでエラーが起きたかは acc_read で判別できる。
1072: // p3-13, Figure3-7 の下半分のメインラインあたりに該当。
1.1.1.12! root 1073: busdata
1.1 root 1074: m88200::MBusXmem(uint32 paddr, uint32 data, int size)
1075: {
1.1.1.12! root 1076: busdata fetched;
! 1077: busdata bd;
1.1 root 1078:
1079: // Read data with intent to modify
1080: acc_read = true;
1.1.1.12! root 1081: bd = MBusRead(paddr, size);
! 1082: parent->AddWait(bd.GetWait());
! 1083: if (__predict_false(bd.IsBusErr())) {
! 1084: return bd;
1.1 root 1085: }
1.1.1.12! root 1086: fetched = bd;
1.1 root 1087:
1088: // Supply data to PBus
1089: // Reply = Success
1090:
1091: // Write data to memory
1092: acc_read = false;
1.1.1.12! root 1093: bd = MBusWrite(paddr, data, size);
! 1094: parent->AddWait(bd.GetWait());
! 1095: if (__predict_false(bd.IsBusErr())) {
! 1096: return bd;
1.1 root 1097: }
1098:
1.1.1.12! root 1099: return fetched;
1.1 root 1100: }
1101:
1102: //
1103: // アクセス関数
1104: //
1105:
1106: template <int bits> uint64
1107: m88200::load(uint32 addr)
1108: {
1109: uint64 data;
1110:
1111: acc_laddr = addr;
1112: acc_read = true;
1.1.1.9 root 1113: if (__predict_false(Translate() == false)) {
1114: putlog(2, "Translation BusError %c:$%08x",
1.1.1.12! root 1115: (IsSuper() ? 'S' : 'U'), acc_laddr);
1.1 root 1116: return (uint64)-1;
1117: }
1.1.1.9 root 1118: if (__predict_false((acc_stat & DESC_CI))) {
1.1.1.3 root 1119: parent->AddCycle(7); // Table.6-2
1.1 root 1120: MBusAcquire();
1.1.1.9 root 1121: MBusMakeSnoop(acc_paddrH, 0);
1.1.1.12! root 1122: uint32 paddr = acc_paddrH + acc_paddrL;
! 1123: busdata bd = MBusRead(paddr, bits / 8);
1.1 root 1124: MBusRelease();
1.1.1.12! root 1125: if (__predict_false(bd.IsBusErr())) {
1.1.1.9 root 1126: putlog(2, "MBus BusError %c:$%08x",
1.1.1.12! root 1127: (IsSuper() ? 'S' : 'U'), acc_laddr);
! 1128: SetFault(FAULT_CODE_BUSERR, paddr);
! 1129: return (uint64)-1;
1.1.1.4 root 1130: }
1.1.1.12! root 1131: return bd.Data();
1.1 root 1132: } else {
1133: data = CacheRead(acc_paddrH);
1.1.1.9 root 1134: if (__predict_false((int64)data < 0)) {
1135: putlog(2, "Cache BusError %c:$%08x",
1.1.1.12! root 1136: (IsSuper() ? 'S' : 'U'), acc_laddr);
1.1 root 1137: return data;
1138: }
1139:
1140: if (bits == 8) {
1141: switch (acc_paddrL) {
1142: case 0:
1143: return (data >> 24);
1144: case 1:
1145: return (data >> 16) & 0xff;
1146: case 2:
1147: return (data >> 8) & 0xff;
1148: case 3:
1149: return data & 0xff;
1.1.1.11 root 1150: default:
1151: PANIC("corrupted acc_paddrL=%d", acc_paddrL);
1.1 root 1152: }
1.1.1.11 root 1153: } else if (bits == 16) {
1.1 root 1154: if (acc_paddrL == 0) {
1155: return data >> 16;
1156: } else {
1157: return data & 0xffff;
1158: }
1.1.1.11 root 1159: } else if (bits == 32) {
1.1 root 1160: return data;
1.1.1.11 root 1161: } else {
1162: PANIC("bits must be 8, 16, 32");
1.1 root 1163: }
1164: }
1165: }
1166:
1167: uint64
1168: m88200::load_8(uint32 addr)
1169: {
1170: return load<8>(addr);
1171: }
1172:
1173: uint64
1174: m88200::load_16(uint32 addr)
1175: {
1176: return load<16>(addr);
1177: }
1178:
1179: uint64
1180: m88200::load_32(uint32 addr)
1181: {
1182: return load<32>(addr);
1183: }
1184:
1185: template <int bits> uint64
1186: m88200::store(uint32 addr, uint32 data)
1187: {
1188: acc_laddr = addr;
1189: acc_read = false;
1.1.1.9 root 1190: if (__predict_false(Translate() == false)) {
1.1 root 1191: return (uint64)-1;
1192: }
1.1.1.12! root 1193: uint32 paddr = acc_paddrH + acc_paddrL;
1.1.1.9 root 1194: if (__predict_false((acc_stat & DESC_CI))) {
1.1.1.3 root 1195: parent->AddCycle(7); // Table.6-2
1.1 root 1196: MBusAcquire();
1.1.1.9 root 1197: MBusMakeSnoop(acc_paddrH, 1);
1.1.1.12! root 1198: busdata bd = MBusWrite(paddr, data, bits / 8);
1.1 root 1199: MBusRelease();
1.1.1.12! root 1200: if (__predict_false(bd.IsBusErr())) {
! 1201: SetFault(FAULT_CODE_BUSERR, paddr);
! 1202: return (uint64)-1;
! 1203: }
! 1204: return 0;
1.1 root 1205: } else {
1.1.1.12! root 1206: return CacheWrite(paddr, data, bits / 8);
1.1 root 1207: }
1208: }
1209:
1210: uint64
1211: m88200::store_8(uint32 addr, uint32 data)
1212: {
1213: return store<8>(addr, data);
1214: }
1215:
1216: uint64
1217: m88200::store_16(uint32 addr, uint32 data)
1218: {
1219: return store<16>(addr, data);
1220: }
1221:
1222: uint64
1223: m88200::store_32(uint32 addr, uint32 data)
1224: {
1225: return store<32>(addr, data);
1226: }
1227:
1228: template <int bits> uint64
1229: m88200::xmem(uint32 addr, uint32 data)
1230: {
1231: acc_laddr = addr;
1232: acc_read = false;
1.1.1.9 root 1233: if (__predict_false(Translate() == false)) {
1.1 root 1234: return (uint64)-1;
1235: }
1.1.1.12! root 1236: uint32 paddr = acc_paddrH + acc_paddrL;
1.1.1.9 root 1237: if (__predict_false((acc_stat & DESC_CI))) {
1.1 root 1238: // XXX キャッシュ禁止領域だとどうなる?
1239: MBusAcquire();
1.1.1.9 root 1240: MBusMakeSnoop(acc_paddrH, 1);
1.1.1.12! root 1241: busdata bd = MBusXmem(paddr, data, bits / 8);
1.1 root 1242: MBusRelease();
1.1.1.12! root 1243: if (__predict_false(bd.IsBusErr())) {
! 1244: SetFault(FAULT_CODE_BUSERR, paddr);
! 1245: return (uint64)-1;
! 1246: }
! 1247: return bd.Data();
1.1 root 1248: } else {
1.1.1.12! root 1249: return CacheXmem(paddr, data, bits / 8);
1.1 root 1250: }
1251: }
1252:
1253: uint64
1254: m88200::xmem_8(uint32 addr, uint32 data)
1255: {
1256: return xmem<8>(addr, data);
1257: }
1258:
1259: uint64
1260: m88200::xmem_32(uint32 addr, uint32 data)
1261: {
1262: return xmem<32>(addr, data);
1263: }
1264:
1265: //
1266: // アドレス変換
1267: //
1268:
1269: // デバッグ用
1270: /*static*/ std::string
1271: m88200::stat2str(uint32 stat)
1272: {
1273: std::string buf;
1274:
1.1.1.9 root 1275: if ((stat & DESC_WT))
1.1 root 1276: buf += ",WT";
1.1.1.9 root 1277: if ((stat & DESC_G))
1.1 root 1278: buf += ",G";
1.1.1.9 root 1279: if ((stat & DESC_CI))
1.1 root 1280: buf += ",CI";
1.1.1.9 root 1281: if ((stat & DESC_M))
1.1 root 1282: buf += ",M";
1.1.1.9 root 1283: if ((stat & DESC_U))
1.1 root 1284: buf += ",U";
1.1.1.9 root 1285: if ((stat & DESC_WP))
1.1 root 1286: buf += ",WP";
1287:
1288: if (buf.empty()) {
1289: buf = ",0";
1290: }
1291: return buf.substr(1);
1292: }
1293:
1.1.1.12! root 1294: // ATC ハッシュを表示。
! 1295: void
! 1296: m88200::DumpATC()
! 1297: {
! 1298: std::string str;
! 1299: uint8 zero[16] {};
! 1300:
! 1301: printf("DumpATC(#%d)\n", id);
! 1302: for (int i = 0; i < atc_hash_all.size(); i += 16) {
! 1303: const uint8 *a = &atc_hash_all[i];
! 1304: if (memcmp(a, zero, 16) != 0) {
! 1305: printf("#%d %c.%08x:", id,
! 1306: ((i >> 20) ? 'S' : 'U'), (uint32)i << 12);
! 1307:
! 1308: for (int j = 0; j < 16; j++) {
! 1309: uint8 n = a[j];
! 1310: if (__predict_true(n == 0)) {
! 1311: printf(" ");
! 1312: } else if (__predict_false((int8)n < 0)) {
! 1313: printf("~%d ", (uint)(uint8)~n);
! 1314: } else {
! 1315: printf("%-2d ", n - 1);
! 1316: }
! 1317: }
! 1318: printf("\n");
! 1319: }
! 1320: }
! 1321: }
! 1322:
1.1 root 1323: // アドレス変換。
1324: // 事前に acc_laddr, acc_super, acc_read を設定しておくこと。
1325: // 成功すれば acc_paddrH, acc_paddrL をセットして true を返す。
1326: // 失敗ならいろいろセットして(?) false を返す。
1327: // p2-3, Figure2-1
1328: bool
1329: m88200::Translate()
1330: {
1331: uint32 la;
1.1.1.12! root 1332: uint8 n;
1.1 root 1333:
1334: // Logical address(LA) presented on PBus
1335:
1.1.1.12! root 1336: putlog(3, "Translate %c:$%08x", (IsSuper() ? 'S' : 'U'), acc_laddr);
1.1 root 1337:
1338: // 下位2ビットは常にこうなる。
1339: acc_paddrL = acc_laddr & 3;
1340:
1.1.1.9 root 1341: // Select Area Descriptor
1342: if (SelectAreaDesc() == false) {
1.1.1.12! root 1343: // 変換しない場合でも暗黙 BWP は有効…。
! 1344: // マッチまではここで独自に行い、マッチしたら下の BWP へ合流。
! 1345: if (__predict_false(acc_laddr >= 0xfff00000) && IsSuper()) {
! 1346: n = (acc_laddr < 0xfff80000) ? 8 : 9;
! 1347: goto batc;
! 1348: }
! 1349:
1.1.1.9 root 1350: // XXX 図のこれはたぶん間違いだよなあ…
1351: // 誤: Physical Address <= LA[18-2] :: 00
1352: // 正: Physical Address <= LA[31-2] :: 00
1353: acc_paddrH = acc_laddr - acc_paddrL;
1.1.1.3 root 1354:
1.1.1.9 root 1355: parent->AddCycle(1);
1356: return true;
1357: }
1358:
1359: // 変換する分だけカウントするのでいいか
1360: translate_total++;
1361:
1362: // type == Valid ここから
1.1 root 1363:
1.1.1.12! root 1364: // 論理アドレスで現在の S/U のハッシュを引く。
! 1365: // 実際にはまず BATC を引いて、なければ次に PATC を引くのだが、
! 1366: // BATC と PATC が同じアドレスを指すことはなく、BATC が同じところを
! 1367: // 指すような指定は (出来るけど結果不定とマニュアルに書いてあるので)
! 1368: // 起きないものとすると、アドレスと BATC もしくは PATC は 1:1 で
! 1369: // マッピング出来るので、この全域を一回で検索する。
! 1370: la = acc_laddr >> 12;
! 1371: try_again:
! 1372: n = atc_hash[la];
! 1373: acc_patc = NULL;
1.1.1.3 root 1374:
1.1.1.12! root 1375: if (n == 0) {
! 1376: // BATC, PATC どちらにも載ってない。
! 1377: atc_miss++;
! 1378: // patc_miss に合流する
! 1379: } else if ((int8)n < 0) {
! 1380: // BATC #(~n) でヒットした。
! 1381: // n=0xff が BATC#0 を、n=0xf6 が BATC#9 を示す。
! 1382: n = ~n;
! 1383: batc:
! 1384: m88200BATC& b = batc[n];
! 1385: assert(b.IsValid());
! 1386: putlog(4, " BATC[%d] hit", n);
! 1387: batc_hit[n]++;
! 1388: if (b.wp && acc_IsWrite()) {
! 1389: goto write_violation;
! 1390: }
! 1391:
! 1392: // Physical Address <= PBA :: LA[18-2] :: 00
! 1393: acc_paddrH = b.pba | (acc_laddr & 0x0007fffc);
! 1394: acc_stat |= b.stat;
! 1395: putlog(4, " BATC hit acc=%s paddr=$%08x",
! 1396: stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.9 root 1397:
1.1.1.12! root 1398: parent->AddCycle(1);
! 1399: return true;
! 1400: } else {
! 1401: // PATC #(n-1) でヒットした。
! 1402: // n=1 が PATC#0 を、n=56 が PATC#55 を示す。
! 1403: n--;
! 1404: m88200PATC& p = patc[n];
! 1405: assert(p.IsValid());
! 1406: patc_hit++;
! 1407:
! 1408: if (acc_IsWrite() && p.wp) {
! 1409: putlog(4, " PATC[%d] hit; stat=%s m=%d wp=%d", n,
! 1410: stat2str(p.stat).c_str(), p.m, p.wp);
! 1411: goto write_violation;
! 1412: }
! 1413: if (acc_IsWrite() && p.m == false) {
! 1414: // Update M bit
! 1415: // フローチャートでは PATC[M] はこの後のテーブルサーチ中
! 1416: // の Update Page Descriptor 処理中で更新するように書いて
! 1417: // あるように読めるのだが、その通りに実装すると、メモリ
! 1418: // 上の Page Descriptor に最初から M ビットが立っていると
! 1419: // (というか OpenBSD カーネルが用意した Page Descriptor
! 1420: // には立っているので) PATC[M] の更新も行われず、PATC[M]
! 1421: // が立っていないので再びここに来てしまい無限ループになる。
! 1422: // 誰が間違ってるのか分からないけど、とりあえずここで
! 1423: // PATC[M] を立てれば問題は起きない。
! 1424: putlog(4, " PATC[%d] hit; Need to update M bit", n);
! 1425: p.m = true;
1.1.1.9 root 1426:
1.1.1.12! root 1427: // この下の PATC miss に合流する
! 1428: acc_patc = &p;
1.1.1.9 root 1429: goto patc_miss;
1430: }
1431:
1.1.1.12! root 1432: // Physical Address <= PFA :: LA[11-2] :: 00
! 1433: acc_paddrH = p.pfa | (acc_laddr & 0x00000ffc);
! 1434: acc_stat |= p.stat;
! 1435: putlog(4, " PATC[%d] hit acc=%s paddr=$%08x", n,
! 1436: stat2str(acc_stat).c_str(), acc_paddrH);
1.1 root 1437:
1.1.1.12! root 1438: parent->AddCycle(1);
! 1439: return true;
! 1440: }
1.1.1.3 root 1441:
1.1.1.12! root 1442: // PATC miss
1.1.1.9 root 1443: patc_miss:
1.1.1.12! root 1444: putlog(4, " BATC/PATC miss");
1.1 root 1445:
1.1.1.12! root 1446: // PATC にヒットして M bit 更新するものは両方カウントされるけど
! 1447: atc_miss++;
1.1 root 1448:
1.1.1.12! root 1449: // Table search operation
! 1450: if (TableSearch() == true) {
! 1451: // テーブルサーチの結果、エントリが見付かって PATC が更新されたので
! 1452: // もう一度やり直す。
! 1453: // フローチャートでは Select Area Descriptor まで戻るように書いて
! 1454: // あるが、PATC ミスによるテーブルサーチでは Area Descriptor と BATC
! 1455: // は変化しないので、Area Descriptor の検索は省略。
! 1456: goto try_again;
1.1 root 1457: }
1.1.1.12! root 1458:
! 1459: // Invalid
! 1460: // Reply with fault (Figure2-10 だがここではすべて不要)
! 1461: return false;
1.1 root 1462:
1463: write_violation:
1.1.1.12! root 1464: // XXX fault_addr 不明
! 1465: SetFault(FAULT_CODE_WRITE, 0xcccccccc);
1.1 root 1466: // Reply with fault (Figure2-10 だがここではすべて不要)
1467: return false;
1468: }
1469:
1470: // Select Area Descriptor.
1471: // 結果が Type=Valid なら true、Type=Untranslated なら false を返す。
1.1.1.12! root 1472: // Probe Command からも呼ばれる (はずだが未実装)。
1.1 root 1473: // p2-21, Figure2-5
1474: bool
1475: m88200::SelectAreaDesc()
1476: {
1.1.1.9 root 1477: acc_stat = acc_apr->stat & ACC_STAT_MASK;
1478: if (acc_apr->enable) {
1.1 root 1479: // セグメントディスクリプタのアドレスはここで決まるが、
1480: // 次に行う BATC、PATC サーチでは使わず、それらが全部ミスして
1481: // テーブルサーチまで来た所で初めて使うので、ここでは表示しない。
1.1.1.9 root 1482: acc_sdaddr = acc_apr->addr | ((acc_laddr >> 20) & ~3U);
1483: putlog(4, " %s acc=%s", acc_apr->name, stat2str(acc_stat).c_str());
1.1 root 1484: return true;
1485: } else {
1486: putlog(3, " %s acc=%s Untranslated",
1.1.1.9 root 1487: acc_apr->name, stat2str(acc_stat).c_str());
1.1 root 1488: return false;
1489: }
1490: }
1491:
1492: // Table Search
1493: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1494: // p2-20, Figure2-4
1495: bool
1496: m88200::TableSearch()
1497: {
1498: putlog(4, " %s $%08x/%s acc=%s", __func__, acc_laddr,
1499: (acc_read ? "Read" : "Write"), stat2str(acc_stat).c_str());
1500:
1501: // XXX フローチャートを厳密に追っかけると MBus の Acquire/Release が
1502: // 対応していないので(orz)、ここでは
1503: // TableSearch() に入ったところで Acquire、
1504: // TableSearch() から出るところで Release だけに統一する。
1505:
1506: MBusAcquire();
1507:
1508: if (FetchSegmentDesc() == false) {
1509: MBusRelease();
1.1.1.3 root 1510:
1511: parent->AddCycle(7); // Table.6-2
1.1 root 1512: return false;
1513: }
1514:
1515: if (FetchPageDesc() == false) {
1516: MBusRelease();
1.1.1.3 root 1517:
1518: parent->AddCycle(11); // Table.6-2
1.1 root 1519: return false;
1520: }
1521:
1522: // 中央の TYPE = VALID のところ
1523: // ( )
1524: // +----------+ +----------+
1525: // | |
1526: // DESC[U]=0 || Otherwise
1527: // DESC[M]=0 && WRITE |
1528: // | |
1529: // UpdatePageDesc |
1530: // | |
1531: // <- RETRY -( )-- INVALID ---------- | -->
1532: // | |
1533: // VALID |
1534: // | |
1535: // ( ) <--------------------+
1536: // | |
1537: // +---+ +------------+
1538: // Otherwise TableSearch due to PATC miss
1539: // | |
1540: // (Only U/M bits CreatePATCEntry
1541: // Updated) |
1542: // | v
1543: // +---------------> ( )
1544:
1545: if ((tmp_desc & DESC_U) == 0 ||
1546: ((tmp_desc & DESC_M) == 0 && acc_IsWrite()))
1547: {
1.1.1.3 root 1548: parent->AddCycle(15); // Table.6-2
1549:
1.1 root 1550: if (UpdatePageDesc() == false) {
1551: MBusRelease();
1552: return false;
1553: }
1.1.1.3 root 1554: } else {
1555: parent->AddCycle(11); // Table.6-2
1.1 root 1556: }
1557:
1558: if (acc_patc == NULL) {
1559: // Table search due to PATC miss
1560: CreatePATCEntry();
1561: }
1562:
1563: MBusRelease();
1564: return true;
1565: }
1566:
1567: // Fetch Segment Descriptor
1568: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1569: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1570: // p2-22, Figure2-6
1571: bool
1572: m88200::FetchSegmentDesc()
1573: {
1.1.1.12! root 1574: busdata data;
1.1 root 1575:
1.1.1.9 root 1576: MBusMakeSnoop(acc_sdaddr, 0);
1.1 root 1577: data = MBusRead(acc_sdaddr, 4);
1.1.1.12! root 1578: if (__predict_false(data.IsBusErr())) {
! 1579: SetFault(FAULT_CODE_BUSERR, acc_sdaddr);
1.1 root 1580: return false;
1581: }
1.1.1.12! root 1582: tmp_desc = data.Data();
1.1 root 1583: tmp_desc &= (0xfffff000 |
1584: DESC_WT | DESC_SP | DESC_G | DESC_CI | DESC_WP | DESC_V);
1585:
1.1.1.9 root 1586: if (__predict_false((tmp_desc & DESC_V) == 0)) {
1.1.1.12! root 1587: SetFault(FAULT_CODE_SEGMENT, acc_sdaddr);
1.1 root 1588: putlog(4, " SD $%08x desc=$%08x SegFault", acc_sdaddr, tmp_desc);
1589: return false;
1590: } else {
1591: // Descriptor is valid
1592:
1.1.1.12! root 1593: if (__predict_false((tmp_desc & DESC_SP) && IsUser())) {
! 1594: SetFault(FAULT_CODE_SUPERVISOR, acc_sdaddr);
1.1 root 1595: putlog(4, " SD $%08x desc=$%08x SupervisorFault",
1596: acc_sdaddr, tmp_desc);
1597: return false;
1598: }
1599:
1600: acc_pdaddr = (tmp_desc & 0xfffff000) | ((acc_laddr >> 10) & 0xffc);
1601: acc_stat |= tmp_desc & ACC_STAT_MASK;
1602: putlog(4, " SD $%08x pdaddr=$%08x stat=%s acc=%s",
1603: acc_sdaddr, acc_pdaddr,
1604: stat2str(tmp_desc).c_str(),
1605: stat2str(acc_stat).c_str());
1606: return true;
1607: }
1608: }
1609:
1610: // Fetch Page Descriptor
1611: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1612: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1613: // p2-23, Figure2-7
1614: bool
1615: m88200::FetchPageDesc()
1616: {
1.1.1.12! root 1617: busdata data;
1.1 root 1618:
1.1.1.9 root 1619: MBusMakeSnoop(acc_pdaddr, 0);
1.1 root 1620: data = MBusRead(acc_pdaddr, 4);
1.1.1.12! root 1621: if (__predict_false(data.IsBusErr())) {
! 1622: SetFault(FAULT_CODE_BUSERR, acc_pdaddr);
1.1 root 1623: return false;
1624: }
1.1.1.12! root 1625: tmp_desc = data.Data();
1.1 root 1626: tmp_desc &= (0xfffff000 | DESC_WT | DESC_SP | DESC_G | DESC_CI |
1627: DESC_M | DESC_U | DESC_WP | DESC_V);
1628:
1.1.1.9 root 1629: if (__predict_false((tmp_desc & DESC_V) == 0)) {
1.1.1.12! root 1630: SetFault(FAULT_CODE_PAGE, acc_pdaddr);
1.1 root 1631: putlog(4, " PD $%08x desc=$%08x PageFault", acc_pdaddr, tmp_desc);
1632: return false;
1633: } else {
1634: // Descriptor is valid
1635:
1.1.1.12! root 1636: if (__predict_false((tmp_desc & DESC_SP) && IsUser())) {
! 1637: SetFault(FAULT_CODE_SUPERVISOR, acc_pdaddr);
1.1 root 1638: putlog(4, " PD $%08x desc=$%08x SupervisorFault",
1639: acc_pdaddr, tmp_desc);
1640: return false;
1641: }
1642:
1643: acc_stat |= tmp_desc & ACC_STAT_MASK;
1644:
1.1.1.9 root 1645: if (__predict_false((acc_stat & DESC_WP) && acc_IsWrite())) {
1.1 root 1646: // fault_addr は invalid data
1.1.1.12! root 1647: SetFault(FAULT_CODE_WRITE, 0xcccccccc);
1.1 root 1648: putlog(4, " PD $%08x desc=$%08x WriteFault", acc_pdaddr, tmp_desc);
1649: return false;
1650: } else {
1651: putlog(4, " PD $%08x stat=%s acc=%s", acc_pdaddr,
1652: stat2str(tmp_desc).c_str(),
1653: stat2str(acc_stat).c_str());
1654: return true;
1655: }
1656: }
1657: }
1658:
1659: // Update Page Descriptor
1660: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1661: // p2-24, Figure2-8
1662: bool
1663: m88200::UpdatePageDesc()
1664: {
1.1.1.12! root 1665: busdata bd;
1.1 root 1666:
1667: if ((tmp_desc & DESC_M) == 0 && acc_IsWrite()) {
1668: // Update Modified bit and accrue status
1669:
1670: // XXX 図中 PATC[M] をセットするとあるが、ここでは遅い気がする。
1671: // Translate() 中の Update M bit のところのコメントも参照。
1672:
1673: // XXX 図中 ACC_STATUS[M] は TEMP_DESCR[M] じゃないの?
1674: tmp_desc |= DESC_M;
1675: }
1676:
1677: // Update Used bit
1678: tmp_desc |= DESC_U;
1679:
1.1.1.9 root 1680: MBusMakeSnoop(acc_pdaddr, 1);
1.1.1.12! root 1681: bd = MBusWrite(acc_pdaddr, tmp_desc, 4);
! 1682: if (__predict_false(bd.IsBusErr())) {
! 1683: SetFault(FAULT_CODE_BUSERR, acc_pdaddr);
1.1 root 1684: return false;
1685: }
1686: putlog(4, " Update PD $%08x desc=$%08x stat=%s",
1687: acc_pdaddr, tmp_desc, stat2str(tmp_desc).c_str());
1688:
1689: return true;
1690: }
1691:
1.1.1.12! root 1692: // 指定の PATC を無効にする。
1.1.1.9 root 1693: void
1.1.1.12! root 1694: m88200::InvalidatePATCEntry(m88200PATC& p)
1.1.1.9 root 1695: {
1.1.1.12! root 1696: uint32 la = addr2hash(p.IsS(), p.lpa);
1.1.1.9 root 1697:
1.1.1.12! root 1698: if (p.IsValid()) {
! 1699: uint8 n = atc_hash_all[la];
! 1700: // - BATC (n<0) なら、atc_hash は触らず PATC エントリだけ消す。
! 1701: // この PATC が作成された後にここに BATC がセットされたとかなので。
! 1702: // - PATC (n>0) なら (自分のはずなので) atc_hash ごと消す。
! 1703: if ((int8)n > 0) {
! 1704: atc_hash_all[la] = 0;
! 1705: }
1.1.1.9 root 1706: }
1.1.1.12! root 1707: //DumpATC();
! 1708:
! 1709: p.lpa |= PATC_INVALID;
! 1710: #if defined(M88200_STAT)
! 1711: stat_patc_invalidate++;
! 1712: #endif
1.1.1.9 root 1713: }
1714:
1.1 root 1715: // Create PATC Entry
1716: // 公式フローチャートと違って MBus Acquire したまま戻ること。
1717: // p2-25, Figure2-9
1718: void
1719: m88200::CreatePATCEntry()
1720: {
1.1.1.9 root 1721: // 空きがあろうがなかろうが、とにかく一番古いエントリを使う。
1722: // おそらく実機も空きエントリを前に詰めるような複雑な処理はして
1723: // ないだろうという推測。
1724:
1725: #if defined(M88200_STAT)
1726: stat_patc_create++;
1727: #endif
1728: m88200PATC& p = patc[patc_next];
1729: // 有効なら無効化
1730: if (p.IsValid()) {
1.1.1.12! root 1731: InvalidatePATCEntry(p);
1.1.1.9 root 1732: }
1733:
1734: // このエントリを潰して作る
1.1 root 1735: memset(&p, 0, sizeof(p));
1736: p.lpa = acc_laddr & 0xfffff000;
1737: p.pfa = tmp_desc & 0xfffff000;
1.1.1.12! root 1738: if (IsSuper()) {
1.1 root 1739: p.lpa |= PATC_S;
1740: }
1741: p.stat = acc_stat;
1742: putlog(4, " %s %c:$%08x:$%08x stat=%s", __func__,
1.1.1.9 root 1743: p.IsS() ? 'S' : 'U', (p.lpa & 0xfffff000), p.pfa,
1.1 root 1744: stat2str(p.stat).c_str());
1.1.1.9 root 1745:
1.1.1.12! root 1746: // ハッシュの値は PATC#0 が 1。
! 1747: uint32 la = p.lpa >> 12;
! 1748: atc_hash[la] = patc_next + 1;
! 1749: //DumpATC();
1.1.1.9 root 1750:
1751: patc_next++;
1752: if (__predict_false(patc_next >= patc.size())) {
1753: patc_next = 0;
1754: }
1.1 root 1755: }
1756:
1757: // アドレス変換 (デバッガ用)
1.1.1.12! root 1758: busaddr
! 1759: m88200::TranslatePeek(busaddr addr_) const
1.1 root 1760: {
1761: const m88200APR *xapr;
1.1.1.12! root 1762: uint32 laddr = addr_.Addr();
! 1763: bool issuper = addr_.IsSuper();
1.1 root 1764: uint32 la;
1765:
1766: // Select Area Descriptor
1767: if (issuper) {
1768: xapr = &sapr;
1769: } else {
1770: xapr = &uapr;
1771: }
1772: if (xapr->enable == 0) {
1773: return laddr;
1774: }
1775:
1.1.1.12! root 1776: la = addr2hash(issuper, laddr);
! 1777: uint8 n = atc_hash_all[la];
1.1 root 1778:
1.1.1.12! root 1779: if (n == 0) {
! 1780: // FALLTHROUGH
! 1781: } else if ((int8)n < 0) {
! 1782: // BATC #(~n) hit
! 1783: n = ~n;
! 1784: const m88200BATC& b = batc[n];
! 1785: return b.pba | (laddr & 0x0007ffff);
! 1786: } else {
! 1787: // BATC #(n-1) hit
! 1788: n--;
! 1789: const m88200PATC& p = patc[n];
! 1790: return p.pfa | (laddr & 0x00000fff);
1.1 root 1791: }
1792:
1793: // ここからテーブルサーチ
1794: uint64 data;
1795: uint32 desc_addr;
1796: uint32 desc;
1797:
1798: // Peek Segment Descriptor
1799: desc_addr = xapr->addr | ((laddr >> 20) & ~3U);
1.1.1.11 root 1800: data = mainbus->Peek32(desc_addr);
1.1 root 1801: if ((int64)data < 0) {
1.1.1.12! root 1802: return busaddr::BusErr | busaddr::TableSearched;
1.1 root 1803: }
1804: desc = (uint32)data;
1805: if ((desc & DESC_V) == 0) {
1.1.1.12! root 1806: return busaddr::BusErr | busaddr::TableSearched;
1.1 root 1807: }
1808: if ((desc & DESC_SP) && issuper == false) {
1.1.1.12! root 1809: return busaddr::BusErr | busaddr::TableSearched;
1.1 root 1810: }
1811:
1812: // Peek Page Descriptor
1813: desc_addr = (desc & 0xfffff000) | ((laddr >> 10) & 0xffc);
1.1.1.11 root 1814: data = mainbus->Peek32(desc_addr);
1.1 root 1815: if ((int64)data < 0) {
1.1.1.12! root 1816: return busaddr::BusErr | busaddr::TableSearched;
1.1 root 1817: }
1818: desc = (uint32)data;
1819: if ((desc & DESC_V) == 0) {
1.1.1.12! root 1820: return busaddr::BusErr | busaddr::TableSearched;
1.1 root 1821: }
1822: if ((desc & DESC_SP) && issuper == false) {
1.1.1.12! root 1823: return busaddr::BusErr | busaddr::TableSearched;
1.1 root 1824: }
1825:
1.1.1.12! root 1826: busaddr r = (desc & 0xfffff000) | (laddr & 0x00000fff);
! 1827: r |= busaddr::TableSearched;
! 1828: return r;
1.1 root 1829: }
1830:
1831:
1832: //
1833: // キャッシュ
1834: //
1835:
1836: // このラインの状態を更新
1837: void
1838: m88200CacheSet::Update(int line, m88200CacheSet::Status status)
1839: {
1840: vv[line] = status;
1.1.1.9 root 1841: if (__predict_false(status == IV)) {
1.1 root 1842: // 無効なら
1843: tag[line] |= TAG_INVALID;
1844: L = TryUnuseLine(L, line);
1845: }
1846: }
1847:
1848: // CSSP L5-L0 の処理。
1849: // 引数 tmpL の状態から line を最新にしたらどうなるか、を返す。
1850: // 表示処理で一時変数に対して処理が必要なため分離してある。
1.1.1.9 root 1851: /*static*/ int
1.1 root 1852: m88200CacheSet::TryUseLine(int tmpL, int line)
1853: {
1854: // L フィールドは 3bit, 2bit, 1bit で構成され、
1855: // 他のラインの対応ビットを落として、
1856: // 自分のラインの対応ビットを全部立てれば、
1857: // 他のラインの順序を保存した状態で、自分が最新になるように
1858: // 順序をつけられる。
1859:
1860: if (line == 3) {
1861: tmpL |= 0b111'00'0;
1862: } else if (line == 2) {
1863: tmpL &= 0b011'11'1;
1864: tmpL |= 0b000'11'0;
1865: } else if (line == 1) {
1866: tmpL &= 0b101'01'1;
1867: tmpL |= 0b000'00'1;
1868: } else {
1869: tmpL &= 0b110'10'0;
1870: }
1871: return tmpL;
1872: }
1873:
1874: // CSSP L5-L0 の処理。
1875: // 引数 tmpL の状態から line を最古にしたらどうなるか、を返す。
1.1.1.9 root 1876: /*static*/ int
1.1 root 1877: m88200CacheSet::TryUnuseLine(int tmpL, int line)
1878: {
1879: // Use のちょうど反転論理
1880: if (line == 3) {
1881: tmpL &= 0b000'11'1;
1882: } else if (line == 2) {
1883: tmpL |= 0b100'00'0;
1884: tmpL &= 0b111'00'1;
1885: } else if (line == 1) {
1886: tmpL |= 0b010'10'0;
1887: tmpL &= 0b111'11'0;
1888: } else {
1889: tmpL |= 0b001'01'1;
1890: }
1891: return tmpL;
1892: }
1893:
1894: // CSSP L5-L0 の処理。
1895: // 引数 tmpL の状態で、最新の line を返す。
1896: // 表示処理で一時変数に対して処理が必要なため分離してある。
1.1.1.9 root 1897: /*static*/ int
1.1 root 1898: m88200CacheSet::TryGetOldestLine(int tmpL)
1899: {
1900: if (tmpL < 8) {
1901: return 3;
1902: }
1903: tmpL &= 7;
1904: if (tmpL < 2) {
1905: return 2;
1906: }
1907: tmpL &= 1;
1908: if (tmpL == 0) {
1909: return 1;
1910: } else {
1911: return 0;
1912: }
1913: }
1914:
1915: // 更新用に最も古いラインを選んで差し出す
1916: int
1917: m88200CacheSet::SelectOldestLine() const
1918: {
1919: // なければ、最も古いラインを差し出す
1920: return TryGetOldestLine(L);
1921: }
1922:
1923: // キャッシュの指定の line, word に data を書き込む。
1924: // size は 1, 2, 4 バイト。
1925: void
1926: m88200CacheSet::Write(int line, uint32 paddr, uint32 data, int size)
1927: {
1928: uint32 wordidx = (paddr >> 2) & 0x03;
1929: uint32 data32;
1930:
1931: if (__predict_true(size == 4)) {
1932: word[line * 4 + wordidx] = data;
1933: return;
1934: }
1935:
1936: data32 = word[line * 4 + wordidx];
1937: if (size == 2) {
1938: if ((paddr & 2) == 0) {
1939: data32 = (data32 & 0x0000ffff) | (data << 16);
1940: } else {
1941: data32 = (data32 & 0xffff0000) | data;
1942: }
1943: } else {
1944: switch (paddr & 3) {
1945: case 0:
1946: data32 = (data32 & 0x00ffffff) | (data << 24);
1947: break;
1948: case 1:
1949: data32 = (data32 & 0xff00ffff) | (data << 16);
1950: break;
1951: case 2:
1952: data32 = (data32 & 0xffff00ff) | (data << 8);
1953: break;
1954: case 3:
1955: data32 = (data32 & 0xffffff00) | data;
1956: break;
1957: default:
1958: __unreachable();
1959: }
1960: }
1961: word[line * 4 + wordidx] = data32;
1962: }
1963:
1.1.1.3 root 1964: // キャッシュを検索。
1965: // ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。
1966: int
1967: m88200CacheSet::Lookup(uint32 tagaddr) const
1968: {
1969: for (int line = 0; line < 4; line++) {
1970: if (tag[line] == tagaddr) {
1971: return line;
1972: }
1973: }
1974: return -1;
1975: }
1976:
1977:
1978: // キャッシュの指定の set, line にメモリから 1 ライン(4word) 読み込む。
1.1 root 1979: // 成功すれば 0 を返す。
1.1.1.3 root 1980: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1.1 root 1981: uint64
1.1.1.3 root 1982: m88200::ReadLine(m88200CacheSet& set, int line, uint32 tagaddr)
1.1 root 1983: {
1.1.1.3 root 1984: // キャッシュラインの充填は実機では Burst Read されているらしいが
1985: // nono では Burst Read 用のメソッドは用意しておらず通常の 32bit
1986: // アクセスをしているため、このままでは所要ウェイト数が正しくない。
1987: // そこでここで差を調整することにする。
1.1.1.11 root 1988: // mainbus->Read32() 4回なのでこれによって 12 wait が加算される。一方
1.1.1.3 root 1989: // 実機の Burst Read は取扱説明書によると 320ns (8 サイクル) で完了
1990: // するようなので、その差 4 をあらかじめ引いておく。
1991: // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.12! root 1992: // XXX busdata のウェイトどうするか
1.1.1.11 root 1993: parent->AddCycle(-4);
1.1.1.3 root 1994:
1995: // タグを更新
1996: set.tag[line] = tagaddr;
1.1 root 1997:
1.1.1.12! root 1998: busaddr addr(set.tag[line] | (set.setidx << 4), acc_super);
1.1 root 1999: for (int i = 0; i < 4; i++) {
1.1.1.12! root 2000: busdata bd = mainbus->Read32(addr);
! 2001: if (__predict_false(bd.IsBusErr())) {
! 2002: SetFault(FAULT_CODE_BUSERR, addr.Addr());
! 2003: return (uint64)-1;
1.1 root 2004: }
1.1.1.12! root 2005: set.word[line * 4 + i] = bd.Data();
1.1 root 2006: addr += 4;
2007: }
2008: return 0;
2009: }
2010:
1.1.1.3 root 2011: // キャッシュの指定の set, line を1ライン、メモリに書き出す(コピーバック)。
2012: // 成功すれば 0 を返す。
2013: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
2014: uint64
2015: m88200::CopyBackLine(m88200CacheSet& set, int line)
1.1 root 2016: {
1.1.1.3 root 2017: // キャッシュラインの書き出しは実機では Burst Write されているらしいが
2018: // nono では Burst Write 用のメソッドは用意しておらず通常の 32bit
2019: // アクセスをしているため、このままでは所要ウェイト数が正しくない。
2020: // そこでここで差を調整することにする。
1.1.1.11 root 2021: // mainbus->Write32() 4回なのでこれによって 8 wait が加算される。一方
1.1.1.3 root 2022: // 実機の Burst Write は取扱説明書によると 280ns (7サイクル) で完了する
2023: // ようなので、その差 1 をあらかじめて引いておく。
2024: // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.12! root 2025: // XXX busdata のウェイトどうするか
1.1.1.11 root 2026: parent->AddCycle(-1);
1.1.1.3 root 2027:
1.1.1.12! root 2028: busaddr addr(set.tag[line] | (set.setidx << 4), acc_super);
1.1.1.3 root 2029: for (int i = 0; i < 4; i++) {
1.1.1.12! root 2030: busdata bd = mainbus->Write32(addr, set.word[line * 4 + i]);
! 2031: if (__predict_false(bd.IsBusErr())) {
! 2032: SetFault(FAULT_CODE_BUSERR, addr.Addr());
! 2033: return (uint64)-1;
1.1 root 2034: }
1.1.1.3 root 2035: addr += 4;
1.1 root 2036: }
1.1.1.3 root 2037: return 0;
1.1 root 2038: }
2039:
2040: // キャッシュに対して paddr の読み込みを行う。
2041: // paddr は 32bit 境界のアドレスであること。
2042: // 読み込めれば該当の32bitワードを返す。
2043: // 何らかエラーが起きれば (uint64)-1 を返す。エラー要因は fault_code とか参照。
2044: // p.3-8 Figure 3-3
2045: uint64
2046: m88200::CacheRead(uint32 paddr)
2047: {
2048: int line;
2049: uint64 rv;
2050:
2051: assert((paddr & 3) == 0);
2052:
2053: // タグとセット番号
2054: uint32 tagaddr = (paddr & 0xfffff000);
2055: uint32 setidx = (paddr >> 4) & 0xff;
2056: uint32 wordidx = (paddr >> 2) & 0x03;
2057:
2058: m88200CacheSet& set = setarray[setidx];
2059: putlog(3, "CacheRead paddr=$%08x (set=$%02x)", paddr, setidx);
2060:
2061: line = set.Lookup(tagaddr);
1.1.1.9 root 2062: if (__predict_true(line >= 0)) {
1.1 root 2063: // Cache Hit
2064: putlog(4, " CacheRead hit (line=%d,word=%d)", line, wordidx);
1.1.1.3 root 2065: parent->AddCycle(1);
1.1 root 2066: goto success;
2067: }
2068:
2069: // Cache Miss
2070:
1.1.1.3 root 2071: parent->AddCycle(10); // Table.6-2
2072:
1.1 root 2073: // reply <- Wait
2074: MBusAcquire();
2075:
2076: // Select cache line for replacement
2077: line = set.SelectOldestLine();
2078: putlog(4, " CacheRead miss (replace line=%d)", line);
2079:
2080: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 2081: parent->AddCycle(7); // Table.6-2
2082: rv = CopyBackLine(set, line);
1.1 root 2083: if ((int64)rv < 0) {
2084: goto error;
2085: }
2086: }
2087:
2088: // Mark cache line invalid
2089: set.Update(line, m88200CacheSet::IV);
2090:
2091: // Read line from memory
1.1.1.9 root 2092: MBusMakeSnoop(paddr, 0);
1.1.1.3 root 2093: rv = ReadLine(set, line, tagaddr);
1.1.1.9 root 2094: if (__predict_false((int64)rv < 0)) {
1.1 root 2095: goto error;
2096: }
2097:
2098: MBusRelease();
2099:
2100: // Update cache line
2101: set.Update(line, m88200CacheSet::SU);
2102:
2103: putlog(4, " CacheRead updated (line=%d,word=%d)", line, wordidx);
2104: success:
2105: set.Use(line);
2106: return set.word[line * 4 + wordidx];
2107:
2108: error:
2109: MBusRelease();
2110: return (uint64)-1;
2111: }
2112:
2113: // キャッシュに対して paddr への data の書き込みを行う。size は 1, 2, 4 バイト。
2114: // paddr は size に応じた境界にあること。
2115: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
2116: // エラー要因は fault_code とか参照。
2117: // p.3-10 Figure 3-5
2118: uint64
2119: m88200::CacheWrite(uint32 paddr, uint32 data, int size)
2120: {
2121: int line;
1.1.1.12! root 2122: busdata bd;
1.1 root 2123: uint64 rv;
2124:
2125: assert((paddr & (size - 1)) == 0);
2126:
2127: // タグとセット番号
2128: uint32 tagaddr = (paddr & 0xfffff000);
2129: uint32 setidx = (paddr >> 4) & 0xff;
2130:
2131: m88200CacheSet& set = setarray[setidx];
2132: putlog(3, "CacheWrite paddr=$%08x (set=$%02x)", paddr, setidx);
2133:
2134: line = set.Lookup(tagaddr);
1.1.1.9 root 2135: if (__predict_true(line >= 0)) {
1.1 root 2136: // Cache Hit
1.1.1.3 root 2137: parent->AddCycle(1);
1.1 root 2138: return CacheWriteHit(set, line, paddr, data, size);
2139: }
2140:
2141: // Cache Miss
2142:
1.1.1.3 root 2143: parent->AddCycle(14); // Table.6-2
2144:
1.1 root 2145: // reply <- Wait
2146: MBusAcquire();
2147:
2148: // Select cache line for replacement
2149: line = set.SelectOldestLine();
2150: putlog(4, " CacheWrite miss (replace line=%d)", line);
2151:
2152: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 2153: parent->AddCycle(7); // Table.6-2
2154: rv = CopyBackLine(set, line);
1.1 root 2155: if ((int64)rv < 0) {
2156: goto error;
2157: }
2158: }
2159:
2160: // Mark line invalid
2161: set.Update(line, m88200CacheSet::IV);
2162:
2163: // Read line with intent to modify
1.1.1.9 root 2164: MBusMakeSnoop(paddr, 1);
1.1.1.3 root 2165: rv = ReadLine(set, line, tagaddr);
1.1 root 2166: if ((int64)rv < 0) {
2167: goto error;
2168: }
2169:
2170: // Write data to memory
1.1.1.12! root 2171: bd = MBusWrite(paddr, data, size);
! 2172: if (__predict_false(bd.IsBusErr())) {
! 2173: SetFault(FAULT_CODE_BUSERR, paddr);
1.1.1.3 root 2174: goto error;
1.1 root 2175: }
2176:
2177: // Write data into cache
2178: set.Write(line, paddr, data, size);
2179:
2180: // Mark line exclusive unmodified
1.1.1.11 root 2181: // p3-9 3.4.2.2 CACHE WRITE:CACHE HIT. の本文に writethrough のときは
2182: // It marks the line as shared unmodified... と書いてある。
2183: // Fig 3-5 には記載はないが、キャッシュエントリが作られるときも
2184: // Fig 3-6 のキャッシュヒット時と同じように SU にならないと矛盾する。
2185: if ((acc_stat & DESC_WT)) {
2186: set.Update(line, m88200CacheSet::SU);
2187: } else {
2188: set.Update(line, m88200CacheSet::EU);
2189: }
1.1 root 2190: set.Use(line);
2191:
2192: MBusRelease();
2193: return 0;
2194:
2195: error:
2196: MBusRelease();
2197: return (uint64)-1;
2198: }
2199:
2200: // キャッシュがヒットした場合。
2201: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
2202: // p3-11 Figure 3-6
2203: uint64
2204: m88200::CacheWriteHit(m88200CacheSet& set, int line,
2205: uint32 paddr, uint32 data, int size)
2206: {
1.1.1.9 root 2207: if (__predict_false(set.vv[line] == m88200CacheSet::SU)) {
1.1 root 2208: // Line Shared Unmodified の場合
2209:
2210: putlog(4, " CacheWrite hit shared unmodified (line=%d)", line);
2211:
2212: // WriteThrough と Global は最後の状態変化だけが違う
2213: if ((acc_stat & (DESC_WT | DESC_G))) {
2214: // reply = Wait;
2215: MBusAcquire();
2216:
2217: // Write data to cache
2218: set.Write(line, paddr, data, size);
2219:
2220: // Write data to memory
1.1.1.9 root 2221: MBusMakeSnoop(paddr, 1);
1.1.1.12! root 2222: busdata bd = MBusWrite(paddr, data, size);
! 2223: if (__predict_false(bd.IsBusErr())) {
1.1 root 2224: MBusRelease();
1.1.1.12! root 2225: SetFault(FAULT_CODE_BUSERR, paddr);
! 2226: return (uint64)-1;
1.1 root 2227: }
2228:
2229: if ((acc_stat & DESC_WT)) {
2230: // Mark line shared unmodified
2231: set.Update(line, m88200CacheSet::SU);
2232: } else {
2233: // Mark line exclusive unmodified
2234: set.Update(line, m88200CacheSet::EU);
2235: }
2236: set.Use(line);
2237:
2238: MBusRelease();
2239: return 0;
2240: }
2241:
2242: // どちらでもない場合は Line Exclusive と同じ処理に落ちる
1.1.1.9 root 2243: } else {
2244: // Line Exclusive の場合
2245: putlog(4, " CacheWrite hit exclusive (line=%d)", line);
1.1 root 2246: }
2247:
2248: // Write data into cache
2249: putlog(4, " CacheWrite line=%d $%08x sz=%d", line, paddr, size);
2250: set.Write(line, paddr, data, size);
2251:
2252: // Mark line exclusive modified
2253: set.Update(line, m88200CacheSet::EM);
2254: set.Use(line);
2255: return 0;
2256: }
2257:
2258: // paddr への xmem を行う。size は 1, 2, 4 バイト。
2259: // 成功すれば読み出した値、エラーが起きれば (uint64)-1 を返す。
2260: // p3-13, Figure3-7
2261: uint64
2262: m88200::CacheXmem(uint32 paddr, uint32 data, int size)
2263: {
2264: int line;
1.1.1.12! root 2265: busdata bd;
1.1 root 2266: uint64 rv;
2267:
2268: assert((paddr & (size - 1)) == 0);
2269:
2270: // タグとセット番号
2271: uint32 tagaddr = (paddr & 0xfffff000);
2272: uint32 setidx = (paddr >> 4) & 0xff;
2273:
2274: m88200CacheSet& set = setarray[setidx];
2275: putlog(3, "CacheXmem paddr=$%08x (set=$%02x)", paddr, setidx);
2276:
2277: line = set.Lookup(tagaddr);
1.1.1.9 root 2278: if (__predict_false(line >= 0 && set.vv[line] == m88200CacheSet::EM)) {
1.1 root 2279: // Cache Hit (and Line exclusive modified)
2280: putlog(4, " CacheXmem hit and EM (line=%d)", line);
2281:
2282: MBusAcquire();
2283:
1.1.1.3 root 2284: parent->AddCycle(7); // Table.6-2
1.1.1.9 root 2285: MBusMakeSnoop(paddr, 1);
1.1.1.3 root 2286: rv = CopyBackLine(set, line);
1.1.1.9 root 2287: if (__predict_false((int64)rv < 0)) {
1.1 root 2288: goto error;
2289: }
2290:
2291: set.Update(line, m88200CacheSet::IV);
2292: } else {
2293: // Cache Miss or (Cache Hit but other than exclusive modified)
2294:
2295: if (line >= 0) {
2296: // Cache Hit and Otherwise (= !EM)
2297: putlog(4, " CacheXmem hit but !EM (line=%d)", line);
2298: set.Update(line, m88200CacheSet::IV);
2299: } else {
2300: putlog(4, " CacheXmem miss");
2301: }
2302:
2303: MBusAcquire();
2304: }
2305:
1.1.1.9 root 2306: MBusMakeSnoop(paddr, 1);
1.1.1.12! root 2307: bd = MBusXmem(paddr, data, size);
1.1 root 2308: MBusRelease();
1.1.1.12! root 2309: if (__predict_false(bd.IsBusErr())) {
! 2310: SetFault(FAULT_CODE_BUSERR, paddr);
! 2311: return (uint64)-1;
! 2312: }
! 2313: return bd.Data();
1.1 root 2314:
2315: error:
2316: MBusRelease();
2317: return rv;
2318: }
1.1.1.3 root 2319:
2320: // MBus 使用権を取得する
2321: void
2322: m88200::MBusAcquire()
2323: {
2324: // アービトレーションのたびに1クロックかかる(?)
2325: // よく分からんけど、とりあえず、CMMU は一度所有権を持ったら放さない、
2326: // 別の CMMU がバスリクエストすると所有権はその CMMU に移る、とする。
1.1.1.9 root 2327: if (__predict_false(mbus_master != this)) {
1.1.1.3 root 2328: mbus_master = this;
2329: parent->AddCycle(1);
2330: }
2331: }
1.1.1.9 root 2332:
2333: // 他 CMMU にバススヌープさせるポイント。
2334: // 本来はバスマスタ CMMU が MBus にアドレスと IM を出すと、それを監視して
2335: // いる他 CMMU が必要に応じて反応するのだが、ここでは全部マスタ主導で行う。
2336: // Figure 3-8, 3-9
2337: void
2338: m88200::MBusMakeSnoop(uint32 paddr, int im)
2339: {
2340: if ((acc_stat & DESC_G) == 0) {
2341: return;
2342: }
2343:
2344: // MBus Status <- Wait (2 clocks)
2345: // 本来はスヌープをするスレーブ側が 2 クロックかかるのだが、
2346: // 個別の CMMU がクロックを持っていない実装なのでマスタ側で
2347: // クロックを消費したことにする。
2348: parent->AddCycle(2);
2349:
2350: // 本来はここで解放ではなく、スレーブ側が反応したい時にバスリクエストを
2351: // 出してそれによって手放すのだが、その機構はないので、こちらが自主的に
2352: // 一旦手放したようにしておく。とは言っても現状 MBusRelease() はダミーで
2353: // 実際には他の誰かが MBusAcquire() を呼ぶまで握りっぱなしなので、
2354: // あまり問題ないはず。
2355: MBusRelease();
2356: for (const auto other : other_cmmu) {
2357: other->Snoop(paddr, im);
2358: }
2359: MBusAcquire();
2360: }
2361:
2362: // バススヌープ (スレーブ側)。
2363: // 本来はバスマスタでない CMMU は、バスマスタが MBus に出すアドレス情報を
2364: // 監視し、必要ならそれに反応するのだが、ここでは全部マスタ主導で行う。
2365: // こっちはそのマスタから呼ばれるスレーブ側。
2366: // Figure 3-8, 3-9
2367: void
2368: m88200::Snoop(uint32 paddr, int im)
2369: {
2370: assert((sctr & SCTR_SE));
2371:
2372: uint32 tagaddr = (paddr & 0xfffff000);
2373: uint32 setidx = (paddr >> 4) & 0xff;
2374:
2375: m88200CacheSet& set = setarray[setidx];
2376: int line = set.Lookup(tagaddr);
2377:
2378: if (line >= 0) {
2379: // Cache hit
2380: if (set.vv[line] == m88200CacheSet::EM) {
2381: // Line exclusive modified
2382:
2383: // Assert retry
2384:
2385: // Request MBus
2386: // 実際にはここで MBus 使用権を要求して獲得するのだが
2387: // その機構はなくその代わり Acquire を呼ぶだけでいける。
2388: MBusAcquire();
2389: uint64 rv = CopyBackLine(set, line);
2390: MBusRelease();
2391: if ((int64)rv < 0) {
2392: // Set CE bit in system status register
2393: return;
2394: }
2395:
2396: if (im == 0) {
2397: // Mark line shared unmodified (if IM=0)
2398: set.Update(line, m88200CacheSet::SU);
2399: } else {
2400: // Mark line invalid (if IM=1)
2401: set.Update(line, m88200CacheSet::IV);
2402: }
2403: }
2404: }
2405: // Resume servicing PBus
2406: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.