--- nono/m680x0/m68030bus.cpp 2026/04/29 17:05:26 1.1.1.6 +++ nono/m680x0/m68030bus.cpp 2026/04/29 17:05:48 1.1.1.9 @@ -17,7 +17,7 @@ // reg.pc からワードをフェッチし reg.pc を進める。 uint32 -MPU680x0Device::fetch_2() +MPU68030Device::fetch_2() { busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size2; @@ -49,7 +49,7 @@ MPU680x0Device::fetch_2() bd = read_nocache(addr); } if (__predict_false(bd.IsBusErr())) { - bus.size = M68K::SSW_SIZE(addr.GetSize() & 3); + bus.size = addr.GetSize(); throw M68K::EXCEP_BUSERR; } reg.pc += 2; @@ -58,7 +58,7 @@ MPU680x0Device::fetch_2() // reg.pc からロングワード(ミスアライン可)をフェッチし reg.pc を進める。 uint32 -MPU680x0Device::fetch_4() +MPU68030Device::fetch_4() { busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size4; @@ -100,7 +100,7 @@ MPU680x0Device::fetch_4() bd = read_nocache(addr); } if (__predict_false(bd.IsBusErr())) { - bus.size = M68K::SSW_SIZE(addr.GetSize() & 3); + bus.size = addr.GetSize(); throw M68K::EXCEP_BUSERR; } reg.pc += 4; @@ -110,7 +110,7 @@ MPU680x0Device::fetch_4() // read_1,2,4() の共通部分。ミスアライン可。 // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 uint32 -MPU680x0Device::read_data(busaddr addr) +MPU68030Device::read_data(busaddr addr) { m68030Cache *cache = dcache.get(); busdata data; @@ -120,7 +120,7 @@ MPU680x0Device::read_data(busaddr addr) data = read_nocache(addr); } if (__predict_false(data.IsBusErr())) { - bus.size = M68K::SSW_SIZE(addr.GetSize() & 3); + bus.size = addr.GetSize(); throw M68K::EXCEP_BUSERR; } return data.Data(); @@ -129,11 +129,11 @@ MPU680x0Device::read_data(busaddr addr) // write_1,2,4() の共通部分。ミスアライン可。 // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 void -MPU680x0Device::write_data(busaddr addr, uint32 data) +MPU68030Device::write_data(busaddr addr, uint32 data) { busdata r = write_bus(addr, data); if (__predict_false(r.IsBusErr())) { - bus.size = M68K::SSW_SIZE(addr.GetSize() & 3); + bus.size = addr.GetSize(); throw M68K::EXCEP_BUSERR; } } @@ -141,7 +141,7 @@ MPU680x0Device::write_data(busaddr addr, // キャッシュ無効時の読み込み。ミスアライン可。 // バスエラーも busdata を返す。 busdata -MPU680x0Device::read_nocache(busaddr addr) +MPU68030Device::read_nocache(busaddr addr) { // デバイスは、addr の下位ビットによらず、自身のデバイスのポートサイズ分 // のデータと、その応答サイズ(自分のポートサイズ) を Size フィールドに @@ -203,7 +203,7 @@ OPERMASK(uint32 offset, uint32 size) // キャッシュ有効時の読み込み。ミスアライン可。 // バスエラーも busdata を返す。 busdata -MPU680x0Device::read_cache(m68030Cache *cache, busaddr addr) +MPU68030Device::read_cache(m68030Cache *cache, busaddr addr) { putlog(2, "read_cache $%u.%08x.%c", addr.GetFC(), addr.Addr(), "0BW3L"[addr.GetSize()]); @@ -327,7 +327,7 @@ MPU680x0Device::read_cache(m68030Cache * // シングル充填によるライン充填。 // 要求オペランドが2エントリ目にかかっていても、バスエラーを起こさないようだ。 busdata -MPU680x0Device::read_line(m68030CacheLine *l, uint32 tag, uint32 opermask) +MPU68030Device::read_line(m68030CacheLine *l, uint32 tag, uint32 opermask) { uint32 sel = (bus.paddr.Addr() & 0x0c) >> 2; @@ -424,7 +424,7 @@ MPU680x0Device::read_line(m68030CacheLin // d) バスアクセスで CI が立てば、読み込んだデータは使うがエントリは更新しない // ので、これは c) と同じ。 busdata -MPU680x0Device::read_single(busdata bd, uint32 readmask, uint32 opermask) +MPU68030Device::read_single(busdata bd, uint32 readmask, uint32 opermask) { uint32 data = 0; uint32 portsize; @@ -441,12 +441,12 @@ MPU680x0Device::read_single(busdata bd, if (portsize == 2) { uint32 off2 = offset & 2; data |= bd.Data() << ((2 - off2) * 8); - set = 0x3 << (2 - off2); + set = 0x3U << (2 - off2); // 次の読み込みにむけて更新。 offset = 2 - off2; } else { data |= bd.Data() << ((3 - offset) * 8); - set = 0x1 << (3 - offset); + set = 0x1U << (3 - offset); // 次の読み込みにむけて更新。 offset = (offset + 1) & 3; } @@ -482,7 +482,7 @@ MPU680x0Device::read_single(busdata bd, // キャッシュ/バスへの書き込み。ミスアライン可。 // バスエラーも busdata を返す。 busdata -MPU680x0Device::write_bus(busaddr addr, uint32 data) +MPU68030Device::write_bus(busaddr addr, uint32 data) { m68030Cache *cache = dcache.get(); @@ -648,6 +648,174 @@ MPU680x0Device::read_phys_burst(uint32 * return !bd.IsBusErr(); } +// 物理メモリからのロングワード読み込み。 +// 現在の bus に影響を与えず指定のアドレスを読み出す。MMU 専用。 +busdata +MPU680x0Device::read_phys_4(uint32 addr) +{ + m68kbus backup; + busdata bd; + + // バス情報を一旦退避 + backup = bus; + + // 物理バスアクセス + bus.laddr = busaddr(addr) | BusAddr::SRead | BusAddr::Size4; + bus.paddr = bus.laddr; + bd = read_phys(); + if (__predict_false(bd.IsBusErr())) { + bus.size = 4; + return bd; + } + + // バス情報を復元 + bus = backup; + return bd; +} + +// 物理メモリへのロングワード書き込み。 +// 現在の bus に影響を与えず指定のアドレスに書き出す。MMU 専用。 +busdata +MPU680x0Device::write_phys_4(uint32 addr, uint32 data) +{ + m68kbus backup; + busdata bd; + + // バス情報を一旦退避 + backup = bus; + + // 物理バスアクセス + bus.laddr = busaddr(addr) | BusAddr::SWrite | BusAddr::Size4; + bus.paddr = bus.laddr; + bd = write_phys(data); + if (__predict_false(bd.IsBusErr())) { + bus.size = 4; + return bd; + } + + // バス情報を復元 + bus = backup; + return bd; +} + +// CACR レジスタ書き込み。 +void +MPU68030Device::SetCACR(uint32 newval) +{ + newval &= M68030::CACR_MASK; + uint32 oldval = reg.cacr; + uint32 chgval = oldval ^ newval; + + // EI (命令キャッシュ有効) + if ((chgval & M68030::CACR_EI) != 0) { + if ((newval & M68030::CACR_EI) != 0) { + // 命令キャッシュ有効 + icache->enable = true; + icache->hist.Clear(); + cycle_table = cycle_table_030cc; + putlog(1, "I-Cache enabled"); + } else { + // 命令キャッシュ無効 + icache->enable = false; + cycle_table = cycle_table_030ncc; + putlog(1, "I-Cache disabled"); + } + } + + // FI (命令キャッシュ凍結) + if ((chgval & M68030::CACR_FI) != 0) { + putlog(0, "CACR:FI Not Implemented"); + icache->freeze = (newval & M68030::CACR_FI); + } + + // CEI (命令キャッシュの指定エントリをクリア) + if ((chgval & M68030::CACR_CEI) != 0) { + // CAAR の b7-2 で示されるロングワードを無効にする。 + uint32 idx = (reg.caar & 0x000000f0) >> 4; + uint32 sel = (reg.caar & 0x0000000c) >> 2; + auto& l = icache->line[idx]; + l.valid[sel] = 0; + + newval &= ~M68030::CACR_CEI; + } + + // CI (命令キャッシュクリア) + if ((chgval & M68030::CACR_CI) != 0) { + for (auto& l : icache->line) { + l.valid_all = 0; + } + + newval &= ~M68030::CACR_CI; + } + + // IBE (命令バースト有効) + if ((chgval & M68030::CACR_IBE) != 0) { + icache->burst_enable = (newval & M68030::CACR_IBE) && has_burst_access; + } + + // ED (データキャッシュ有効) + if ((chgval & M68030::CACR_ED) != 0) { + if ((newval & M68030::CACR_ED) != 0) { + // データキャッシュ有効。 + dcache->enable = true; + dcache->hist.Clear(); + putlog(1, "D-Cache enabled"); + } else { + // データキャッシュ無効。 + dcache->enable = false; + putlog(1, "D-Cache disabled"); + } + } + + // FD (データキャッシュ凍結) + if ((chgval & M68030::CACR_FD) != 0) { + dcache->freeze = (newval & M68030::CACR_FD); + putlog(1, "CACR:FD -> %u", dcache->freeze); + } + + // CED (データキャッシュの指定エントリをクリア) + if ((chgval & M68030::CACR_CED) != 0) { + // CAAR の b7-2 で示されるロングワードを無効にする。 + uint32 idx = (reg.caar & 0x000000f0) >> 4; + uint32 sel = (reg.caar & 0x0000000c) >> 2; + auto& l = dcache->line[idx]; + l.valid[sel] = 0; + + newval &= ~M68030::CACR_CED; + } + + // CD (データキャッシュクリア) + if ((chgval & M68030::CACR_CD) != 0) { + for (auto& l : dcache->line) { + l.valid_all = 0; + } + + newval &= ~M68030::CACR_CD; + } + + // DBE (データバースト有効) + if ((chgval & M68030::CACR_DBE) != 0) { + dcache->burst_enable = (newval & M68030::CACR_DBE) && has_burst_access; + } + + // WA (ライトアロケート) + if ((chgval & M68030::CACR_WA) != 0) { + dcache->wa = (newval & M68030::CACR_WA); + } + + // とりあえずレジスタイメージも保存。 + reg.cacr = newval; +} + +// リセット例外の CPU 固有部分。 +void +MPU68030Device::ResetCache() +{ + SetCACR(M68030::CACR_CD | M68030::CACR_CI); + icache->hist.Clear(); + dcache->hist.Clear(); +} + // キャッシュの統計情報を計算。 void m68030Cache::CalcStat() @@ -668,7 +836,7 @@ m68030Cache::CalcStat() // 前回から今回までの間に disable になったのなら有効な値がある。 if (__predict_true(enable || total_read != 0)) { // ここはロックする。 - std::unique_lock lock(hist_mtx); + std::lock_guard lock(hist_mtx); hist.EnqueueForce(s); } }