|
|
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:
1.1.1.13! root 195: screen.Print(0, 0, "SAPR %05x'000 TE=%u %c%c%c",
1.1.1.7 root 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.13! root 202: screen.Print(40, 0, "UAPR %05x'000 TE=%u %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) {
1.1.1.13! root 221: screen.Print(x, y, " %u:", i);
1.1.1.7 root 222: } else {
1.1.1.13! root 223: screen.Print(x, y, "(%u)", i);
1.1.1.7 root 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: }
1.1.1.13! root 257: screen.Print(x, y, "%2u:", i);
1.1.1.7 root 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: {
1.1.1.13! root 324: uint setidx = screen.userdata;
1.1.1.7 root 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
1.1.1.13! root 336: m88200::MonitorCacheSet(TextScreen& s, int y, uint setidx)
1.1 root 337: {
1.1.1.13! root 338: assertmsg(setidx < setarray.size(), "setidx=%u", 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: }
1.1.1.13! root 374: s.Print(0, y, attr, "%u", 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: // メモリに対してダーティならボールドにする
1.1.1.13! root 383: for (uint w = 0; w < 4; w++) {
1.1 root 384: uint32 addr;
385: uint32 m;
386: addr = (set.tag[line] & 0xfffff000) | (setidx << 4) | (w << 2);
1.1.1.13! root 387: m = (mainbus->Peek1(addr) << 24)
! 388: | (mainbus->Peek1(addr + 1) << 16)
! 389: | (mainbus->Peek1(addr + 2) << 8)
! 390: | (mainbus->Peek1(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: // 順序
1.1.1.13! root 406: s.Print(58, y, "%u", Lorder[line]);
1.1 root 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
1.1.1.13! root 420: m88200::MonitorCacheOverview(TextScreen& s, int y, uint cursor, bool is_gui)
1.1 root 421: {
422: // X ガイド
1.1.1.13! root 423: for (uint i = 0; i < 16; i++) {
! 424: uint x;
1.1 root 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 ガイド
1.1.1.13! root 435: for (uint i = 0; i < 16; i++) {
1.1 root 436: s.Print(0, y + i, "%02x", i * 16);
437: }
438:
1.1.1.13! root 439: for (uint i = 0; i < setarray.size(); i++) {
1.1 root 440: const auto& set = setarray[i];
1.1.1.3 root 441: const char str[] = "EMS-";
1.1.1.13! root 442: uint col = i % 16;
! 443: uint row = i / 16;
! 444: uint x;
1.1 root 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--;
1.1.1.13! root 732: putlog(4, "Invalidate PATCEntry from GG_PAGE n=%u", n);
1.1.1.12 root 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.13! root 769: putlog(4, "Invalidate PATCEntry from GG_* n=%u", i);
1.1.1.12 root 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 {};
1.1.1.13! root 785: uint 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--;
1.1.1.13! root 953: putlog(4, "Invalidate PATCEntry from SetBATC(%u) n=%u", n, pn);
1.1.1.12 root 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) {
1.1.1.13! root 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.13! 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.13! root 1032: busaddr baddr = busaddr(paddr) | acc_super | busaddr::Size(size);
1.1.1.12 root 1033: busdata bd;
1.1 root 1034:
1.1.1.13! root 1035: // m88k システムに接続しているデバイスはすべて、m68030 システムでいう
! 1036: // ところのロングワードポートデバイスなので応答は常に 4 バイト分ある。
! 1037: bd = mainbus->Read(baddr);
! 1038:
1.1 root 1039: if (size == 4) {
1040: } else if (size == 2) {
1.1.1.13! root 1041: if ((paddr & 2) == 0) {
! 1042: bd >>= 16;
! 1043: } else {
! 1044: bd &= 0xffff;
! 1045: }
1.1 root 1046: } else {
1.1.1.13! root 1047: bd >>= (3 - (paddr & 3)) * 8;
! 1048: bd &= 0xff;
1.1 root 1049: }
1.1.1.13! root 1050:
1.1.1.12 root 1051: parent->AddWait(bd.GetWait());
1052: return bd;
1.1 root 1053: }
1054:
1055: // MBus に書き込みを行う。
1056: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
1.1.1.12 root 1057: // バスエラーなら呼び出し側で SetFault(FAULT_CODE_BUSERR, paddr) を呼ぶこと。
1058: busdata
1.1 root 1059: m88200::MBusWrite(uint32 paddr, uint32 data, int size)
1060: {
1.1.1.13! root 1061: busaddr baddr = busaddr(paddr) | acc_super | busaddr::Size(size);
1.1.1.12 root 1062: busdata bd;
1.1 root 1063:
1.1.1.13! root 1064: bd = mainbus->Write(baddr, data);
1.1.1.12 root 1065: parent->AddWait(bd.GetWait());
1066: return bd;
1.1 root 1067: }
1068:
1069: // MBus に xmem トランザクションを行う。
1.1.1.6 root 1070: // paddr は size によって 1, 4 バイト境界に整列していること (2バイトはない)。
1.1 root 1071: // MBus Acquire された状態で呼び出すこと。
1072: // 成功すれば読み込めた値を返す。
1.1.1.12 root 1073: // バスエラーなら呼び出し側で SetFault(FAULT_CODE_BUSERR, paddr) を呼ぶこと。
1.1 root 1074: // read/write どちらでエラーが起きたかは acc_read で判別できる。
1075: // p3-13, Figure3-7 の下半分のメインラインあたりに該当。
1.1.1.12 root 1076: busdata
1.1 root 1077: m88200::MBusXmem(uint32 paddr, uint32 data, int size)
1078: {
1.1.1.12 root 1079: busdata fetched;
1080: busdata bd;
1.1 root 1081:
1082: // Read data with intent to modify
1083: acc_read = true;
1.1.1.12 root 1084: bd = MBusRead(paddr, size);
1085: parent->AddWait(bd.GetWait());
1086: if (__predict_false(bd.IsBusErr())) {
1087: return bd;
1.1 root 1088: }
1.1.1.12 root 1089: fetched = bd;
1.1 root 1090:
1091: // Supply data to PBus
1092: // Reply = Success
1093:
1094: // Write data to memory
1095: acc_read = false;
1.1.1.12 root 1096: bd = MBusWrite(paddr, data, size);
1097: parent->AddWait(bd.GetWait());
1098: if (__predict_false(bd.IsBusErr())) {
1099: return bd;
1.1 root 1100: }
1101:
1.1.1.12 root 1102: return fetched;
1.1 root 1103: }
1104:
1105: //
1106: // アクセス関数
1107: //
1108:
1.1.1.13! root 1109: template <uint size> uint64
1.1 root 1110: m88200::load(uint32 addr)
1111: {
1112: uint64 data;
1113:
1114: acc_laddr = addr;
1115: acc_read = true;
1.1.1.9 root 1116: if (__predict_false(Translate() == false)) {
1117: putlog(2, "Translation BusError %c:$%08x",
1.1.1.12 root 1118: (IsSuper() ? 'S' : 'U'), acc_laddr);
1.1 root 1119: return (uint64)-1;
1120: }
1.1.1.9 root 1121: if (__predict_false((acc_stat & DESC_CI))) {
1.1.1.3 root 1122: parent->AddCycle(7); // Table.6-2
1.1 root 1123: MBusAcquire();
1.1.1.9 root 1124: MBusMakeSnoop(acc_paddrH, 0);
1.1.1.12 root 1125: uint32 paddr = acc_paddrH + acc_paddrL;
1.1.1.13! root 1126: busdata bd = MBusRead(paddr, size);
1.1 root 1127: MBusRelease();
1.1.1.12 root 1128: if (__predict_false(bd.IsBusErr())) {
1.1.1.9 root 1129: putlog(2, "MBus BusError %c:$%08x",
1.1.1.12 root 1130: (IsSuper() ? 'S' : 'U'), acc_laddr);
1131: SetFault(FAULT_CODE_BUSERR, paddr);
1132: return (uint64)-1;
1.1.1.4 root 1133: }
1.1.1.12 root 1134: return bd.Data();
1.1 root 1135: } else {
1136: data = CacheRead(acc_paddrH);
1.1.1.9 root 1137: if (__predict_false((int64)data < 0)) {
1138: putlog(2, "Cache BusError %c:$%08x",
1.1.1.12 root 1139: (IsSuper() ? 'S' : 'U'), acc_laddr);
1.1 root 1140: return data;
1141: }
1142:
1.1.1.13! root 1143: if (size == 1) {
1.1 root 1144: switch (acc_paddrL) {
1145: case 0:
1146: return (data >> 24);
1147: case 1:
1148: return (data >> 16) & 0xff;
1149: case 2:
1150: return (data >> 8) & 0xff;
1151: case 3:
1152: return data & 0xff;
1.1.1.11 root 1153: default:
1.1.1.13! root 1154: PANIC("corrupted acc_paddrL=%u", acc_paddrL);
1.1 root 1155: }
1.1.1.13! root 1156: } else if (size == 2) {
1.1 root 1157: if (acc_paddrL == 0) {
1158: return data >> 16;
1159: } else {
1160: return data & 0xffff;
1161: }
1.1.1.13! root 1162: } else if (size == 4) {
1.1 root 1163: return data;
1.1.1.11 root 1164: } else {
1165: PANIC("bits must be 8, 16, 32");
1.1 root 1166: }
1167: }
1168: }
1169:
1170: uint64
1.1.1.13! root 1171: m88200::load_1(uint32 addr)
1.1 root 1172: {
1.1.1.13! root 1173: return load<1>(addr);
1.1 root 1174: }
1175:
1176: uint64
1.1.1.13! root 1177: m88200::load_2(uint32 addr)
1.1 root 1178: {
1.1.1.13! root 1179: return load<2>(addr);
1.1 root 1180: }
1181:
1182: uint64
1.1.1.13! root 1183: m88200::load_4(uint32 addr)
1.1 root 1184: {
1.1.1.13! root 1185: return load<4>(addr);
1.1 root 1186: }
1187:
1.1.1.13! root 1188: template <uint size> uint64
1.1 root 1189: m88200::store(uint32 addr, uint32 data)
1190: {
1191: acc_laddr = addr;
1192: acc_read = false;
1.1.1.9 root 1193: if (__predict_false(Translate() == false)) {
1.1 root 1194: return (uint64)-1;
1195: }
1.1.1.12 root 1196: uint32 paddr = acc_paddrH + acc_paddrL;
1.1.1.9 root 1197: if (__predict_false((acc_stat & DESC_CI))) {
1.1.1.3 root 1198: parent->AddCycle(7); // Table.6-2
1.1 root 1199: MBusAcquire();
1.1.1.9 root 1200: MBusMakeSnoop(acc_paddrH, 1);
1.1.1.13! root 1201: busdata bd = MBusWrite(paddr, data, size);
1.1 root 1202: MBusRelease();
1.1.1.12 root 1203: if (__predict_false(bd.IsBusErr())) {
1204: SetFault(FAULT_CODE_BUSERR, paddr);
1205: return (uint64)-1;
1206: }
1207: return 0;
1.1 root 1208: } else {
1.1.1.13! root 1209: return CacheWrite(paddr, data, size);
1.1 root 1210: }
1211: }
1212:
1213: uint64
1.1.1.13! root 1214: m88200::store_1(uint32 addr, uint32 data)
1.1 root 1215: {
1.1.1.13! root 1216: return store<1>(addr, data);
1.1 root 1217: }
1218:
1219: uint64
1.1.1.13! root 1220: m88200::store_2(uint32 addr, uint32 data)
1.1 root 1221: {
1.1.1.13! root 1222: return store<2>(addr, data);
1.1 root 1223: }
1224:
1225: uint64
1.1.1.13! root 1226: m88200::store_4(uint32 addr, uint32 data)
1.1 root 1227: {
1.1.1.13! root 1228: return store<4>(addr, data);
1.1 root 1229: }
1230:
1.1.1.13! root 1231: template <uint size> uint64
1.1 root 1232: m88200::xmem(uint32 addr, uint32 data)
1233: {
1234: acc_laddr = addr;
1235: acc_read = false;
1.1.1.9 root 1236: if (__predict_false(Translate() == false)) {
1.1 root 1237: return (uint64)-1;
1238: }
1.1.1.12 root 1239: uint32 paddr = acc_paddrH + acc_paddrL;
1.1.1.9 root 1240: if (__predict_false((acc_stat & DESC_CI))) {
1.1 root 1241: // XXX キャッシュ禁止領域だとどうなる?
1242: MBusAcquire();
1.1.1.9 root 1243: MBusMakeSnoop(acc_paddrH, 1);
1.1.1.13! root 1244: busdata bd = MBusXmem(paddr, data, size);
1.1 root 1245: MBusRelease();
1.1.1.12 root 1246: if (__predict_false(bd.IsBusErr())) {
1247: SetFault(FAULT_CODE_BUSERR, paddr);
1248: return (uint64)-1;
1249: }
1250: return bd.Data();
1.1 root 1251: } else {
1.1.1.13! root 1252: return CacheXmem(paddr, data, size);
1.1 root 1253: }
1254: }
1255:
1256: uint64
1.1.1.13! root 1257: m88200::xmem_1(uint32 addr, uint32 data)
1.1 root 1258: {
1.1.1.13! root 1259: return xmem<1>(addr, data);
1.1 root 1260: }
1261:
1262: uint64
1.1.1.13! root 1263: m88200::xmem_4(uint32 addr, uint32 data)
1.1 root 1264: {
1.1.1.13! root 1265: return xmem<4>(addr, data);
1.1 root 1266: }
1267:
1268: //
1269: // アドレス変換
1270: //
1271:
1272: // デバッグ用
1273: /*static*/ std::string
1274: m88200::stat2str(uint32 stat)
1275: {
1276: std::string buf;
1277:
1.1.1.9 root 1278: if ((stat & DESC_WT))
1.1 root 1279: buf += ",WT";
1.1.1.9 root 1280: if ((stat & DESC_G))
1.1 root 1281: buf += ",G";
1.1.1.9 root 1282: if ((stat & DESC_CI))
1.1 root 1283: buf += ",CI";
1.1.1.9 root 1284: if ((stat & DESC_M))
1.1 root 1285: buf += ",M";
1.1.1.9 root 1286: if ((stat & DESC_U))
1.1 root 1287: buf += ",U";
1.1.1.9 root 1288: if ((stat & DESC_WP))
1.1 root 1289: buf += ",WP";
1290:
1291: if (buf.empty()) {
1292: buf = ",0";
1293: }
1294: return buf.substr(1);
1295: }
1296:
1.1.1.12 root 1297: // ATC ハッシュを表示。
1298: void
1299: m88200::DumpATC()
1300: {
1301: uint8 zero[16] {};
1302:
1.1.1.13! root 1303: printf("DumpATC(#%u)\n", id);
! 1304: for (uint i = 0; i < atc_hash_all.size(); i += 16) {
1.1.1.12 root 1305: const uint8 *a = &atc_hash_all[i];
1306: if (memcmp(a, zero, 16) != 0) {
1.1.1.13! root 1307: printf("#%u %c.%08x:", id, ((i >> 20) ? 'S' : 'U'), i << 12);
1.1.1.12 root 1308:
1309: for (int j = 0; j < 16; j++) {
1310: uint8 n = a[j];
1311: if (__predict_true(n == 0)) {
1312: printf(" ");
1313: } else if (__predict_false((int8)n < 0)) {
1.1.1.13! root 1314: printf("~%u ", (uint)(uint8)~n);
1.1.1.12 root 1315: } else {
1.1.1.13! root 1316: printf("%-2u ", n - 1);
1.1.1.12 root 1317: }
1318: }
1319: printf("\n");
1320: }
1321: }
1322: }
1323:
1.1 root 1324: // アドレス変換。
1325: // 事前に acc_laddr, acc_super, acc_read を設定しておくこと。
1326: // 成功すれば acc_paddrH, acc_paddrL をセットして true を返す。
1327: // 失敗ならいろいろセットして(?) false を返す。
1328: // p2-3, Figure2-1
1329: bool
1330: m88200::Translate()
1331: {
1332: uint32 la;
1.1.1.12 root 1333: uint8 n;
1.1 root 1334:
1335: // Logical address(LA) presented on PBus
1336:
1.1.1.12 root 1337: putlog(3, "Translate %c:$%08x", (IsSuper() ? 'S' : 'U'), acc_laddr);
1.1 root 1338:
1339: // 下位2ビットは常にこうなる。
1340: acc_paddrL = acc_laddr & 3;
1341:
1.1.1.9 root 1342: // Select Area Descriptor
1343: if (SelectAreaDesc() == false) {
1.1.1.12 root 1344: // 変換しない場合でも暗黙 BWP は有効…。
1345: // マッチまではここで独自に行い、マッチしたら下の BWP へ合流。
1346: if (__predict_false(acc_laddr >= 0xfff00000) && IsSuper()) {
1347: n = (acc_laddr < 0xfff80000) ? 8 : 9;
1348: goto batc;
1349: }
1350:
1.1.1.9 root 1351: // XXX 図のこれはたぶん間違いだよなあ…
1352: // 誤: Physical Address <= LA[18-2] :: 00
1353: // 正: Physical Address <= LA[31-2] :: 00
1354: acc_paddrH = acc_laddr - acc_paddrL;
1.1.1.3 root 1355:
1.1.1.9 root 1356: parent->AddCycle(1);
1357: return true;
1358: }
1359:
1360: // 変換する分だけカウントするのでいいか
1361: translate_total++;
1362:
1363: // type == Valid ここから
1.1 root 1364:
1.1.1.12 root 1365: // 論理アドレスで現在の S/U のハッシュを引く。
1366: // 実際にはまず BATC を引いて、なければ次に PATC を引くのだが、
1367: // BATC と PATC が同じアドレスを指すことはなく、BATC が同じところを
1368: // 指すような指定は (出来るけど結果不定とマニュアルに書いてあるので)
1369: // 起きないものとすると、アドレスと BATC もしくは PATC は 1:1 で
1370: // マッピング出来るので、この全域を一回で検索する。
1371: la = acc_laddr >> 12;
1372: try_again:
1373: n = atc_hash[la];
1374: acc_patc = NULL;
1.1.1.3 root 1375:
1.1.1.12 root 1376: if (n == 0) {
1377: // BATC, PATC どちらにも載ってない。
1378: atc_miss++;
1379: // patc_miss に合流する
1380: } else if ((int8)n < 0) {
1381: // BATC #(~n) でヒットした。
1382: // n=0xff が BATC#0 を、n=0xf6 が BATC#9 を示す。
1383: n = ~n;
1384: batc:
1385: m88200BATC& b = batc[n];
1386: assert(b.IsValid());
1.1.1.13! root 1387: putlog(4, " BATC[%u] hit", n);
1.1.1.12 root 1388: batc_hit[n]++;
1389: if (b.wp && acc_IsWrite()) {
1390: goto write_violation;
1391: }
1392:
1393: // Physical Address <= PBA :: LA[18-2] :: 00
1394: acc_paddrH = b.pba | (acc_laddr & 0x0007fffc);
1395: acc_stat |= b.stat;
1396: putlog(4, " BATC hit acc=%s paddr=$%08x",
1397: stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.9 root 1398:
1.1.1.12 root 1399: parent->AddCycle(1);
1400: return true;
1401: } else {
1402: // PATC #(n-1) でヒットした。
1403: // n=1 が PATC#0 を、n=56 が PATC#55 を示す。
1404: n--;
1405: m88200PATC& p = patc[n];
1406: assert(p.IsValid());
1407: patc_hit++;
1408:
1409: if (acc_IsWrite() && p.wp) {
1.1.1.13! root 1410: putlog(4, " PATC[%u] hit; stat=%s m=%u wp=%u", n,
1.1.1.12 root 1411: stat2str(p.stat).c_str(), p.m, p.wp);
1412: goto write_violation;
1413: }
1414: if (acc_IsWrite() && p.m == false) {
1415: // Update M bit
1416: // フローチャートでは PATC[M] はこの後のテーブルサーチ中
1417: // の Update Page Descriptor 処理中で更新するように書いて
1418: // あるように読めるのだが、その通りに実装すると、メモリ
1419: // 上の Page Descriptor に最初から M ビットが立っていると
1420: // (というか OpenBSD カーネルが用意した Page Descriptor
1421: // には立っているので) PATC[M] の更新も行われず、PATC[M]
1422: // が立っていないので再びここに来てしまい無限ループになる。
1423: // 誰が間違ってるのか分からないけど、とりあえずここで
1424: // PATC[M] を立てれば問題は起きない。
1.1.1.13! root 1425: putlog(4, " PATC[%u] hit; Need to update M bit", n);
1.1.1.12 root 1426: p.m = true;
1.1.1.9 root 1427:
1.1.1.12 root 1428: // この下の PATC miss に合流する
1429: acc_patc = &p;
1.1.1.9 root 1430: goto patc_miss;
1431: }
1432:
1.1.1.12 root 1433: // Physical Address <= PFA :: LA[11-2] :: 00
1434: acc_paddrH = p.pfa | (acc_laddr & 0x00000ffc);
1435: acc_stat |= p.stat;
1.1.1.13! root 1436: putlog(4, " PATC[%u] hit acc=%s paddr=$%08x", n,
1.1.1.12 root 1437: stat2str(acc_stat).c_str(), acc_paddrH);
1.1 root 1438:
1.1.1.12 root 1439: parent->AddCycle(1);
1440: return true;
1441: }
1.1.1.3 root 1442:
1.1.1.12 root 1443: // PATC miss
1.1.1.9 root 1444: patc_miss:
1.1.1.12 root 1445: putlog(4, " BATC/PATC miss");
1.1 root 1446:
1.1.1.12 root 1447: // PATC にヒットして M bit 更新するものは両方カウントされるけど
1448: atc_miss++;
1.1 root 1449:
1.1.1.12 root 1450: // Table search operation
1451: if (TableSearch() == true) {
1452: // テーブルサーチの結果、エントリが見付かって PATC が更新されたので
1453: // もう一度やり直す。
1454: // フローチャートでは Select Area Descriptor まで戻るように書いて
1455: // あるが、PATC ミスによるテーブルサーチでは Area Descriptor と BATC
1456: // は変化しないので、Area Descriptor の検索は省略。
1457: goto try_again;
1.1 root 1458: }
1.1.1.12 root 1459:
1460: // Invalid
1461: // Reply with fault (Figure2-10 だがここではすべて不要)
1462: return false;
1.1 root 1463:
1464: write_violation:
1.1.1.12 root 1465: // XXX fault_addr 不明
1466: SetFault(FAULT_CODE_WRITE, 0xcccccccc);
1.1 root 1467: // Reply with fault (Figure2-10 だがここではすべて不要)
1468: return false;
1469: }
1470:
1471: // Select Area Descriptor.
1472: // 結果が Type=Valid なら true、Type=Untranslated なら false を返す。
1.1.1.12 root 1473: // Probe Command からも呼ばれる (はずだが未実装)。
1.1 root 1474: // p2-21, Figure2-5
1475: bool
1476: m88200::SelectAreaDesc()
1477: {
1.1.1.9 root 1478: acc_stat = acc_apr->stat & ACC_STAT_MASK;
1479: if (acc_apr->enable) {
1.1 root 1480: // セグメントディスクリプタのアドレスはここで決まるが、
1481: // 次に行う BATC、PATC サーチでは使わず、それらが全部ミスして
1482: // テーブルサーチまで来た所で初めて使うので、ここでは表示しない。
1.1.1.9 root 1483: acc_sdaddr = acc_apr->addr | ((acc_laddr >> 20) & ~3U);
1484: putlog(4, " %s acc=%s", acc_apr->name, stat2str(acc_stat).c_str());
1.1 root 1485: return true;
1486: } else {
1487: putlog(3, " %s acc=%s Untranslated",
1.1.1.9 root 1488: acc_apr->name, stat2str(acc_stat).c_str());
1.1 root 1489: return false;
1490: }
1491: }
1492:
1493: // Table Search
1494: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1495: // p2-20, Figure2-4
1496: bool
1497: m88200::TableSearch()
1498: {
1499: putlog(4, " %s $%08x/%s acc=%s", __func__, acc_laddr,
1500: (acc_read ? "Read" : "Write"), stat2str(acc_stat).c_str());
1501:
1502: // XXX フローチャートを厳密に追っかけると MBus の Acquire/Release が
1503: // 対応していないので(orz)、ここでは
1504: // TableSearch() に入ったところで Acquire、
1505: // TableSearch() から出るところで Release だけに統一する。
1506:
1507: MBusAcquire();
1508:
1509: if (FetchSegmentDesc() == false) {
1510: MBusRelease();
1.1.1.3 root 1511:
1512: parent->AddCycle(7); // Table.6-2
1.1 root 1513: return false;
1514: }
1515:
1516: if (FetchPageDesc() == false) {
1517: MBusRelease();
1.1.1.3 root 1518:
1519: parent->AddCycle(11); // Table.6-2
1.1 root 1520: return false;
1521: }
1522:
1523: // 中央の TYPE = VALID のところ
1524: // ( )
1525: // +----------+ +----------+
1526: // | |
1527: // DESC[U]=0 || Otherwise
1528: // DESC[M]=0 && WRITE |
1529: // | |
1530: // UpdatePageDesc |
1531: // | |
1532: // <- RETRY -( )-- INVALID ---------- | -->
1533: // | |
1534: // VALID |
1535: // | |
1536: // ( ) <--------------------+
1537: // | |
1538: // +---+ +------------+
1539: // Otherwise TableSearch due to PATC miss
1540: // | |
1541: // (Only U/M bits CreatePATCEntry
1542: // Updated) |
1543: // | v
1544: // +---------------> ( )
1545:
1546: if ((tmp_desc & DESC_U) == 0 ||
1547: ((tmp_desc & DESC_M) == 0 && acc_IsWrite()))
1548: {
1.1.1.3 root 1549: parent->AddCycle(15); // Table.6-2
1550:
1.1 root 1551: if (UpdatePageDesc() == false) {
1552: MBusRelease();
1553: return false;
1554: }
1.1.1.3 root 1555: } else {
1556: parent->AddCycle(11); // Table.6-2
1.1 root 1557: }
1558:
1559: if (acc_patc == NULL) {
1560: // Table search due to PATC miss
1561: CreatePATCEntry();
1562: }
1563:
1564: MBusRelease();
1565: return true;
1566: }
1567:
1568: // Fetch Segment Descriptor
1569: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1570: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1571: // p2-22, Figure2-6
1572: bool
1573: m88200::FetchSegmentDesc()
1574: {
1.1.1.12 root 1575: busdata data;
1.1 root 1576:
1.1.1.9 root 1577: MBusMakeSnoop(acc_sdaddr, 0);
1.1 root 1578: data = MBusRead(acc_sdaddr, 4);
1.1.1.12 root 1579: if (__predict_false(data.IsBusErr())) {
1580: SetFault(FAULT_CODE_BUSERR, acc_sdaddr);
1.1 root 1581: return false;
1582: }
1.1.1.12 root 1583: tmp_desc = data.Data();
1.1 root 1584: tmp_desc &= (0xfffff000 |
1585: DESC_WT | DESC_SP | DESC_G | DESC_CI | DESC_WP | DESC_V);
1586:
1.1.1.9 root 1587: if (__predict_false((tmp_desc & DESC_V) == 0)) {
1.1.1.12 root 1588: SetFault(FAULT_CODE_SEGMENT, acc_sdaddr);
1.1 root 1589: putlog(4, " SD $%08x desc=$%08x SegFault", acc_sdaddr, tmp_desc);
1590: return false;
1591: } else {
1592: // Descriptor is valid
1593:
1.1.1.12 root 1594: if (__predict_false((tmp_desc & DESC_SP) && IsUser())) {
1595: SetFault(FAULT_CODE_SUPERVISOR, acc_sdaddr);
1.1 root 1596: putlog(4, " SD $%08x desc=$%08x SupervisorFault",
1597: acc_sdaddr, tmp_desc);
1598: return false;
1599: }
1600:
1601: acc_pdaddr = (tmp_desc & 0xfffff000) | ((acc_laddr >> 10) & 0xffc);
1602: acc_stat |= tmp_desc & ACC_STAT_MASK;
1603: putlog(4, " SD $%08x pdaddr=$%08x stat=%s acc=%s",
1604: acc_sdaddr, acc_pdaddr,
1605: stat2str(tmp_desc).c_str(),
1606: stat2str(acc_stat).c_str());
1607: return true;
1608: }
1609: }
1610:
1611: // Fetch Page Descriptor
1612: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1613: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
1614: // p2-23, Figure2-7
1615: bool
1616: m88200::FetchPageDesc()
1617: {
1.1.1.12 root 1618: busdata data;
1.1 root 1619:
1.1.1.9 root 1620: MBusMakeSnoop(acc_pdaddr, 0);
1.1 root 1621: data = MBusRead(acc_pdaddr, 4);
1.1.1.12 root 1622: if (__predict_false(data.IsBusErr())) {
1623: SetFault(FAULT_CODE_BUSERR, acc_pdaddr);
1.1 root 1624: return false;
1625: }
1.1.1.12 root 1626: tmp_desc = data.Data();
1.1 root 1627: tmp_desc &= (0xfffff000 | DESC_WT | DESC_SP | DESC_G | DESC_CI |
1628: DESC_M | DESC_U | DESC_WP | DESC_V);
1629:
1.1.1.9 root 1630: if (__predict_false((tmp_desc & DESC_V) == 0)) {
1.1.1.12 root 1631: SetFault(FAULT_CODE_PAGE, acc_pdaddr);
1.1 root 1632: putlog(4, " PD $%08x desc=$%08x PageFault", acc_pdaddr, tmp_desc);
1633: return false;
1634: } else {
1635: // Descriptor is valid
1636:
1.1.1.12 root 1637: if (__predict_false((tmp_desc & DESC_SP) && IsUser())) {
1638: SetFault(FAULT_CODE_SUPERVISOR, acc_pdaddr);
1.1 root 1639: putlog(4, " PD $%08x desc=$%08x SupervisorFault",
1640: acc_pdaddr, tmp_desc);
1641: return false;
1642: }
1643:
1644: acc_stat |= tmp_desc & ACC_STAT_MASK;
1645:
1.1.1.9 root 1646: if (__predict_false((acc_stat & DESC_WP) && acc_IsWrite())) {
1.1 root 1647: // fault_addr は invalid data
1.1.1.12 root 1648: SetFault(FAULT_CODE_WRITE, 0xcccccccc);
1.1 root 1649: putlog(4, " PD $%08x desc=$%08x WriteFault", acc_pdaddr, tmp_desc);
1650: return false;
1651: } else {
1652: putlog(4, " PD $%08x stat=%s acc=%s", acc_pdaddr,
1653: stat2str(tmp_desc).c_str(),
1654: stat2str(acc_stat).c_str());
1655: return true;
1656: }
1657: }
1658: }
1659:
1660: // Update Page Descriptor
1661: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
1662: // p2-24, Figure2-8
1663: bool
1664: m88200::UpdatePageDesc()
1665: {
1.1.1.12 root 1666: busdata bd;
1.1 root 1667:
1668: if ((tmp_desc & DESC_M) == 0 && acc_IsWrite()) {
1669: // Update Modified bit and accrue status
1670:
1671: // XXX 図中 PATC[M] をセットするとあるが、ここでは遅い気がする。
1672: // Translate() 中の Update M bit のところのコメントも参照。
1673:
1674: // XXX 図中 ACC_STATUS[M] は TEMP_DESCR[M] じゃないの?
1675: tmp_desc |= DESC_M;
1676: }
1677:
1678: // Update Used bit
1679: tmp_desc |= DESC_U;
1680:
1.1.1.9 root 1681: MBusMakeSnoop(acc_pdaddr, 1);
1.1.1.12 root 1682: bd = MBusWrite(acc_pdaddr, tmp_desc, 4);
1683: if (__predict_false(bd.IsBusErr())) {
1684: SetFault(FAULT_CODE_BUSERR, acc_pdaddr);
1.1 root 1685: return false;
1686: }
1687: putlog(4, " Update PD $%08x desc=$%08x stat=%s",
1688: acc_pdaddr, tmp_desc, stat2str(tmp_desc).c_str());
1689:
1690: return true;
1691: }
1692:
1.1.1.12 root 1693: // 指定の PATC を無効にする。
1.1.1.9 root 1694: void
1.1.1.12 root 1695: m88200::InvalidatePATCEntry(m88200PATC& p)
1.1.1.9 root 1696: {
1.1.1.12 root 1697: uint32 la = addr2hash(p.IsS(), p.lpa);
1.1.1.9 root 1698:
1.1.1.12 root 1699: if (p.IsValid()) {
1700: uint8 n = atc_hash_all[la];
1701: // - BATC (n<0) なら、atc_hash は触らず PATC エントリだけ消す。
1702: // この PATC が作成された後にここに BATC がセットされたとかなので。
1703: // - PATC (n>0) なら (自分のはずなので) atc_hash ごと消す。
1704: if ((int8)n > 0) {
1705: atc_hash_all[la] = 0;
1706: }
1.1.1.9 root 1707: }
1.1.1.12 root 1708: //DumpATC();
1709:
1710: p.lpa |= PATC_INVALID;
1711: #if defined(M88200_STAT)
1712: stat_patc_invalidate++;
1713: #endif
1.1.1.9 root 1714: }
1715:
1.1 root 1716: // Create PATC Entry
1717: // 公式フローチャートと違って MBus Acquire したまま戻ること。
1718: // p2-25, Figure2-9
1719: void
1720: m88200::CreatePATCEntry()
1721: {
1.1.1.9 root 1722: // 空きがあろうがなかろうが、とにかく一番古いエントリを使う。
1723: // おそらく実機も空きエントリを前に詰めるような複雑な処理はして
1724: // ないだろうという推測。
1725:
1726: #if defined(M88200_STAT)
1727: stat_patc_create++;
1728: #endif
1729: m88200PATC& p = patc[patc_next];
1730: // 有効なら無効化
1731: if (p.IsValid()) {
1.1.1.12 root 1732: InvalidatePATCEntry(p);
1.1.1.9 root 1733: }
1734:
1735: // このエントリを潰して作る
1.1 root 1736: memset(&p, 0, sizeof(p));
1737: p.lpa = acc_laddr & 0xfffff000;
1738: p.pfa = tmp_desc & 0xfffff000;
1.1.1.12 root 1739: if (IsSuper()) {
1.1 root 1740: p.lpa |= PATC_S;
1741: }
1742: p.stat = acc_stat;
1743: putlog(4, " %s %c:$%08x:$%08x stat=%s", __func__,
1.1.1.9 root 1744: p.IsS() ? 'S' : 'U', (p.lpa & 0xfffff000), p.pfa,
1.1 root 1745: stat2str(p.stat).c_str());
1.1.1.9 root 1746:
1.1.1.12 root 1747: // ハッシュの値は PATC#0 が 1。
1748: uint32 la = p.lpa >> 12;
1749: atc_hash[la] = patc_next + 1;
1750: //DumpATC();
1.1.1.9 root 1751:
1752: patc_next++;
1753: if (__predict_false(patc_next >= patc.size())) {
1754: patc_next = 0;
1755: }
1.1 root 1756: }
1757:
1758: // アドレス変換 (デバッガ用)
1.1.1.12 root 1759: busaddr
1760: m88200::TranslatePeek(busaddr addr_) const
1.1 root 1761: {
1762: const m88200APR *xapr;
1.1.1.12 root 1763: uint32 laddr = addr_.Addr();
1764: bool issuper = addr_.IsSuper();
1.1 root 1765: uint32 la;
1766:
1767: // Select Area Descriptor
1768: if (issuper) {
1769: xapr = &sapr;
1770: } else {
1771: xapr = &uapr;
1772: }
1773: if (xapr->enable == 0) {
1.1.1.13! root 1774: return busaddr(laddr);
1.1 root 1775: }
1776:
1.1.1.12 root 1777: la = addr2hash(issuper, laddr);
1778: uint8 n = atc_hash_all[la];
1.1 root 1779:
1.1.1.12 root 1780: if (n == 0) {
1781: // FALLTHROUGH
1782: } else if ((int8)n < 0) {
1783: // BATC #(~n) hit
1784: n = ~n;
1785: const m88200BATC& b = batc[n];
1.1.1.13! root 1786: return busaddr(b.pba | (laddr & 0x0007ffff));
1.1.1.12 root 1787: } else {
1788: // BATC #(n-1) hit
1789: n--;
1790: const m88200PATC& p = patc[n];
1.1.1.13! root 1791: return busaddr(p.pfa | (laddr & 0x00000fff));
1.1 root 1792: }
1793:
1794: // ここからテーブルサーチ
1795: uint64 data;
1796: uint32 desc_addr;
1797: uint32 desc;
1798:
1799: // Peek Segment Descriptor
1800: desc_addr = xapr->addr | ((laddr >> 20) & ~3U);
1.1.1.13! root 1801: data = mainbus->Peek4(desc_addr);
1.1 root 1802: if ((int64)data < 0) {
1.1.1.13! root 1803: return BusAddr::BusErr | BusAddr::TableSearched;
1.1 root 1804: }
1805: desc = (uint32)data;
1806: if ((desc & DESC_V) == 0) {
1.1.1.13! root 1807: return BusAddr::BusErr | BusAddr::TableSearched;
1.1 root 1808: }
1809: if ((desc & DESC_SP) && issuper == false) {
1.1.1.13! root 1810: return BusAddr::BusErr | BusAddr::TableSearched;
1.1 root 1811: }
1812:
1813: // Peek Page Descriptor
1814: desc_addr = (desc & 0xfffff000) | ((laddr >> 10) & 0xffc);
1.1.1.13! root 1815: data = mainbus->Peek4(desc_addr);
1.1 root 1816: if ((int64)data < 0) {
1.1.1.13! root 1817: return BusAddr::BusErr | BusAddr::TableSearched;
1.1 root 1818: }
1819: desc = (uint32)data;
1820: if ((desc & DESC_V) == 0) {
1.1.1.13! root 1821: return BusAddr::BusErr | BusAddr::TableSearched;
1.1 root 1822: }
1823: if ((desc & DESC_SP) && issuper == false) {
1.1.1.13! root 1824: return BusAddr::BusErr | BusAddr::TableSearched;
1.1 root 1825: }
1826:
1.1.1.13! root 1827: busaddr r((desc & 0xfffff000) | (laddr & 0x00000fff));
! 1828: r |= BusAddr::TableSearched;
1.1.1.12 root 1829: return r;
1.1 root 1830: }
1831:
1832:
1833: //
1834: // キャッシュ
1835: //
1836:
1837: // このラインの状態を更新
1838: void
1.1.1.13! root 1839: m88200CacheSet::Update(uint line, m88200CacheSet::Status status)
1.1 root 1840: {
1841: vv[line] = status;
1.1.1.9 root 1842: if (__predict_false(status == IV)) {
1.1 root 1843: // 無効なら
1844: tag[line] |= TAG_INVALID;
1845: L = TryUnuseLine(L, line);
1846: }
1847: }
1848:
1849: // CSSP L5-L0 の処理。
1850: // 引数 tmpL の状態から line を最新にしたらどうなるか、を返す。
1851: // 表示処理で一時変数に対して処理が必要なため分離してある。
1.1.1.9 root 1852: /*static*/ int
1.1 root 1853: m88200CacheSet::TryUseLine(int tmpL, int line)
1854: {
1855: // L フィールドは 3bit, 2bit, 1bit で構成され、
1856: // 他のラインの対応ビットを落として、
1857: // 自分のラインの対応ビットを全部立てれば、
1858: // 他のラインの順序を保存した状態で、自分が最新になるように
1859: // 順序をつけられる。
1860:
1861: if (line == 3) {
1862: tmpL |= 0b111'00'0;
1863: } else if (line == 2) {
1864: tmpL &= 0b011'11'1;
1865: tmpL |= 0b000'11'0;
1866: } else if (line == 1) {
1867: tmpL &= 0b101'01'1;
1868: tmpL |= 0b000'00'1;
1869: } else {
1870: tmpL &= 0b110'10'0;
1871: }
1872: return tmpL;
1873: }
1874:
1875: // CSSP L5-L0 の処理。
1876: // 引数 tmpL の状態から line を最古にしたらどうなるか、を返す。
1.1.1.9 root 1877: /*static*/ int
1.1 root 1878: m88200CacheSet::TryUnuseLine(int tmpL, int line)
1879: {
1880: // Use のちょうど反転論理
1881: if (line == 3) {
1882: tmpL &= 0b000'11'1;
1883: } else if (line == 2) {
1884: tmpL |= 0b100'00'0;
1885: tmpL &= 0b111'00'1;
1886: } else if (line == 1) {
1887: tmpL |= 0b010'10'0;
1888: tmpL &= 0b111'11'0;
1889: } else {
1890: tmpL |= 0b001'01'1;
1891: }
1892: return tmpL;
1893: }
1894:
1895: // CSSP L5-L0 の処理。
1896: // 引数 tmpL の状態で、最新の line を返す。
1897: // 表示処理で一時変数に対して処理が必要なため分離してある。
1.1.1.9 root 1898: /*static*/ int
1.1 root 1899: m88200CacheSet::TryGetOldestLine(int tmpL)
1900: {
1901: if (tmpL < 8) {
1902: return 3;
1903: }
1904: tmpL &= 7;
1905: if (tmpL < 2) {
1906: return 2;
1907: }
1908: tmpL &= 1;
1909: if (tmpL == 0) {
1910: return 1;
1911: } else {
1912: return 0;
1913: }
1914: }
1915:
1916: // 更新用に最も古いラインを選んで差し出す
1917: int
1918: m88200CacheSet::SelectOldestLine() const
1919: {
1920: // なければ、最も古いラインを差し出す
1921: return TryGetOldestLine(L);
1922: }
1923:
1924: // キャッシュの指定の line, word に data を書き込む。
1925: // size は 1, 2, 4 バイト。
1926: void
1.1.1.13! root 1927: m88200CacheSet::Write(uint line, uint32 paddr, uint32 data, uint size)
1.1 root 1928: {
1929: uint32 wordidx = (paddr >> 2) & 0x03;
1930: uint32 data32;
1931:
1932: if (__predict_true(size == 4)) {
1933: word[line * 4 + wordidx] = data;
1934: return;
1935: }
1936:
1937: data32 = word[line * 4 + wordidx];
1938: if (size == 2) {
1939: if ((paddr & 2) == 0) {
1940: data32 = (data32 & 0x0000ffff) | (data << 16);
1941: } else {
1942: data32 = (data32 & 0xffff0000) | data;
1943: }
1944: } else {
1945: switch (paddr & 3) {
1946: case 0:
1947: data32 = (data32 & 0x00ffffff) | (data << 24);
1948: break;
1949: case 1:
1950: data32 = (data32 & 0xff00ffff) | (data << 16);
1951: break;
1952: case 2:
1953: data32 = (data32 & 0xffff00ff) | (data << 8);
1954: break;
1955: case 3:
1956: data32 = (data32 & 0xffffff00) | data;
1957: break;
1958: default:
1959: __unreachable();
1960: }
1961: }
1962: word[line * 4 + wordidx] = data32;
1963: }
1964:
1.1.1.3 root 1965: // キャッシュを検索。
1966: // ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。
1967: int
1968: m88200CacheSet::Lookup(uint32 tagaddr) const
1969: {
1970: for (int line = 0; line < 4; line++) {
1971: if (tag[line] == tagaddr) {
1972: return line;
1973: }
1974: }
1975: return -1;
1976: }
1977:
1978:
1979: // キャッシュの指定の set, line にメモリから 1 ライン(4word) 読み込む。
1.1 root 1980: // 成功すれば 0 を返す。
1.1.1.3 root 1981: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1.1 root 1982: uint64
1.1.1.13! root 1983: m88200::ReadLine(m88200CacheSet& set, uint line, uint32 tagaddr)
1.1 root 1984: {
1.1.1.3 root 1985: // タグを更新
1986: set.tag[line] = tagaddr;
1.1 root 1987:
1.1.1.13! root 1988: busaddr addr = busaddr(set.tag[line] | (set.setidx << 4)) | acc_super;
! 1989: busdata r = mainbus->ReadBurst16(addr, &set.word[line * 4]);
! 1990: parent->AddWait(r.GetWait());
! 1991: if (__predict_false(r.IsBusErr())) {
! 1992: SetFault(FAULT_CODE_BUSERR, addr.Addr());
! 1993: return (uint64)-1;
1.1 root 1994: }
1995: return 0;
1996: }
1997:
1.1.1.13! root 1998: // キャッシュの指定の set, line の1ライン(4word) を書き出す (コピーバック)。
1.1.1.3 root 1999: // 成功すれば 0 を返す。
2000: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
2001: uint64
1.1.1.13! root 2002: m88200::CopyBackLine(m88200CacheSet& set, uint line)
1.1 root 2003: {
1.1.1.13! root 2004: busaddr addr = busaddr(set.tag[line] | (set.setidx << 4)) | acc_super;
! 2005: busdata r = mainbus->WriteBurst16(addr, &set.word[line * 4]);
! 2006: parent->AddWait(r.GetWait());
! 2007: if (__predict_false(r.IsBusErr())) {
! 2008: SetFault(FAULT_CODE_BUSERR, addr.Addr());
! 2009: return (uint64)-1;
1.1 root 2010: }
1.1.1.3 root 2011: return 0;
1.1 root 2012: }
2013:
2014: // キャッシュに対して paddr の読み込みを行う。
2015: // paddr は 32bit 境界のアドレスであること。
2016: // 読み込めれば該当の32bitワードを返す。
2017: // 何らかエラーが起きれば (uint64)-1 を返す。エラー要因は fault_code とか参照。
2018: // p.3-8 Figure 3-3
2019: uint64
2020: m88200::CacheRead(uint32 paddr)
2021: {
2022: int line;
2023: uint64 rv;
2024:
2025: assert((paddr & 3) == 0);
2026:
2027: // タグとセット番号
2028: uint32 tagaddr = (paddr & 0xfffff000);
2029: uint32 setidx = (paddr >> 4) & 0xff;
2030: uint32 wordidx = (paddr >> 2) & 0x03;
2031:
2032: m88200CacheSet& set = setarray[setidx];
2033: putlog(3, "CacheRead paddr=$%08x (set=$%02x)", paddr, setidx);
2034:
2035: line = set.Lookup(tagaddr);
1.1.1.9 root 2036: if (__predict_true(line >= 0)) {
1.1 root 2037: // Cache Hit
1.1.1.13! root 2038: putlog(4, " CacheRead hit (line=%u,word=%u)", line, wordidx);
1.1.1.3 root 2039: parent->AddCycle(1);
1.1 root 2040: goto success;
2041: }
2042:
2043: // Cache Miss
2044:
1.1.1.3 root 2045: parent->AddCycle(10); // Table.6-2
2046:
1.1 root 2047: // reply <- Wait
2048: MBusAcquire();
2049:
2050: // Select cache line for replacement
2051: line = set.SelectOldestLine();
1.1.1.13! root 2052: putlog(4, " CacheRead miss (replace line=%u)", line);
1.1 root 2053:
2054: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 2055: parent->AddCycle(7); // Table.6-2
2056: rv = CopyBackLine(set, line);
1.1 root 2057: if ((int64)rv < 0) {
2058: goto error;
2059: }
2060: }
2061:
2062: // Mark cache line invalid
2063: set.Update(line, m88200CacheSet::IV);
2064:
2065: // Read line from memory
1.1.1.9 root 2066: MBusMakeSnoop(paddr, 0);
1.1.1.3 root 2067: rv = ReadLine(set, line, tagaddr);
1.1.1.9 root 2068: if (__predict_false((int64)rv < 0)) {
1.1 root 2069: goto error;
2070: }
2071:
2072: MBusRelease();
2073:
2074: // Update cache line
2075: set.Update(line, m88200CacheSet::SU);
2076:
1.1.1.13! root 2077: putlog(4, " CacheRead updated (line=%u,word=%u)", line, wordidx);
1.1 root 2078: success:
2079: set.Use(line);
2080: return set.word[line * 4 + wordidx];
2081:
2082: error:
2083: MBusRelease();
2084: return (uint64)-1;
2085: }
2086:
2087: // キャッシュに対して paddr への data の書き込みを行う。size は 1, 2, 4 バイト。
2088: // paddr は size に応じた境界にあること。
2089: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
2090: // エラー要因は fault_code とか参照。
2091: // p.3-10 Figure 3-5
2092: uint64
1.1.1.13! root 2093: m88200::CacheWrite(uint32 paddr, uint32 data, uint size)
1.1 root 2094: {
2095: int line;
1.1.1.12 root 2096: busdata bd;
1.1 root 2097: uint64 rv;
2098:
2099: assert((paddr & (size - 1)) == 0);
2100:
2101: // タグとセット番号
2102: uint32 tagaddr = (paddr & 0xfffff000);
2103: uint32 setidx = (paddr >> 4) & 0xff;
2104:
2105: m88200CacheSet& set = setarray[setidx];
2106: putlog(3, "CacheWrite paddr=$%08x (set=$%02x)", paddr, setidx);
2107:
2108: line = set.Lookup(tagaddr);
1.1.1.9 root 2109: if (__predict_true(line >= 0)) {
1.1 root 2110: // Cache Hit
1.1.1.3 root 2111: parent->AddCycle(1);
1.1 root 2112: return CacheWriteHit(set, line, paddr, data, size);
2113: }
2114:
2115: // Cache Miss
2116:
1.1.1.3 root 2117: parent->AddCycle(14); // Table.6-2
2118:
1.1 root 2119: // reply <- Wait
2120: MBusAcquire();
2121:
2122: // Select cache line for replacement
2123: line = set.SelectOldestLine();
1.1.1.13! root 2124: putlog(4, " CacheWrite miss (replace line=%u)", line);
1.1 root 2125:
2126: if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3 root 2127: parent->AddCycle(7); // Table.6-2
2128: rv = CopyBackLine(set, line);
1.1 root 2129: if ((int64)rv < 0) {
2130: goto error;
2131: }
2132: }
2133:
2134: // Mark line invalid
2135: set.Update(line, m88200CacheSet::IV);
2136:
2137: // Read line with intent to modify
1.1.1.9 root 2138: MBusMakeSnoop(paddr, 1);
1.1.1.3 root 2139: rv = ReadLine(set, line, tagaddr);
1.1 root 2140: if ((int64)rv < 0) {
2141: goto error;
2142: }
2143:
2144: // Write data to memory
1.1.1.12 root 2145: bd = MBusWrite(paddr, data, size);
2146: if (__predict_false(bd.IsBusErr())) {
2147: SetFault(FAULT_CODE_BUSERR, paddr);
1.1.1.3 root 2148: goto error;
1.1 root 2149: }
2150:
2151: // Write data into cache
2152: set.Write(line, paddr, data, size);
2153:
2154: // Mark line exclusive unmodified
1.1.1.11 root 2155: // p3-9 3.4.2.2 CACHE WRITE:CACHE HIT. の本文に writethrough のときは
2156: // It marks the line as shared unmodified... と書いてある。
2157: // Fig 3-5 には記載はないが、キャッシュエントリが作られるときも
2158: // Fig 3-6 のキャッシュヒット時と同じように SU にならないと矛盾する。
2159: if ((acc_stat & DESC_WT)) {
2160: set.Update(line, m88200CacheSet::SU);
2161: } else {
2162: set.Update(line, m88200CacheSet::EU);
2163: }
1.1 root 2164: set.Use(line);
2165:
2166: MBusRelease();
2167: return 0;
2168:
2169: error:
2170: MBusRelease();
2171: return (uint64)-1;
2172: }
2173:
2174: // キャッシュがヒットした場合。
2175: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
2176: // p3-11 Figure 3-6
2177: uint64
1.1.1.13! root 2178: m88200::CacheWriteHit(m88200CacheSet& set, uint line,
! 2179: uint32 paddr, uint32 data, uint size)
1.1 root 2180: {
1.1.1.9 root 2181: if (__predict_false(set.vv[line] == m88200CacheSet::SU)) {
1.1 root 2182: // Line Shared Unmodified の場合
2183:
1.1.1.13! root 2184: putlog(4, " CacheWrite hit shared unmodified (line=%u)", line);
1.1 root 2185:
2186: // WriteThrough と Global は最後の状態変化だけが違う
2187: if ((acc_stat & (DESC_WT | DESC_G))) {
2188: // reply = Wait;
2189: MBusAcquire();
2190:
2191: // Write data to cache
2192: set.Write(line, paddr, data, size);
2193:
2194: // Write data to memory
1.1.1.9 root 2195: MBusMakeSnoop(paddr, 1);
1.1.1.12 root 2196: busdata bd = MBusWrite(paddr, data, size);
2197: if (__predict_false(bd.IsBusErr())) {
1.1 root 2198: MBusRelease();
1.1.1.12 root 2199: SetFault(FAULT_CODE_BUSERR, paddr);
2200: return (uint64)-1;
1.1 root 2201: }
2202:
2203: if ((acc_stat & DESC_WT)) {
2204: // Mark line shared unmodified
2205: set.Update(line, m88200CacheSet::SU);
2206: } else {
2207: // Mark line exclusive unmodified
2208: set.Update(line, m88200CacheSet::EU);
2209: }
2210: set.Use(line);
2211:
2212: MBusRelease();
2213: return 0;
2214: }
2215:
2216: // どちらでもない場合は Line Exclusive と同じ処理に落ちる
1.1.1.9 root 2217: } else {
2218: // Line Exclusive の場合
1.1.1.13! root 2219: putlog(4, " CacheWrite hit exclusive (line=%u)", line);
1.1 root 2220: }
2221:
2222: // Write data into cache
1.1.1.13! root 2223: putlog(4, " CacheWrite line=%u $%08x sz=%u", line, paddr, size);
1.1 root 2224: set.Write(line, paddr, data, size);
2225:
2226: // Mark line exclusive modified
2227: set.Update(line, m88200CacheSet::EM);
2228: set.Use(line);
2229: return 0;
2230: }
2231:
2232: // paddr への xmem を行う。size は 1, 2, 4 バイト。
2233: // 成功すれば読み出した値、エラーが起きれば (uint64)-1 を返す。
2234: // p3-13, Figure3-7
2235: uint64
1.1.1.13! root 2236: m88200::CacheXmem(uint32 paddr, uint32 data, uint size)
1.1 root 2237: {
2238: int line;
1.1.1.12 root 2239: busdata bd;
1.1 root 2240: uint64 rv;
2241:
2242: assert((paddr & (size - 1)) == 0);
2243:
2244: // タグとセット番号
2245: uint32 tagaddr = (paddr & 0xfffff000);
2246: uint32 setidx = (paddr >> 4) & 0xff;
2247:
2248: m88200CacheSet& set = setarray[setidx];
2249: putlog(3, "CacheXmem paddr=$%08x (set=$%02x)", paddr, setidx);
2250:
2251: line = set.Lookup(tagaddr);
1.1.1.9 root 2252: if (__predict_false(line >= 0 && set.vv[line] == m88200CacheSet::EM)) {
1.1 root 2253: // Cache Hit (and Line exclusive modified)
1.1.1.13! root 2254: putlog(4, " CacheXmem hit and EM (line=%u)", line);
1.1 root 2255:
2256: MBusAcquire();
2257:
1.1.1.3 root 2258: parent->AddCycle(7); // Table.6-2
1.1.1.9 root 2259: MBusMakeSnoop(paddr, 1);
1.1.1.3 root 2260: rv = CopyBackLine(set, line);
1.1.1.9 root 2261: if (__predict_false((int64)rv < 0)) {
1.1 root 2262: goto error;
2263: }
2264:
2265: set.Update(line, m88200CacheSet::IV);
2266: } else {
2267: // Cache Miss or (Cache Hit but other than exclusive modified)
2268:
2269: if (line >= 0) {
2270: // Cache Hit and Otherwise (= !EM)
1.1.1.13! root 2271: putlog(4, " CacheXmem hit but !EM (line=%u)", line);
1.1 root 2272: set.Update(line, m88200CacheSet::IV);
2273: } else {
2274: putlog(4, " CacheXmem miss");
2275: }
2276:
2277: MBusAcquire();
2278: }
2279:
1.1.1.9 root 2280: MBusMakeSnoop(paddr, 1);
1.1.1.12 root 2281: bd = MBusXmem(paddr, data, size);
1.1 root 2282: MBusRelease();
1.1.1.12 root 2283: if (__predict_false(bd.IsBusErr())) {
2284: SetFault(FAULT_CODE_BUSERR, paddr);
2285: return (uint64)-1;
2286: }
2287: return bd.Data();
1.1 root 2288:
2289: error:
2290: MBusRelease();
2291: return rv;
2292: }
1.1.1.3 root 2293:
2294: // MBus 使用権を取得する
2295: void
2296: m88200::MBusAcquire()
2297: {
2298: // アービトレーションのたびに1クロックかかる(?)
2299: // よく分からんけど、とりあえず、CMMU は一度所有権を持ったら放さない、
2300: // 別の CMMU がバスリクエストすると所有権はその CMMU に移る、とする。
1.1.1.9 root 2301: if (__predict_false(mbus_master != this)) {
1.1.1.3 root 2302: mbus_master = this;
2303: parent->AddCycle(1);
2304: }
2305: }
1.1.1.9 root 2306:
2307: // 他 CMMU にバススヌープさせるポイント。
2308: // 本来はバスマスタ CMMU が MBus にアドレスと IM を出すと、それを監視して
2309: // いる他 CMMU が必要に応じて反応するのだが、ここでは全部マスタ主導で行う。
2310: // Figure 3-8, 3-9
2311: void
1.1.1.13! root 2312: m88200::MBusMakeSnoop(uint32 paddr, uint im)
1.1.1.9 root 2313: {
2314: if ((acc_stat & DESC_G) == 0) {
2315: return;
2316: }
2317:
2318: // MBus Status <- Wait (2 clocks)
2319: // 本来はスヌープをするスレーブ側が 2 クロックかかるのだが、
2320: // 個別の CMMU がクロックを持っていない実装なのでマスタ側で
2321: // クロックを消費したことにする。
2322: parent->AddCycle(2);
2323:
2324: // 本来はここで解放ではなく、スレーブ側が反応したい時にバスリクエストを
2325: // 出してそれによって手放すのだが、その機構はないので、こちらが自主的に
2326: // 一旦手放したようにしておく。とは言っても現状 MBusRelease() はダミーで
2327: // 実際には他の誰かが MBusAcquire() を呼ぶまで握りっぱなしなので、
2328: // あまり問題ないはず。
2329: MBusRelease();
2330: for (const auto other : other_cmmu) {
2331: other->Snoop(paddr, im);
2332: }
2333: MBusAcquire();
2334: }
2335:
2336: // バススヌープ (スレーブ側)。
2337: // 本来はバスマスタでない CMMU は、バスマスタが MBus に出すアドレス情報を
2338: // 監視し、必要ならそれに反応するのだが、ここでは全部マスタ主導で行う。
2339: // こっちはそのマスタから呼ばれるスレーブ側。
2340: // Figure 3-8, 3-9
2341: void
1.1.1.13! root 2342: m88200::Snoop(uint32 paddr, uint im)
1.1.1.9 root 2343: {
2344: assert((sctr & SCTR_SE));
2345:
2346: uint32 tagaddr = (paddr & 0xfffff000);
2347: uint32 setidx = (paddr >> 4) & 0xff;
2348:
2349: m88200CacheSet& set = setarray[setidx];
2350: int line = set.Lookup(tagaddr);
2351:
2352: if (line >= 0) {
2353: // Cache hit
2354: if (set.vv[line] == m88200CacheSet::EM) {
2355: // Line exclusive modified
2356:
2357: // Assert retry
2358:
2359: // Request MBus
2360: // 実際にはここで MBus 使用権を要求して獲得するのだが
2361: // その機構はなくその代わり Acquire を呼ぶだけでいける。
2362: MBusAcquire();
2363: uint64 rv = CopyBackLine(set, line);
2364: MBusRelease();
2365: if ((int64)rv < 0) {
2366: // Set CE bit in system status register
2367: return;
2368: }
2369:
2370: if (im == 0) {
2371: // Mark line shared unmodified (if IM=0)
2372: set.Update(line, m88200CacheSet::SU);
2373: } else {
2374: // Mark line invalid (if IM=1)
2375: set.Update(line, m88200CacheSet::IV);
2376: }
2377: }
2378: }
2379: // Resume servicing PBus
2380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.