--- nono/m88xx0/m88200.cpp 2026/04/29 17:04:34 1.1 +++ nono/m88xx0/m88200.cpp 2026/04/29 17:04:58 1.1.1.8 @@ -8,14 +8,26 @@ #include "m88100.h" #include "m88200.h" -#include "mystring.h" + +// static 変数 +m88200 *m88200::mbus_master = NULL; // m88200 コンストラクタ +// +// ここのオブジェクト名は仮で、ID が確定した時点でもう一度セットする +// (see SetID()) m88200::m88200() + : inherited("CMMU") { - // logname, devname は Init() で確定する + // objname 等は SetID() で確定する - monitor.Init(48, 8); + reg_monitor.func = (MonitorCallback_t)&m88200::MonitorUpdateReg; + reg_monitor.SetSize(52, 8); + atc_monitor.func = (MonitorCallback_t)&m88200::MonitorUpdateATC; + atc_monitor.SetSize(65, 38); + cache_monitor.func = (MonitorCallback_t)&m88200::MonitorUpdateCache; + cache_monitor.SetSize(82, 23); + // モニタ名も SetID() で決まるので、続きは向こうでやる // ログ表示用の名前 sapr.name = "SAPR"; @@ -48,55 +60,62 @@ m88200::Ctor(m88kcpu *parent_) void m88200::Reset() { + const uint32 Undefined = 0xcccccccc; + // レジスタ (p6-4, Table6-3) + // ID, version は別途 Set される。 command = 0; ssr = 0; - sar = 0xdeadbeef; // undefined + sar = Undefined; sctr = 0; fault_code = 0; - fault_addr = 0xdeadbeef; // undefined + fault_addr = Undefined; sapr.enable = false; sapr.stat = APR_CI; uapr.enable = false; uapr.stat = APR_CI; } -bool -m88200::MonitorUpdate() +// モニター更新 (CMMU レジスタ) +void +m88200::MonitorUpdateReg(Monitor *, TextScreen& screen) { + uint32 baseaddr; uint32 reg; int x; int y; - monitor.Clear(); - x = 20; + baseaddr = 0xfff00000 + (id << 12); + + screen.Clear(); + x = 24; y = 0; - monitor.Print(0, y++, "+$000 IDR:%08x ID=$%02x Type=5(88200) Ver=$%x", - GetIDR(), id, version); + screen.Print(0, y++, "$%08x IDR:%08x ID=$%02x Type=5(88200) Ver=$%x", + baseaddr + 0, GetIDR(), id, version); reg = GetSSR(); - monitor.Print(0, y, "+$008 SSR:%08x", reg); - monitor.Puts(x, y, TA::OnOff(reg & SSR_CE), "CE"); - monitor.Puts(x + 3, y, TA::OnOff(reg & SSR_BE), "BE"); - monitor.Puts(x + 6, y, TA::OnOff(reg & SSR_WT), "WT"); - monitor.Puts(x + 9, y, TA::OnOff(reg & SSR_SP), "SP"); - monitor.Puts(x + 12, y, TA::OnOff(reg & SSR_G), "G"); - monitor.Puts(x + 14, y, TA::OnOff(reg & SSR_CI), "CI"); - monitor.Puts(x + 17, y, TA::OnOff(reg & SSR_M), "M"); - monitor.Puts(x + 19, y, TA::OnOff(reg & SSR_U), "U"); - monitor.Puts(x + 21, y, TA::OnOff(reg & SSR_WP), "WP"); - monitor.Puts(x + 24, y, TA::OnOff(reg & SSR_BH), "BH"); - monitor.Puts(x + 27, y, TA::OnOff(reg & SSR_V), "V"); + screen.Print(0, y, "$%08x SSR:%08x", baseaddr + 0x008, reg); + screen.Puts(x, y, TA::OnOff(reg & SSR_CE), "CE"); + screen.Puts(x + 3, y, TA::OnOff(reg & SSR_BE), "BE"); + screen.Puts(x + 6, y, TA::OnOff(reg & SSR_WT), "WT"); + screen.Puts(x + 9, y, TA::OnOff(reg & SSR_SP), "SP"); + screen.Puts(x + 12, y, TA::OnOff(reg & SSR_G), "G"); + screen.Puts(x + 14, y, TA::OnOff(reg & SSR_CI), "CI"); + screen.Puts(x + 17, y, TA::OnOff(reg & SSR_M), "M"); + screen.Puts(x + 19, y, TA::OnOff(reg & SSR_U), "U"); + screen.Puts(x + 21, y, TA::OnOff(reg & SSR_WP), "WP"); + screen.Puts(x + 24, y, TA::OnOff(reg & SSR_BH), "BH"); + screen.Puts(x + 27, y, TA::OnOff(reg & SSR_V), "V"); y++; - monitor.Print(0, y++, "+$00c SAR:%08x", GetSAR()); + screen.Print(0, y++, "$%08x SAR:%08x", baseaddr + 0x00c, GetSAR()); reg = GetSCTR(); - monitor.Print(0, y, "+$104 SCTR:%08x", GetSCTR()); - monitor.Puts(x, y, TA::OnOff(reg & SCTR_PE), "PE"); - monitor.Puts(x + 3, y, TA::OnOff(reg & SCTR_SE), "SE"); - monitor.Puts(x + 6, y, TA::OnOff(reg & SCTR_PR), "PR"); + screen.Print(0, y, "$%08x SCTR:%08x", baseaddr + 0x104, GetSCTR()); + screen.Puts(x, y, TA::OnOff(reg & SCTR_PE), "PE"); + screen.Puts(x + 3, y, TA::OnOff(reg & SCTR_SE), "SE"); + screen.Puts(x + 6, y, TA::OnOff(reg & SCTR_PR), "PR"); y++; reg = GetPFSR(); @@ -110,15 +129,17 @@ m88200::MonitorUpdate() "Supervisor Violation", "Write Violation", }; - monitor.Print(0, y++, "+$108 PFSR:%08x %s", reg, codestr[fault_code]); + screen.Print(0, y++, "$%08x PFSR:%08x %s", baseaddr + 0x108, + reg, codestr[fault_code]); - monitor.Print(0, y++, "+$10c PFAR:%08x", GetPFAR()); + screen.Print(0, y++, "$%08x PFAR:%08x", baseaddr + 0x10c, GetPFAR()); for (int i = 0; i < 2; i++) { int s = 1 - i; reg = GetAPR(s); - monitor.Print(0, y, "+$20%d %cAPR:%08x", i * 4, s ? 'S' : 'U', reg); - monitor.Print(x, y, "STBA=%05x'000 %c%c%c%c", + screen.Print(0, y, "$%08x %cAPR:%08x", baseaddr + 0x200 + i * 4, + s ? 'S' : 'U', reg); + screen.Print(x, y, "STBA=%05x'000 %c%c%c%c", reg >> 12, (reg & APR_WT) ? 'T' : '-', (reg & APR_G) ? 'G' : '-', @@ -126,8 +147,100 @@ m88200::MonitorUpdate() (reg & APR_TE) ? 'E' : '-'); y++; } +} - return true; +// モニター更新 (ATC) +void +m88200::MonitorUpdateATC(Monitor *, TextScreen& screen) +{ + int x; + int y; + + screen.Clear(); + + screen.Print(0, 0, "SAPR %05x'000 TE=%d %c%c%c", + (sapr.addr >> 12) & 0xfffff, + sapr.enable ? 1 : 0, + (sapr.stat & m88200::APR_WT) ? 'T' : '-', + (sapr.stat & m88200::APR_G) ? 'G' : '-', + (sapr.stat & m88200::APR_CI) ? 'C' : '-'); + + screen.Print(34, 0, "UAPR %05x'000 TE=%d %c%c%c", + (uapr.addr >> 12) & 0xfffff, + uapr.enable ? 1 : 0, + (uapr.stat & m88200::APR_WT) ? 'T' : '-', + (uapr.stat & m88200::APR_G) ? 'G' : '-', + (uapr.stat & m88200::APR_CI) ? 'C' : '-'); + + screen.Puts(0, 1, ""); + screen.Puts(0, 2, "No. LBA PBA Stat"); + screen.Puts(34, 2, "No. LBA PBA Stat"); + x = 0; + y = 3; + for (int i = 0; i < 10; i++) { + if (i == batc.size() / 2) { + x = 34; + y = 3; + } + if (i < 8) { + screen.Print(x, y, " %d:", i); + } else { + screen.Print(x, y, "(%d)", i); + } + + const m88200BATC& b = batc[i]; + if ((b.lba & 1) == 0) { + screen.Print(x + 4, y, "%c:%04x'0000 %04x'0000 %c%c%c%c", + (b.lba & m88200::BATC_S) ? 'S' : 'U', + b.lba >> 16, b.pba >> 16, + (b.stat & m88200::DESC_WT) ? 'T' : '-', + (b.stat & m88200::DESC_G) ? 'G' : '-', + (b.stat & m88200::DESC_CI) ? 'C' : '-', + (b.stat & m88200::DESC_WP) ? 'P' : '-'); + } + y++; + } + + screen.Puts(0, 8, ""); + screen.Puts(0, 9, "No. LPA PFA Stat"); + screen.Puts(34, 9, "No. LPA PFA Stat"); + + x = 0; + y = 10; + for (int i = 0; i < patc.size(); i++) { + if (i == patc.size() / 2) { + x = 34; + y = 10; + } + screen.Print(x, y, "%2d:", i); + + const m88200PATC& p = patc[i]; + if ((p.lpa & 1) == 0) { + screen.Print(x + 4, y, "%c:%05x'000 %05x'000 %c%c%c%c%c", + (p.lpa & m88200::PATC_S) ? 'S' : 'U', + p.lpa >> 12, p.pfa >> 12, + (p.stat & m88200::DESC_WT) ? 'T' : '-', + (p.stat & m88200::DESC_G) ? 'G' : '-', + (p.stat & m88200::DESC_CI) ? 'C' : '-', + (p.stat & m88200::DESC_WP) ? 'P' : '-', + p.m ? 'M' : '-'); + } + + y++; + } +} + +// モニター更新 (キャッシュ、概要と詳細の両方、GUI から呼ばれる) +// screen.userdata は注目しているセット番号。 +void +m88200::MonitorUpdateCache(Monitor *, TextScreen& screen) +{ + int setidx = screen.userdata; + + // 上半分(概要) + MonitorCacheOverview(screen, 0, setidx, true); + // 下半分(セット詳細) + MonitorCacheSet(screen, 18, setidx); } // データキャッシュの特定セットの詳細を TextScreen に出力する。 @@ -136,6 +249,7 @@ m88200::MonitorUpdate() void m88200::MonitorCacheSet(TextScreen& s, int y, int setidx) { + assertmsg(0 <= setidx && setidx < setarray.size(), "setidx=%d", setidx); const m88200CacheSet& set = setarray[setidx]; /* @@ -172,7 +286,7 @@ m88200::MonitorCacheSet(TextScreen& s, i break; } s.Print(0, y, attr, "%d", line); - static const char * const statusstr[] = { "EU", "EM", "SU", "IV" }; + static const char statusstr[][4] = { "EU", "EM", "SU", "IV" }; s.Print(2, y, attr, "$%05x'%03x %s", (set.tag[line] >> 12), (setidx << 4), @@ -238,7 +352,7 @@ m88200::MonitorCacheOverview(TextScreen& for (int i = 0; i < setarray.size(); i++) { const auto& set = setarray[i]; - const char * const str = "EMS-"; + const char str[] = "EMS-"; int col = i % 16; int row = i / 16; int x; @@ -263,8 +377,13 @@ m88200::SetID(uint id_) { id = id_; - logname = string_format("cmmu%u", id); - devname = string_format("CMMU#%u", 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 フィールドを設定する @@ -427,19 +546,45 @@ m88200::FlushCache() switch (gg) { case GG_LINE: addr &= 0xfffffffc; + parent->AddCycle(1); // Table.6-1 break; case GG_PAGE: addr &= 0xfffff000; + parent->AddCycle(256); // Table.6-1 break; case GG_SEG: addr &= 0xffc00000; + parent->AddCycle(1024); // Table.6-1 break; case GG_ALL: + parent->AddCycle(1024); // Table.6-1 break; default: __unreachable(); } + // サイクル(基本部分) Table.6-1 + uint32 cycle = 0; + if (invalidate) { + switch (gg) { + case GG_LINE: cycle = 1; break; + case GG_PAGE: cycle = 256; break; + case GG_SEG: cycle = 1024; break; + case GG_ALL: cycle = 256; break; + default: __unreachable(); + } + } + if (copyback) { + switch (gg) { + case GG_LINE: cycle = 1; break; + case GG_PAGE: cycle = 256; break; + case GG_SEG: cycle = 1024; break; + case GG_ALL: cycle = 1024; break; + default: __unreachable(); + } + } + // XXX ループ中のサイクル数は正しくないかも。よく分からん + for (auto& set : setarray) { for (int line = 0; line < 4; line++) { // 条件にマッチするか @@ -466,16 +611,20 @@ m88200::FlushCache() // Copyback ならまず EM なエントリを書き戻す。 if (copyback) { if (set.vv[line] == m88200CacheSet::EM) { - set.CopyBackLine(line); + cycle += 7; // Table.6-1 + CopyBackLine(set, line); } } // Invalidate なら無効化する if (invalidate) { + cycle += 1; // Table.6-1 set.Update(line, m88200CacheSet::IV); } } } + + parent->AddCycle(cycle); } // command に応じて PATC を無効化する。SetSCR() の下請け。 @@ -751,7 +900,7 @@ m88200::MBusWrite(uint32 paddr, uint32 d } // MBus に xmem トランザクションを行う。 -// paddr は size によって 1, 2, 4 バイト境界に整列していること。 +// paddr は size によって 1, 4 バイト境界に整列していること (2バイトはない)。 // MBus Acquire された状態で呼び出すこと。 // 成功すれば読み込めた値を返す。 // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。 @@ -798,16 +947,22 @@ m88200::load(uint32 addr) acc_laddr = addr; acc_read = true; if (Translate() == false) { + putlog(2, "Translation BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr); return (uint64)-1; } if ((acc_stat & DESC_CI)) { + parent->AddCycle(7); // Table.6-2 MBusAcquire(); data = MBusRead(acc_paddrH + acc_paddrL, bits / 8); MBusRelease(); + if ((int64)data < 0) { + putlog(2, "MBus BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr); + } return data; } else { data = CacheRead(acc_paddrH); if ((int64)data < 0) { + putlog(2, "Cache BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr); return data; } @@ -868,13 +1023,17 @@ m88200::store(uint32 addr, uint32 data) return (uint64)-1; } if ((acc_stat & DESC_CI)) { + parent->AddCycle(7); // Table.6-2 MBusAcquire(); rv = MBusWrite(acc_paddrH + acc_paddrL, data, bits / 8); MBusRelease(); return rv; } else { - if (DEBUG_WT) + if (DEBUG_WT) { + MBusAcquire(); MBusWrite(acc_paddrH + acc_paddrL, data, bits / 8); + MBusRelease(); + } return CacheWrite(acc_paddrH + acc_paddrL, data, bits / 8); } } @@ -925,12 +1084,6 @@ m88200::xmem_8(uint32 addr, uint32 data) } uint64 -m88200::xmem_16(uint32 addr, uint32 data) -{ - return xmem<16>(addr, data); -} - -uint64 m88200::xmem_32(uint32 addr, uint32 data) { return xmem<32>(addr, data); @@ -986,11 +1139,12 @@ m88200::Translate() for (int loop = 0; loop < 3; loop++) { // Select Area Descriptor if (SelectAreaDesc() == false) { - // XXX 図には - // Physical Address <= LA[18-2] :: 00 - // と書いてあるけどたぶんこうだよなあ... - // Physical Address <= LA[31-2] :: 00 + // XXX 図のこれはたぶん間違いだよなあ… + // 誤: Physical Address <= LA[18-2] :: 00 + // 正: Physical Address <= LA[31-2] :: 00 acc_paddrH = acc_laddr - acc_paddrL; + + parent->AddCycle(1); return true; } @@ -1013,6 +1167,8 @@ m88200::Translate() acc_stat |= b.stat; putlog(4, " BATC hit acc=%s paddr=$%08x", stat2str(acc_stat).c_str(), acc_paddrH); + + parent->AddCycle(1); return true; } } @@ -1054,9 +1210,12 @@ m88200::Translate() acc_stat |= p.stat; putlog(4, " PATC[%d] hit acc=%s paddr=$%08x", i, stat2str(acc_stat).c_str(), acc_paddrH); + + parent->AddCycle(1); return true; } } + putlog(4, " BATC/PATC miss"); // PATC miss @@ -1133,11 +1292,15 @@ m88200::TableSearch() if (FetchSegmentDesc() == false) { MBusRelease(); + + parent->AddCycle(7); // Table.6-2 return false; } if (FetchPageDesc() == false) { MBusRelease(); + + parent->AddCycle(11); // Table.6-2 return false; } @@ -1167,10 +1330,14 @@ m88200::TableSearch() if ((tmp_desc & DESC_U) == 0 || ((tmp_desc & DESC_M) == 0 && acc_IsWrite())) { + parent->AddCycle(15); // Table.6-2 + if (UpdatePageDesc() == false) { MBusRelease(); return false; } + } else { + parent->AddCycle(11); // Table.6-2 } if (acc_patc == NULL) { @@ -1494,48 +1661,10 @@ m88200CacheSet::TryGetOldestLine(int tmp int m88200CacheSet::SelectOldestLine() const { -#if 0 - int line; - - // Invalid にしたときに順序を逆回しすればこの比較は不要? - - // Invalid line があればそれを選択 - for (line = 0; line < 4; line++) { - if (vv[line] == Status::IV) { - return line; - } - } -#endif - // なければ、最も古いラインを差し出す return TryGetOldestLine(L); } -// 指定の line に1ライン(4word)読み込む。 -// 成功すれば 0 を返す。 -// バスエラーなら (uint64)-1 を返す。この場合呼び出し側で fault_code, -// fault_addr を設定すること。(ここは m88200 クラスではないのでセットできない) -uint64 -m88200CacheSet::ReadLine(int line, uint32 tagaddr) -{ - uint32 addr; - uint64 data; - - // タグを更新 - tag[line] = tagaddr; - - addr = tag[line] | (setidx << 4); - for (int i = 0; i < 4; i++) { - data = vm_phys_read_32(addr); - if ((int64)data < 0) { - return data; - } - word[line * 4 + i] = data; - addr += 4; - } - return 0; -} - // キャッシュの指定の line, word に data を書き込む。 // size は 1, 2, 4 バイト。 void @@ -1577,41 +1706,87 @@ m88200CacheSet::Write(int line, uint32 p word[line * 4 + wordidx] = data32; } -// 指定の set,line をコピーバックする。 +// キャッシュを検索。 +// ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。 +int +m88200CacheSet::Lookup(uint32 tagaddr) const +{ + for (int line = 0; line < 4; line++) { + if (tag[line] == tagaddr) { + return line; + } + } + return -1; +} + + +// キャッシュの指定の set, line にメモリから 1 ライン(4word) 読み込む。 // 成功すれば 0 を返す。 -// バスエラーなら (uint64)-1 を返す。この場合呼び出し側で fault_code, -// fault_addr を設定すること。(ここは m88200 クラスではないのでセットできない) +// バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。 uint64 -m88200CacheSet::CopyBackLine(int line) +m88200::ReadLine(m88200CacheSet& set, int line, uint32 tagaddr) { uint32 addr; + uint64 data; - addr = tag[line] | (setidx << 4); + // キャッシュラインの充填は実機では Burst Read されているらしいが + // nono では Burst Read 用のメソッドは用意しておらず通常の 32bit + // アクセスをしているため、このままでは所要ウェイト数が正しくない。 + // そこでここで差を調整することにする。 + // vm_phys_read_32() 4回なのでこれによって 12 wait が加算される。一方 + // 実機の Burst Read は取扱説明書によると 320ns (8 サイクル) で完了 + // するようなので、その差 4 をあらかじめ引いておく。 + // 途中でバスエラーが起きたらとかそこまでは考慮しない。 + AddCycle(-4); + + // タグを更新 + set.tag[line] = tagaddr; + + addr = set.tag[line] | (set.setidx << 4); for (int i = 0; i < 4; i++) { - uint64 rv = vm_phys_write_32(addr, word[line * 4 + i]); - if ((int64)rv < 0) { - return rv; + data = vm_phys_read_32(addr); + if ((int64)data < 0) { + fault_code = FAULT_CODE_BUSERR; + fault_addr = addr; + return data; } + set.word[line * 4 + i] = data; addr += 4; } return 0; } -// キャッシュを検索。 -// ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。 -int -m88200CacheSet::Lookup(uint32 tagaddr) const +// キャッシュの指定の set, line を1ライン、メモリに書き出す(コピーバック)。 +// 成功すれば 0 を返す。 +// バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。 +uint64 +m88200::CopyBackLine(m88200CacheSet& set, int line) { - for (int line = 0; line < 4; line++) { - if (tag[line] == tagaddr) { - return line; + uint32 addr; + + // キャッシュラインの書き出しは実機では Burst Write されているらしいが + // nono では Burst Write 用のメソッドは用意しておらず通常の 32bit + // アクセスをしているため、このままでは所要ウェイト数が正しくない。 + // そこでここで差を調整することにする。 + // vm_phys_write_32() 4回なのでこれによって 8 wait が加算される。一方 + // 実機の Burst Write は取扱説明書によると 280ns (7サイクル) で完了する + // ようなので、その差 1 をあらかじめて引いておく。 + // 途中でバスエラーが起きたらとかそこまでは考慮しない。 + 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]); + if ((int64)rv < 0) { + fault_code = FAULT_CODE_BUSERR; + fault_addr = addr; + return rv; } + addr += 4; } - return -1; + return 0; } - - // キャッシュに対して paddr の読み込みを行う。 // paddr は 32bit 境界のアドレスであること。 // 読み込めれば該当の32bitワードを返す。 @@ -1637,11 +1812,14 @@ m88200::CacheRead(uint32 paddr) if (line >= 0) { // Cache Hit putlog(4, " CacheRead hit (line=%d,word=%d)", line, wordidx); + parent->AddCycle(1); goto success; } // Cache Miss + parent->AddCycle(10); // Table.6-2 + // reply <- Wait MBusAcquire(); @@ -1650,7 +1828,8 @@ m88200::CacheRead(uint32 paddr) putlog(4, " CacheRead miss (replace line=%d)", line); if (set.vv[line] == m88200CacheSet::EM) { - rv = set.CopyBackLine(line); + parent->AddCycle(7); // Table.6-2 + rv = CopyBackLine(set, line); if ((int64)rv < 0) { goto error; } @@ -1660,7 +1839,7 @@ m88200::CacheRead(uint32 paddr) set.Update(line, m88200CacheSet::IV); // Read line from memory - rv = set.ReadLine(line, tagaddr); + rv = ReadLine(set, line, tagaddr); if ((int64)rv < 0) { goto error; } @@ -1677,8 +1856,6 @@ m88200::CacheRead(uint32 paddr) error: MBusRelease(); - fault_code = FAULT_CODE_BUSERR; - fault_addr = paddr; return (uint64)-1; } @@ -1705,11 +1882,14 @@ m88200::CacheWrite(uint32 paddr, uint32 line = set.Lookup(tagaddr); if (line >= 0) { // Cache Hit + parent->AddCycle(1); return CacheWriteHit(set, line, paddr, data, size); } // Cache Miss + parent->AddCycle(14); // Table.6-2 + // reply <- Wait MBusAcquire(); @@ -1718,7 +1898,8 @@ m88200::CacheWrite(uint32 paddr, uint32 putlog(4, " CacheWrite miss (replace line=%d)", line); if (set.vv[line] == m88200CacheSet::EM) { - rv = set.CopyBackLine(line); + parent->AddCycle(7); // Table.6-2 + rv = CopyBackLine(set, line); if ((int64)rv < 0) { goto error; } @@ -1728,7 +1909,7 @@ m88200::CacheWrite(uint32 paddr, uint32 set.Update(line, m88200CacheSet::IV); // Read line with intent to modify - rv = set.ReadLine(line, tagaddr); + rv = ReadLine(set, line, tagaddr); if ((int64)rv < 0) { goto error; } @@ -1736,7 +1917,7 @@ m88200::CacheWrite(uint32 paddr, uint32 // Write data to memory rv = MBusWrite(paddr, data, size); if ((int64)rv < 0) { - return rv; + goto error; } // Write data into cache @@ -1751,8 +1932,6 @@ m88200::CacheWrite(uint32 paddr, uint32 error: MBusRelease(); - fault_code = FAULT_CODE_BUSERR; - fault_addr = paddr; return (uint64)-1; } @@ -1840,7 +2019,8 @@ m88200::CacheXmem(uint32 paddr, uint32 d MBusAcquire(); - rv = set.CopyBackLine(line); + parent->AddCycle(7); // Table.6-2 + rv = CopyBackLine(set, line); if ((int64)rv < 0) { goto error; } @@ -1868,3 +2048,23 @@ m88200::CacheXmem(uint32 paddr, uint32 d MBusRelease(); return rv; } + +// サイクルを加算する (VM から使う) +void +m88200::AddCycle(int32 cycle) +{ + parent->AddCycle(cycle); +} + +// MBus 使用権を取得する +void +m88200::MBusAcquire() +{ + // アービトレーションのたびに1クロックかかる(?) + // よく分からんけど、とりあえず、CMMU は一度所有権を持ったら放さない、 + // 別の CMMU がバスリクエストすると所有権はその CMMU に移る、とする。 + if (mbus_master != this) { + mbus_master = this; + parent->AddCycle(1); + } +}