--- nono/vm/mpu680x0.cpp 2026/04/29 17:05:28 1.1.1.17 +++ nono/vm/mpu680x0.cpp 2026/04/29 17:05:37 1.1.1.19 @@ -5,14 +5,28 @@ // // -// MPU (MC68030) +// MPU (MC68030/MC68040) // +// MPU/FPU 種別について: +// +// 構造上やむをえないが MPU が 68030 なら FPU は fpu-type で指定し、 +// MPU が 68040/68LC040 なら mpu-type で MPU/FPU を指定する。 +// +// mpu-type fpu-type +// -------- -------- +// 68030 none : 68030、FPU なし +// 68030 68881 : 68030 + 68881 +// 68LC040 - : 68040 (FPU なし) +// 68040 - : 68040 (FPU あり) + #include "mpu680x0.h" #include "config.h" #include "debugger.h" +#include "exttostr.h" #include "interrupt.h" #include "m68030cache.h" +#include "m68040mmu.h" #include "mainapp.h" #include "mainbus.h" #include "scheduler.h" @@ -20,40 +34,44 @@ #include "uimessage.h" #include "vectortable.h" -static Syncer *gSyncer; +// ブートストラップ。設定に応じてインスタンスを生成して返す。 +// ここではとりあえず 68040 かそれ以外なら 68030 を生成しておき、 +// Init() でもう一度 (機種情報も含めて) チェックする。 +// Init() (か Create()) まで進まないとエラー終了出来ないが、 +// その時点では MainMPU のインスタンスは必要なので。 +MPU680x0Device * +NewMPU680x0Device() +{ + const ConfigItem& item = gConfig->Find("mpu-type"); + std::string mpu_type = item.AsString(); + + // 設定に応じて継承側のクラスを作成する。 + // この段階では知らないものは一旦 68030 にしておく。 + if (mpu_type == "68040" || strcasecmp(mpu_type.c_str(), "68LC040") == 0) { + return new MPU68040Device(); + } else { + return new MPU68030Device(); + } +} + + +// +// 68030/040 共通クラス +// // コンストラクタ MPU680x0Device::MPU680x0Device() : inherited() { - SetName("MPU(68030)"); + // MPU 種別は継承側で設定する。設定されないままなら Init() でエラー。 + mpu_type = m680x0MPUType::NONE; - // MMU.xRP.DT == 0 になってはいけない(MMU 構成例外)。 - SetSRP(0x00000001, 0); - SetCRP(0x00000001, 0); // FPU fpu_init(); - // キャッシュ - icache.reset(new m68030Cache()); - dcache.reset(new m68030Cache()); // 例外カウンタ excep_counter.resize(256); - // レジスタモニター (サイズは Init で確定する) - reg_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateReg); - reg_monitor.Regist(ID_MONITOR_MPUREG); - - // ATC モニター - atc_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateATC); - atc_monitor.SetSize(114, m68030ATCTable::LINES + 6); - atc_monitor.Regist(ID_MONITOR_MPUATC); - - // キャッシュモニター - cache_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateCache); - cache_monitor.SetSize(48, 20 * 2 + 1); - cache_monitor.Regist(ID_MONITOR_MPUCACHE); - SetTrace(false); } @@ -62,14 +80,6 @@ MPU680x0Device::~MPU680x0Device() { } -void -MPU680x0Device::SetLogLevel(int loglevel_) -{ - inherited::SetLogLevel(loglevel_); - - atc.SetLogLevel(loglevel_); -} - // 初期化 bool MPU680x0Device::Init() @@ -78,12 +88,73 @@ MPU680x0Device::Init() return false; } + // なる早で、もう一度 MPU 設定を読んで判定。そのついでに FPU も判定。 + // "mpu-type" の設定値が不正な場合でも (コンストラクト時点ではまだエラーを + // 報告できない構造なので) 一旦 MPU68030Device インスタンスとしてここに + // 来る。なのでここで改めてチェックしてエラー報告する必要がある。 + // mpu_type (メンバ変数) 自体はすでにセットされている。 + const ConfigItem& mputype_item = gConfig->Find("mpu-type"); + std::string mputype = mputype_item.AsString(); + if (mputype == "68030") { + // FPU はこのすぐ次で機種ごとに選ぶ。 + } else if (mputype == "68040") { + fpu_type = m680x0FPUType::M68040; + } else if (strcasecmp(mputype.c_str(), "68LC040") == 0) { + fpu_type = m680x0FPUType::M68LC040; + // 名前も再設定? + mpu_name = "MC68LC040"; + SetName("MPU(68LC040)"); + } else { + mputype_item.Err(); + return false; + } + + // 機種ごとに MPU/FPU のサポート状況が違う。 + // 68030 なら fpu_type はここでセットする。 + switch (gMainApp.GetVMType()) { + case VMType::LUNA1: + case VMType::NEWS: + // NEWS は元々 68030 モデルのみ。 + // うち NWS-1750 は 68030/68882 固定のようだがここでは 68881 とする。 + // LUNA-I は基本的に 68030/68881 モデルのみ。 + if (mpu_type != m680x0MPUType::M68030) { + mputype_item.Err("Only 68030 can be specified for vmtype=%s", + gMainApp.GetVMTypeStr().c_str()); + return false; + } + fpu_type = m680x0FPUType::M68881; + break; + + case VMType::X68030: + case VMType::VIRT68K: + // 68030/68040 をサポート。mpu_type は継承コンストラクタで設定済み。 + if (mpu_type == m680x0MPUType::M68030) { + // 68030 なら FPU は設定で指定可能。 + const ConfigItem& fputype_item = gConfig->Find("fpu-type"); + std::string fputype = fputype_item.AsString(); + if (fputype == "none" || fputype == "0") { + fpu_type = m680x0FPUType::M68030_NOFPU; + } else if (fputype == "68881" || fputype == "1") { + fpu_type = m680x0FPUType::M68881; + } else { + fputype_item.Err(); + return false; + } + } else { + // 68040 なら FPU はすぐ上で設定済み。 + } + break; + + default: + VMPANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str()); + break; + } + debugger = GetDebugger(); interruptdev = GetInterruptDevice(); - // static 関数から参照するため。うーん…。 - gSyncer = syncer; + vectortable = GetVectorTable(); - // 割り込み時のディレイ。 + // 割り込みイベントコールバック設定。 // // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを // 認識(確定)するのに 1 ~ 2 クロックかかる。 @@ -91,35 +162,23 @@ MPU680x0Device::Init() // その後 /IPEND をアサートするのはその次のアップエッジ。 // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは // 2 ~ 3 クロックかかる。(Figure 8-4) + intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback); intr_event.time = 3 * clock_nsec; + intr_event.SetName(GetName() + " Interrupt"); + scheduler->RegistEvent(intr_event); - // FPU (6888x) - if (gMainApp.IsX68030()) { - // X68k は設定による - const ConfigItem& item = gConfig->Find("fpu-type"); - std::string type = item.AsString(); - if (type == "none" || type == "0") { - has_fpu = 0; - } else if (type == "68881" || type == "1") { - has_fpu = 1; - } else { - item.Err(); - return false; + // レジスタモニタの行数。 + int height = 9; + if (mpu_type == m680x0MPUType::M68030) { + height++; + } + if (HasFPU()) { + height += 12; + if (GetFPUType().Is4060FPU()) { + height += 3; } - } else { - // LUNA は 68881 固定 (設定は見ない) - has_fpu = 1; } - - // レジスタモニタに FPU を載せるか。 - reg_monitor.SetSize(78, 10 + (has_fpu ? 9 : 0)); - - vectortable = GetVectorTable(); - - // 割り込みイベントコールバック設定 - intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback); - intr_event.SetName(GetName() + " Interrupt"); - scheduler->RegistEvent(intr_event); + reg_monitor->SetSize(78, height); return true; } @@ -328,11 +387,11 @@ void MPU680x0Device::ChangeState(uint32 new_state) { // new_mode (CPU_STATE_*) と - // RequestCPUMode() の引数 Syncer::SCHED_CPU_* は + // RequestCPUMode() の引数 Syncer::SYNCMODE_CPU_* は // 実は同じ値なのでそのまま渡してよいことにする。 - static_assert(CPU_STATE_NORMAL == Syncer::SCHED_CPU_NORMAL, ""); - static_assert(CPU_STATE_STOP == Syncer::SCHED_CPU_STOP, ""); - static_assert(CPU_STATE_HALT == Syncer::SCHED_CPU_HALT, ""); + static_assert(CPU_STATE_NORMAL == Syncer::SYNCMODE_CPU_NORMAL, ""); + static_assert(CPU_STATE_STOP == Syncer::SYNCMODE_CPU_STOP, ""); + static_assert(CPU_STATE_HALT == Syncer::SYNCMODE_CPU_HALT, ""); if (cpu_state != new_state) { cpu_state = new_state; @@ -380,23 +439,12 @@ MPU680x0Device::Halt() UIMessage::Post(UIMessage::HALT); } -// モニター更新 (レジスタウィンドウ) +// モニター更新の下請け (レジスタ共通部分) void -MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen) +MPU680x0Device::MonitorUpdateRegCommon(TextScreen& screen, + m68kreg& tmp, uint32 tmp_ppc, uint32 tmp_state) { - m68kreg tmp; - uint32 tmp_ppc; - uint32 tmp_state; int x; - int y; - - screen.Clear(); - - // ローカルにコピー - // ただし一部は reg ではなく cpu クラス本体にある - tmp = reg; - tmp_ppc = ppc; - tmp_state = cpu_state; // データレジスタ、アドレスレジスタ for (int i = 0; i < 4; i++) { @@ -457,21 +505,190 @@ MPU680x0Device::MonitorUpdateReg(Monitor screen.Print(50, 3, TA::On, "corrupted cpu_state=%u", tmp_state); break; } +} - // Cache +// モニタ更新の下請け (FPU) +int +MPU680x0Device::MonitorUpdateFPU(TextScreen& screen, int y, m68kreg& tmp) +{ + int x; + +/* +0123456789012345678901234567890123456789012345678901234567890123456789012345 +FP0:7fff_ffffffff_ffffffff = NAN +FPCR: 0000 BS SN OP OV UF DZ I2 I1 Prec=.X Mode=Minus +FPSR: 00000000 N Z INF NAN Q=$xx BS SN OP OV UF DZ I2 I1 AV AO AU AD AI +FPIAR:00000000 +*/ + + x = 0; + screen.Puts(x, y++, ""); + for (int i = 0; i < 8; i++) { + screen.Print(x, y++, "FP%u:%04x_%08x_%08x = %s", + i, + tmp.fpframe.fpf_regs[i * 3 + 0] >> 16, + tmp.fpframe.fpf_regs[i * 3 + 1], + tmp.fpframe.fpf_regs[i * 3 + 2], + ExtToStr(&tmp.fpframe.fpf_regs[i * 3]).c_str()); + } + + // FPCR + uint32 fpcr = tmp.fpframe.fpf_fpcr; + screen.Puts(0, y, "FPCR:"); + screen.Print(10, y, "%04x", fpcr); + x = 34; + screen.Puts(x + 0, y, TA::OnOff(fpcr & 0x8000), "BS"); + screen.Puts(x + 3, y, TA::OnOff(fpcr & 0x4000), "SN"); + screen.Puts(x + 6, y, TA::OnOff(fpcr & 0x2000), "OE"); + screen.Puts(x + 9, y, TA::OnOff(fpcr & 0x1000), "OF"); + screen.Puts(x + 12, y, TA::OnOff(fpcr & 0x0800), "UF"); + screen.Puts(x + 15, y, TA::OnOff(fpcr & 0x0400), "DZ"); + screen.Puts(x + 18, y, TA::OnOff(fpcr & 0x0200), "X2"); + screen.Puts(x + 21, y, TA::OnOff(fpcr & 0x0100), "X1"); + screen.Print(x + 25, y, "RP=.%c RM=%s", + "XSD?"[(fpcr >> 6) & 3], + rmstr[(fpcr >> 4) & 3]); + y++; + + // FPSR + uint32 fpsr = tmp.fpframe.fpf_fpsr; + uint32 cc = fpsr >> 24; + screen.Print(0, y, "FPSR: %08x", fpsr); + x = 15; + screen.Puts(x + 0, y, TA::OnOff(cc & 0x08), "N"); + screen.Puts(x + 2, y, TA::OnOff(cc & 0x04), "Z"); + screen.Puts(x + 4, y, TA::OnOff(cc & 0x02), "Inf"); + screen.Puts(x + 8, y, TA::OnOff(cc & 0x01), "NAN"); + screen.Print(x + 12, y, "Q=$%02x", (fpsr >> 16) & 0xff); + x = 34; + screen.Puts(x + 0, y, TA::OnOff(fpsr & 0x8000), "BS"); + screen.Puts(x + 3, y, TA::OnOff(fpsr & 0x4000), "SN"); + screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x2000), "OE"); + screen.Puts(x + 9, y, TA::OnOff(fpsr & 0x1000), "OF"); + screen.Puts(x + 12, y, TA::OnOff(fpsr & 0x0800), "UF"); + screen.Puts(x + 15, y, TA::OnOff(fpsr & 0x0400), "DZ"); + screen.Puts(x + 18, y, TA::OnOff(fpsr & 0x0200), "X2"); + screen.Puts(x + 21, y, TA::OnOff(fpsr & 0x0100), "X1"); + screen.Puts(x + 25, y, TA::OnOff(fpsr & 0x80), "AV"); + screen.Puts(x + 28, y, TA::OnOff(fpsr & 0x40), "AO"); + screen.Puts(x + 31, y, TA::OnOff(fpsr & 0x20), "AU"); + screen.Puts(x + 34, y, TA::OnOff(fpsr & 0x10), "AZ"); + screen.Puts(x + 37, y, TA::OnOff(fpsr & 0x08), "AX"); + y++; + + // FPIAR + screen.Print(0, y++, "FPIAR:%08x", tmp.fpframe.fpf_fpiar); + + return y; +} + + +// +// 68030 +// + +// コンストラクタ +MPU68030Device::MPU68030Device() + : inherited() +{ + mpu_type = m680x0MPUType::M68030; + mpu_name = "MC68030"; + SetName("MPU(68030)"); + + // MMU.xRP.DT == 0 になってはいけない(MMU 構成例外)。 + SetSRP(0x00000001, 0); + SetCRP(0x00000001, 0); + + // キャッシュ + icache.reset(new m68030Cache()); + dcache.reset(new m68030Cache()); + + // レジスタモニター (サイズは Init で確定する) + reg_monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this); + reg_monitor->func = ToMonitorCallback(&MPU68030Device::MonitorUpdateReg); + + // ATC モニター + atc_monitor = gMonitorManager->Regist(ID_MONITOR_MPUATC, this); + atc_monitor->func = ToMonitorCallback(&MPU68030Device::MonitorUpdateATC); + atc_monitor->SetSize(114, m68030ATCTable::LINES + 6); + + // キャッシュモニター + cache_monitor = gMonitorManager->Regist(ID_MONITOR_MPUCACHE, this); + cache_monitor->func = + ToMonitorCallback(&MPU68030Device::MonitorUpdateCache); + cache_monitor->SetSize(48, 20 * 2 + 1); +} + +// デストラクタ +MPU68030Device::~MPU68030Device() +{ +} + +void +MPU68030Device::SetLogLevel(int loglevel_) +{ + inherited::SetLogLevel(loglevel_); + + atc.SetLogLevel(loglevel_); +} + +static int +sort_atc(const void *a, const void *b) +{ + const uint32 *ua = (const uint32 *)a; + const uint32 *ub = (const uint32 *)b; + return *ub - *ua; +} + +// モニター更新 (レジスタ) +void +MPU68030Device::MonitorUpdateReg(Monitor *, TextScreen& screen) +{ + m68kreg tmp; + uint32 tmp_ppc; + uint32 tmp_state; + int y; + + screen.Clear(); + + // ローカルにコピーする。 + // ただし一部は reg ではなく cpu クラス本体にある。 + tmp = reg; + tmp_ppc = ppc; + tmp_state = cpu_state; + + // 共通部分。 + MonitorUpdateRegCommon(screen, tmp, tmp_ppc, tmp_state); + + // Cache/MMU 部分。 y = 4; + y = MonitorUpdateMMU(screen, y, tmp); + + // FPU はある時だけ表示。 + if (HasFPU()) { + MonitorUpdateFPU(screen, y, tmp); + } +} + +// モニター更新の下請け (Cache/MMU 部分) +int +MPU68030Device::MonitorUpdateMMU(TextScreen& screen, int y, m68kreg& tmp) +{ + int x; + + // Cache screen.Puts(0, y++, ""); screen.Print(0, y, "CACR:%08x(", tmp.cacr); - screen.Puts(14, y, TA::OnOff(tmp.cacr & M68K::CACR_WA), "WA"); - screen.Puts(17, y, TA::OnOff(tmp.cacr & M68K::CACR_DBE), "DBE"); + screen.Puts(14, y, TA::OnOff(tmp.cacr & M68030::CACR_WA), "WA"); + screen.Puts(17, y, TA::OnOff(tmp.cacr & M68030::CACR_DBE), "DBE"); screen.Puts(21, y, "- -"); - screen.Puts(25, y, TA::OnOff(tmp.cacr & M68K::CACR_FD), "FD"); - screen.Puts(28, y, TA::OnOff(tmp.cacr & M68K::CACR_ED), "ED"); + screen.Puts(25, y, TA::OnOff(tmp.cacr & M68030::CACR_FD), "FD"); + screen.Puts(28, y, TA::OnOff(tmp.cacr & M68030::CACR_ED), "ED"); screen.Puts(31, y, "000"); - screen.Puts(35, y, TA::OnOff(tmp.cacr & M68K::CACR_IBE), "IBE"); + screen.Puts(35, y, TA::OnOff(tmp.cacr & M68030::CACR_IBE), "IBE"); screen.Puts(39, y, "- -"); - screen.Puts(43, y, TA::OnOff(tmp.cacr & M68K::CACR_FI), "FI"); - screen.Puts(46, y, TA::OnOff(tmp.cacr & M68K::CACR_EI), "EI"); + screen.Puts(43, y, TA::OnOff(tmp.cacr & M68030::CACR_FI), "FI"); + screen.Puts(46, y, TA::OnOff(tmp.cacr & M68030::CACR_EI), "EI"); screen.Putc(48, y, ')'); screen.Print(50, y, "CAAR:%08x", tmp.caar); y++; @@ -524,95 +741,12 @@ MPU680x0Device::MonitorUpdateReg(Monitor screen.Print(x, y, "---N=%u)", tmp.mmusr & m68030MMUSR::N); y++; - // FPU - if (has_fpu != 0) { - MonitorUpdateFPU(screen, y, tmp); - } -} - -// モニタ (FPU) -void -MPU680x0Device::MonitorUpdateFPU(TextScreen& screen, int y, m68kreg& tmp) -{ - int x; - - x = 0; - screen.Puts(x, y++, ""); - for (int i = 0; i < 8; i++) { - screen.Print(x, y + i, "FP%u:%04x_%08x_%08x (%-20s)", - i, - tmp.fpframe.fpf_regs[i * 3 + 0] >> 16, - tmp.fpframe.fpf_regs[i * 3 + 1], - tmp.fpframe.fpf_regs[i * 3 + 2], - "not yet"); - } - - x = 51; - - // FPCR - static const char * const rpstr[] = { - ".EXT", - ".SGL", - ".DBL", - ".???", - }; - uint32 fpcr = tmp.fpframe.fpf_fpcr; - screen.Print(x, y++, "FPCR:%04x", fpcr); - screen.Puts(x + 2, y, TA::OnOff(fpcr & 0x8000), "BS"); - screen.Puts(x + 5, y, TA::OnOff(fpcr & 0x4000), "SN"); - screen.Puts(x + 8, y, TA::OnOff(fpcr & 0x2000), "OP"); - screen.Puts(x + 11, y, TA::OnOff(fpcr & 0x1000), "OV"); - screen.Puts(x + 14, y, TA::OnOff(fpcr & 0x0800), "UF"); - screen.Puts(x + 17, y, TA::OnOff(fpcr & 0x0400), "DZ"); - screen.Puts(x + 20, y, TA::OnOff(fpcr & 0x0200), "I2"); - screen.Puts(x + 23, y, TA::OnOff(fpcr & 0x0100), "I1"); - y++; - screen.Print(x + 2, y++, "RP=%s RM=%s", - rpstr[(fpcr >> 6) & 3], - rmstr[(fpcr >> 4) & 3]); - - // FPSR - uint32 fpsr = tmp.fpframe.fpf_fpsr; - uint32 cc = fpsr >> 24; - screen.Print(x, y++, "FPSR:%08x", fpsr); - screen.Puts(x + 2, y, TA::OnOff(cc & 0x08), "N"); - screen.Puts(x + 4, y, TA::OnOff(cc & 0x04), "Z"); - screen.Puts(x + 6, y, TA::OnOff(cc & 0x02), "Inf"); - screen.Puts(x + 10, y, TA::OnOff(cc & 0x01), "NAN"); - screen.Print(x + 14, y, "Q=$%02x", (fpsr >> 16) & 0xff); - y++; - screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x8000), "BS"); - screen.Puts(x + 5, y, TA::OnOff(fpsr & 0x4000), "SN"); - screen.Puts(x + 8, y, TA::OnOff(fpsr & 0x2000), "OP"); - screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x1000), "OV"); - screen.Puts(x + 14, y, TA::OnOff(fpsr & 0x0800), "UF"); - screen.Puts(x + 17, y, TA::OnOff(fpsr & 0x0400), "DZ"); - screen.Puts(x + 20, y, TA::OnOff(fpsr & 0x0200), "I2"); - screen.Puts(x + 23, y, TA::OnOff(fpsr & 0x0100), "I1"); - y++; - screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x80), "IOP"); - screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x80), "OVFL"); - screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x80), "UNFL"); - screen.Puts(x + 16, y, TA::OnOff(fpsr & 0x80), "DZ"); - screen.Puts(x + 19, y, TA::OnOff(fpsr & 0x80), "INEX"); - y++; - - // FPIAR - screen.Print(x, y++, "FPIAR:%08x", tmp.fpframe.fpf_fpiar); -} - -static int -sort_atc(const void *a, const void *b) -{ - const uint32 *ua = (const uint32 *)a; - const uint32 *ub = (const uint32 *)b; - return *ub - *ua; + return y; } - -// モニター更新 (ATC) +// モニター更新 (68030 ATC) void -MPU680x0Device::MonitorUpdateATC(Monitor *, TextScreen& screen) +MPU68030Device::MonitorUpdateATC(Monitor *, TextScreen& screen) { m68030ATCTable *table; @@ -717,7 +851,7 @@ MPU680x0Device::MonitorUpdateATC(Monitor // 統計情報を更新 (Syncer から呼ばれる) void -MPU680x0Device::CalcStat() +MPU68030Device::CalcStat() { // ATC のヒット率。 for (auto& table : atc.tables) { @@ -758,9 +892,9 @@ dcache_fc2str(const m68030CacheLine& l) return "0U234S67"[l.GetFC()]; } -// モニタ更新 (キャッシュ) +// モニタ更新 (68030 キャッシュ) void -MPU680x0Device::MonitorUpdateCache(Monitor *, TextScreen& screen) +MPU68030Device::MonitorUpdateCache(Monitor *, TextScreen& screen) { int y; @@ -780,9 +914,9 @@ MPU680x0Device::MonitorUpdateCache(Monit MonitorUpdateCache1(screen, y, dcache.get(), dcache_fc2str); } -// モニタ更新 (キャッシュ片方の下請け) +// モニタ更新 (68030 キャッシュ片方の下請け) int -MPU680x0Device::MonitorUpdateCache1(TextScreen& screen, int y, +MPU68030Device::MonitorUpdateCache1(TextScreen& screen, int y, m68030Cache *cache, char (*fc2str)(const m68030CacheLine&)) { screen.Puts(0, y, "Tag Address Data[0]"); @@ -826,3 +960,155 @@ MPU680x0Device::MonitorUpdateCache1(Text return y; } + + +// +// 68040 +// + +// コンストラクタ +MPU68040Device::MPU68040Device() + : inherited() +{ + mpu_type = m680x0MPUType::M68040; + mpu_name = "MC68040"; + SetName("MPU(68040)"); + + mmu_itt[0].reset(new m68040TT("ITT0", ®.itt[0])); + mmu_itt[1].reset(new m68040TT("ITT1", ®.itt[1])); + mmu_dtt[0].reset(new m68040TT("DTT0", ®.dtt[0])); + mmu_dtt[1].reset(new m68040TT("DTT1", ®.dtt[1])); + mmu_tc.reset(new m68040TC()); + atc_inst.reset(new m68040ATC()); + atc_data.reset(new m68040ATC()); + + // レジスタモニター (サイズは Init で確定する) + reg_monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this); + reg_monitor->func = ToMonitorCallback(&MPU68040Device::MonitorUpdateReg); + + // ATC モニター (Inst/Data) + atc_monitor = gMonitorManager->Regist(ID_MONITOR_MPUATC, this); + atc_monitor->func = ToMonitorCallback(&MPU68040Device::MonitorUpdateATC); + atc_monitor->SetSize(121, 34); +} + +// デストラクタ +MPU68040Device::~MPU68040Device() +{ +} + +// モニター更新 (レジスタ) +void +MPU68040Device::MonitorUpdateReg(Monitor *, TextScreen& screen) +{ + m68kreg tmp; + uint32 tmp_ppc; + uint32 tmp_state; + FPU40 tmp_fpu40; + int y; + + screen.Clear(); + + // ローカルにコピーする。 + // ただし一部は reg ではなく cpu クラス本体にある。 + tmp = reg; + tmp_ppc = ppc; + tmp_state = cpu_state; + tmp_fpu40 = fpu40; + + // 共通部分。 + MonitorUpdateRegCommon(screen, tmp, tmp_ppc, tmp_state); + + // Cache/MMU 部分。 + y = 4; + y = MonitorUpdateMMU(screen, y, tmp); + + // FPU はある時だけ表示。 + if (HasFPU()) { + y = MonitorUpdateFPU(screen, y, tmp); + MonitorUpdateFPU40(screen, y, tmp_fpu40); + } +} + +// モニター更新の下請け (Cache/MMU 部分) +int +MPU68040Device::MonitorUpdateMMU(TextScreen& screen, int y, m68kreg& tmp) +{ + int x; + + screen.Puts(0, y++, ""); + screen.Print(0, y, "SRP:%08x TC:%04x( )", tmp.srp40, tmp.tc40); + screen.Putc(24, y, TA::OnOff(tmp.tc40 & m68040TC::E) | 'E'); + screen.Putc(26, y, TA::OnOff(tmp.tc40 & m68040TC::P) | 'P'); + y++; + screen.Print(0, y++, "URP:%08x", tmp.urp40); + screen.Print(0, y, "MMUSR:%05x'%03x", + (tmp.mmusr40 >> 12), + (tmp.mmusr40 & 0xfff)); + x = 16; + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::B) | 'B'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::G) | 'G'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::U1)| 'U'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::U0)| 'U'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::S) | 'S'); + x++; + screen.Print(x, y, "CM%u", (tmp.mmusr40 & m68040MMUSR::CM) >> 5); + x += 4; + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::M) | 'M'); + screen.Putc(x++, y, '-'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::W) | 'W'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::T) | 'T'); + screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::R) | 'R'); + y++; + + screen.Print(0, y, "CACR:%08x(", tmp.cacr); + screen.Puts(14, y, TA::OnOff(tmp.cacr & M68040::CACR_DE), "DE"); + screen.Puts(17, y, TA::OnOff(tmp.cacr & M68040::CACR_IE), "IE"); + screen.Putc(19, y, ')'); + y++; + + y -= 4; + x = 33; + MonitorUpdateTT(screen, x, y++, "ITT0", tmp.itt[0]); + MonitorUpdateTT(screen, x, y++, "ITT1", tmp.itt[1]); + MonitorUpdateTT(screen, x, y++, "DTT0", tmp.dtt[0]); + MonitorUpdateTT(screen, x, y++, "DTT1", tmp.dtt[1]); + + return y; +} + +// *TTn 1つ分の下請け。 +void +MPU68040Device::MonitorUpdateTT(TextScreen& screen, int x, int y, + const char *name, uint32 tt) +{ + bool e = (tt & m68040TT::E); + + screen.Print(x, y, "%s:%08x(", name, tt); + x += 14; + screen.Putc(x++, y, TA::OnOff(e) | 'E'); + x++; + screen.Print(x, y, (e ? TA::Normal : TA::Disable), + "Base=$%02x Mask=$%02x", (tt >> 24), (tt >> 16) & 0xff); + + x += 18; + if (e) { + screen.Putc(x++, y, TA::OnOff(tt & m68040TT::S_IGN) | 'S'); + screen.Putc(x++, y, TA::OnOff(tt & m68040TT::S_FC2) | 'S'); + screen.Putc(x++, y, TA::OnOff(tt & m68040TT::U1) | 'U'); + screen.Putc(x++, y, TA::OnOff(tt & m68040TT::U0) | 'U'); + x++; + screen.Print(x, y, "CM%u", (tt & m68040TT::CM) >> 5); + x += 4; + screen.Putc(x++, y, TA::OnOff(tt & m68040TT::W) | 'W'); + } else { + screen.Puts(x, y, TA::Disable, "---- --- -"); + x += 10; + } + screen.Putc(x, y, ')'); +} + +void +MPU68040Device::CalcStat() +{ +}