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

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

unix.superglobalmegacorp.com

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