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