|
|
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.6 ! root 20: MPU680x0Device::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)) {
! 27: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 28: uint32 idx = (reg.pc & 0x000000f0) >> 4;
! 29: uint32 sel = (reg.pc & 0x0000000c) >> 2;
! 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: bus.size = M68K::SSW_SIZE(addr.GetSize() & 3);
! 53: throw M68K::EXCEP_BUSERR;
1.1 root 54: }
1.1.1.5 root 55: reg.pc += 2;
1.1.1.6 ! root 56: return bd.Data();
1.1 root 57: }
58:
1.1.1.5 root 59: // reg.pc からロングワード(ミスアライン可)をフェッチし reg.pc を進める。
60: uint32
1.1.1.6 ! root 61: MPU680x0Device::fetch_4()
1.1 root 62: {
1.1.1.6 ! root 63: busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size4;
1.1.1.5 root 64:
1.1.1.6 ! root 65: // まず可能ならキャッシュから探す。
! 66: m68030Cache *cache = icache.get();
! 67: if (__predict_true(cache->enable)) {
! 68: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 69: uint32 idx = (reg.pc & 0x000000f0) >> 4;
! 70: uint32 sel = (reg.pc & 0x0000000c) >> 2;
! 71: m68030CacheLine *l = &cache->line[idx];
! 72:
! 73: if (__predict_true(l->tag == tag && l->valid[sel])) {
! 74: uint32 data;
! 75: if ((reg.pc & 2) == 0) {
! 76: cache->stat_fasthit++;
! 77: data = l->data[sel];
! 78: } else {
! 79: // 次のエントリにまたがる場合。
! 80: if (sel < 3 && l->valid[sel + 1]) {
! 81: cache->stat_fasthit += 2;
! 82: data = l->data[sel] << 16;
! 83: data |= l->data[sel + 1] >> 16;
! 84: } else {
! 85: // 片方でキャッシュミスした。
! 86: // この場合は fast* はカウントしない。
! 87: goto fetch;
! 88: }
! 89: }
! 90: reg.pc += 4;
! 91: return data;
1.1.1.5 root 92: }
1.1 root 93: }
94:
1.1.1.6 ! root 95: fetch:
! 96: busdata bd;
! 97: if (__predict_true(cache->enable)) {
! 98: bd = read_cache(cache, addr);
! 99: } else {
! 100: bd = read_nocache(addr);
! 101: }
! 102: if (__predict_false(bd.IsBusErr())) {
! 103: bus.size = M68K::SSW_SIZE(addr.GetSize() & 3);
! 104: throw M68K::EXCEP_BUSERR;
! 105: }
! 106: reg.pc += 4;
! 107: return bd.Data();
1.1 root 108: }
109:
1.1.1.6 ! root 110: // read_1,2,4() の共通部分。ミスアライン可。
! 111: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.5 root 112: uint32
1.1.1.6 ! root 113: MPU680x0Device::read_data(busaddr addr)
1.1 root 114: {
1.1.1.6 ! root 115: m68030Cache *cache = dcache.get();
! 116: busdata data;
! 117: if (__predict_true(cache->enable)) {
! 118: data = read_cache(cache, addr);
! 119: } else {
! 120: data = read_nocache(addr);
! 121: }
! 122: if (__predict_false(data.IsBusErr())) {
! 123: bus.size = M68K::SSW_SIZE(addr.GetSize() & 3);
! 124: throw M68K::EXCEP_BUSERR;
! 125: }
! 126: return data.Data();
1.1 root 127: }
128:
1.1.1.6 ! root 129: // write_1,2,4() の共通部分。ミスアライン可。
1.1.1.5 root 130: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.6 ! root 131: void
! 132: MPU680x0Device::write_data(busaddr addr, uint32 data)
1.1 root 133: {
1.1.1.6 ! root 134: busdata r = write_bus(addr, data);
! 135: if (__predict_false(r.IsBusErr())) {
! 136: bus.size = M68K::SSW_SIZE(addr.GetSize() & 3);
! 137: throw M68K::EXCEP_BUSERR;
1.1.1.5 root 138: }
1.1 root 139: }
140:
1.1.1.6 ! root 141: // キャッシュ無効時の読み込み。ミスアライン可。
! 142: // バスエラーも busdata を返す。
! 143: busdata
! 144: MPU680x0Device::read_nocache(busaddr addr)
! 145: {
! 146: // デバイスは、addr の下位ビットによらず、自身のデバイスのポートサイズ分
! 147: // のデータと、その応答サイズ(自分のポートサイズ) を Size フィールドに
! 148: // セットして返してくる。
! 149: //
! 150: // MPU(68030) は、A1-A0、残りバイト数、デバイスの応答サイズの情報から
! 151: // 受け取ったデータバスのうち適切なところを切り出して使う。
! 152:
! 153: uint32 data = 0;
! 154: for (;;) {
! 155: bus.laddr = addr;
! 156: bus.paddr = addr;
! 157: if (__predict_false(TranslateRead() == false)) {
! 158: return BusData::BusErr;
! 159: }
! 160: busdata bd = read_phys();
! 161: if (__predict_false(bd.IsBusErr())) {
! 162: return bd;
! 163: }
1.1.1.5 root 164:
1.1.1.6 ! root 165: uint32 reqsize = addr.GetSize();
! 166: // デバイスのポートサイズ(応答サイズ)
! 167: uint32 portsize = bd.GetSize();
! 168: // 今回のアドレスオフセット
! 169: uint32 offset = addr.Addr() & (portsize - 1);
! 170: uint32 datasize = portsize - offset;
! 171: uint32 tmp = bd.Data();
! 172: // 下詰めされたデータに対するマスク
! 173: uint32 mask = 0xffffffffU >> ((4 - datasize) * 8);
! 174: // 今回必要なところ
! 175: tmp &= mask;
! 176: if (datasize == reqsize) {
! 177: data |= tmp;
! 178: break;
! 179: } else if (datasize > reqsize) {
! 180: tmp >>= (datasize - reqsize) * 8;
! 181: data |= tmp;
! 182: break;
1.1.1.5 root 183: } else {
1.1.1.6 ! root 184: tmp <<= (reqsize - datasize) * 8;
! 185: data |= tmp;
1.1.1.5 root 186: }
187:
1.1.1.6 ! root 188: addr += datasize;
! 189: reqsize -= datasize;
! 190: addr.ChangeSize(reqsize);
! 191: }
1.1.1.5 root 192: return data;
1.1 root 193: }
194:
1.1.1.6 ! root 195: // offset [0, 4) から size [1, 4] バイトのマスクを作成する。
! 196: // マスクは +0, +1, +2, +3 バイト目がビット 3, 2, 1, 0 に対応している。
! 197: static inline uint32
! 198: OPERMASK(uint32 offset, uint32 size)
! 199: {
! 200: return ((1U << size) - 1) << (4 - offset - size);
! 201: }
! 202:
! 203: // キャッシュ有効時の読み込み。ミスアライン可。
! 204: // バスエラーも busdata を返す。
! 205: busdata
! 206: MPU680x0Device::read_cache(m68030Cache *cache, busaddr addr)
! 207: {
! 208: putlog(2, "read_cache $%u.%08x.%c",
! 209: addr.GetFC(), addr.Addr(), "0BW3L"[addr.GetSize()]);
! 210:
! 211: uint32 data = 0;
! 212: bus.ci = false;
! 213: for (;;) {
! 214: uint32 entry_data = 0;
! 215:
! 216: // addr から今回対象とするロングワードエントリに対するマスクを作成。
! 217: uint32 reqoffset = addr.Addr() & 3;
! 218: uint32 reqsize = addr.GetSize();
! 219: uint32 opersize = std::min(reqsize, 4 - reqoffset);
! 220:
! 221: // まず可能ならキャッシュから探す。
! 222: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 223: uint32 idx = (addr.Addr() & 0x000000f0) >> 4;
! 224: uint32 sel = (addr.Addr() & 0x0000000c) >> 2;
! 225: m68030CacheLine *l = &cache->line[idx];
! 226: if (__predict_true(l->tag == tag && l->valid[sel])) {
! 227: cache->stat_hit++;
! 228: entry_data = l->data[sel];
! 229: putlog(2, " entry_data=$%08x (match)", entry_data);
! 230: } else {
! 231: cache->stat_miss++;
! 232:
! 233: // キャッシュになければバスアクセス。
! 234: bus.laddr = addr;
! 235: bus.paddr = addr;
! 236: if (__predict_false(TranslateRead() == false)) {
! 237: putlog(2, " TranslateRead BusErr");
! 238: return BusData::BusErr;
! 239: }
! 240: putlog(2, " paddr=$%08x.%c",
! 241: bus.paddr.Addr(), "0BW3L"[bus.paddr.GetSize()]);
! 242:
! 243: busdata bd;
! 244: if (__predict_true(cache->freeze == false && bus.ci == false)) {
! 245: // キャッシュ可。
! 246: if (l->tag != tag) {
! 247: // タグが違う場合、出来ればバーストリードを使う。
! 248: // XXX: タグが同じでもエントリがすべて無効ならバーストリード
! 249: // するのだが、パフォーマンス落ちるので保留。
! 250: // TODO: 要求オペランドがラインをまたぐ場合の1エントリ目は
! 251: // バースト転送しない。
! 252: if (__predict_true(cache->burst_enable) &&
! 253: __predict_true(read_phys_burst(&l->data[0])))
! 254: {
! 255: l->tag = tag;
! 256: l->valid_all = -1;
! 257: entry_data = l->data[sel];
! 258: putlog(2, " entry_data=$%08x (burst)", entry_data);
! 259: } else {
! 260: // シングル充填を4回。
! 261: uint32 opermask = OPERMASK(reqoffset, opersize);
! 262: bd = read_line(l, tag, opermask);
! 263: if (__predict_false(bd.IsBusErr())) {
! 264: return bd;
! 265: }
! 266: entry_data = bd.Data();
! 267: putlog(2, " entry_data=$%08x (line)", entry_data);
! 268: }
! 269: } else {
! 270: // このエントリだけ充填。
! 271: bd = read_phys();
! 272: if (__predict_false(bd.IsBusErr())) {
! 273: return bd;
! 274: }
! 275: if (__predict_false(bus.ci)) {
! 276: goto nofill;
! 277: }
! 278: if (__predict_false(bd.GetSize() != 4)) {
! 279: uint32 opermask = OPERMASK(reqoffset, opersize);
! 280: bd = read_single(bd, 0xf, opermask);
! 281: if (__predict_false(bd.IsBusErr())) {
! 282: return bd;
! 283: }
! 284: }
! 285: l->valid[sel] = 1;
! 286: l->data[sel] = bd.Data();
! 287: entry_data = bd.Data();
! 288: }
! 289: } else {
! 290: // キャッシュに充填しないので、要求サイズだけ読み出す。
! 291: bd = read_phys();
! 292: if (__predict_false(bd.IsBusErr())) {
! 293: return bd;
! 294: }
! 295: nofill:
! 296: if (__predict_false(bd.GetSize() != 4)) {
! 297: uint32 opermask = OPERMASK(reqoffset, opersize);
! 298: bd = read_single(bd, opermask, opermask);
! 299: if (__predict_false(bd.IsBusErr())) {
! 300: return bd;
! 301: }
! 302: }
! 303: entry_data = bd.Data();
! 304: }
! 305: }
1.1.1.5 root 306:
1.1.1.6 ! root 307: data <<= opersize * 8;
! 308: // このエントリから必要な部分を抜き出す。
! 309: uint32 mask = 0xffffffffU >> ((4 - opersize) * 8);
! 310: if (reqsize == opersize) {
! 311: // 要求サイズがこのエントリをはみ出していない。
! 312: entry_data >>= (4 - reqoffset - opersize) * 8;
! 313: data |= entry_data & mask;
! 314: putlog(2, " data=$%0*x (done)", opersize * 2, data);
! 315: break;
1.1.1.5 root 316: } else {
1.1.1.6 ! root 317: data |= entry_data & mask;
! 318: putlog(2, " data=$%0*x", opersize * 2, data);
1.1.1.5 root 319: }
1.1.1.6 ! root 320: addr += opersize;
! 321: addr.ChangeSize(reqsize - opersize);
1.1.1.5 root 322: }
323:
324: return data;
1.1 root 325: }
326:
1.1.1.6 ! root 327: // シングル充填によるライン充填。
! 328: // 要求オペランドが2エントリ目にかかっていても、バスエラーを起こさないようだ。
! 329: busdata
! 330: MPU680x0Device::read_line(m68030CacheLine *l, uint32 tag, uint32 opermask)
! 331: {
! 332: uint32 sel = (bus.paddr.Addr() & 0x0c) >> 2;
! 333:
! 334: // 1エントリ目。
! 335: busdata bd = read_phys();
! 336: if (__predict_false(bd.IsBusErr())) {
! 337: // 初手は必ず要求オペランドなのでバスエラーは発報。
! 338: return bd;
1.1.1.5 root 339: }
1.1.1.6 ! root 340: if (__predict_false(bd.GetSize() != 4)) {
! 341: // このエントリの残りを埋める。
! 342: bd = read_single(bd, 0xf, opermask);
! 343: if (__predict_false(bd.IsBusErr())) {
! 344: return bd;
1.1.1.5 root 345: }
346: }
1.1.1.6 ! root 347: if (__predict_false(bus.ci)) {
! 348: // CI ならキャッシュを更新せず、現状のデータを返す。
! 349: // 要求オペランド外でのバスエラーもここに来る。
! 350: return bd.Data();
! 351: }
! 352: // そうでなければ、ここでタグとエントリを更新。
! 353: l->tag = tag;
! 354: l->valid_all = 0;
! 355: l->valid[sel] = 1;
! 356: l->data[sel] = bd.Data();
! 357:
! 358: // 2エントリ目以降は充填してもしなくても1エントリ目のこれが戻り値。
! 359: uint32 data = bd.Data();
! 360:
! 361: // 2エントリ目以降。
! 362: // 要求オペランドが2エントリ目にまたがっていても、
! 363: // 2エントリ目以降はバスエラーを起こさないらしい。
! 364: for (int i = 1; i < 4; i++) {
! 365: // アドレスを更新。
! 366: if (++sel >= 4) {
! 367: sel = 0;
! 368: }
! 369: bus.paddr.ChangeAddr((bus.paddr.Addr() & ~0xf) | (sel << 2));
! 370: bus.paddr.ChangeSize(4);
1.1 root 371:
1.1.1.6 ! root 372: bd = read_phys();
! 373: if (__predict_false(bd.IsBusErr())) {
! 374: break;
! 375: }
! 376: if (__predict_false(bd.GetSize() != 4)) {
! 377: // このエントリの残りを埋める。
! 378: bd = read_single(bd, 0xf, 0);
! 379: if (__predict_false(bd.IsBusErr())) {
! 380: // バスエラーならエントリを無効にして充填をアボート。
! 381: // エントリはまだ有効にしていないので何もしなくていい。
! 382: break;
! 383: }
! 384: }
! 385: if (__predict_false(bus.ci)) {
! 386: // CI は1ライン中で変化しないと思うが、
! 387: // 要求オペランド外でのバスエラーもここに来る。
! 388: break;
1.1.1.5 root 389: }
1.1.1.6 ! root 390:
! 391: l->valid[sel] = 1;
! 392: l->data[sel] = bd.Data();
1.1.1.5 root 393: }
1.1.1.6 ! root 394:
! 395: return data;
1.1 root 396: }
397:
1.1.1.6 ! root 398: // シングル充填の残りの読み出し。
! 399: // まず bus.paddr を1回読んでみて、ロングワードポートならそのまま使える
! 400: // (し、大抵はこのケースなので早期に抜けたい) のでここには来ない。
! 401: // ロングワードでない時だけここへ来て残りを埋める、という分担になっている。
! 402: //
! 403: // readmask は読み込みを行うバイト (キャッシュ充填なら %1111)。
! 404: // opermask はバスエラーを起こすバイト。
! 405: // readmask、opermask はともに下位の 4 ビットで、
! 406: // ビット 3, 2, 1, 0 がそれぞれ +0, +1, +2, +3 バイト目を示す。
! 407: //
! 408: // bd = read_phys();
! 409: // if (BusErr) ...;
! 410: // if (bd.GetSize() != 4) {
! 411: // bd = read_single(bd, readmask, opermask);
! 412: // :
! 413: // }
! 414: // if (bus.ci) ...;
! 415: // のように呼ぶ。
! 416: //
! 417: // 応答は、
! 418: // a) 成功すれば、readmask で示した読み出しバイトをロングワードで返す。
! 419: // 下詰めではなくロングワード境界からの所定のバイト位置。
! 420: // b) opermask で示したバイトでバスエラーが起きれば、その場で処理を中断して
! 421: // BusErr を返す (上位に発報するため)。
! 422: // c) opermask で示したバイト以外でバスエラーが起きれば、その場で処理を中断
! 423: // し bus.ci を立てて、現状のデータを返す (エントリを更新しないため)。
! 424: // d) バスアクセスで CI が立てば、読み込んだデータは使うがエントリは更新しない
! 425: // ので、これは c) と同じ。
! 426: busdata
! 427: MPU680x0Device::read_single(busdata bd, uint32 readmask, uint32 opermask)
! 428: {
! 429: uint32 data = 0;
! 430: uint32 portsize;
! 431:
! 432: // この時点で bd は一回目の読み込み後で、
! 433: // バスエラーは起きておらず、ロングワードポートでなかった。
! 434: portsize = bd.GetSize();
! 435:
! 436: uint32 offset = bus.paddr.Addr() & 3;
! 437: for (;;) {
! 438: // bd.Data をエントリの所定の位置に移動。
! 439: // set には今回読めたところのビットを立てていく。
! 440: uint32 set;
! 441: if (portsize == 2) {
! 442: uint32 off2 = offset & 2;
! 443: data |= bd.Data() << ((2 - off2) * 8);
! 444: set = 0x3 << (2 - off2);
! 445: // 次の読み込みにむけて更新。
! 446: offset = 2 - off2;
! 447: } else {
! 448: data |= bd.Data() << ((3 - offset) * 8);
! 449: set = 0x1 << (3 - offset);
! 450: // 次の読み込みにむけて更新。
! 451: offset = (offset + 1) & 3;
! 452: }
1.1.1.5 root 453:
1.1.1.6 ! root 454: // readmask を全部下ろせたら終了。
! 455: readmask &= ~set;
! 456: if (readmask == 0) {
! 457: break;
! 458: }
1.1.1.5 root 459:
1.1.1.6 ! root 460: // 次の読み込み。
! 461: // 同一エントリ内なので paddr の更新だけでいい。
! 462: bus.paddr.ChangeAddr((bus.paddr.Addr() & ~3U) | offset);
! 463: bus.paddr.ChangeSize(__builtin_popcount(readmask));
! 464:
! 465: bd = read_phys();
! 466: portsize = bd.GetSize();
! 467: if (__predict_false(bd.IsBusErr())) {
! 468: if ((set & opermask) != 0) {
! 469: // ターゲットオペランドと重なっていれば即バスエラー。
! 470: return BusData::BusErr;
! 471: } else {
! 472: // オペランド外の充填中なら CI と同じパスになる。
! 473: bus.ci = true;
! 474: break;
! 475: }
! 476: }
! 477: }
1.1.1.5 root 478:
1.1.1.6 ! root 479: return data;
1.1 root 480: }
481:
1.1.1.6 ! root 482: // キャッシュ/バスへの書き込み。ミスアライン可。
! 483: // バスエラーも busdata を返す。
! 484: busdata
! 485: MPU680x0Device::write_bus(busaddr addr, uint32 data)
! 486: {
! 487: m68030Cache *cache = dcache.get();
! 488:
! 489: putlog(2, "write_bus %u.%08x sz=%u data=$%0*x",
! 490: addr.GetFC(), addr.Addr(), addr.GetSize(), addr.GetSize() * 2, data);
! 491: for (;;) {
! 492: uint32 nextdata;
! 493: uint32 reqoffset = addr.Addr() & 3;
! 494: uint32 reqsize = addr.GetSize();
! 495:
! 496: // ロングワード境界をはみ出す場合は持ち越し分を覚えておく。
! 497: int nextsize = reqoffset + reqsize - 4;
! 498: if (nextsize > 0) {
! 499: // 後ろにはみ出すケース。
! 500: nextdata = data & ((1U << (nextsize * 8)) - 1);
! 501: data >>= nextsize * 8;
! 502: reqsize -= nextsize;
! 503: addr.ChangeSize(reqsize);
! 504: } else {
! 505: nextsize = 0;
! 506: }
1.1.1.5 root 507:
1.1.1.6 ! root 508: // まず外部バスを駆動して CI を得る。
! 509: // バスエラーなら記録だけしておく。キャッシュへは書き込むため。
! 510: busdata bd = BusData::BusErr;
! 511: bus.ci = false;
! 512: bus.laddr = addr;
! 513: bus.paddr = addr;
! 514: if (__predict_true(TranslateWrite())) {
! 515: uint32 outdata = data;
! 516: for (;;) {
! 517: bd = write_phys(outdata);
! 518: if (__predict_false(bd.IsBusErr())) {
! 519: putlog(2, " write_phys -> BusErr");
! 520: break;
! 521: }
! 522: uint32 breqsize = bus.paddr.GetSize();
! 523: putlog(2, " write_phys $%08x data=$%0*x",
! 524: bus.paddr.Addr(), breqsize * 2, outdata);
! 525: uint32 portsize = bd.GetSize();
! 526: uint32 offset = bus.paddr.Addr() & (portsize - 1);
! 527: uint32 datasize = portsize - offset;
! 528: if (datasize >= breqsize) {
! 529: break;
! 530: }
! 531: // 同一ロングワード内なので bus.paddr の更新だけでいい。
! 532: bus.paddr += datasize;
! 533: breqsize -= datasize;
! 534: bus.paddr.ChangeSize(breqsize);
! 535: // データは下詰めで、不要な上位ビットはクリアする仕様。
! 536: outdata &= (1U << (breqsize * 8)) - 1;
! 537: }
! 538: }
1.1.1.5 root 539:
1.1.1.6 ! root 540: bool cache_writable = (cache->enable && bus.ci == false);
! 541: if (cache_writable) {
! 542: uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
! 543: uint32 idx = (addr.Addr() & 0x000000f0) >> 4;
! 544: uint32 sel = (addr.Addr() & 0x0000000c) >> 2;
! 545: auto *l = &cache->line[idx];
! 546:
! 547: // Hit Frz WA Tag LA
! 548: // 1 0 - - - : UpdateEntry
! 549: // 1 1 - - - : UpdateEntry (ex1, ex2のb8-b9
! 550: // 0 1 - - - : Nop
! 551: // 0 0 0 - - : Nop
! 552: // 0 0 1 1 1 : (ex3
! 553: // 0 0 1 1 0 : Nop (ex2のb6-b7
! 554: // 0 0 1 0 1 : (ex4
! 555: // 0 0 1 0 0 : (ex5
! 556: bool tag_match = (l->tag == tag);
! 557: bool cache_hit = (tag_match && l->valid[sel]);
! 558: if (cache_hit) {
! 559: // エントリの更新。
! 560: // reqsize はロングワード境界を超えないよう調整済み。
! 561: // data は下詰め(上はクリア)なので、所定の位置まで左シフト。
! 562: // 整列ロングワードもここに来ることに注意。
! 563: // Fig.6-4 の ex1, ex2のb8-b9
! 564: int lshift = (4 - reqoffset - reqsize) * 8;
! 565: uint32 mask = (0xffffffffU >> ((4 - reqsize) * 8)) << lshift;
! 566: l->data[sel] = (data << lshift) | (l->data[sel] & ~mask);
! 567: } else if (cache->freeze == false && cache->wa) {
! 568: bool long_aligned = (reqoffset == 0 && reqsize == 4);
! 569: // Fig.6-4
! 570: if (tag_match) {
! 571: if (long_aligned) {
! 572: // ex3
! 573: l->valid[sel] = 1;
! 574: l->data[sel] = data;
! 575: } else {
! 576: // ex2 の b6-b7
! 577: // nop
! 578: }
! 579: } else {
! 580: if (long_aligned) {
! 581: // ex4
! 582: l->tag = tag;
! 583: l->valid_all = 0;
! 584: l->valid[sel] = 1;
! 585: l->data[sel] = data;
! 586: } else {
! 587: // ex5
! 588: l->valid[sel] = 0;
! 589: }
! 590: }
! 591: }
! 592: }
1.1 root 593:
1.1.1.6 ! root 594: // バスアクセスでバスエラーが出たらキャッシュ更新後に発報。
! 595: if (__predict_false(bd.IsBusErr())) {
! 596: return bd;
! 597: }
1.1.1.5 root 598:
1.1.1.6 ! root 599: // ロングワード境界をまたいだ余りがあればもう一回。
! 600: if (nextsize == 0) {
! 601: break;
! 602: }
! 603: putlog(2, " nextsize=%u", nextsize);
! 604: addr += addr.GetSize();
! 605: addr.ChangeSize(nextsize);
! 606: data = nextdata;
! 607: }
1.1.1.5 root 608:
1.1.1.6 ! root 609: return 0;
1.1 root 610: }
611:
1.1.1.6 ! root 612: // mainbus の bus.paddr から指定サイズで1回読み込む。
! 613: // ウェイトはこちらで加算して、バスエラーも含めた bd を返す。
! 614: busdata
! 615: MPU680x0Device::read_phys()
1.1 root 616: {
1.1.1.6 ! root 617: busaddr paddr = bus.paddr;
! 618: busdata bd = mainbus->Read(paddr);
! 619: buswait += bd.GetWait();
! 620: return bd;
1.1 root 621: }
622:
1.1.1.6 ! root 623: // mainbus の bus.paddr に指定サイズで1回書き込む。
! 624: // ウェイトはこちらで加算して、バスエラーも含めた bd を返す。
! 625: busdata
! 626: MPU680x0Device::write_phys(uint32 data)
1.1 root 627: {
1.1.1.6 ! root 628: busaddr paddr = bus.paddr;
! 629: busdata bd = mainbus->Write(paddr, data);
! 630: buswait += bd.GetWait();
! 631: return bd;
1.1 root 632: }
633:
1.1.1.6 ! root 634: // バースト転送。
! 635: // bus.paddr の下位4ビットは無視する。
! 636: // addr がバースト転送可能なら dst に 16 バイト転送して true を返す。
! 637: // addr がバースト転送不可なら dst は触らず false を返す。
! 638: // VM (バス) がバースト転送対応している場合のみ呼ぶこと。
! 639: bool
! 640: MPU680x0Device::read_phys_burst(uint32 *dst)
! 641: {
! 642: busaddr paddr = bus.paddr;
! 643: paddr &= 0xfffffff0U;
! 644: busdata bd = mainbus->ReadBurst16(paddr, dst);
! 645: buswait += bd.GetWait();
1.1.1.5 root 646:
1.1.1.6 ! root 647: // BusErr ビットをバースト転送不可フラグとして使っている。
! 648: return !bd.IsBusErr();
1.1 root 649: }
650:
1.1.1.6 ! root 651: // キャッシュの統計情報を計算。
1.1 root 652: void
1.1.1.6 ! root 653: m68030Cache::CalcStat()
1.1 root 654: {
1.1.1.6 ! root 655: m68030CacheStat s;
1.1.1.5 root 656:
1.1.1.6 ! root 657: memset(&s, 0, sizeof(s));
1.1 root 658:
1.1.1.6 ! root 659: // fasthit はファストパスでヒットした回数。
! 660: uint32 total_read = stat_fasthit + stat_hit + stat_miss;
! 661: if (__predict_true(total_read != 0)) {
! 662: s.hit = (float)(stat_fasthit + stat_hit) * 100 / total_read;
! 663: stat_fasthit = 0;
! 664: stat_hit = 0;
! 665: stat_miss = 0;
! 666: }
1.1.1.5 root 667:
1.1.1.6 ! root 668: // 前回から今回までの間に disable になったのなら有効な値がある。
! 669: if (__predict_true(enable || total_read != 0)) {
! 670: // ここはロックする。
! 671: std::unique_lock<std::mutex> lock(hist_mtx);
! 672: hist.EnqueueForce(s);
! 673: }
1.1 root 674: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.