--- nono/m680x0/m68040mmu.cpp 2026/04/29 17:05:31 1.1 +++ nono/m680x0/m68040mmu.cpp 2026/04/29 17:05:57 1.1.1.4 @@ -10,75 +10,76 @@ #include "m88200.h" // 読み込みのアドレス変換を行う。 -bool -MPU68040Device::TranslateRead() +busaddr +MPU68040Device::TranslateRead(busaddr laddr) { - m68040TT *tt; + const m68040TT *tt; m68040ATC *atc; putlog(3, "TranslateRead %c.$%08x", - (bus.laddr.IsSuper() ? 'S' : 'U'), bus.laddr.Addr()); + (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr()); // まず TT をチェック。 - if (bus.laddr.IsData()) { + if (laddr.IsData()) { atc = atc_data.get(); - tt = CheckTT(mmu_dtt); + tt = TTMatch(mmu_dtt, laddr); } else { atc = atc_inst.get(); - tt = CheckTT(mmu_itt); + tt = TTMatch(mmu_itt, laddr); } if (tt != NULL) { putlog(3, "TranslateRead %s matched", tt->GetName()); - return true; + return laddr; } // TC がオフならここで終わり。 if (__predict_false(mmu_tc->e == false)) { putlog(3, "TranslateRead TC:E OFF"); - return true; + return laddr; } - return LookupATC(*atc); + return LookupATC(*atc, laddr); } // 書き込みのアドレス変換を行う。 -bool -MPU68040Device::TranslateWrite() +busaddr +MPU68040Device::TranslateWrite(busaddr laddr) { putlog(3, "TranslateWrite %c.$%08x", - (bus.laddr.IsSuper() ? 'S' : 'U'), bus.laddr.Addr()); + (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr()); // まず TT をチェック。 - m68040TT *tt = CheckTT(mmu_dtt); + const m68040TT *tt = TTMatch(mmu_dtt, laddr); if (tt) { if (tt->w) { putlog(3, "TranslateWrite %s matched (WriteProtected)", tt->GetName()); - return false; + return BusAddr::BusErr; } else { putlog(3, "TranslateWrite %s matched", tt->GetName()); - return true; + return laddr; } } // TC がオフならここで終わり。 if (__predict_false(mmu_tc->e == false)) { putlog(3, "TranslateWrite TC:E OFF"); - return true; + return laddr; } m68040ATC *atc = atc_data.get(); - return LookupATC(*atc); + return LookupATC(*atc, laddr); } // *TTn にマッチすれば、マッチした方のポインタを返す。 // マッチしなければ NULL を返す。 m68040TT * -MPU68040Device::CheckTT(std::array, 2>& ttbase) const +MPU68040Device::TTMatch(std::array, 2>& ttbase, + const busaddr laddr) const { for (int n = 0; n < 2; n++) { m68040TT *tt = ttbase[n].get(); - if (tt->Match(bus.laddr)) { + if (tt->Match(laddr)) { return tt; } } @@ -86,8 +87,8 @@ MPU68040Device::CheckTT(std::array> mmu_tc->tic_shift) & 0xf; - tag = (bus.laddr.Get() >> 4) & atc.tag_mask; // FC2+Addr(+Index) + idx = (laddr.Addr() >> mmu_tc->tic_shift) & 0xf; + tag = (laddr.Get() >> 4) & atc.tag_mask; // FC2+Addr(+Index) m68040ATCSet& set = atc.sets[idx]; // このセットから探す。 for (n = 0; n < set.entry.size(); n++) { entry = &set.entry[n]; if (entry->tag == tag) { - if (entry->MatchStatus(bus.laddr)) { + if (entry->MatchStatus(laddr)) { // 見付かった。 goto found; } else { @@ -142,25 +143,21 @@ MPU68040Device::LookupATC(m68040ATC& atc entry->tag = tag; // テーブルサーチを行い、エントリを更新する。 - // (true なら entry を埋めて帰ってきてる) - if (Search(entry) == false) { - entry->Invalidate(); - putlog(3, " LookupATC invalid"); - return false; - } + Search(entry, laddr); // このエントリで再度ステータスが一致するか。(タグは一致している) - if (entry->MatchStatus(bus.laddr) == false) { + if (entry->MatchStatus(laddr) == false) { putlog(3, " LookupATC entry not matched"); - return false; + return BusAddr::BusErr; } found: - // 見付かったので bus.paddr を更新。 + // 見付かったのでこれを返す。 set.LRU = m88200CacheSet::TryUseLine(set.LRU, n); - uint32 offset = bus.laddr.Addr() & ~mmu_tc->page_mask; - bus.paddr.ChangeAddr(entry->paddr | offset); - putlog(3, " result $%08x", bus.paddr.Addr()); - return true; + uint32 offset = laddr.Addr() & ~mmu_tc->page_mask; + busaddr paddr = laddr; + paddr.ChangeAddr(entry->paddr | offset); + putlog(3, " result $%08x", paddr.Addr()); + return paddr; } // laddr がこのエントリの各種ステータスにマッチするか調べる。 @@ -194,19 +191,18 @@ m68040ATCSet::GetEntry() const return oldest; } -// テーブルサーチを行う。 -// 成功すると entry を埋めて true を返す。 -// 失敗すると false を返す (呼び出し側で entry を無効にすること)。 -bool -MPU68040Device::Search(m68040ATCEntry *entry) +// テーブルサーチを行い、entry を埋める。 +void +MPU68040Device::Search(m68040ATCEntry *entry, const busaddr laddr) { uint32 base; uint32 idx; uint32 mask; uint32 addr; uint32 desc; - - busaddr laddr = bus.laddr; + uint32 pdt; + busdata bd; + bool acc_wp = false; bool is_write = laddr.IsWrite(); putlog(3, " Search %c.$%08x", (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr()); @@ -220,12 +216,14 @@ MPU68040Device::Search(m68040ATCEntry *e mask = 0xfffffe00; for (int lv = 0; lv < 2; lv++) { addr = base + idx * 4; - putlog(4, " root=$%08x [$%02x] descaddr=$%08x", base, idx, addr); + putlog(4, " base=$%08x [$%02x] descaddr=$%08x", base, idx, addr); - busdata bd = read_phys_4(addr); + bd = read_phys_4(addr); if (__predict_false(bd.IsBusErr())) { putlog(4, " BusErr (on read desc)"); - return false; + // エラーなので R を落としたエントリを作成。 + desc = 0; + goto done; } desc = bd.Data(); @@ -234,33 +232,41 @@ MPU68040Device::Search(m68040ATCEntry *e "Invalid", "Invalid", "Resident", "Resident", }; uint32 dt = desc & m68040MMU::DESC_DT; - putlogn(" desc=$%08x %c%c DT%u(%s)", desc, + putlogn(" desc=$%08x %c%c UDT%u(%s)", desc, ((desc & m68040MMU::DESC_U) ? 'U' : '-'), ((desc & m68040MMU::DESC_W) ? 'W' : '-'), dt, udtname[dt]); } + // ここから Fig. 3-10 左下あたり。 + // UDT はビット1 が %0 なら無効。 if ((desc & 2) == 0) { putlog(4, " invalid"); - return false; + // R を落としたエントリを作成。(Fig. 3-9) + // UDT の Resident はビット1だが、desc の Resident はビット0。 + desc &= ~m68040MMU::DESC_R; + goto done; + } + + // WP を積算。 + if ((desc & m68040MMU::DESC_W) != 0) { + acc_wp = true; } // U が立ってなければ U を立てて更新。 + // 実際には次のタイミングに遅延するらしいが。 if ((desc & m68040MMU::DESC_U) == 0) { desc |= m68040MMU::DESC_U; bd = write_phys_4(addr, desc); if (__predict_false(bd.IsBusErr())) { putlog(4, " BusErr (on writeback U)"); - return false; + // エラーなので R を落としたエントリを作成。 + desc &= ~m68040MMU::DESC_R; + goto done; } } - if (__predict_false(is_write) && (desc & m68040MMU::DESC_W)) { - putlog(4, " write protected"); - return false; - } - // 次の段へ。 base = desc & mask; idx = (laddr.Addr() >> 18) & 0x7f; @@ -270,20 +276,22 @@ MPU68040Device::Search(m68040ATCEntry *e // ページディスクリプタを処理。 idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask; addr = base + idx * 4; - putlog(4, " root=$%08x [$%02x] descaddr=$%08x", base, idx, addr); - busdata bd = read_phys_4(addr); + putlog(4, " base=$%08x [$%02x] descaddr=$%08x", base, idx, addr); + bd = read_phys_4(addr); if (__predict_false(bd.IsBusErr())) { putlog(4, " BusErr (on read desc)"); - return false; + // エラーなので R を落としたエントリを作成。 + desc &= ~m68040MMU::DESC_R; + goto done; } desc = bd.Data(); - uint32 pdt = desc & m68040MMU::DESC_DT; + pdt = desc & m68040MMU::DESC_DT; if (__predict_false(loglevel >= 4)) { static const char *pdtname[] = { - "Invalid", "Resident", "Indirect", "Resident", + "Invalid", "Resident", "INDIRECT", "Resident", }; - putlogn(" desc=$%08x %c%c%c%c%c CM%u DT%u(%s)", desc, + putlogn(" desc=$%08x %c%c%c%c%c CM%u PDT%u(%s)", desc, ((desc & m68040MMU::DESC_G) ? 'G' : '-'), ((desc & m68040MMU::DESC_S) ? 'S' : '-'), ((desc & m68040MMU::DESC_M) ? 'M' : '-'), @@ -293,51 +301,66 @@ MPU68040Device::Search(m68040ATCEntry *e pdt, pdtname[pdt]); } - // PDT は %00 なら無効。 + // ここから Fig. 3-10 右下あたり。 + + // PDT は %00 なら無効。この場合エントリは作成しない。 if (__predict_false(pdt == m68040MMU::PDT_INVALID)) { putlog(4, " invalid"); - return false; + // R を落としたエントリを作成。(Fig. 3-9) + desc &= ~m68040MMU::DESC_R; + goto done; } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) { PANIC("indirect descriptor"); } + // WP を積算。 + if ((desc & m68040MMU::DESC_W) != 0) { + acc_wp = true; + } + if (__predict_true(is_write == false)) { - // 読み込みなら、U を立てるかどうか。 + // READ ACCESS if ((desc & m68040MMU::DESC_U) == 0) { desc |= m68040MMU::DESC_U; + // 本当は Read-Modify-Write。 bd = write_phys_4(addr, desc); if (__predict_false(bd.IsBusErr())) { putlog(4, " BusErr (on writeback U)"); - return false; + // エラーなので R を落としたエントリを作成。 + desc &= ~m68040MMU::DESC_R; + goto done; } } } else { - // 書き込みなら、U と M と WP。 + // WRITE ACCESS uint32 olddesc = desc; - if ((desc & m68040MMU::DESC_U) == 0) { + if (acc_wp == false && (desc & m68040MMU::DESC_M) == 0) { + desc |= m68040MMU::DESC_U | m68040MMU::DESC_M; + } else if ((desc & m68040MMU::DESC_U) == 0) { desc |= m68040MMU::DESC_U; + // こっちの場合は本当は Read-Modify-Write。 } - if ((desc & (m68040MMU::DESC_M | m68040MMU::DESC_W)) == 0) { - desc |= m68040MMU::DESC_M; - } - if (olddesc != desc) { + if (__predict_false(olddesc != desc)) { bd = write_phys_4(addr, desc); if (__predict_false(bd.IsBusErr())) { putlog(4, " BusErr (on writeback U)"); - return false; + // エラーなので R を落としたエントリを作成。 + desc &= ~m68040MMU::DESC_R; + goto done; } } - - if ((desc & m68040MMU::DESC_W)) { - putlog(4, " write protected"); - return false; - } } + done: entry->paddr = desc & mmu_tc->page_mask; entry->desc = desc; - putlog(3, " frame addr $%08x", entry->paddr); - return true; + if (__predict_false(loglevel >= 3)) { + if ((entry->desc & m68040MMU::DESC_R)) { + putlogn(" frame addr $%08x", entry->paddr); + } else { + putlogn(" Not Resident"); + } + } } // ピーク用のアドレス変換を行う。 @@ -350,9 +373,9 @@ MPU68040Device::TranslatePeek(busaddr la // TT を自前でサーチ。 if (laddr.IsData()) { - tt = CheckTT(mmu_dtt); + tt = TTMatch(mmu_dtt, laddr); } else { - tt = CheckTT(mmu_itt); + tt = TTMatch(mmu_itt, laddr); } if (__predict_false(tt != NULL)) { if (tt->Match(laddr)) { @@ -510,7 +533,7 @@ MPU68040Device::SetURP(uint32 data) { // とりあえず reg.urp40 = data & m68040RP::ADDR_MASK; - putlog(1, "URP <- $%08x", reg.urp40); + putlog(2, "URP <- $%08x", reg.urp40); } void @@ -639,34 +662,38 @@ m68040ATC::Flush(busaddr addr, bool only // モニター更新 (68040 ATC) void -MPU68040Device::MonitorUpdateATC(Monitor *, TextScreen& screen) +MPU68040Device::MonitorScreenATC(Monitor *, TextScreen& screen) { - int x = 62; + int x = 64; // 0 1 2 3 4 5 - // 012345678901234567890123456789012345678901234567890123456789 - // IDX TagAddr PAddr Stat IDX TagAddr PAddr Stat - // [0] S.12345'000 12345'000 --- [1] S.12345'000 12345'000 --- + // 0123456789012345678901234567890123456789012345678901234567890 + // IDX TagAddr PAddr Stat IDX TagAddr PAddr Stat + // [0] S.12345'000 12345'000 ---- [1] S.12345'000 12345'000 ---- + + bool enable = mmu_tc->e; + TA attr_e = enable ? TA::Normal : TA::Disable; screen.Clear(); - screen.Puts(0, 0, ""); - screen.Puts(x, 0, ""); + screen.Puts(0, 0, attr_e, ""); + screen.Puts(x, 0, attr_e, ""); for (int i = 0; i < 4; i++) { - screen.Puts(i * 30 + (i & 2), 1, "IDX TagAddr PAddr Stat"); + screen.Puts(i * 31 + (i & 2), 1, "IDX TagAddr PAddr Stat"); } - MonitorUpdateATC1(screen, 0, atc_data.get()); - MonitorUpdateATC1(screen, x, atc_inst.get()); + MonitorScreenATC1(screen, 0, enable, atc_data.get()); + MonitorScreenATC1(screen, x, enable, atc_inst.get()); } void -MPU68040Device::MonitorUpdateATC1(TextScreen& screen, int x, +MPU68040Device::MonitorScreenATC1(TextScreen& screen, int x, bool enable, const m68040ATC *atc) { int y = 2; + TA attr_e = enable ? TA::Normal : TA::Disable; for (uint i = 0; i < atc->sets.size(); i++) { const m68040ATCSet& set = atc->sets[i]; - screen.Print(x, y, "[%x]", i); + screen.Print(x, y, attr_e, "[%x]", i); // 古い順に取り出して 3-0 の順序をつける。(新しい順に表示するため) int order[4]; @@ -682,18 +709,19 @@ MPU68040Device::MonitorUpdateATC1(TextSc const m68040ATCEntry& entry = set.entry[line]; TA attr = entry.IsValid() ? TA::Normal : TA::Disable; screen.Print(x + 4, y, attr, - "%c.%05x'000 %05x'000 %c%c%c", + "%c.%05x'000 %05x'000 %c%c%c%c", (entry.IsSuper() ? 'S' : 'U'), ((entry.tag >> 8) & 0xfffff), entry.paddr >> 12, ((entry.desc & m68040MMU::DESC_G) ? 'G' : '-'), ((entry.desc & m68040MMU::DESC_S) ? 'S' : '-'), - ((entry.desc & m68040MMU::DESC_W) ? 'W' : '-')); + ((entry.desc & m68040MMU::DESC_W) ? 'W' : '-'), + ((entry.desc & m68040MMU::DESC_R) ? 'R' : '-')); y++; } if (i == 7) { - x += 30; + x += 31; y = 2; } }