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

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:        // テーブルサーチを行い、エントリを更新する。
1.1.1.3 ! root      145:        Search(entry);
1.1       root      146: 
                    147:        // このエントリで再度ステータスが一致するか。(タグは一致している)
                    148:        if (entry->MatchStatus(bus.laddr) == false) {
                    149:                putlog(3, " LookupATC entry not matched");
                    150:                return false;
                    151:        }
                    152:  found:
                    153:        // 見付かったので bus.paddr を更新。
                    154:        set.LRU = m88200CacheSet::TryUseLine(set.LRU, n);
                    155:        uint32 offset = bus.laddr.Addr() & ~mmu_tc->page_mask;
                    156:        bus.paddr.ChangeAddr(entry->paddr | offset);
                    157:        putlog(3, " result $%08x", bus.paddr.Addr());
                    158:        return true;
                    159: }
                    160: 
                    161: // laddr がこのエントリの各種ステータスにマッチするか調べる。
                    162: // タグが一致している状態で呼ぶこと。
                    163: bool
                    164: m68040ATCEntry::MatchStatus(busaddr laddr) const
                    165: {
                    166:        if (IsResident() == false) {
                    167:                return false;
                    168:        }
                    169:        if (laddr.IsSuper() == false && IsSuperProtected()) {
                    170:                return false;
                    171:        }
                    172:        if (laddr.IsWrite() && IsWriteProtected()) {
                    173:                return false;
                    174:        }
                    175:        return true;
                    176: }
                    177: 
                    178: // 更新用に空きエントリか、空きがなければどれかを差し出す。
                    179: int
                    180: m68040ATCSet::GetEntry() const
                    181: {
                    182:        for (int i = 0; i < 4; i++) {
                    183:                if (entry[i].IsValid() == false) {
                    184:                        return i;
                    185:                }
                    186:        }
                    187: 
                    188:        int oldest = m88200CacheSet::TryGetOldestLine(LRU);
                    189:        return oldest;
                    190: }
                    191: 
1.1.1.3 ! root      192: // テーブルサーチを行い、entry を埋める。
        !           193: void
1.1       root      194: MPU68040Device::Search(m68040ATCEntry *entry)
                    195: {
                    196:        uint32 base;
                    197:        uint32 idx;
                    198:        uint32 mask;
                    199:        uint32 addr;
                    200:        uint32 desc;
1.1.1.3 ! root      201:        uint32 pdt;
        !           202:        busdata bd;
        !           203:        bool acc_wp = false;
1.1       root      204: 
                    205:        busaddr laddr = bus.laddr;
                    206:        bool is_write = laddr.IsWrite();
                    207: 
                    208:        putlog(3, " Search %c.$%08x", (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr());
                    209: 
                    210:        // FC2 からルートポインタを決定。
                    211:        // XXX FC2 なのかこれからアクセスする空間の FC なのか。
                    212:        base = laddr.IsSuper() ? reg.srp40 : reg.urp40;
                    213: 
                    214:        // 第1、第2 レベルのディスクリプタを処理。
                    215:        idx = laddr.Addr() >> 25;
                    216:        mask = 0xfffffe00;
                    217:        for (int lv = 0; lv < 2; lv++) {
                    218:                addr = base + idx * 4;
1.1.1.3 ! root      219:                putlog(4, "  base=$%08x [$%02x] descaddr=$%08x", base, idx, addr);
1.1       root      220: 
1.1.1.3 ! root      221:                bd = read_phys_4(addr);
1.1       root      222:                if (__predict_false(bd.IsBusErr())) {
                    223:                        putlog(4, "  BusErr (on read desc)");
1.1.1.3 ! root      224:                        // エラーなので R を落としたエントリを作成。
        !           225:                        desc = 0;
        !           226:                        goto done;
1.1       root      227:                }
                    228:                desc = bd.Data();
                    229: 
                    230:                if (__predict_false(loglevel >= 4)) {
                    231:                        static const char *udtname[] = {
                    232:                                "Invalid", "Invalid", "Resident", "Resident",
                    233:                        };
                    234:                        uint32 dt = desc & m68040MMU::DESC_DT;
1.1.1.3 ! root      235:                        putlogn("  desc=$%08x %c%c UDT%u(%s)", desc,
1.1       root      236:                                ((desc & m68040MMU::DESC_U) ? 'U' : '-'),
                    237:                                ((desc & m68040MMU::DESC_W) ? 'W' : '-'),
                    238:                                dt, udtname[dt]);
                    239:                }
                    240: 
1.1.1.3 ! root      241:                // ここから Fig. 3-10 左下あたり。
        !           242: 
1.1       root      243:                // UDT はビット1 が %0 なら無効。
                    244:                if ((desc & 2) == 0) {
                    245:                        putlog(4, "  invalid");
1.1.1.3 ! root      246:                        // R を落としたエントリを作成。(Fig. 3-9)
        !           247:                        // UDT の Resident はビット1だが、desc の Resident はビット0。
        !           248:                        desc &= ~m68040MMU::DESC_R;
        !           249:                        goto done;
        !           250:                }
        !           251: 
        !           252:                // WP を積算。
        !           253:                if ((desc & m68040MMU::DESC_W) != 0) {
        !           254:                        acc_wp = true;
1.1       root      255:                }
                    256: 
                    257:                // U が立ってなければ U を立てて更新。
1.1.1.3 ! root      258:                // 実際には次のタイミングに遅延するらしいが。
1.1       root      259:                if ((desc & m68040MMU::DESC_U) == 0) {
                    260:                        desc |= m68040MMU::DESC_U;
                    261:                        bd = write_phys_4(addr, desc);
                    262:                        if (__predict_false(bd.IsBusErr())) {
                    263:                                putlog(4, "  BusErr (on writeback U)");
1.1.1.3 ! root      264:                                // エラーなので R を落としたエントリを作成。
        !           265:                                desc &= ~m68040MMU::DESC_R;
        !           266:                                goto done;
1.1       root      267:                        }
                    268:                }
                    269: 
                    270:                // 次の段へ。
                    271:                base = desc & mask;
                    272:                idx = (laddr.Addr() >> 18) & 0x7f;
                    273:                mask = mmu_tc->table_mask;
                    274:        }
                    275: 
                    276:        // ページディスクリプタを処理。
                    277:        idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask;
                    278:        addr = base + idx * 4;
1.1.1.3 ! root      279:        putlog(4, "  base=$%08x [$%02x] descaddr=$%08x", base, idx, addr);
        !           280:        bd = read_phys_4(addr);
1.1       root      281:        if (__predict_false(bd.IsBusErr())) {
                    282:                putlog(4, "  BusErr (on read desc)");
1.1.1.3 ! root      283:                // エラーなので R を落としたエントリを作成。
        !           284:                desc &= ~m68040MMU::DESC_R;
        !           285:                goto done;
1.1       root      286:        }
                    287:        desc = bd.Data();
1.1.1.3 ! root      288:        pdt = desc & m68040MMU::DESC_DT;
1.1       root      289: 
                    290:        if (__predict_false(loglevel >= 4)) {
                    291:                static const char *pdtname[] = {
1.1.1.3 ! root      292:                        "Invalid", "Resident", "INDIRECT", "Resident",
1.1       root      293:                };
1.1.1.3 ! root      294:                putlogn("  desc=$%08x %c%c%c%c%c CM%u PDT%u(%s)", desc,
1.1       root      295:                        ((desc & m68040MMU::DESC_G) ? 'G' : '-'),
                    296:                        ((desc & m68040MMU::DESC_S) ? 'S' : '-'),
                    297:                        ((desc & m68040MMU::DESC_M) ? 'M' : '-'),
                    298:                        ((desc & m68040MMU::DESC_U) ? 'U' : '-'),
                    299:                        ((desc & m68040MMU::DESC_W) ? 'W' : '-'),
                    300:                        ((desc & m68040MMU::DESC_CM) >> 5),
                    301:                        pdt, pdtname[pdt]);
                    302:        }
                    303: 
1.1.1.3 ! root      304:        // ここから Fig. 3-10 右下あたり。
        !           305: 
        !           306:        // PDT は %00 なら無効。この場合エントリは作成しない。
1.1       root      307:        if (__predict_false(pdt == m68040MMU::PDT_INVALID)) {
                    308:                putlog(4, "  invalid");
1.1.1.3 ! root      309:                // R を落としたエントリを作成。(Fig. 3-9)
        !           310:                desc &= ~m68040MMU::DESC_R;
        !           311:                goto done;
1.1       root      312:        } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) {
                    313:                PANIC("indirect descriptor");
                    314:        }
                    315: 
1.1.1.3 ! root      316:        // WP を積算。
        !           317:        if ((desc & m68040MMU::DESC_W) != 0) {
        !           318:                acc_wp = true;
        !           319:        }
        !           320: 
1.1       root      321:        if (__predict_true(is_write == false)) {
1.1.1.3 ! root      322:                // READ ACCESS
1.1       root      323:                if ((desc & m68040MMU::DESC_U) == 0) {
                    324:                        desc |= m68040MMU::DESC_U;
1.1.1.3 ! root      325:                        // 本当は Read-Modify-Write。
1.1       root      326:                        bd = write_phys_4(addr, desc);
                    327:                        if (__predict_false(bd.IsBusErr())) {
                    328:                                putlog(4, "  BusErr (on writeback U)");
1.1.1.3 ! root      329:                                // エラーなので R を落としたエントリを作成。
        !           330:                                desc &= ~m68040MMU::DESC_R;
        !           331:                                goto done;
1.1       root      332:                        }
                    333:                }
                    334:        } else {
1.1.1.3 ! root      335:                // WRITE ACCESS
1.1       root      336:                uint32 olddesc = desc;
1.1.1.3 ! root      337:                if (acc_wp == false && (desc & m68040MMU::DESC_M) == 0) {
        !           338:                        desc |= m68040MMU::DESC_U | m68040MMU::DESC_M;
        !           339:                } else if ((desc & m68040MMU::DESC_U) == 0) {
1.1       root      340:                        desc |= m68040MMU::DESC_U;
1.1.1.3 ! root      341:                        // こっちの場合は本当は Read-Modify-Write。
1.1       root      342:                }
1.1.1.3 ! root      343:                if (__predict_false(olddesc != desc)) {
1.1       root      344:                        bd = write_phys_4(addr, desc);
                    345:                        if (__predict_false(bd.IsBusErr())) {
                    346:                                putlog(4, "  BusErr (on writeback U)");
1.1.1.3 ! root      347:                                // エラーなので R を落としたエントリを作成。
        !           348:                                desc &= ~m68040MMU::DESC_R;
        !           349:                                goto done;
1.1       root      350:                        }
                    351:                }
                    352:        }
                    353: 
1.1.1.3 ! root      354:  done:
1.1       root      355:        entry->paddr = desc & mmu_tc->page_mask;
                    356:        entry->desc  = desc;
1.1.1.3 ! root      357:        if (__predict_false(loglevel >= 3)) {
        !           358:                if ((entry->desc & m68040MMU::DESC_R)) {
        !           359:                        putlogn("  frame addr $%08x", entry->paddr);
        !           360:                } else {
        !           361:                        putlogn("  Not Resident");
        !           362:                }
        !           363:        }
1.1       root      364: }
                    365: 
                    366: // ピーク用のアドレス変換を行う。
                    367: // 変換できれば対応する物理アドレスを、バスエラーなら BusErr を返す。
                    368: // テーブルサーチを行ったら TableSearched ビットを立てる。
                    369: busaddr
                    370: MPU68040Device::TranslatePeek(busaddr laddr)
                    371: {
                    372:        const m68040TT *tt;
                    373: 
                    374:        // TT を自前でサーチ。
                    375:        if (laddr.IsData()) {
                    376:                tt = CheckTT(mmu_dtt);
                    377:        } else {
                    378:                tt = CheckTT(mmu_itt);
                    379:        }
                    380:        if (__predict_false(tt != NULL)) {
                    381:                if (tt->Match(laddr)) {
                    382:                        return laddr;
                    383:                }
                    384:        }
                    385: 
                    386:        if (__predict_false(mmu_tc->e == false)) {
                    387:                return laddr;
                    388:        }
                    389: 
                    390:        // ATC を自前でサーチ。
                    391:        const m68040ATC *atc;
                    392:        if (laddr.IsData()) {
                    393:                atc = atc_data.get();
                    394:        } else {
                    395:                atc = atc_inst.get();
                    396:        }
                    397:        uint32 idx = (laddr.Addr() >> mmu_tc->tic_shift) & 0xf;
                    398:        uint32 tag = (laddr.Get() >> 4) & atc->tag_mask;        // FC2+Addr(+Index)
                    399:        const m68040ATCSet& set = atc->sets[idx];
                    400:        for (const auto& entry : set.entry) {
                    401:                if (entry.tag == tag) {
                    402:                        if (entry.MatchStatus(laddr)) {
                    403:                                // 見付かった。
                    404:                                uint32 offset = laddr.Addr() & ~mmu_tc->page_mask;
                    405:                                laddr.ChangeAddr(entry.paddr | offset);
                    406:                                return laddr;
                    407:                        } else {
                    408:                                break;
                    409:                        }
                    410:                }
                    411:        }
                    412: 
                    413:        // ATC になければ、テーブルサーチ相当を自前で行う。
                    414:        laddr |= BusAddr::TableSearched;
                    415:        bool is_write = laddr.IsWrite();
                    416:        uint32 desc;
                    417: 
                    418:        // FC2 からルートポインタを決定。
                    419:        uint32 base = laddr.IsSuper() ? reg.srp40 : reg.urp40;
                    420: 
                    421:        // 第1レベル。
                    422:        idx = laddr.Addr() >> 25;
                    423:        desc = PeekDesc(base, idx);
                    424:        // UDT はビット1 が %0 なら無効。
                    425:        if ((desc & 2) == 0) {
                    426:                return BusAddr::BusErr;
                    427:        }
                    428:        if (__predict_false(is_write) && (desc & 4)) {
                    429:                return BusAddr::BusErr;
                    430:        }
                    431:        base = desc & 0xfffffe00;
                    432: 
                    433:        // 第2レベル。
                    434:        idx = (laddr.Addr() >> 18) & 0x7f;
                    435:        desc = PeekDesc(base, idx);
                    436:        // UDT はビット1 が %0 なら無効。
                    437:        if ((desc & 2) == 0) {
                    438:                return BusAddr::BusErr;
                    439:        }
                    440:        if (__predict_false(is_write) && (desc & 4)) {
                    441:                return BusAddr::BusErr;
                    442:        }
                    443:        base = desc & mmu_tc->table_mask;
                    444: 
                    445:        // ページディスクリプタ。
                    446:        idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask;
                    447:        desc = PeekDesc(base, idx);
                    448:        // PDT は %00 なら無効。
                    449:        uint32 pdt = desc & m68040MMU::DESC_DT;
                    450:        if (pdt == m68040MMU::PDT_INVALID) {
                    451:                return BusAddr::BusErr;
                    452:        } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) {
                    453:                PANIC("indirect descriptor");
                    454:        }
                    455:        if (__predict_false(is_write) && (desc & 4)) {
                    456:                return BusAddr::BusErr;
                    457:        }
                    458: 
                    459:        uint32 paddr = (desc & mmu_tc->page_mask)
                    460:                | (laddr.Addr() & ~mmu_tc->page_mask);
                    461:        laddr.ChangeAddr(paddr);
                    462:        return laddr;
                    463: }
                    464: 
                    465: // base[idx] からディスクリプタを副作用なく読み出す。(デバッガ用)
                    466: // U フラグは更新しない。
                    467: // バスエラーが起きれば 0 を返す (ディスクリプタの下位2ビットが %00 なら
                    468: // 無効を示すので)。
                    469: uint32
                    470: MPU68040Device::PeekDesc(uint32 base, uint32 idx)
                    471: {
                    472:        uint32 addr = base + idx * 4;
                    473:        uint64 data = mainbus->Peek4(addr);
                    474:        if ((int64)data < 0) {
                    475:                return 0;
                    476:        }
                    477:        return data;
                    478: }
                    479: 
                    480: // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。
                    481: // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp
                    482: void
                    483: MPU68040Device::mmu_enable_changed()
                    484: {
                    485:        bool enable;
                    486: 
                    487:        // TC、ITT*、DTT* のいずれかが有効ならアドレス変換あり。
                    488:        enable  = (reg.tc40 & m68040TC::E);
                    489:        enable |= mmu_itt[0]->e || mmu_itt[1]->e;
                    490:        enable |= mmu_dtt[0]->e || mmu_dtt[1]->e;
                    491: 
                    492:        // 変化した時だけ
                    493:        if (mmu_enable && !enable) {
                    494:                // 無効にする
                    495:                mmu_enable = false;
                    496:                putlog(1, "MMU Translation Disabled");
                    497:        } else if (!mmu_enable && enable) {
                    498:                // 有効にする
                    499:                mmu_enable = true;
                    500:                putlog(1, "MMU Translation Enabled");
                    501:        }
                    502: }
                    503: 
                    504: // *TTn レジスタへの書き込み。
                    505: void
                    506: MPU68040Device::SetTT(m68040TT *tt, uint32 data)
                    507: {
                    508:        *tt->reg  = (data & m68040TT::MASK);
                    509:        putlog(1, "%s <- $%08x", tt->GetName(), *tt->reg);
                    510: 
                    511:        tt->base  = (data & m68040TT::LBASE_MASK);
                    512:        tt->mask  = (~data & m68040TT::LMASK_MASK) << 8;
                    513:        tt->e     = (data & m68040TT::E);
                    514:        tt->s_ign = (data & m68040TT::S_IGN);
                    515:        tt->s_fc2 = (data & m68040TT::S_FC2);
                    516:        tt->u     = (data & m68040TT::U_MASK);
                    517:        tt->cm    = (data & m68040TT::CM) >> 5;
                    518:        tt->w     = (data & m68040TT::W);
                    519: 
                    520:        mmu_enable_changed();
                    521: }
                    522: 
                    523: void
                    524: MPU68040Device::SetSRP(uint32 data)
                    525: {
                    526:        // とりあえず
                    527:        reg.srp40 = data & m68040RP::ADDR_MASK;
                    528:        putlog(1, "SRP <- $%08x", reg.srp40);
                    529: }
                    530: 
                    531: void
                    532: MPU68040Device::SetURP(uint32 data)
                    533: {
                    534:        // とりあえず
                    535:        reg.urp40 = data & m68040RP::ADDR_MASK;
1.1.1.2   root      536:        putlog(2, "URP <- $%08x", reg.urp40);
1.1       root      537: }
                    538: 
                    539: void
                    540: MPU68040Device::SetTC(uint32 data)
                    541: {
                    542:        // とりあえず
                    543:        reg.tc40 = data & m68040TC::MASK;
                    544:        putlog(1, "TC <- $%04x", reg.tc40);
                    545: 
                    546:        mmu_tc->e = reg.tc40 & m68040TC::E;
                    547:        if ((reg.tc40 & m68040TC::P) == 0) {
                    548:                // 4KB/page
                    549:                mmu_tc->ps4k = true;
                    550:                mmu_tc->table_mask = 0xffffff00;
                    551:                mmu_tc->tic_shift  = 12;
                    552:                mmu_tc->tic_mask   = 0x0000003f;
                    553:                mmu_tc->page_mask  = 0xfffff000;
                    554:        } else {
                    555:                // 8KB/page
                    556:                mmu_tc->ps4k = false;
                    557:                mmu_tc->table_mask = 0xffffff80;
                    558:                mmu_tc->tic_shift  = 13;
                    559:                mmu_tc->tic_mask   = 0x0000001f;
                    560:                mmu_tc->page_mask  = 0xffffe000;
                    561:        }
                    562: 
                    563:        // ページサイズと連動している ATC の変数もセット。
                    564:        uint32 tag_mask = (mmu_tc->page_mask >> 4) | 0x1000'0000;
                    565:        atc_inst->tag_mask = tag_mask;
                    566:        atc_data->tag_mask = tag_mask;
                    567: 
                    568:        mmu_enable_changed();
                    569: }
                    570: 
                    571: // リセット例外の CPU 固有部分。
                    572: void
                    573: MPU68040Device::ResetMMU()
                    574: {
                    575:        mmu_tc->e = false;
                    576:        mmu_itt[0]->e = false;
                    577:        mmu_itt[1]->e = false;
                    578:        mmu_dtt[0]->e = false;
                    579:        mmu_dtt[1]->e = false;
                    580: 
                    581:        // ATC は影響を受けない。
                    582: }
                    583: 
                    584: // *TT
                    585: 
                    586: // コンストラクタ
                    587: m68040TT::m68040TT(const char *name_, uint32 *reg_)
                    588: {
                    589:        name = name_;
                    590:        reg  = reg_;
                    591: }
                    592: 
                    593: // デストラクタ
                    594: m68040TT::~m68040TT()
                    595: {
                    596: }
                    597: 
                    598: // addr がマッチすれば true を返す。
                    599: bool
                    600: m68040TT::Match(busaddr addr) const
                    601: {
                    602:        if (__predict_true(e == false)) {
                    603:                return false;
                    604:        }
                    605:        if (s_ign == false) {
                    606:                if (addr.IsSuper() != s_fc2) {
                    607:                        return false;
                    608:                }
                    609:        }
                    610:        if ((addr.Addr() & mask) != base) {
                    611:                return false;
                    612:        }
                    613: 
                    614:        // 一致した。
                    615:        return true;
                    616: }
                    617: 
                    618: // ATC
                    619: 
                    620: // ATC の指定の権限空間をすべて無効にする。
                    621: void
                    622: m68040ATC::Flush(bool s, bool only_non_global)
                    623: {
                    624:        uint32 target = s ? 0x1000'0000 : 0;
                    625: 
                    626:        //  G  only_non_global
                    627:        // --- ---
                    628:        //      0       0       invalidate
                    629:        //      0       1       invalidate
                    630:        //      1       0       invalidate
                    631:        //      1       1       nop
                    632: 
                    633:        for (auto& set : sets) {
                    634:                for (auto& entry : set.entry) {
                    635:                        // S/U と Valid ビットのみ比較。
                    636:                        if ((entry.tag & 0x1000'0001) == target) {
                    637:                                if (only_non_global == false || entry.IsGlobal() == false) {
                    638:                                        entry.Invalidate();
                    639:                                }
                    640:                        }
                    641:                }
                    642:        }
                    643: }
                    644: 
                    645: // ATC の指定の空間+アドレスを無効にする。
                    646: void
                    647: m68040ATC::Flush(busaddr addr, bool only_non_global)
                    648: {
                    649:        uint32 tag = (addr.Get() >> 4) & tag_mask;
                    650: 
                    651:        for (auto& set : sets) {
                    652:                for (auto& entry : set.entry) {
                    653:                        // S/U、アドレス、Valid ビットすべてを比較。
                    654:                        if (entry.tag == tag) {
                    655:                                if (only_non_global == false || entry.IsGlobal() == false) {
                    656:                                        entry.Invalidate();
                    657:                                }
                    658:                        }
                    659:                }
                    660:        }
                    661: }
                    662: 
                    663: // モニター更新 (68040 ATC)
                    664: void
                    665: MPU68040Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
                    666: {
1.1.1.3 ! root      667:        int x = 64;
1.1       root      668: 
                    669:        // 0         1         2         3         4         5
1.1.1.3 ! root      670:        // 0123456789012345678901234567890123456789012345678901234567890
        !           671:        // IDX TagAddr     PAddr     Stat IDX TagAddr     PAddr     Stat
        !           672:        // [0] S.12345'000 12345'000 ---- [1] S.12345'000 12345'000 ----
1.1       root      673: 
                    674:        screen.Clear();
                    675:        screen.Puts(0, 0, "<Data ATC>");
                    676:        screen.Puts(x, 0, "<Instruction ATC>");
                    677:        for (int i = 0; i < 4; i++) {
1.1.1.3 ! root      678:                screen.Puts(i * 31 + (i & 2), 1, "IDX TagAddr     PAddr     Stat");
1.1       root      679:        }
                    680:        MonitorUpdateATC1(screen, 0, atc_data.get());
                    681:        MonitorUpdateATC1(screen, x, atc_inst.get());
                    682: }
                    683: 
                    684: void
                    685: MPU68040Device::MonitorUpdateATC1(TextScreen& screen, int x,
                    686:        const m68040ATC *atc)
                    687: {
                    688:        int y = 2;
                    689: 
                    690:        for (uint i = 0; i < atc->sets.size(); i++) {
                    691:                const m68040ATCSet& set = atc->sets[i];
                    692:                screen.Print(x, y, "[%x]", i);
                    693: 
                    694:                // 古い順に取り出して 3-0 の順序をつける。(新しい順に表示するため)
                    695:                int order[4];
                    696:                uint tmpL = set.LRU;
                    697:                for (int j = 3; j >= 0; j--) {
                    698:                        int line = m88200CacheSet::TryGetOldestLine(tmpL);
                    699:                        order[j] = line;
                    700:                        tmpL = m88200CacheSet::TryUseLine(tmpL, line);
                    701:                }
                    702: 
                    703:                for (int j = 0; j < set.entry.size(); j++) {
                    704:                        int line = order[j];
                    705:                        const m68040ATCEntry& entry = set.entry[line];
                    706:                        TA attr = entry.IsValid() ? TA::Normal : TA::Disable;
                    707:                        screen.Print(x + 4, y, attr,
1.1.1.3 ! root      708:                                "%c.%05x'000 %05x'000 %c%c%c%c",
1.1       root      709:                                (entry.IsSuper() ? 'S' : 'U'),
                    710:                                ((entry.tag >> 8) & 0xfffff),
                    711:                                entry.paddr >> 12,
                    712:                                ((entry.desc & m68040MMU::DESC_G) ? 'G' : '-'),
                    713:                                ((entry.desc & m68040MMU::DESC_S) ? 'S' : '-'),
1.1.1.3 ! root      714:                                ((entry.desc & m68040MMU::DESC_W) ? 'W' : '-'),
        !           715:                                ((entry.desc & m68040MMU::DESC_R) ? 'R' : '-'));
1.1       root      716:                        y++;
                    717:                }
                    718: 
                    719:                if (i == 7) {
1.1.1.3 ! root      720:                        x += 31;
1.1       root      721:                        y = 2;
                    722:                }
                    723:        }
                    724: }

unix.superglobalmegacorp.com

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