|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
1.1.1.3 root 6:
1.1.1.4 root 7: #include "mpu680x0.h"
1.1.1.6 root 8: #include "mainbus.h"
9: #include "m68030cache.h"
1.1 root 10:
1.1.1.5 root 11: // 現在の FC での通常アクセス (MPU 内部から使用する)
12: // ミスアライン可。
13: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.6 root 14: // uint32 fetch_{2,4}()
15: // uint32 read_{1,2,4}(laddr) .. vm/mpu680x0.h にある
16: // void write_{1,2,4}(laddr, data) .. vm/mpu680x0.h にある
1.1 root 17:
1.1.1.5 root 18: // reg.pc からワードをフェッチし reg.pc を進める。
19: uint32
1.1.1.7 root 20: MPU68030Device::fetch_2()
1.1 root 21: {
1.1.1.6 root 22: busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size2;
1.1.1.5 root 23:
1.1.1.6 root 24: // まず可能ならキャッシュから探す。
25: m68030Cache *cache = icache.get();
26: if (__predict_true(cache->enable)) {
1.1.1.10! root 27: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 28: uint32 idx = (addr.Addr() >> 4) & 0x0000000f;
! 29: uint32 sel = (addr.Addr() >> 2) & 0x00000003;
1.1.1.6 root 30: m68030CacheLine *l = &cache->line[idx];
31:
32: if (__predict_true(l->tag == tag && l->valid[sel])) {
33: cache->stat_fasthit++;
34: uint32 data = l->data[sel];
35: if ((reg.pc & 2) == 0) {
36: data >>= 16;
37: } else {
38: data &= 0xffff;
39: }
40: reg.pc += 2;
41: return data;
42: }
43: }
44:
45: busdata bd;
46: if (__predict_true(cache->enable)) {
47: bd = read_cache(cache, addr);
1.1 root 48: } else {
1.1.1.6 root 49: bd = read_nocache(addr);
50: }
51: if (__predict_false(bd.IsBusErr())) {
52: throw M68K::EXCEP_BUSERR;
1.1 root 53: }
1.1.1.5 root 54: reg.pc += 2;
1.1.1.6 root 55: return bd.Data();
1.1 root 56: }
57:
1.1.1.5 root 58: // reg.pc からロングワード(ミスアライン可)をフェッチし reg.pc を進める。
59: uint32
1.1.1.7 root 60: MPU68030Device::fetch_4()
1.1 root 61: {
1.1.1.6 root 62: busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size4;
1.1.1.5 root 63:
1.1.1.6 root 64: // まず可能ならキャッシュから探す。
65: m68030Cache *cache = icache.get();
66: if (__predict_true(cache->enable)) {
1.1.1.10! root 67: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 68: uint32 idx = (addr.Addr() >> 4) & 0x0000000f;
! 69: uint32 sel = (addr.Addr() >> 2) & 0x00000003;
1.1.1.6 root 70: m68030CacheLine *l = &cache->line[idx];
71:
72: if (__predict_true(l->tag == tag && l->valid[sel])) {
73: uint32 data;
74: if ((reg.pc & 2) == 0) {
75: cache->stat_fasthit++;
76: data = l->data[sel];
77: } else {
78: // 次のエントリにまたがる場合。
79: if (sel < 3 && l->valid[sel + 1]) {
80: cache->stat_fasthit += 2;
81: data = l->data[sel] << 16;
82: data |= l->data[sel + 1] >> 16;
83: } else {
84: // 片方でキャッシュミスした。
85: // この場合は fast* はカウントしない。
86: goto fetch;
87: }
88: }
89: reg.pc += 4;
90: return data;
1.1.1.5 root 91: }
1.1 root 92: }
93:
1.1.1.6 root 94: fetch:
95: busdata bd;
96: if (__predict_true(cache->enable)) {
97: bd = read_cache(cache, addr);
98: } else {
99: bd = read_nocache(addr);
100: }
101: if (__predict_false(bd.IsBusErr())) {
102: throw M68K::EXCEP_BUSERR;
103: }
104: reg.pc += 4;
105: return bd.Data();
1.1 root 106: }
107:
1.1.1.6 root 108: // read_1,2,4() の共通部分。ミスアライン可。
109: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.5 root 110: uint32
1.1.1.7 root 111: MPU68030Device::read_data(busaddr addr)
1.1 root 112: {
1.1.1.6 root 113: m68030Cache *cache = dcache.get();
114: busdata data;
115: if (__predict_true(cache->enable)) {
116: data = read_cache(cache, addr);
117: } else {
118: data = read_nocache(addr);
119: }
120: if (__predict_false(data.IsBusErr())) {
121: throw M68K::EXCEP_BUSERR;
122: }
123: return data.Data();
1.1 root 124: }
125:
1.1.1.6 root 126: // write_1,2,4() の共通部分。ミスアライン可。
1.1.1.5 root 127: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.6 root 128: void
1.1.1.7 root 129: MPU68030Device::write_data(busaddr addr, uint32 data)
1.1 root 130: {
1.1.1.6 root 131: busdata r = write_bus(addr, data);
132: if (__predict_false(r.IsBusErr())) {
133: throw M68K::EXCEP_BUSERR;
1.1.1.5 root 134: }
1.1 root 135: }
136:
1.1.1.6 root 137: // キャッシュ無効時の読み込み。ミスアライン可。
138: // バスエラーも busdata を返す。
139: busdata
1.1.1.7 root 140: MPU68030Device::read_nocache(busaddr addr)
1.1.1.6 root 141: {
142: // デバイスは、addr の下位ビットによらず、自身のデバイスのポートサイズ分
143: // のデータと、その応答サイズ(自分のポートサイズ) を Size フィールドに
144: // セットして返してくる。
145: //
146: // MPU(68030) は、A1-A0、残りバイト数、デバイスの応答サイズの情報から
147: // 受け取ったデータバスのうち適切なところを切り出して使う。
148:
1.1.1.10! root 149: putlog(3, "read_nocache %u.%08x sz=%c",
! 150: addr.GetFC(), addr.Addr(), "0BW3L"[addr.GetSize()]);
! 151:
1.1.1.6 root 152: uint32 data = 0;
153: for (;;) {
154: bus.laddr = addr;
1.1.1.10! root 155: busaddr paddr = TranslateRead(addr);
! 156: if (__predict_false(paddr.IsBusErr())) {
1.1.1.6 root 157: return BusData::BusErr;
158: }
1.1.1.10! root 159: bus.ci = paddr.IsCInhibit();
! 160:
! 161: busdata bd = read_phys(paddr);
1.1.1.6 root 162: if (__predict_false(bd.IsBusErr())) {
163: return bd;
164: }
1.1.1.5 root 165:
1.1.1.6 root 166: uint32 reqsize = addr.GetSize();
167: // デバイスのポートサイズ(応答サイズ)
168: uint32 portsize = bd.GetSize();
169: // 今回のアドレスオフセット
170: uint32 offset = addr.Addr() & (portsize - 1);
171: uint32 datasize = portsize - offset;
172: uint32 tmp = bd.Data();
173: // 下詰めされたデータに対するマスク
174: uint32 mask = 0xffffffffU >> ((4 - datasize) * 8);
175: // 今回必要なところ
176: tmp &= mask;
177: if (datasize == reqsize) {
178: data |= tmp;
179: break;
180: } else if (datasize > reqsize) {
181: tmp >>= (datasize - reqsize) * 8;
182: data |= tmp;
183: break;
1.1.1.5 root 184: } else {
1.1.1.6 root 185: tmp <<= (reqsize - datasize) * 8;
186: data |= tmp;
1.1.1.5 root 187: }
188:
1.1.1.6 root 189: addr += datasize;
190: reqsize -= datasize;
191: addr.ChangeSize(reqsize);
192: }
1.1.1.5 root 193: return data;
1.1 root 194: }
195:
1.1.1.6 root 196: // キャッシュ有効時の読み込み。ミスアライン可。
197: // バスエラーも busdata を返す。
1.1.1.10! root 198: //
! 199: // 簡略化・高速化のため実機と異なる制約を設けてある。
! 200: // 1) 実際の 68030 システムでは、「ロングワードの全バイトがキャッシュ可能なら
! 201: // !CIIN をネゲートしなければならない」「いずれかのバイトでもキャッシュ可能
! 202: // でないなら CIIN をアサートしなければならない」(MC68030UM.pdf p6-15、
! 203: // 日本語本 p296 ※誤訳あり) とあり、CIIN は同一ロングワード内で変化しては
! 204: // いけないが、ロングワードごとには変化してよい。
! 205: // nono の実装ではこれを同一ライン(16バイト)単位の制約にする。
! 206: // 現状サポートしている機種ではこれで困ることはない。
1.1.1.6 root 207: busdata
1.1.1.7 root 208: MPU68030Device::read_cache(m68030Cache *cache, busaddr addr)
1.1.1.6 root 209: {
1.1.1.10! root 210: putlog(3, "read_cache %u.%08x sz=%c",
1.1.1.6 root 211: addr.GetFC(), addr.Addr(), "0BW3L"[addr.GetSize()]);
212:
213: uint32 data = 0;
214: for (;;) {
215: uint32 entry_data = 0;
216:
217: // まず可能ならキャッシュから探す。
1.1.1.10! root 218: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 219: uint32 idx = (addr.Addr() >> 4) & 0x0000000f;
! 220: uint32 sel = (addr.Addr() >> 2) & 0x00000003;
1.1.1.6 root 221: m68030CacheLine *l = &cache->line[idx];
222: if (__predict_true(l->tag == tag && l->valid[sel])) {
1.1.1.10! root 223: // タグが一致してエントリも有効 (キャッシュヒット)。
1.1.1.6 root 224: cache->stat_hit++;
225: entry_data = l->data[sel];
1.1.1.10! root 226: putlog(3, " entry_data=$%08x (%s)", entry_data, "match");
1.1.1.6 root 227: } else {
1.1.1.10! root 228: // タグが違うか、エントリが無効。
1.1.1.6 root 229: cache->stat_miss++;
230:
231: bus.laddr = addr;
1.1.1.10! root 232: busaddr paddr = TranslateRead(addr);
! 233: if (__predict_false(paddr.IsBusErr())) {
! 234: putlog(3, " TranslateRead BusErr");
1.1.1.6 root 235: return BusData::BusErr;
236: }
1.1.1.10! root 237: bus.ci = paddr.IsCInhibit();
! 238: putlog(3, " paddr=$%08x.%c",
! 239: paddr.Addr(), "0BW3L"[paddr.GetSize()]);
! 240:
! 241: // タグが違うか、全エントリが無効ならライン充填する。
! 242: // ただし要求がラインをまたぐ場合 (例えば +$e からのロングワード
! 243: // 要求) は除く。
! 244: bool is_linefill = (l->tag != tag || l->valid_all == 0) &&
! 245: ((addr.Addr() & 0xf) + addr.GetSize() <= 0x10);
! 246:
! 247: // 可能ならバーストリードを使う。
! 248: if (is_linefill &&
! 249: __predict_true(bus.ci == false) &&
! 250: __predict_true(cache->burst_enable) &&
! 251: __predict_true(read_phys_burst(paddr, &l->data[0])))
! 252: {
! 253: // read_phys_burst() はライン充填したら true を返している。
! 254: entry_data = l->data[sel];
! 255: putlog(3, " entry_data=$%08x (%s)", entry_data, "burst");
! 256: l->tag = tag;
! 257: l->valid_all = -1;
1.1.1.6 root 258: } else {
1.1.1.10! root 259: // シングル充填。
! 260: busdata bd = read_single(paddr);
1.1.1.6 root 261: if (__predict_false(bd.IsBusErr())) {
262: return bd;
263: }
1.1.1.10! root 264: entry_data = bd.Data();
! 265: putlog(3, " entry_data=$%08x (%s)", entry_data, "single");
! 266:
! 267: if (__predict_false(bus.ci) || __predict_false(cache->freeze)) {
! 268: // エントリを更新しない。
! 269: } else {
! 270: l->data[sel] = entry_data;
! 271: if (l->tag != tag) {
! 272: // タグを更新して、このラインの他のエントリは無効。
! 273: l->tag = tag;
! 274: l->valid_all = 0;
1.1.1.6 root 275: }
1.1.1.10! root 276: l->valid[sel] = 1;
1.1.1.6 root 277: }
278: }
279: }
1.1.1.5 root 280:
1.1.1.10! root 281: // addr から今回対象とするロングワードエントリに対するマスクを作成。
! 282: uint32 reqoffset = addr.Addr() & 3;
! 283: uint32 reqsize = addr.GetSize();
! 284: uint32 opersize = std::min(reqsize, 4 - reqoffset);
! 285:
1.1.1.6 root 286: data <<= opersize * 8;
287: // このエントリから必要な部分を抜き出す。
288: uint32 mask = 0xffffffffU >> ((4 - opersize) * 8);
289: if (reqsize == opersize) {
290: // 要求サイズがこのエントリをはみ出していない。
291: entry_data >>= (4 - reqoffset - opersize) * 8;
292: data |= entry_data & mask;
1.1.1.10! root 293: putlog(3, " data=$%0*x (done)", opersize * 2, data);
1.1.1.6 root 294: break;
1.1.1.5 root 295: } else {
1.1.1.6 root 296: data |= entry_data & mask;
1.1.1.10! root 297: putlog(3, " data=$%0*x", opersize * 2, data);
1.1.1.5 root 298: }
1.1.1.6 root 299: addr += opersize;
300: addr.ChangeSize(reqsize - opersize);
1.1.1.5 root 301: }
302:
303: return data;
1.1 root 304: }
305:
1.1.1.10! root 306: // シングル充填を行い、(CI でなければ) 完全なロングワードを返す。
! 307: // CI なら第1サイクルだけを行い、ロングワードの所定の位置においたものを返す。
! 308: // バスエラーなら BusErr を返す。
1.1.1.6 root 309: busdata
1.1.1.10! root 310: MPU68030Device::read_single(busaddr paddr)
1.1.1.6 root 311: {
1.1.1.10! root 312: // 一発目。
! 313: busdata bd = read_phys(paddr);
! 314: if (__predict_true(bd.IsOK()) && bd.GetSize() != 4) {
! 315: // 必要なら残りのサイクル。
! 316: bd = fill_single(paddr, bd);
1.1.1.5 root 317: }
1.1.1.10! root 318: // いずれにしても bd を返す。
! 319: return bd;
1.1 root 320: }
321:
1.1.1.10! root 322: // シングル充填の第2サイクル以降を行って、(CI でなければ) 完全なロングワードを
! 323: // 返す。
! 324: // 引数 paddr に第1サイクルの物理アドレス (インクリメントなどする前)。
! 325: // 引数 bd は第1サイクルの結果の busdata。
1.1.1.6 root 326: //
1.1.1.10! root 327: // 第1サイクルがバスエラーになっていれば事前に弾いておくこと。
! 328: // 第1サイクルでロングワード全部埋まったケースも事前に弾いておくこと。
1.1.1.6 root 329: busdata
1.1.1.10! root 330: MPU68030Device::fill_single(busaddr paddr, busdata bd)
1.1.1.6 root 331: {
1.1.1.10! root 332: busaddr addr_h(paddr.Get() & ~0x3ULL);
! 333: uint32 data;
1.1.1.6 root 334:
1.1.1.10! root 335: //assert(bd.IsOK());
! 336: //assert(bd.GetSize() < 4);
1.1.1.6 root 337:
1.1.1.10! root 338: if (bd.GetSize() == 2) {
! 339: // ワードポートアクセスだったなら、第1アクセスが上位か下位かだけ。
! 340: if ((paddr.Addr() & 2) == 0) {
! 341: data = bd.Data() << 16;
1.1.1.6 root 342: } else {
1.1.1.10! root 343: data = bd.Data();
1.1.1.6 root 344: }
1.1.1.10! root 345: if (__predict_false(bus.ci)) {
! 346: goto done;
1.1.1.6 root 347: }
1.1.1.10! root 348: // 次のアクセスはワード境界にアラインされるので
! 349: // 0x3 じゃなく0x2 でマスク。
! 350: uint32 offset = (paddr.Addr() + 2) & 0x2;
! 351: paddr = addr_h | offset;
! 352:
! 353: bd = read_phys(paddr);
! 354: // CI はもう起きないはず。バスエラーは?
! 355: if (offset == 0) {
! 356: data |= bd.Data() << 16;
! 357: } else {
! 358: data |= bd.Data();
! 359: }
! 360: } else {
! 361: // バイトポートアクセスの場合。
1.1.1.5 root 362:
1.1.1.10! root 363: // 第1サイクルのデータを所定のバイト位置に。
! 364: uint32 offset = paddr.Addr() & 0x3;
! 365: data = bd.Data() << ((3 - offset) * 8);
! 366: if (__predict_false(bus.ci)) {
! 367: goto done;
! 368: }
! 369: for (uint i = 1; i < 4; i++) {
! 370: // インクリメント。
! 371: offset = (offset + 1) & 0x3;
! 372: paddr = addr_h | offset;
1.1.1.6 root 373:
1.1.1.10! root 374: bd = read_phys(paddr);
! 375: // CI はもう起きないはず。バスエラーは?
! 376: data |= bd.Data() << ((3 - offset) * 8);
1.1.1.6 root 377: }
378: }
1.1.1.5 root 379:
1.1.1.10! root 380: done:
1.1.1.6 root 381: return data;
1.1 root 382: }
383:
1.1.1.6 root 384: // キャッシュ/バスへの書き込み。ミスアライン可。
385: // バスエラーも busdata を返す。
386: busdata
1.1.1.7 root 387: MPU68030Device::write_bus(busaddr addr, uint32 data)
1.1.1.6 root 388: {
389: m68030Cache *cache = dcache.get();
390:
1.1.1.10! root 391: putlog(3, "write_bus %u.%08x sz=%c data=$%0*x",
! 392: addr.GetFC(), addr.Addr(), "0BW3L"[addr.GetSize()],
! 393: addr.GetSize() * 2, data);
1.1.1.6 root 394: for (;;) {
395: uint32 nextdata;
396: uint32 reqoffset = addr.Addr() & 3;
397: uint32 reqsize = addr.GetSize();
398:
399: // ロングワード境界をはみ出す場合は持ち越し分を覚えておく。
400: int nextsize = reqoffset + reqsize - 4;
401: if (nextsize > 0) {
402: // 後ろにはみ出すケース。
403: nextdata = data & ((1U << (nextsize * 8)) - 1);
404: data >>= nextsize * 8;
405: reqsize -= nextsize;
406: addr.ChangeSize(reqsize);
407: } else {
408: nextsize = 0;
409: }
1.1.1.5 root 410:
1.1.1.6 root 411: // まず外部バスを駆動して CI を得る。
412: // バスエラーなら記録だけしておく。キャッシュへは書き込むため。
413: busdata bd = BusData::BusErr;
414: bus.laddr = addr;
1.1.1.10! root 415: busaddr paddr = TranslateWrite(addr);
! 416: bus.ci = paddr.IsCInhibit();
! 417: if (__predict_true(paddr.IsOK())) {
1.1.1.6 root 418: uint32 outdata = data;
419: for (;;) {
1.1.1.10! root 420: bd = write_phys(paddr, outdata);
1.1.1.6 root 421: if (__predict_false(bd.IsBusErr())) {
1.1.1.10! root 422: putlog(3, " write_phys -> BusErr");
1.1.1.6 root 423: break;
424: }
1.1.1.10! root 425: uint32 breqsize = paddr.GetSize();
! 426: putlog(3, " write_phys $%08x data=$%0*x",
! 427: paddr.Addr(), breqsize * 2, outdata);
1.1.1.6 root 428: uint32 portsize = bd.GetSize();
1.1.1.10! root 429: uint32 offset = paddr.Addr() & (portsize - 1);
1.1.1.6 root 430: uint32 datasize = portsize - offset;
431: if (datasize >= breqsize) {
432: break;
433: }
1.1.1.10! root 434: // 同一ロングワード内なので paddr の更新だけでいい。
! 435: paddr += datasize;
1.1.1.6 root 436: breqsize -= datasize;
1.1.1.10! root 437: paddr.ChangeSize(breqsize);
1.1.1.6 root 438: // データは下詰めで、不要な上位ビットはクリアする仕様。
439: outdata &= (1U << (breqsize * 8)) - 1;
440: }
441: }
1.1.1.5 root 442:
1.1.1.6 root 443: bool cache_writable = (cache->enable && bus.ci == false);
444: if (cache_writable) {
445: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
446: uint32 idx = (addr.Addr() & 0x000000f0) >> 4;
447: uint32 sel = (addr.Addr() & 0x0000000c) >> 2;
448: auto *l = &cache->line[idx];
449:
450: // Hit Frz WA Tag LA
451: // 1 0 - - - : UpdateEntry
452: // 1 1 - - - : UpdateEntry (ex1, ex2のb8-b9
453: // 0 1 - - - : Nop
454: // 0 0 0 - - : Nop
455: // 0 0 1 1 1 : (ex3
456: // 0 0 1 1 0 : Nop (ex2のb6-b7
457: // 0 0 1 0 1 : (ex4
458: // 0 0 1 0 0 : (ex5
459: bool tag_match = (l->tag == tag);
460: bool cache_hit = (tag_match && l->valid[sel]);
461: if (cache_hit) {
462: // エントリの更新。
463: // reqsize はロングワード境界を超えないよう調整済み。
464: // data は下詰め(上はクリア)なので、所定の位置まで左シフト。
465: // 整列ロングワードもここに来ることに注意。
466: // Fig.6-4 の ex1, ex2のb8-b9
467: int lshift = (4 - reqoffset - reqsize) * 8;
468: uint32 mask = (0xffffffffU >> ((4 - reqsize) * 8)) << lshift;
469: l->data[sel] = (data << lshift) | (l->data[sel] & ~mask);
470: } else if (cache->freeze == false && cache->wa) {
471: bool long_aligned = (reqoffset == 0 && reqsize == 4);
472: // Fig.6-4
473: if (tag_match) {
474: if (long_aligned) {
475: // ex3
476: l->valid[sel] = 1;
477: l->data[sel] = data;
478: } else {
479: // ex2 の b6-b7
480: // nop
481: }
482: } else {
483: if (long_aligned) {
484: // ex4
485: l->tag = tag;
486: l->valid_all = 0;
487: l->valid[sel] = 1;
488: l->data[sel] = data;
489: } else {
490: // ex5
491: l->valid[sel] = 0;
492: }
493: }
494: }
495: }
1.1 root 496:
1.1.1.6 root 497: // バスアクセスでバスエラーが出たらキャッシュ更新後に発報。
498: if (__predict_false(bd.IsBusErr())) {
499: return bd;
500: }
1.1.1.5 root 501:
1.1.1.6 root 502: // ロングワード境界をまたいだ余りがあればもう一回。
503: if (nextsize == 0) {
504: break;
505: }
1.1.1.10! root 506: putlog(3, " nextsize=%u", nextsize);
1.1.1.6 root 507: addr += addr.GetSize();
508: addr.ChangeSize(nextsize);
509: data = nextdata;
510: }
1.1.1.5 root 511:
1.1.1.6 root 512: return 0;
1.1 root 513: }
514:
1.1.1.10! root 515: // mainbus の paddr から指定サイズで1回読み込む。
1.1.1.6 root 516: // ウェイトはこちらで加算して、バスエラーも含めた bd を返す。
517: busdata
1.1.1.10! root 518: MPU680x0Device::read_phys(const busaddr paddr)
1.1 root 519: {
1.1.1.6 root 520: busdata bd = mainbus->Read(paddr);
521: buswait += bd.GetWait();
522: return bd;
1.1 root 523: }
524:
1.1.1.10! root 525: // mainbus の paddr に指定サイズで1回書き込む。
1.1.1.6 root 526: // ウェイトはこちらで加算して、バスエラーも含めた bd を返す。
527: busdata
1.1.1.10! root 528: MPU680x0Device::write_phys(const busaddr paddr, uint32 data)
1.1 root 529: {
1.1.1.6 root 530: busdata bd = mainbus->Write(paddr, data);
531: buswait += bd.GetWait();
532: return bd;
1.1 root 533: }
534:
1.1.1.6 root 535: // バースト転送。
1.1.1.10! root 536: // paddr の下位4ビットは無視する。
! 537: // paddr がバースト転送可能なら dst に 16 バイト転送して true を返す。
! 538: // paddr がバースト転送不可なら dst は触らず false を返す。
1.1.1.6 root 539: // VM (バス) がバースト転送対応している場合のみ呼ぶこと。
540: bool
1.1.1.10! root 541: MPU680x0Device::read_phys_burst(busaddr paddr, uint32 *dst)
1.1.1.6 root 542: {
543: paddr &= 0xfffffff0U;
544: busdata bd = mainbus->ReadBurst16(paddr, dst);
545: buswait += bd.GetWait();
1.1.1.5 root 546:
1.1.1.6 root 547: // BusErr ビットをバースト転送不可フラグとして使っている。
548: return !bd.IsBusErr();
1.1 root 549: }
550:
1.1.1.7 root 551: // 物理メモリからのロングワード読み込み。
552: // 現在の bus に影響を与えず指定のアドレスを読み出す。MMU 専用。
553: busdata
554: MPU680x0Device::read_phys_4(uint32 addr)
555: {
556: m68kbus backup;
557: busdata bd;
558:
559: // バス情報を一旦退避
560: backup = bus;
561:
562: // 物理バスアクセス
563: bus.laddr = busaddr(addr) | BusAddr::SRead | BusAddr::Size4;
1.1.1.10! root 564: bd = read_phys(bus.laddr);
1.1.1.7 root 565: if (__predict_false(bd.IsBusErr())) {
566: return bd;
567: }
568:
569: // バス情報を復元
570: bus = backup;
571: return bd;
572: }
573:
574: // 物理メモリへのロングワード書き込み。
575: // 現在の bus に影響を与えず指定のアドレスに書き出す。MMU 専用。
576: busdata
577: MPU680x0Device::write_phys_4(uint32 addr, uint32 data)
578: {
579: m68kbus backup;
580: busdata bd;
581:
582: // バス情報を一旦退避
583: backup = bus;
584:
585: // 物理バスアクセス
586: bus.laddr = busaddr(addr) | BusAddr::SWrite | BusAddr::Size4;
1.1.1.10! root 587: bd = write_phys(bus.laddr, data);
1.1.1.7 root 588: if (__predict_false(bd.IsBusErr())) {
589: return bd;
590: }
591:
592: // バス情報を復元
593: bus = backup;
594: return bd;
595: }
596:
597: // CACR レジスタ書き込み。
598: void
599: MPU68030Device::SetCACR(uint32 newval)
600: {
601: newval &= M68030::CACR_MASK;
602: uint32 oldval = reg.cacr;
603: uint32 chgval = oldval ^ newval;
604:
605: // EI (命令キャッシュ有効)
606: if ((chgval & M68030::CACR_EI) != 0) {
607: if ((newval & M68030::CACR_EI) != 0) {
1.1.1.10! root 608: if (force_disable_icache) {
! 609: putlog(1, "I-Cache not enabled (mpu-force-disable-icache)");
! 610: newval &= ~M68030::CACR_EI;
! 611: } else {
! 612: // 命令キャッシュ有効
! 613: icache->enable = true;
! 614: icache->hist.Clear();
! 615: cycle_table = cycle_table_030cc;
! 616: putlog(1, "I-Cache enabled");
! 617: }
1.1.1.7 root 618: } else {
619: // 命令キャッシュ無効
620: icache->enable = false;
1.1.1.8 root 621: cycle_table = cycle_table_030ncc;
1.1.1.7 root 622: putlog(1, "I-Cache disabled");
623: }
624: }
625:
626: // FI (命令キャッシュ凍結)
627: if ((chgval & M68030::CACR_FI) != 0) {
628: icache->freeze = (newval & M68030::CACR_FI);
1.1.1.10! root 629: putlog(1, "CACR:FI <- %u", icache->freeze);
1.1.1.7 root 630: }
631:
632: // CEI (命令キャッシュの指定エントリをクリア)
633: if ((chgval & M68030::CACR_CEI) != 0) {
634: // CAAR の b7-2 で示されるロングワードを無効にする。
635: uint32 idx = (reg.caar & 0x000000f0) >> 4;
636: uint32 sel = (reg.caar & 0x0000000c) >> 2;
637: auto& l = icache->line[idx];
638: l.valid[sel] = 0;
639:
640: newval &= ~M68030::CACR_CEI;
641: }
642:
643: // CI (命令キャッシュクリア)
644: if ((chgval & M68030::CACR_CI) != 0) {
645: for (auto& l : icache->line) {
646: l.valid_all = 0;
647: }
648:
649: newval &= ~M68030::CACR_CI;
650: }
651:
652: // IBE (命令バースト有効)
653: if ((chgval & M68030::CACR_IBE) != 0) {
1.1.1.10! root 654: icache->burst_enable =
! 655: (newval & M68030::CACR_IBE) &&
! 656: (icache->freeze == false) &&
! 657: has_burst_access;
1.1.1.7 root 658: }
659:
660: // ED (データキャッシュ有効)
661: if ((chgval & M68030::CACR_ED) != 0) {
662: if ((newval & M68030::CACR_ED) != 0) {
1.1.1.10! root 663: if (force_disable_dcache) {
! 664: putlog(1, "D-Cache not enabled (mpu-force-disable-dcache)");
! 665: newval &= ~M68030::CACR_ED;
! 666: } else {
! 667: // データキャッシュ有効。
! 668: dcache->enable = true;
! 669: dcache->hist.Clear();
! 670: putlog(1, "D-Cache enabled");
! 671: }
1.1.1.7 root 672: } else {
673: // データキャッシュ無効。
674: dcache->enable = false;
675: putlog(1, "D-Cache disabled");
676: }
677: }
678:
679: // FD (データキャッシュ凍結)
680: if ((chgval & M68030::CACR_FD) != 0) {
681: dcache->freeze = (newval & M68030::CACR_FD);
1.1.1.10! root 682: putlog(1, "CACR:FD <- %u", dcache->freeze);
1.1.1.7 root 683: }
684:
685: // CED (データキャッシュの指定エントリをクリア)
686: if ((chgval & M68030::CACR_CED) != 0) {
687: // CAAR の b7-2 で示されるロングワードを無効にする。
688: uint32 idx = (reg.caar & 0x000000f0) >> 4;
689: uint32 sel = (reg.caar & 0x0000000c) >> 2;
690: auto& l = dcache->line[idx];
691: l.valid[sel] = 0;
692:
693: newval &= ~M68030::CACR_CED;
694: }
695:
696: // CD (データキャッシュクリア)
697: if ((chgval & M68030::CACR_CD) != 0) {
698: for (auto& l : dcache->line) {
699: l.valid_all = 0;
700: }
701:
702: newval &= ~M68030::CACR_CD;
703: }
704:
705: // DBE (データバースト有効)
706: if ((chgval & M68030::CACR_DBE) != 0) {
1.1.1.10! root 707: dcache->burst_enable =
! 708: (newval & M68030::CACR_DBE) &&
! 709: (dcache->freeze == false) &&
! 710: has_burst_access;
1.1.1.7 root 711: }
712:
713: // WA (ライトアロケート)
714: if ((chgval & M68030::CACR_WA) != 0) {
715: dcache->wa = (newval & M68030::CACR_WA);
716: }
717:
718: // とりあえずレジスタイメージも保存。
719: reg.cacr = newval;
720: }
721:
722: // リセット例外の CPU 固有部分。
723: void
724: MPU68030Device::ResetCache()
725: {
726: SetCACR(M68030::CACR_CD | M68030::CACR_CI);
727: icache->hist.Clear();
728: dcache->hist.Clear();
729: }
730:
1.1.1.6 root 731: // キャッシュの統計情報を計算。
1.1 root 732: void
1.1.1.6 root 733: m68030Cache::CalcStat()
1.1 root 734: {
1.1.1.6 root 735: m68030CacheStat s;
1.1.1.5 root 736:
1.1.1.6 root 737: memset(&s, 0, sizeof(s));
1.1 root 738:
1.1.1.6 root 739: // fasthit はファストパスでヒットした回数。
740: uint32 total_read = stat_fasthit + stat_hit + stat_miss;
741: if (__predict_true(total_read != 0)) {
742: s.hit = (float)(stat_fasthit + stat_hit) * 100 / total_read;
743: stat_fasthit = 0;
744: stat_hit = 0;
745: stat_miss = 0;
746: }
1.1.1.5 root 747:
1.1.1.6 root 748: // 前回から今回までの間に disable になったのなら有効な値がある。
749: if (__predict_true(enable || total_read != 0)) {
750: // ここはロックする。
1.1.1.9 root 751: std::lock_guard<std::mutex> lock(hist_mtx);
1.1.1.6 root 752: hist.EnqueueForce(s);
753: }
1.1 root 754: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.