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