Annotation of nono/m680x0/m68040mmu.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2024 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: #include "mpu680x0.h"
        !             8: #include "mainbus.h"
        !             9: #include "m68040mmu.h"
        !            10: #include "m88200.h"
        !            11: 
        !            12: // 読み込みのアドレス変換を行う。
        !            13: bool
        !            14: MPU68040Device::TranslateRead()
        !            15: {
        !            16:        m68040TT *tt;
        !            17:        m68040ATC *atc;
        !            18: 
        !            19:        putlog(3, "TranslateRead  %c.$%08x",
        !            20:                (bus.laddr.IsSuper() ? 'S' : 'U'), bus.laddr.Addr());
        !            21: 
        !            22:        // まず TT をチェック。
        !            23:        if (bus.laddr.IsData()) {
        !            24:                atc = atc_data.get();
        !            25:                tt = CheckTT(mmu_dtt);
        !            26:        } else {
        !            27:                atc = atc_inst.get();
        !            28:                tt = CheckTT(mmu_itt);
        !            29:        }
        !            30:        if (tt != NULL) {
        !            31:                putlog(3, "TranslateRead  %s matched", tt->GetName());
        !            32:                return true;
        !            33:        }
        !            34: 
        !            35:        // TC がオフならここで終わり。
        !            36:        if (__predict_false(mmu_tc->e == false)) {
        !            37:                putlog(3, "TranslateRead  TC:E OFF");
        !            38:                return true;
        !            39:        }
        !            40: 
        !            41:        return LookupATC(*atc);
        !            42: }
        !            43: 
        !            44: // 書き込みのアドレス変換を行う。
        !            45: bool
        !            46: MPU68040Device::TranslateWrite()
        !            47: {
        !            48:        putlog(3, "TranslateWrite %c.$%08x",
        !            49:                (bus.laddr.IsSuper() ? 'S' : 'U'), bus.laddr.Addr());
        !            50: 
        !            51:        // まず TT をチェック。
        !            52:        m68040TT *tt = CheckTT(mmu_dtt);
        !            53:        if (tt) {
        !            54:                if (tt->w) {
        !            55:                        putlog(3, "TranslateWrite %s matched (WriteProtected)",
        !            56:                                tt->GetName());
        !            57:                        return false;
        !            58:                } else {
        !            59:                        putlog(3, "TranslateWrite %s matched", tt->GetName());
        !            60:                        return true;
        !            61:                }
        !            62:        }
        !            63: 
        !            64:        // TC がオフならここで終わり。
        !            65:        if (__predict_false(mmu_tc->e == false)) {
        !            66:                putlog(3, "TranslateWrite TC:E OFF");
        !            67:                return true;
        !            68:        }
        !            69: 
        !            70:        m68040ATC *atc = atc_data.get();
        !            71:        return LookupATC(*atc);
        !            72: }
        !            73: 
        !            74: // *TTn にマッチすれば、マッチした方のポインタを返す。
        !            75: // マッチしなければ NULL を返す。
        !            76: m68040TT *
        !            77: MPU68040Device::CheckTT(std::array<std::unique_ptr<m68040TT>, 2>& ttbase) const
        !            78: {
        !            79:        for (int n = 0; n < 2; n++) {
        !            80:                m68040TT *tt = ttbase[n].get();
        !            81:                if (tt->Match(bus.laddr)) {
        !            82:                        return tt;
        !            83:                }
        !            84:        }
        !            85:        return NULL;
        !            86: }
        !            87: 
        !            88: // ATC を検索する。
        !            89: bool
        !            90: MPU68040Device::LookupATC(m68040ATC& atc)
        !            91: {
        !            92:        m68040ATCEntry *entry;
        !            93:        uint32 tag;
        !            94:        uint32 idx;
        !            95:        int n;
        !            96: 
        !            97:        // ATC のタグに使う論理アドレスはページサイズによって区切る位置が変わる。
        !            98:        // インデックスは本来タグの比較には使わないが、
        !            99:        // 表示の際にはインデックス部分がないとだいぶ意味が分からないのと、
        !           100:        // 4KB/page なら 16進数で下から 4桁目をインデックスで補完出来るからいいが
        !           101:        // 8KB/page の時にはつらいので、最初からタグに含めておく。
        !           102:        //
        !           103:        //      3                   2                   1                   0
        !           104:        //    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        !           105:        // +-+-------------------------------+-------+-----------------------+
        !           106:        // |S|  Logical Address (16bit)      | Index | Page Offset (4KB/page)|
        !           107:        // +-+-------------------------------+-------+-----------------------+
        !           108:        // :<-- FC2 + LAddress (+ Index) = 21bit --->:
        !           109:        //
        !           110:        // +-+-----------------------------+-------+-------------------------+
        !           111:        // |S|  Logical Address (15bit)    | Index |   Page Offset (8KB/page)|
        !           112:        // +-+-----------------------------+-------+-------------------------+
        !           113:        // :<-- FC2 + LAddress (+ Index) = 20bit ->:
        !           114:        //
        !           115:        // タグはこの位置までシフト(とマスク)したもの。
        !           116:        //      3                   2                   1                    0
        !           117:        //    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1  0
        !           118:        //   +-----+-+---------------------------------------+-------------+--+
        !           119:        //   |  0  |S| Logical Address + Index (19/20bit)  : |      0      |~V|
        !           120:        //   +-----+-+---------------------------------------+-------------+--+
        !           121: 
        !           122:        idx = (bus.laddr.Addr() >> mmu_tc->tic_shift) & 0xf;
        !           123:        tag = (bus.laddr.Get() >> 4) & atc.tag_mask;    // FC2+Addr(+Index)
        !           124:        m68040ATCSet& set = atc.sets[idx];
        !           125: 
        !           126:        // このセットから探す。
        !           127:        for (n = 0; n < set.entry.size(); n++) {
        !           128:                entry = &set.entry[n];
        !           129:                if (entry->tag == tag) {
        !           130:                        if (entry->MatchStatus(bus.laddr)) {
        !           131:                                // 見付かった。
        !           132:                                goto found;
        !           133:                        } else {
        !           134:                                break;
        !           135:                        }
        !           136:                }
        !           137:        }
        !           138: 
        !           139:        // 空きラインか、空いてなければ生贄を差し出す。
        !           140:        n = set.GetEntry();
        !           141:        entry = &set.entry[n];
        !           142:        entry->tag = tag;
        !           143: 
        !           144:        // テーブルサーチを行い、エントリを更新する。
        !           145:        // (true なら entry を埋めて帰ってきてる)
        !           146:        if (Search(entry) == false) {
        !           147:                entry->Invalidate();
        !           148:                putlog(3, " LookupATC invalid");
        !           149:                return false;
        !           150:        }
        !           151: 
        !           152:        // このエントリで再度ステータスが一致するか。(タグは一致している)
        !           153:        if (entry->MatchStatus(bus.laddr) == false) {
        !           154:                putlog(3, " LookupATC entry not matched");
        !           155:                return false;
        !           156:        }
        !           157:  found:
        !           158:        // 見付かったので bus.paddr を更新。
        !           159:        set.LRU = m88200CacheSet::TryUseLine(set.LRU, n);
        !           160:        uint32 offset = bus.laddr.Addr() & ~mmu_tc->page_mask;
        !           161:        bus.paddr.ChangeAddr(entry->paddr | offset);
        !           162:        putlog(3, " result $%08x", bus.paddr.Addr());
        !           163:        return true;
        !           164: }
        !           165: 
        !           166: // laddr がこのエントリの各種ステータスにマッチするか調べる。
        !           167: // タグが一致している状態で呼ぶこと。
        !           168: bool
        !           169: m68040ATCEntry::MatchStatus(busaddr laddr) const
        !           170: {
        !           171:        if (IsResident() == false) {
        !           172:                return false;
        !           173:        }
        !           174:        if (laddr.IsSuper() == false && IsSuperProtected()) {
        !           175:                return false;
        !           176:        }
        !           177:        if (laddr.IsWrite() && IsWriteProtected()) {
        !           178:                return false;
        !           179:        }
        !           180:        return true;
        !           181: }
        !           182: 
        !           183: // 更新用に空きエントリか、空きがなければどれかを差し出す。
        !           184: int
        !           185: m68040ATCSet::GetEntry() const
        !           186: {
        !           187:        for (int i = 0; i < 4; i++) {
        !           188:                if (entry[i].IsValid() == false) {
        !           189:                        return i;
        !           190:                }
        !           191:        }
        !           192: 
        !           193:        int oldest = m88200CacheSet::TryGetOldestLine(LRU);
        !           194:        return oldest;
        !           195: }
        !           196: 
        !           197: // テーブルサーチを行う。
        !           198: // 成功すると entry を埋めて true を返す。
        !           199: // 失敗すると false を返す (呼び出し側で entry を無効にすること)。
        !           200: bool
        !           201: MPU68040Device::Search(m68040ATCEntry *entry)
        !           202: {
        !           203:        uint32 base;
        !           204:        uint32 idx;
        !           205:        uint32 mask;
        !           206:        uint32 addr;
        !           207:        uint32 desc;
        !           208: 
        !           209:        busaddr laddr = bus.laddr;
        !           210:        bool is_write = laddr.IsWrite();
        !           211: 
        !           212:        putlog(3, " Search %c.$%08x", (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr());
        !           213: 
        !           214:        // FC2 からルートポインタを決定。
        !           215:        // XXX FC2 なのかこれからアクセスする空間の FC なのか。
        !           216:        base = laddr.IsSuper() ? reg.srp40 : reg.urp40;
        !           217: 
        !           218:        // 第1、第2 レベルのディスクリプタを処理。
        !           219:        idx = laddr.Addr() >> 25;
        !           220:        mask = 0xfffffe00;
        !           221:        for (int lv = 0; lv < 2; lv++) {
        !           222:                addr = base + idx * 4;
        !           223:                putlog(4, "  root=$%08x [$%02x] descaddr=$%08x", base, idx, addr);
        !           224: 
        !           225:                busdata bd = read_phys_4(addr);
        !           226:                if (__predict_false(bd.IsBusErr())) {
        !           227:                        putlog(4, "  BusErr (on read desc)");
        !           228:                        return false;
        !           229:                }
        !           230:                desc = bd.Data();
        !           231: 
        !           232:                if (__predict_false(loglevel >= 4)) {
        !           233:                        static const char *udtname[] = {
        !           234:                                "Invalid", "Invalid", "Resident", "Resident",
        !           235:                        };
        !           236:                        uint32 dt = desc & m68040MMU::DESC_DT;
        !           237:                        putlogn("  desc=$%08x %c%c DT%u(%s)", desc,
        !           238:                                ((desc & m68040MMU::DESC_U) ? 'U' : '-'),
        !           239:                                ((desc & m68040MMU::DESC_W) ? 'W' : '-'),
        !           240:                                dt, udtname[dt]);
        !           241:                }
        !           242: 
        !           243:                // UDT はビット1 が %0 なら無効。
        !           244:                if ((desc & 2) == 0) {
        !           245:                        putlog(4, "  invalid");
        !           246:                        return false;
        !           247:                }
        !           248: 
        !           249:                // U が立ってなければ U を立てて更新。
        !           250:                if ((desc & m68040MMU::DESC_U) == 0) {
        !           251:                        desc |= m68040MMU::DESC_U;
        !           252:                        bd = write_phys_4(addr, desc);
        !           253:                        if (__predict_false(bd.IsBusErr())) {
        !           254:                                putlog(4, "  BusErr (on writeback U)");
        !           255:                                return false;
        !           256:                        }
        !           257:                }
        !           258: 
        !           259:                if (__predict_false(is_write) && (desc & m68040MMU::DESC_W)) {
        !           260:                        putlog(4, "  write protected");
        !           261:                        return false;
        !           262:                }
        !           263: 
        !           264:                // 次の段へ。
        !           265:                base = desc & mask;
        !           266:                idx = (laddr.Addr() >> 18) & 0x7f;
        !           267:                mask = mmu_tc->table_mask;
        !           268:        }
        !           269: 
        !           270:        // ページディスクリプタを処理。
        !           271:        idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask;
        !           272:        addr = base + idx * 4;
        !           273:        putlog(4, "  root=$%08x [$%02x] descaddr=$%08x", base, idx, addr);
        !           274:        busdata bd = read_phys_4(addr);
        !           275:        if (__predict_false(bd.IsBusErr())) {
        !           276:                putlog(4, "  BusErr (on read desc)");
        !           277:                return false;
        !           278:        }
        !           279:        desc = bd.Data();
        !           280:        uint32 pdt = desc & m68040MMU::DESC_DT;
        !           281: 
        !           282:        if (__predict_false(loglevel >= 4)) {
        !           283:                static const char *pdtname[] = {
        !           284:                        "Invalid", "Resident", "Indirect", "Resident",
        !           285:                };
        !           286:                putlogn("  desc=$%08x %c%c%c%c%c CM%u DT%u(%s)", desc,
        !           287:                        ((desc & m68040MMU::DESC_G) ? 'G' : '-'),
        !           288:                        ((desc & m68040MMU::DESC_S) ? 'S' : '-'),
        !           289:                        ((desc & m68040MMU::DESC_M) ? 'M' : '-'),
        !           290:                        ((desc & m68040MMU::DESC_U) ? 'U' : '-'),
        !           291:                        ((desc & m68040MMU::DESC_W) ? 'W' : '-'),
        !           292:                        ((desc & m68040MMU::DESC_CM) >> 5),
        !           293:                        pdt, pdtname[pdt]);
        !           294:        }
        !           295: 
        !           296:        // PDT は %00 なら無効。
        !           297:        if (__predict_false(pdt == m68040MMU::PDT_INVALID)) {
        !           298:                putlog(4, "  invalid");
        !           299:                return false;
        !           300:        } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) {
        !           301:                PANIC("indirect descriptor");
        !           302:        }
        !           303: 
        !           304:        if (__predict_true(is_write == false)) {
        !           305:                // 読み込みなら、U を立てるかどうか。
        !           306:                if ((desc & m68040MMU::DESC_U) == 0) {
        !           307:                        desc |= m68040MMU::DESC_U;
        !           308:                        bd = write_phys_4(addr, desc);
        !           309:                        if (__predict_false(bd.IsBusErr())) {
        !           310:                                putlog(4, "  BusErr (on writeback U)");
        !           311:                                return false;
        !           312:                        }
        !           313:                }
        !           314:        } else {
        !           315:                // 書き込みなら、U と M と WP。
        !           316:                uint32 olddesc = desc;
        !           317:                if ((desc & m68040MMU::DESC_U) == 0) {
        !           318:                        desc |= m68040MMU::DESC_U;
        !           319:                }
        !           320:                if ((desc & (m68040MMU::DESC_M | m68040MMU::DESC_W)) == 0) {
        !           321:                        desc |= m68040MMU::DESC_M;
        !           322:                }
        !           323:                if (olddesc != desc) {
        !           324:                        bd = write_phys_4(addr, desc);
        !           325:                        if (__predict_false(bd.IsBusErr())) {
        !           326:                                putlog(4, "  BusErr (on writeback U)");
        !           327:                                return false;
        !           328:                        }
        !           329:                }
        !           330: 
        !           331:                if ((desc & m68040MMU::DESC_W)) {
        !           332:                        putlog(4, "  write protected");
        !           333:                        return false;
        !           334:                }
        !           335:        }
        !           336: 
        !           337:        entry->paddr = desc & mmu_tc->page_mask;
        !           338:        entry->desc  = desc;
        !           339:        putlog(3, "  frame addr $%08x", entry->paddr);
        !           340:        return true;
        !           341: }
        !           342: 
        !           343: // ピーク用のアドレス変換を行う。
        !           344: // 変換できれば対応する物理アドレスを、バスエラーなら BusErr を返す。
        !           345: // テーブルサーチを行ったら TableSearched ビットを立てる。
        !           346: busaddr
        !           347: MPU68040Device::TranslatePeek(busaddr laddr)
        !           348: {
        !           349:        const m68040TT *tt;
        !           350: 
        !           351:        // TT を自前でサーチ。
        !           352:        if (laddr.IsData()) {
        !           353:                tt = CheckTT(mmu_dtt);
        !           354:        } else {
        !           355:                tt = CheckTT(mmu_itt);
        !           356:        }
        !           357:        if (__predict_false(tt != NULL)) {
        !           358:                if (tt->Match(laddr)) {
        !           359:                        return laddr;
        !           360:                }
        !           361:        }
        !           362: 
        !           363:        if (__predict_false(mmu_tc->e == false)) {
        !           364:                return laddr;
        !           365:        }
        !           366: 
        !           367:        // ATC を自前でサーチ。
        !           368:        const m68040ATC *atc;
        !           369:        if (laddr.IsData()) {
        !           370:                atc = atc_data.get();
        !           371:        } else {
        !           372:                atc = atc_inst.get();
        !           373:        }
        !           374:        uint32 idx = (laddr.Addr() >> mmu_tc->tic_shift) & 0xf;
        !           375:        uint32 tag = (laddr.Get() >> 4) & atc->tag_mask;        // FC2+Addr(+Index)
        !           376:        const m68040ATCSet& set = atc->sets[idx];
        !           377:        for (const auto& entry : set.entry) {
        !           378:                if (entry.tag == tag) {
        !           379:                        if (entry.MatchStatus(laddr)) {
        !           380:                                // 見付かった。
        !           381:                                uint32 offset = laddr.Addr() & ~mmu_tc->page_mask;
        !           382:                                laddr.ChangeAddr(entry.paddr | offset);
        !           383:                                return laddr;
        !           384:                        } else {
        !           385:                                break;
        !           386:                        }
        !           387:                }
        !           388:        }
        !           389: 
        !           390:        // ATC になければ、テーブルサーチ相当を自前で行う。
        !           391:        laddr |= BusAddr::TableSearched;
        !           392:        bool is_write = laddr.IsWrite();
        !           393:        uint32 desc;
        !           394: 
        !           395:        // FC2 からルートポインタを決定。
        !           396:        uint32 base = laddr.IsSuper() ? reg.srp40 : reg.urp40;
        !           397: 
        !           398:        // 第1レベル。
        !           399:        idx = laddr.Addr() >> 25;
        !           400:        desc = PeekDesc(base, idx);
        !           401:        // UDT はビット1 が %0 なら無効。
        !           402:        if ((desc & 2) == 0) {
        !           403:                return BusAddr::BusErr;
        !           404:        }
        !           405:        if (__predict_false(is_write) && (desc & 4)) {
        !           406:                return BusAddr::BusErr;
        !           407:        }
        !           408:        base = desc & 0xfffffe00;
        !           409: 
        !           410:        // 第2レベル。
        !           411:        idx = (laddr.Addr() >> 18) & 0x7f;
        !           412:        desc = PeekDesc(base, idx);
        !           413:        // UDT はビット1 が %0 なら無効。
        !           414:        if ((desc & 2) == 0) {
        !           415:                return BusAddr::BusErr;
        !           416:        }
        !           417:        if (__predict_false(is_write) && (desc & 4)) {
        !           418:                return BusAddr::BusErr;
        !           419:        }
        !           420:        base = desc & mmu_tc->table_mask;
        !           421: 
        !           422:        // ページディスクリプタ。
        !           423:        idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask;
        !           424:        desc = PeekDesc(base, idx);
        !           425:        // PDT は %00 なら無効。
        !           426:        uint32 pdt = desc & m68040MMU::DESC_DT;
        !           427:        if (pdt == m68040MMU::PDT_INVALID) {
        !           428:                return BusAddr::BusErr;
        !           429:        } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) {
        !           430:                PANIC("indirect descriptor");
        !           431:        }
        !           432:        if (__predict_false(is_write) && (desc & 4)) {
        !           433:                return BusAddr::BusErr;
        !           434:        }
        !           435: 
        !           436:        uint32 paddr = (desc & mmu_tc->page_mask)
        !           437:                | (laddr.Addr() & ~mmu_tc->page_mask);
        !           438:        laddr.ChangeAddr(paddr);
        !           439:        return laddr;
        !           440: }
        !           441: 
        !           442: // base[idx] からディスクリプタを副作用なく読み出す。(デバッガ用)
        !           443: // U フラグは更新しない。
        !           444: // バスエラーが起きれば 0 を返す (ディスクリプタの下位2ビットが %00 なら
        !           445: // 無効を示すので)。
        !           446: uint32
        !           447: MPU68040Device::PeekDesc(uint32 base, uint32 idx)
        !           448: {
        !           449:        uint32 addr = base + idx * 4;
        !           450:        uint64 data = mainbus->Peek4(addr);
        !           451:        if ((int64)data < 0) {
        !           452:                return 0;
        !           453:        }
        !           454:        return data;
        !           455: }
        !           456: 
        !           457: // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。
        !           458: // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp
        !           459: void
        !           460: MPU68040Device::mmu_enable_changed()
        !           461: {
        !           462:        bool enable;
        !           463: 
        !           464:        // TC、ITT*、DTT* のいずれかが有効ならアドレス変換あり。
        !           465:        enable  = (reg.tc40 & m68040TC::E);
        !           466:        enable |= mmu_itt[0]->e || mmu_itt[1]->e;
        !           467:        enable |= mmu_dtt[0]->e || mmu_dtt[1]->e;
        !           468: 
        !           469:        // 変化した時だけ
        !           470:        if (mmu_enable && !enable) {
        !           471:                // 無効にする
        !           472:                mmu_enable = false;
        !           473:                putlog(1, "MMU Translation Disabled");
        !           474:        } else if (!mmu_enable && enable) {
        !           475:                // 有効にする
        !           476:                mmu_enable = true;
        !           477:                putlog(1, "MMU Translation Enabled");
        !           478:        }
        !           479: }
        !           480: 
        !           481: // *TTn レジスタへの書き込み。
        !           482: void
        !           483: MPU68040Device::SetTT(m68040TT *tt, uint32 data)
        !           484: {
        !           485:        *tt->reg  = (data & m68040TT::MASK);
        !           486:        putlog(1, "%s <- $%08x", tt->GetName(), *tt->reg);
        !           487: 
        !           488:        tt->base  = (data & m68040TT::LBASE_MASK);
        !           489:        tt->mask  = (~data & m68040TT::LMASK_MASK) << 8;
        !           490:        tt->e     = (data & m68040TT::E);
        !           491:        tt->s_ign = (data & m68040TT::S_IGN);
        !           492:        tt->s_fc2 = (data & m68040TT::S_FC2);
        !           493:        tt->u     = (data & m68040TT::U_MASK);
        !           494:        tt->cm    = (data & m68040TT::CM) >> 5;
        !           495:        tt->w     = (data & m68040TT::W);
        !           496: 
        !           497:        mmu_enable_changed();
        !           498: }
        !           499: 
        !           500: void
        !           501: MPU68040Device::SetSRP(uint32 data)
        !           502: {
        !           503:        // とりあえず
        !           504:        reg.srp40 = data & m68040RP::ADDR_MASK;
        !           505:        putlog(1, "SRP <- $%08x", reg.srp40);
        !           506: }
        !           507: 
        !           508: void
        !           509: MPU68040Device::SetURP(uint32 data)
        !           510: {
        !           511:        // とりあえず
        !           512:        reg.urp40 = data & m68040RP::ADDR_MASK;
        !           513:        putlog(1, "URP <- $%08x", reg.urp40);
        !           514: }
        !           515: 
        !           516: void
        !           517: MPU68040Device::SetTC(uint32 data)
        !           518: {
        !           519:        // とりあえず
        !           520:        reg.tc40 = data & m68040TC::MASK;
        !           521:        putlog(1, "TC <- $%04x", reg.tc40);
        !           522: 
        !           523:        mmu_tc->e = reg.tc40 & m68040TC::E;
        !           524:        if ((reg.tc40 & m68040TC::P) == 0) {
        !           525:                // 4KB/page
        !           526:                mmu_tc->ps4k = true;
        !           527:                mmu_tc->table_mask = 0xffffff00;
        !           528:                mmu_tc->tic_shift  = 12;
        !           529:                mmu_tc->tic_mask   = 0x0000003f;
        !           530:                mmu_tc->page_mask  = 0xfffff000;
        !           531:        } else {
        !           532:                // 8KB/page
        !           533:                mmu_tc->ps4k = false;
        !           534:                mmu_tc->table_mask = 0xffffff80;
        !           535:                mmu_tc->tic_shift  = 13;
        !           536:                mmu_tc->tic_mask   = 0x0000001f;
        !           537:                mmu_tc->page_mask  = 0xffffe000;
        !           538:        }
        !           539: 
        !           540:        // ページサイズと連動している ATC の変数もセット。
        !           541:        uint32 tag_mask = (mmu_tc->page_mask >> 4) | 0x1000'0000;
        !           542:        atc_inst->tag_mask = tag_mask;
        !           543:        atc_data->tag_mask = tag_mask;
        !           544: 
        !           545:        mmu_enable_changed();
        !           546: }
        !           547: 
        !           548: // リセット例外の CPU 固有部分。
        !           549: void
        !           550: MPU68040Device::ResetMMU()
        !           551: {
        !           552:        mmu_tc->e = false;
        !           553:        mmu_itt[0]->e = false;
        !           554:        mmu_itt[1]->e = false;
        !           555:        mmu_dtt[0]->e = false;
        !           556:        mmu_dtt[1]->e = false;
        !           557: 
        !           558:        // ATC は影響を受けない。
        !           559: }
        !           560: 
        !           561: // *TT
        !           562: 
        !           563: // コンストラクタ
        !           564: m68040TT::m68040TT(const char *name_, uint32 *reg_)
        !           565: {
        !           566:        name = name_;
        !           567:        reg  = reg_;
        !           568: }
        !           569: 
        !           570: // デストラクタ
        !           571: m68040TT::~m68040TT()
        !           572: {
        !           573: }
        !           574: 
        !           575: // addr がマッチすれば true を返す。
        !           576: bool
        !           577: m68040TT::Match(busaddr addr) const
        !           578: {
        !           579:        if (__predict_true(e == false)) {
        !           580:                return false;
        !           581:        }
        !           582:        if (s_ign == false) {
        !           583:                if (addr.IsSuper() != s_fc2) {
        !           584:                        return false;
        !           585:                }
        !           586:        }
        !           587:        if ((addr.Addr() & mask) != base) {
        !           588:                return false;
        !           589:        }
        !           590: 
        !           591:        // 一致した。
        !           592:        return true;
        !           593: }
        !           594: 
        !           595: // ATC
        !           596: 
        !           597: // ATC の指定の権限空間をすべて無効にする。
        !           598: void
        !           599: m68040ATC::Flush(bool s, bool only_non_global)
        !           600: {
        !           601:        uint32 target = s ? 0x1000'0000 : 0;
        !           602: 
        !           603:        //  G  only_non_global
        !           604:        // --- ---
        !           605:        //      0       0       invalidate
        !           606:        //      0       1       invalidate
        !           607:        //      1       0       invalidate
        !           608:        //      1       1       nop
        !           609: 
        !           610:        for (auto& set : sets) {
        !           611:                for (auto& entry : set.entry) {
        !           612:                        // S/U と Valid ビットのみ比較。
        !           613:                        if ((entry.tag & 0x1000'0001) == target) {
        !           614:                                if (only_non_global == false || entry.IsGlobal() == false) {
        !           615:                                        entry.Invalidate();
        !           616:                                }
        !           617:                        }
        !           618:                }
        !           619:        }
        !           620: }
        !           621: 
        !           622: // ATC の指定の空間+アドレスを無効にする。
        !           623: void
        !           624: m68040ATC::Flush(busaddr addr, bool only_non_global)
        !           625: {
        !           626:        uint32 tag = (addr.Get() >> 4) & tag_mask;
        !           627: 
        !           628:        for (auto& set : sets) {
        !           629:                for (auto& entry : set.entry) {
        !           630:                        // S/U、アドレス、Valid ビットすべてを比較。
        !           631:                        if (entry.tag == tag) {
        !           632:                                if (only_non_global == false || entry.IsGlobal() == false) {
        !           633:                                        entry.Invalidate();
        !           634:                                }
        !           635:                        }
        !           636:                }
        !           637:        }
        !           638: }
        !           639: 
        !           640: // モニター更新 (68040 ATC)
        !           641: void
        !           642: MPU68040Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
        !           643: {
        !           644:        int x = 62;
        !           645: 
        !           646:        // 0         1         2         3         4         5
        !           647:        // 012345678901234567890123456789012345678901234567890123456789
        !           648:        // IDX TagAddr     PAddr    Stat IDX TagAddr     PAddr    Stat
        !           649:        // [0] S.12345'000 12345'000 --- [1] S.12345'000 12345'000 ---
        !           650: 
        !           651:        screen.Clear();
        !           652:        screen.Puts(0, 0, "<Data ATC>");
        !           653:        screen.Puts(x, 0, "<Instruction ATC>");
        !           654:        for (int i = 0; i < 4; i++) {
        !           655:                screen.Puts(i * 30 + (i & 2), 1, "IDX TagAddr     PAddr    Stat");
        !           656:        }
        !           657:        MonitorUpdateATC1(screen, 0, atc_data.get());
        !           658:        MonitorUpdateATC1(screen, x, atc_inst.get());
        !           659: }
        !           660: 
        !           661: void
        !           662: MPU68040Device::MonitorUpdateATC1(TextScreen& screen, int x,
        !           663:        const m68040ATC *atc)
        !           664: {
        !           665:        int y = 2;
        !           666: 
        !           667:        for (uint i = 0; i < atc->sets.size(); i++) {
        !           668:                const m68040ATCSet& set = atc->sets[i];
        !           669:                screen.Print(x, y, "[%x]", i);
        !           670: 
        !           671:                // 古い順に取り出して 3-0 の順序をつける。(新しい順に表示するため)
        !           672:                int order[4];
        !           673:                uint tmpL = set.LRU;
        !           674:                for (int j = 3; j >= 0; j--) {
        !           675:                        int line = m88200CacheSet::TryGetOldestLine(tmpL);
        !           676:                        order[j] = line;
        !           677:                        tmpL = m88200CacheSet::TryUseLine(tmpL, line);
        !           678:                }
        !           679: 
        !           680:                for (int j = 0; j < set.entry.size(); j++) {
        !           681:                        int line = order[j];
        !           682:                        const m68040ATCEntry& entry = set.entry[line];
        !           683:                        TA attr = entry.IsValid() ? TA::Normal : TA::Disable;
        !           684:                        screen.Print(x + 4, y, attr,
        !           685:                                "%c.%05x'000 %05x'000 %c%c%c",
        !           686:                                (entry.IsSuper() ? 'S' : 'U'),
        !           687:                                ((entry.tag >> 8) & 0xfffff),
        !           688:                                entry.paddr >> 12,
        !           689:                                ((entry.desc & m68040MMU::DESC_G) ? 'G' : '-'),
        !           690:                                ((entry.desc & m68040MMU::DESC_S) ? 'S' : '-'),
        !           691:                                ((entry.desc & m68040MMU::DESC_W) ? 'W' : '-'));
        !           692:                        y++;
        !           693:                }
        !           694: 
        !           695:                if (i == 7) {
        !           696:                        x += 30;
        !           697:                        y = 2;
        !           698:                }
        !           699:        }
        !           700: }

unix.superglobalmegacorp.com

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