--- nono/m88xx0/m88200.cpp 2026/04/29 17:05:11 1.1.1.10 +++ nono/m88xx0/m88200.cpp 2026/04/29 17:05:15 1.1.1.11 @@ -6,32 +6,46 @@ // MC88200(CMMU) -#include "m88100.h" #include "m88200.h" +#include "mainbus.h" +#include "mpu88xx0.h" // static 変数 m88200 *m88200::mbus_master = NULL; // m88200 コンストラクタ -// -// ここのオブジェクト名は仮で、ID が確定した時点でもう一度セットする -// (see SetID()) -m88200::m88200() - : inherited("CMMU") +m88200::m88200(MPU88xx0Device *parent_, uint id_) + : inherited(OBJ_M88200(id_)) { - // objname 等は SetID() で確定する + parent = parent_; + + // ID は IDR レジスタへの書き込みで後から変更できるように読めるが、 + // ハードウェアパラメータのはずだし変更する意味はないのと、仮に変更しても + // 実際訳の分からんことにしかならんと思う。 + // そして PROM も OpenBSD/luna88k も IDR へ書き込んでいないので、やはり + // あらかじめ決まっているハードウェアパラメータだと思うことにする。 + // それと、コンストラクタ時点で ID が決まってないのは何かと困るという + // こちらの都合もある。 + id = id_; + + ClearAlias(); + AddAlias(string_format("CMMU%u", id)); reg_monitor.func = ToMonitorCallback(&m88200::MonitorUpdateReg); reg_monitor.SetSize(52, 8); + reg_monitor.Regist(ID_MONITOR_CMMU(id)); + atc_monitor.func = ToMonitorCallback(&m88200::MonitorUpdateATC); #if defined(M88200_STAT) atc_monitor.SetSize(77, 39 + 15); #else atc_monitor.SetSize(77, 39); #endif + atc_monitor.Regist(ID_MONITOR_ATC(id)); + cache_monitor.func = ToMonitorCallback(&m88200::MonitorUpdateCache); cache_monitor.SetSize(82, 23); - // モニタ名も SetID() で決まるので、続きは向こうでやる + cache_monitor.Regist(ID_SUBWIN_CACHE(id)); // ログ表示用の名前 sapr.name = "SAPR"; @@ -53,11 +67,17 @@ m88200::~m88200() { } -// 本当はコンストラクタ渡ししたかったもの -void -m88200::Ctor(m88kcpu *parent_) +// 初期化 +bool +m88200::Init() { - parent = parent_; + if (inherited::Init() == false) { + return false; + } + + mainbus = GetMainbusDevice(); + + return true; } // リセット @@ -390,10 +410,10 @@ m88200::MonitorCacheSet(TextScreen& s, i uint32 addr; uint32 m; addr = (set.tag[line] & 0xfffff000) | (setidx << 4) | (w << 2); - m = (vm_phys_peek_8(addr) << 24) - | (vm_phys_peek_8(addr + 1) << 16) - | (vm_phys_peek_8(addr + 2) << 8) - | (vm_phys_peek_8(addr + 3)); + m = (mainbus->Peek8(addr) << 24) + | (mainbus->Peek8(addr + 1) << 16) + | (mainbus->Peek8(addr + 2) << 8) + | (mainbus->Peek8(addr + 3)); if (set.word[line * 4 + w] != m) { attr = TA::Em; } else { @@ -463,21 +483,6 @@ m88200::MonitorCacheOverview(TextScreen& } } -// ID を設定する (IDR ではない) -void -m88200::SetID(uint id_) -{ - id = id_; - - SetName(string_format("CMMU#%u", id)); - ClearAlias(); - AddAlias(string_format("CMMU%u", id)); - - reg_monitor.Regist(ID_MONITOR_CMMU(id)); - atc_monitor.Regist(ID_MONITOR_ATC(id)); - cache_monitor.Regist(ID_SUBWIN_CACHE(id)); -} - // IDR の Version フィールドを設定する void m88200::SetVersion(uint version_) @@ -600,7 +605,7 @@ m88200::SetSCR(uint32 data) InvalidatePATC(); return; } - __unreachable(); + PANIC("should not reach: command=$%02x", command); } // command に応じてデータキャッシュをフラッシュする。SetSCR() の下請け。 @@ -615,6 +620,8 @@ m88200::FlushCache() bool copyback; bool invalidate; + assert(0x14 <= op && op <= 0x1f); + // op CopyBack Invalidate // %01'01gg false true | Data Cache Invalidate // %01'10gg true false | Data Cache Copyback to Memory @@ -627,17 +634,15 @@ m88200::FlushCache() } else if (op == 0x18) { copyback = true; invalidate = false; - } else if (op == 0x1c) { + } else { copyback = true; invalidate = true; - } else { - PANIC("unknown op = $%02x", op); } // 影響範囲 switch (gg) { case GG_LINE: - addr &= 0xfffffffc; + addr &= 0xfffffff0; parent->AddCycle(1); // Table.6-1 break; case GG_PAGE: @@ -807,14 +812,20 @@ m88200::SetSCTR(uint32 data) // 全 CMMU について、それぞれスヌープ相手になる CMMU リストを更新。 // どの CMMU の SCTR への書き込みでも毎回全ての CMMU を書き換える。 - int n = parent->cmmu.size(); + std::array cmmu {}; + int n = cmmu.size(); for (int i = 0; i < n; i++) { - parent->cmmu[i].other_cmmu.clear(); + cmmu[i] = gMainApp.FindObject(OBJ_M88200(i)); + } + for (int i = 0; i < n; i++) { + if (cmmu[i] == NULL) + continue; + cmmu[i]->other_cmmu.clear(); for (int j = 0; j < n; j++) { - if (i == j) + if (cmmu[j] == NULL || i == j) continue; - if ((parent->cmmu[j].sctr & SCTR_SE)) { - parent->cmmu[i].other_cmmu.push_back(&parent->cmmu[j]); + if ((cmmu[j]->sctr & SCTR_SE)) { + cmmu[i]->other_cmmu.push_back(cmmu[j]); } } } @@ -1034,11 +1045,11 @@ m88200::MBusRead(uint32 paddr, int size) uint64 data; if (size == 4) { - data = vm_phys_read_32(paddr); + data = mainbus->Read32(paddr); } else if (size == 2) { - data = vm_phys_read_16(paddr); + data = mainbus->Read16(paddr); } else { - data = vm_phys_read_8(paddr); + data = mainbus->Read8(paddr); } if (__predict_false((int64)data < 0)) { fault_code = FAULT_CODE_BUSERR; @@ -1057,11 +1068,11 @@ m88200::MBusWrite(uint32 paddr, uint32 d uint64 rv; if (size == 4) { - rv = vm_phys_write_32(paddr, data); + rv = mainbus->Write32(paddr, data); } else if (size == 2) { - rv = vm_phys_write_16(paddr, data); + rv = mainbus->Write16(paddr, data); } else { - rv = vm_phys_write_8(paddr, data); + rv = mainbus->Write8(paddr, data); } if (__predict_false((int64)rv < 0)) { fault_code = FAULT_CODE_BUSERR; @@ -1151,19 +1162,20 @@ m88200::load(uint32 addr) return (data >> 8) & 0xff; case 3: return data & 0xff; + default: + PANIC("corrupted acc_paddrL=%d", acc_paddrL); } - } - if (bits == 16) { + } else if (bits == 16) { if (acc_paddrL == 0) { return data >> 16; } else { return data & 0xffff; } - } - if (bits == 32) { + } else if (bits == 32) { return data; + } else { + PANIC("bits must be 8, 16, 32"); } - __unreachable(); } } @@ -1796,7 +1808,7 @@ m88200::TranslatePeek(uint32 laddr, bool // Peek Segment Descriptor desc_addr = xapr->addr | ((laddr >> 20) & ~3U); - data = vm_phys_peek_32(desc_addr); + data = mainbus->Peek32(desc_addr); if ((int64)data < 0) { return data; } @@ -1810,7 +1822,7 @@ m88200::TranslatePeek(uint32 laddr, bool // Peek Page Descriptor desc_addr = (desc & 0xfffff000) | ((laddr >> 10) & 0xffc); - data = vm_phys_peek_32(desc_addr); + data = mainbus->Peek32(desc_addr); if ((int64)data < 0) { return data; } @@ -1985,18 +1997,18 @@ m88200::ReadLine(m88200CacheSet& set, in // nono では Burst Read 用のメソッドは用意しておらず通常の 32bit // アクセスをしているため、このままでは所要ウェイト数が正しくない。 // そこでここで差を調整することにする。 - // vm_phys_read_32() 4回なのでこれによって 12 wait が加算される。一方 + // mainbus->Read32() 4回なのでこれによって 12 wait が加算される。一方 // 実機の Burst Read は取扱説明書によると 320ns (8 サイクル) で完了 // するようなので、その差 4 をあらかじめ引いておく。 // 途中でバスエラーが起きたらとかそこまでは考慮しない。 - AddCycle(-4); + parent->AddCycle(-4); // タグを更新 set.tag[line] = tagaddr; addr = set.tag[line] | (set.setidx << 4); for (int i = 0; i < 4; i++) { - data = vm_phys_read_32(addr); + data = mainbus->Read32(addr); if (__predict_false((int64)data < 0)) { fault_code = FAULT_CODE_BUSERR; fault_addr = addr; @@ -2020,15 +2032,15 @@ m88200::CopyBackLine(m88200CacheSet& set // nono では Burst Write 用のメソッドは用意しておらず通常の 32bit // アクセスをしているため、このままでは所要ウェイト数が正しくない。 // そこでここで差を調整することにする。 - // vm_phys_write_32() 4回なのでこれによって 8 wait が加算される。一方 + // mainbus->Write32() 4回なのでこれによって 8 wait が加算される。一方 // 実機の Burst Write は取扱説明書によると 280ns (7サイクル) で完了する // ようなので、その差 1 をあらかじめて引いておく。 // 途中でバスエラーが起きたらとかそこまでは考慮しない。 - AddCycle(-1); + parent->AddCycle(-1); addr = set.tag[line] | (set.setidx << 4); for (int i = 0; i < 4; i++) { - uint64 rv = vm_phys_write_32(addr, set.word[line * 4 + i]); + uint64 rv = mainbus->Write32(addr, set.word[line * 4 + i]); if (__predict_false((int64)rv < 0)) { fault_code = FAULT_CODE_BUSERR; fault_addr = addr; @@ -2178,7 +2190,15 @@ m88200::CacheWrite(uint32 paddr, uint32 set.Write(line, paddr, data, size); // Mark line exclusive unmodified - set.Update(line, m88200CacheSet::EU); + // p3-9 3.4.2.2 CACHE WRITE:CACHE HIT. の本文に writethrough のときは + // It marks the line as shared unmodified... と書いてある。 + // Fig 3-5 には記載はないが、キャッシュエントリが作られるときも + // Fig 3-6 のキャッシュヒット時と同じように SU にならないと矛盾する。 + if ((acc_stat & DESC_WT)) { + set.Update(line, m88200CacheSet::SU); + } else { + set.Update(line, m88200CacheSet::EU); + } set.Use(line); MBusRelease(); @@ -2305,13 +2325,6 @@ m88200::CacheXmem(uint32 paddr, uint32 d return rv; } -// サイクルを加算する (VM から使う) -void -m88200::AddCycle(int32 cycle) -{ - parent->AddCycle(cycle); -} - // MBus 使用権を取得する void m88200::MBusAcquire()