--- nono/m680x0/m68040mmu.cpp 2026/04/29 17:05:35 1.1.1.2 +++ nono/m680x0/m68040mmu.cpp 2026/04/29 17:05:40 1.1.1.3 @@ -142,12 +142,7 @@ MPU68040Device::LookupATC(m68040ATC& atc entry->tag = tag; // テーブルサーチを行い、エントリを更新する。 - // (true なら entry を埋めて帰ってきてる) - if (Search(entry) == false) { - entry->Invalidate(); - putlog(3, " LookupATC invalid"); - return false; - } + Search(entry); // このエントリで再度ステータスが一致するか。(タグは一致している) if (entry->MatchStatus(bus.laddr) == false) { @@ -194,10 +189,8 @@ m68040ATCSet::GetEntry() const return oldest; } -// テーブルサーチを行う。 -// 成功すると entry を埋めて true を返す。 -// 失敗すると false を返す (呼び出し側で entry を無効にすること)。 -bool +// テーブルサーチを行い、entry を埋める。 +void MPU68040Device::Search(m68040ATCEntry *entry) { uint32 base; @@ -205,6 +198,9 @@ MPU68040Device::Search(m68040ATCEntry *e uint32 mask; uint32 addr; uint32 desc; + uint32 pdt; + busdata bd; + bool acc_wp = false; busaddr laddr = bus.laddr; bool is_write = laddr.IsWrite(); @@ -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"); + } + } } // ピーク用のアドレス変換を行う。 @@ -641,18 +664,18 @@ m68040ATC::Flush(busaddr addr, bool only void MPU68040Device::MonitorUpdateATC(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 ---- screen.Clear(); screen.Puts(0, 0, ""); screen.Puts(x, 0, ""); 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()); @@ -682,18 +705,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; } }