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