Annotation of nono/m680x0/m68030bus.cpp, revision 1.1.1.10

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.