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

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: // 読み込みのアドレス変換を行う。
1.1.1.4 ! root       13: busaddr
        !            14: MPU68040Device::TranslateRead(busaddr laddr)
1.1       root       15: {
1.1.1.4 ! root       16:        const m68040TT *tt;
1.1       root       17:        m68040ATC *atc;
                     18: 
                     19:        putlog(3, "TranslateRead  %c.$%08x",
1.1.1.4 ! root       20:                (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr());
1.1       root       21: 
                     22:        // まず TT をチェック。
1.1.1.4 ! root       23:        if (laddr.IsData()) {
1.1       root       24:                atc = atc_data.get();
1.1.1.4 ! root       25:                tt = TTMatch(mmu_dtt, laddr);
1.1       root       26:        } else {
                     27:                atc = atc_inst.get();
1.1.1.4 ! root       28:                tt = TTMatch(mmu_itt, laddr);
1.1       root       29:        }
                     30:        if (tt != NULL) {
                     31:                putlog(3, "TranslateRead  %s matched", tt->GetName());
1.1.1.4 ! root       32:                return laddr;
1.1       root       33:        }
                     34: 
                     35:        // TC がオフならここで終わり。
                     36:        if (__predict_false(mmu_tc->e == false)) {
                     37:                putlog(3, "TranslateRead  TC:E OFF");
1.1.1.4 ! root       38:                return laddr;
1.1       root       39:        }
                     40: 
1.1.1.4 ! root       41:        return LookupATC(*atc, laddr);
1.1       root       42: }
                     43: 
                     44: // 書き込みのアドレス変換を行う。
1.1.1.4 ! root       45: busaddr
        !            46: MPU68040Device::TranslateWrite(busaddr laddr)
1.1       root       47: {
                     48:        putlog(3, "TranslateWrite %c.$%08x",
1.1.1.4 ! root       49:                (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr());
1.1       root       50: 
                     51:        // まず TT をチェック。
1.1.1.4 ! root       52:        const m68040TT *tt = TTMatch(mmu_dtt, laddr);
1.1       root       53:        if (tt) {
                     54:                if (tt->w) {
                     55:                        putlog(3, "TranslateWrite %s matched (WriteProtected)",
                     56:                                tt->GetName());
1.1.1.4 ! root       57:                        return BusAddr::BusErr;
1.1       root       58:                } else {
                     59:                        putlog(3, "TranslateWrite %s matched", tt->GetName());
1.1.1.4 ! root       60:                        return laddr;
1.1       root       61:                }
                     62:        }
                     63: 
                     64:        // TC がオフならここで終わり。
                     65:        if (__predict_false(mmu_tc->e == false)) {
                     66:                putlog(3, "TranslateWrite TC:E OFF");
1.1.1.4 ! root       67:                return laddr;
1.1       root       68:        }
                     69: 
                     70:        m68040ATC *atc = atc_data.get();
1.1.1.4 ! root       71:        return LookupATC(*atc, laddr);
1.1       root       72: }
                     73: 
                     74: // *TTn にマッチすれば、マッチした方のポインタを返す。
                     75: // マッチしなければ NULL を返す。
                     76: m68040TT *
1.1.1.4 ! root       77: MPU68040Device::TTMatch(std::array<std::unique_ptr<m68040TT>, 2>& ttbase,
        !            78:        const busaddr laddr) const
1.1       root       79: {
                     80:        for (int n = 0; n < 2; n++) {
                     81:                m68040TT *tt = ttbase[n].get();
1.1.1.4 ! root       82:                if (tt->Match(laddr)) {
1.1       root       83:                        return tt;
                     84:                }
                     85:        }
                     86:        return NULL;
                     87: }
                     88: 
                     89: // ATC を検索する。
1.1.1.4 ! root       90: busaddr
        !            91: MPU68040Device::LookupATC(m68040ATC& atc, const busaddr laddr)
1.1       root       92: {
                     93:        m68040ATCEntry *entry;
                     94:        uint32 tag;
                     95:        uint32 idx;
                     96:        int n;
                     97: 
                     98:        // ATC のタグに使う論理アドレスはページサイズによって区切る位置が変わる。
                     99:        // インデックスは本来タグの比較には使わないが、
                    100:        // 表示の際にはインデックス部分がないとだいぶ意味が分からないのと、
                    101:        // 4KB/page なら 16進数で下から 4桁目をインデックスで補完出来るからいいが
                    102:        // 8KB/page の時にはつらいので、最初からタグに含めておく。
                    103:        //
                    104:        //      3                   2                   1                   0
                    105:        //    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
                    106:        // +-+-------------------------------+-------+-----------------------+
                    107:        // |S|  Logical Address (16bit)      | Index | Page Offset (4KB/page)|
                    108:        // +-+-------------------------------+-------+-----------------------+
                    109:        // :<-- FC2 + LAddress (+ Index) = 21bit --->:
                    110:        //
                    111:        // +-+-----------------------------+-------+-------------------------+
                    112:        // |S|  Logical Address (15bit)    | Index |   Page Offset (8KB/page)|
                    113:        // +-+-----------------------------+-------+-------------------------+
                    114:        // :<-- FC2 + LAddress (+ Index) = 20bit ->:
                    115:        //
                    116:        // タグはこの位置までシフト(とマスク)したもの。
                    117:        //      3                   2                   1                    0
                    118:        //    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
                    119:        //   +-----+-+---------------------------------------+-------------+--+
                    120:        //   |  0  |S| Logical Address + Index (19/20bit)  : |      0      |~V|
                    121:        //   +-----+-+---------------------------------------+-------------+--+
                    122: 
1.1.1.4 ! root      123:        idx = (laddr.Addr() >> mmu_tc->tic_shift) & 0xf;
        !           124:        tag = (laddr.Get() >> 4) & atc.tag_mask;        // FC2+Addr(+Index)
1.1       root      125:        m68040ATCSet& set = atc.sets[idx];
                    126: 
                    127:        // このセットから探す。
                    128:        for (n = 0; n < set.entry.size(); n++) {
                    129:                entry = &set.entry[n];
                    130:                if (entry->tag == tag) {
1.1.1.4 ! root      131:                        if (entry->MatchStatus(laddr)) {
1.1       root      132:                                // 見付かった。
                    133:                                goto found;
                    134:                        } else {
                    135:                                break;
                    136:                        }
                    137:                }
                    138:        }
                    139: 
                    140:        // 空きラインか、空いてなければ生贄を差し出す。
                    141:        n = set.GetEntry();
                    142:        entry = &set.entry[n];
                    143:        entry->tag = tag;
                    144: 
                    145:        // テーブルサーチを行い、エントリを更新する。
1.1.1.4 ! root      146:        Search(entry, laddr);
1.1       root      147: 
                    148:        // このエントリで再度ステータスが一致するか。(タグは一致している)
1.1.1.4 ! root      149:        if (entry->MatchStatus(laddr) == false) {
1.1       root      150:                putlog(3, " LookupATC entry not matched");
1.1.1.4 ! root      151:                return BusAddr::BusErr;
1.1       root      152:        }
                    153:  found:
1.1.1.4 ! root      154:        // 見付かったのでこれを返す。
1.1       root      155:        set.LRU = m88200CacheSet::TryUseLine(set.LRU, n);
1.1.1.4 ! root      156:        uint32 offset = laddr.Addr() & ~mmu_tc->page_mask;
        !           157:        busaddr paddr = laddr;
        !           158:        paddr.ChangeAddr(entry->paddr | offset);
        !           159:        putlog(3, " result $%08x", paddr.Addr());
        !           160:        return paddr;
1.1       root      161: }
                    162: 
                    163: // laddr がこのエントリの各種ステータスにマッチするか調べる。
                    164: // タグが一致している状態で呼ぶこと。
                    165: bool
                    166: m68040ATCEntry::MatchStatus(busaddr laddr) const
                    167: {
                    168:        if (IsResident() == false) {
                    169:                return false;
                    170:        }
                    171:        if (laddr.IsSuper() == false && IsSuperProtected()) {
                    172:                return false;
                    173:        }
                    174:        if (laddr.IsWrite() && IsWriteProtected()) {
                    175:                return false;
                    176:        }
                    177:        return true;
                    178: }
                    179: 
                    180: // 更新用に空きエントリか、空きがなければどれかを差し出す。
                    181: int
                    182: m68040ATCSet::GetEntry() const
                    183: {
                    184:        for (int i = 0; i < 4; i++) {
                    185:                if (entry[i].IsValid() == false) {
                    186:                        return i;
                    187:                }
                    188:        }
                    189: 
                    190:        int oldest = m88200CacheSet::TryGetOldestLine(LRU);
                    191:        return oldest;
                    192: }
                    193: 
1.1.1.3   root      194: // テーブルサーチを行い、entry を埋める。
                    195: void
1.1.1.4 ! root      196: MPU68040Device::Search(m68040ATCEntry *entry, const busaddr laddr)
1.1       root      197: {
                    198:        uint32 base;
                    199:        uint32 idx;
                    200:        uint32 mask;
                    201:        uint32 addr;
                    202:        uint32 desc;
1.1.1.3   root      203:        uint32 pdt;
                    204:        busdata bd;
                    205:        bool acc_wp = false;
1.1       root      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()) {
1.1.1.4 ! root      376:                tt = TTMatch(mmu_dtt, laddr);
1.1       root      377:        } else {
1.1.1.4 ! root      378:                tt = TTMatch(mmu_itt, laddr);
1.1       root      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
1.1.1.4 ! root      665: MPU68040Device::MonitorScreenATC(Monitor *, TextScreen& screen)
1.1       root      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: 
1.1.1.4 ! root      674:        bool enable = mmu_tc->e;
        !           675:        TA attr_e = enable ? TA::Normal : TA::Disable;
        !           676: 
1.1       root      677:        screen.Clear();
1.1.1.4 ! root      678:        screen.Puts(0, 0, attr_e, "<Data ATC>");
        !           679:        screen.Puts(x, 0, attr_e, "<Instruction ATC>");
1.1       root      680:        for (int i = 0; i < 4; i++) {
1.1.1.3   root      681:                screen.Puts(i * 31 + (i & 2), 1, "IDX TagAddr     PAddr     Stat");
1.1       root      682:        }
1.1.1.4 ! root      683:        MonitorScreenATC1(screen, 0, enable, atc_data.get());
        !           684:        MonitorScreenATC1(screen, x, enable, atc_inst.get());
1.1       root      685: }
                    686: 
                    687: void
1.1.1.4 ! root      688: MPU68040Device::MonitorScreenATC1(TextScreen& screen, int x, bool enable,
1.1       root      689:        const m68040ATC *atc)
                    690: {
                    691:        int y = 2;
1.1.1.4 ! root      692:        TA attr_e = enable ? TA::Normal : TA::Disable;
1.1       root      693: 
                    694:        for (uint i = 0; i < atc->sets.size(); i++) {
                    695:                const m68040ATCSet& set = atc->sets[i];
1.1.1.4 ! root      696:                screen.Print(x, y, attr_e, "[%x]", i);
1.1       root      697: 
                    698:                // 古い順に取り出して 3-0 の順序をつける。(新しい順に表示するため)
                    699:                int order[4];
                    700:                uint tmpL = set.LRU;
                    701:                for (int j = 3; j >= 0; j--) {
                    702:                        int line = m88200CacheSet::TryGetOldestLine(tmpL);
                    703:                        order[j] = line;
                    704:                        tmpL = m88200CacheSet::TryUseLine(tmpL, line);
                    705:                }
                    706: 
                    707:                for (int j = 0; j < set.entry.size(); j++) {
                    708:                        int line = order[j];
                    709:                        const m68040ATCEntry& entry = set.entry[line];
                    710:                        TA attr = entry.IsValid() ? TA::Normal : TA::Disable;
                    711:                        screen.Print(x + 4, y, attr,
1.1.1.3   root      712:                                "%c.%05x'000 %05x'000 %c%c%c%c",
1.1       root      713:                                (entry.IsSuper() ? 'S' : 'U'),
                    714:                                ((entry.tag >> 8) & 0xfffff),
                    715:                                entry.paddr >> 12,
                    716:                                ((entry.desc & m68040MMU::DESC_G) ? 'G' : '-'),
                    717:                                ((entry.desc & m68040MMU::DESC_S) ? 'S' : '-'),
1.1.1.3   root      718:                                ((entry.desc & m68040MMU::DESC_W) ? 'W' : '-'),
                    719:                                ((entry.desc & m68040MMU::DESC_R) ? 'R' : '-'));
1.1       root      720:                        y++;
                    721:                }
                    722: 
                    723:                if (i == 7) {
1.1.1.3   root      724:                        x += 31;
1.1       root      725:                        y = 2;
                    726:                }
                    727:        }
                    728: }

unix.superglobalmegacorp.com

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