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