|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2017 [email protected] ! 4: // ! 5: ! 6: // MPU (m680x0) ! 7: ! 8: #include "mpu680x0.h" ! 9: #include "m68030excep.h" ! 10: #include "config.h" ! 11: #include "mainapp.h" ! 12: #include "vm.h" ! 13: #include <math.h> ! 14: ! 15: std::unique_ptr<MPUATC> gMPUATC; ! 16: std::unique_ptr<MPUBrHist> gMPUBrHist; ! 17: ! 18: // コンストラクタ ! 19: // ! 20: // reset_vector にはリセットベクタの番地を指定する。 ! 21: // 本来の MPU の動作は、リセット例外時にメモリの $0, $4 番地 (もっと言えば ! 22: // FC がプログラム空間の) から SP, PC を読み込むのだが、そのためにメモリ空間 ! 23: // を切り替える処理はリセット時にしか必要ないわりに結構手間である。そしてこの ! 24: // m68k 恒例のブートストラップ動作はソフトウェア的には一切観測する手段がない。 ! 25: // であれば、リセット例外時にこのアドレスから SP, PC の値を直接読み込んだと ! 26: // しても動作にはまったく違いは出ない。そしてバス・メモリ空間の実装も簡略化 ! 27: // できる。すごい楽。 ! 28: MPU680x0Device::MPU680x0Device(uint32 reset_vector) ! 29: { ! 30: monitor.Init(79, 16); ! 31: ! 32: cpu = m68030_init(reset_vector); ! 33: ! 34: // モニタ用の別オブジェクト ! 35: gMPUATC.reset(new MPUATC(cpu)); ! 36: gMPUBrHist.reset(new MPUBrHist(cpu)); ! 37: } ! 38: ! 39: // デストラクタ ! 40: MPU680x0Device::~MPU680x0Device() ! 41: { ! 42: } ! 43: ! 44: bool ! 45: MPU680x0Device::Init() ! 46: { ! 47: // FPU (6888x) ! 48: if (gMainApp.GetVMType() == VMTYPE_LUNA) { ! 49: // LUNA は 68881 固定 (設定は見ない) ! 50: cpu->has_fpu = 1; ! 51: } else { ! 52: // X68k は設定による ! 53: const ConfigItem& item = gConfig->Get("mpu-has-fpu"); ! 54: cpu->has_fpu = item.AsInt(); ! 55: if (cpu->has_fpu < 0 || cpu->has_fpu > 2) { ! 56: item.Err(); ! 57: return false; ! 58: } ! 59: } ! 60: ! 61: return true; ! 62: } ! 63: ! 64: // リセット ! 65: // (MPU が動くのはこの後 Scheduler::Run() を発行した後) ! 66: void ! 67: MPU680x0Device::ResetHard() ! 68: { ! 69: m68030_exception_reset(cpu); ! 70: } ! 71: ! 72: // MPU を request で指定されたクロックサイクルだけ実行する。 ! 73: // 今回の実行サイクル数が request を越えた命令境界まで実行するので ! 74: // 実際には少しはみ出る。 ! 75: // また実行中にデバイスアクセスなどによりスケジューラにイベントが ! 76: // 追加されるとその次の命令境界で処理を打ち切って戻ってくる。 ! 77: // 戻り値は CPU の outer フラグ。 ! 78: uint32 ! 79: MPU680x0Device::Run(uint64 request) ! 80: { ! 81: return m68030_run(cpu, request); ! 82: } ! 83: ! 84: // 割り込み発生を MPU に通知 (オートベクタ) ! 85: void ! 86: MPU680x0Device::Interrupt(int level) ! 87: { ! 88: int vector = M68K_EXCEP_LEVEL_BASE + level; ! 89: m68030_interrupt(cpu, level, vector); ! 90: } ! 91: ! 92: // 割り込み発生を MPU に通知 (ベクタ) ! 93: void ! 94: MPU680x0Device::Interrupt(int level, int vector) ! 95: { ! 96: m68030_interrupt(cpu, level, vector); ! 97: } ! 98: ! 99: // A-Line 命令エミュレーションのコールバックを指定。 ! 100: void ! 101: MPU680x0Device::SetALineCallback(bool (*callback)(m68kcpu *, void*), void *arg) ! 102: { ! 103: cpu->aline_callback = callback; ! 104: cpu->aline_arg = arg; ! 105: } ! 106: ! 107: // F-Line 命令エミュレーションのコールバックを指定。 ! 108: void ! 109: MPU680x0Device::SetFLineCallback(bool (*callback)(m68kcpu *, void*), void *arg) ! 110: { ! 111: cpu->fline_callback = callback; ! 112: cpu->fline_arg = arg; ! 113: } ! 114: ! 115: // モニター更新 (レジスタウィンドウ) ! 116: bool ! 117: MPU680x0Device::MonitorUpdate() ! 118: { ! 119: m68kreg reg; ! 120: uint32 ppc; ! 121: int x; ! 122: int y; ! 123: ! 124: monitor.Clear(); ! 125: ! 126: // ローカルにコピー ! 127: // ただし PPC だけ reg 構造体ではなく cpu クラス側にある ! 128: reg = cpu->reg; ! 129: ppc = cpu->ppc; ! 130: ! 131: // データレジスタ、アドレスレジスタ ! 132: for (int i = 0; i < 4; i++) { ! 133: monitor.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x", ! 134: i + 0, reg.da[i], ! 135: i + 4, reg.da[i + 4], ! 136: i + 0, reg.da[i + 8], ! 137: i + 4, reg.da[i + 12]); ! 138: } ! 139: ! 140: // 5列目 ! 141: x = 50; ! 142: // SR ! 143: monitor.Print(x, 0, "SR:%04x(%c%c%c%c%c)", ! 144: (reg.sr_h() | reg.ccr.Get()), ! 145: (reg.ccr.IsX()) ? 'X' : '-', ! 146: (reg.ccr.IsN()) ? 'N' : '-', ! 147: (reg.ccr.IsZ()) ? 'Z' : '-', ! 148: (reg.ccr.IsV()) ? 'V' : '-', ! 149: (reg.ccr.IsC()) ? 'C' : '-'); ! 150: ! 151: // VBR ! 152: monitor.Print(x, 1, "VBR:%08x", reg.vbr); ! 153: ! 154: // *SP ! 155: uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M ! 156: if (ms == 3) { ! 157: // Supervisor (Master) mode (A7=MSP, USP/ISP) ! 158: monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); ! 159: monitor.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp); ! 160: } else if (ms == 2) { ! 161: // Supervisor (Interrupt) mode (A7=ISP, USP/MSP) ! 162: monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); ! 163: monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); ! 164: } else { ! 165: // User mode (A7=USP, ISP/MSP) ! 166: monitor.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp); ! 167: monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); ! 168: } ! 169: ! 170: // 6列目 ! 171: // PC: 01234567 ! 172: // SFC:1 DFC:1 ! 173: // CACR:01234567 ! 174: // CAAR:01234567 ! 175: x = 66; ! 176: monitor.Print(x, 0, "PC: %08x", ppc); ! 177: monitor.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc); ! 178: monitor.Print(x, 2, "CACR:%08x", reg.cacr); ! 179: monitor.Print(x, 3, "CAAR:%08x", reg.caar); ! 180: ! 181: // XXX どこに置くのがいいか ! 182: if (reg.state == 0) { ! 183: monitor.Print(25, 4, "State: Running"); ! 184: } else if (reg.state == CPU_REQ_STOP) { ! 185: monitor.Print(25, 4, "State: STOP instruction"); ! 186: } else if (reg.state == CPU_REQ_HALT) { ! 187: monitor.Print(25, 4, "State: Double Bus Fault"); ! 188: } ! 189: ! 190: // MMU ! 191: x = 0; ! 192: y = 4; ! 193: monitor.Print(x, y++, "<MMU>"); ! 194: monitor.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l); ! 195: monitor.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l); ! 196: x += 23; ! 197: for (int i = 0; i < 2; i++) { ! 198: uint32 tt = reg.tt[i]; ! 199: monitor.Print(x, y + i, "TT%d:%08x(%c%c%c)", ! 200: i, tt, ! 201: (tt & m68030TT::E) ? 'E' : '-', ! 202: (tt & m68030TT::CI) ? 'C' : '-', ! 203: (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W')); ! 204: } ! 205: x += 19; ! 206: monitor.Print(x, y, "TC:%08x(%c%c%c)", ! 207: reg.tc, ! 208: (reg.tc & m68030TC::TC_E) ? 'E' : '-', ! 209: (reg.tc & m68030TC::TC_SRE) ? 'S' : '-', ! 210: (reg.tc & m68030TC::TC_FCL) ? 'F' : '-'); ! 211: monitor.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)", ! 212: reg.mmusr, ! 213: (reg.mmusr & m68030MMUSR::B) ? 'B' : '-', ! 214: (reg.mmusr & m68030MMUSR::L) ? 'L' : '-', ! 215: (reg.mmusr & m68030MMUSR::S) ? 'S' : '-', ! 216: (reg.mmusr & m68030MMUSR::W) ? 'W' : '-', ! 217: (reg.mmusr & m68030MMUSR::I) ? 'I' : '-', ! 218: (reg.mmusr & m68030MMUSR::M) ? 'M' : '-', ! 219: (reg.mmusr & m68030MMUSR::T) ? 'T' : '-', ! 220: (reg.mmusr & m68030MMUSR::N)); ! 221: ! 222: // FPU ! 223: x = 0; ! 224: y = 7; ! 225: monitor.Print(x, y++, "<FPU>"); ! 226: for (int i = 0; i < 8; i++) { ! 227: monitor.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)", ! 228: i, ! 229: reg.fpframe.fpf_regs[i * 3 + 0] >> 16, ! 230: reg.fpframe.fpf_regs[i * 3 + 1], ! 231: reg.fpframe.fpf_regs[i * 3 + 2], ! 232: "not yet"); ! 233: } ! 234: ! 235: x = 51; ! 236: ! 237: // FPCR ! 238: static const char * const rpstr[] = { ! 239: ".EXT", ! 240: ".SGL", ! 241: ".DBL", ! 242: ".???", ! 243: }; ! 244: static const char * const rmstr[] = { ! 245: "Near", ! 246: "Zero", ! 247: "Minus", ! 248: "Plus", ! 249: }; ! 250: uint32 fpcr = reg.fpframe.fpf_fpcr; ! 251: monitor.Print(x, y++, "FPCR:%04x", fpcr); ! 252: monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s", ! 253: (fpcr & 0x8000) ? "BS" : "--", ! 254: (fpcr & 0x4000) ? "SN" : "--", ! 255: (fpcr & 0x2000) ? "OP" : "--", ! 256: (fpcr & 0x1000) ? "OV" : "--", ! 257: (fpcr & 0x0800) ? "UF" : "--", ! 258: (fpcr & 0x0400) ? "DZ" : "--", ! 259: (fpcr & 0x0200) ? "I2" : "--", ! 260: (fpcr & 0x0100) ? "I1" : "--"); ! 261: monitor.Print(x + 2, y++, "RP=%s RM=%s", ! 262: rpstr[(fpcr >> 6) & 3], ! 263: rmstr[(fpcr >> 4) & 3]); ! 264: ! 265: // FPSR ! 266: uint32 fpsr = reg.fpframe.fpf_fpsr; ! 267: uint32 cc = fpsr >> 24; ! 268: monitor.Print(x, y++, "FPSR:%08x", fpsr); ! 269: monitor.Print(x + 2, y++, "%c %c %s %s Q=$%02x", ! 270: (cc & 0x08) ? 'N' : '-', ! 271: (cc & 0x04) ? 'Z' : '-', ! 272: (cc & 0x02) ? "Inf" : "---", ! 273: (cc & 0x01) ? "NAN" : "---", ! 274: (fpsr >> 16) & 0xff); ! 275: monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s", ! 276: (fpsr & 0x8000) ? "BS" : "--", ! 277: (fpsr & 0x4000) ? "SN" : "--", ! 278: (fpsr & 0x2000) ? "OP" : "--", ! 279: (fpsr & 0x1000) ? "OV" : "--", ! 280: (fpsr & 0x0800) ? "UF" : "--", ! 281: (fpsr & 0x0400) ? "DZ" : "--", ! 282: (fpsr & 0x0200) ? "I2" : "--", ! 283: (fpsr & 0x0100) ? "I1" : "--"); ! 284: monitor.Print(x + 2, y++, "%s %s %s %s %s", ! 285: (fpsr & 0x80) ? "IOP" : "---", ! 286: (fpsr & 0x40) ? "OVFL" : "----", ! 287: (fpsr & 0x20) ? "UNFL" : "----", ! 288: (fpsr & 0x10) ? "DZ" : "--", ! 289: (fpsr & 0x08) ? "INEX" : "----"); ! 290: ! 291: // FPIAR ! 292: monitor.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar); ! 293: ! 294: return true; ! 295: } ! 296: ! 297: // CPU 側からのコールバック。RESET 命令ハンドラ ! 298: void ! 299: m68030_reset_inst(m68kcpu *cpu) ! 300: { ! 301: gVM->ResetSoft(); ! 302: } ! 303: ! 304: // ! 305: // ATC モニタ ! 306: // ! 307: MPUATC::MPUATC(m68kcpu *arg) ! 308: { ! 309: cpu = arg; ! 310: #if !defined(ATC_SINGLE) ! 311: monitor.Init(131, m68030ATCTable::LINES + 3); ! 312: #else ! 313: monitor.Init(31, 24); ! 314: #endif ! 315: } ! 316: ! 317: bool ! 318: MPUATC::MonitorUpdate() ! 319: { ! 320: m68030ATCTable *table; ! 321: #if !defined(ATC_SINGLE) ! 322: struct { ! 323: int fc; ! 324: const char *name; ! 325: } fclist[] = { ! 326: { 1, "User/Data" }, ! 327: { 2, "User/Program" }, ! 328: { 5, "Super/Data" }, ! 329: { 6, "Super/Program" }, ! 330: }; ! 331: ! 332: monitor.Clear(); ! 333: ! 334: // 行数は左端にだけ ! 335: for (int i = 0; i < m68030ATCTable::LINES; i++) { ! 336: monitor.Print(0, i + 2, "%02d:", i); ! 337: } ! 338: ! 339: for (int t = 0; t < countof(fclist); t++) { ! 340: int x = t * 32 + 4; ! 341: int fc = fclist[t].fc; ! 342: const char *name = fclist[t].name; ! 343: double r; ! 344: int i; ! 345: ! 346: table = &cpu->atc.tables[fc]; ! 347: monitor.Print(x, 0, "FC=%d %s", fc, name); ! 348: monitor.Print(x, 1, "LAddr PAddr Flag Hit%% Age"); ! 349: // 先に統計用の母数を計算 ! 350: uint64 total = 0; ! 351: for (i = 0; i < countof(table->hit); i++) { ! 352: total += table->hit[i]; ! 353: } ! 354: total += table->hit_head; ! 355: ! 356: // エントリ表示 ! 357: for (i = 0; i < countof(table->line); i++) { ! 358: m68030ATCLine& a = table->line[i]; ! 359: int attr; ! 360: if (a.IsInvalid()) { ! 361: attr = TA::Disable; ! 362: } else if (table->head == &a) { ! 363: attr = TA::Em; ! 364: } else { ! 365: attr = TA::Normal; ! 366: } ! 367: ! 368: monitor.Print(x, i + 2, attr, "%08x %08x %c%c%c", ! 369: a.GetLAddr(), ! 370: a.GetPAddr(), ! 371: a.IsBusError() ? 'B' : '-', ! 372: a.IsWProtect() ? 'P' : '-', ! 373: a.IsModified() ? 'M' : '-'); ! 374: } ! 375: // ヘッドのヒット率 ! 376: monitor.Print(x + 0, i + 2, "head"); ! 377: r = (double)table->hit_head * 100 / total; ! 378: if (!isnan(r)) { ! 379: monitor.Print(x + 5, i + 2, "%4.1f%%", r); ! 380: } ! 381: // 配列のヒット率とミス率 ! 382: monitor.Print(x + 17, i + 2, "miss"); ! 383: for (i = 0; i < countof(table->hit); i++) { ! 384: r = (double)(table->hit[i] * 100) / total; ! 385: if (!isnan(r)) { ! 386: monitor.Print(x + 22, i + 2, "%4.1f%%", r); ! 387: } ! 388: } ! 389: // カウンタ ! 390: // 分かりやすさのため最大値からの差(距離)を表示 ! 391: for (i = 0; i < countof(table->line); i++) { ! 392: m68030ATCLine& a = table->line[i]; ! 393: if (!a.IsInvalid()) { ! 394: monitor.Print(x + 27, i + 2, "%4d", table->head->age - a.age); ! 395: } ! 396: } ! 397: } ! 398: #else ! 399: m68030ATCLine *a; ! 400: int i; ! 401: ! 402: table = &cpu->atc.tables[0]; ! 403: monitor.Clear(); ! 404: ! 405: monitor.Print(0, 0, "No. FC LAddr PAddr Flag"); ! 406: for (a = table->head, i = 0; a; a = a->next, i++) { ! 407: monitor.Print(0, i + 1, "%02d:", i); ! 408: if (!a->IsInvalid()) { ! 409: char dp; ! 410: switch (a->fc & 3) { ! 411: case 1: dp = 'D'; break; ! 412: case 2: dp = 'P'; break; ! 413: default: dp = '?'; break; ! 414: } ! 415: monitor.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c", ! 416: a->fc, ! 417: (a->fc & 4) ? 'S' : 'U', ! 418: dp, ! 419: a->GetLAddr(), a->GetPAddr(), ! 420: a->IsBusError() ? 'B' : '-', ! 421: a->IsWProtect() ? 'W' : '-', ! 422: a->IsModified() ? 'M' : '-'); ! 423: } ! 424: } ! 425: #endif ! 426: return true; ! 427: } ! 428: ! 429: // ! 430: // ブランチ履歴モニタ ! 431: // ! 432: MPUBrHist::MPUBrHist(m68kcpu *arg) ! 433: { ! 434: cpu = arg; ! 435: monitor.Init(70, 16); ! 436: } ! 437: ! 438: bool ! 439: MPUBrHist::MonitorUpdate() ! 440: { ! 441: int i; ! 442: uint8 t; ! 443: ! 444: // 0 1 2 3 4 5 6 ! 445: // 0123456789012345678901234567890123456789012345678901234567890123456789 ! 446: // 01 $01234567->$01234567 x123456789 16 $01234567->$01234567 x123456789 ! 447: ! 448: monitor.Clear(); ! 449: ! 450: // top は現在の位置。 ! 451: // brhist[] は古い順に書き込まれるが、表示は新しい順にしたい。 ! 452: // ブランチ履歴は書き込み最適化のため256エントリあるが、そんなに ! 453: // 奥のほうが気になることはないだろう。 ! 454: t = cpu->brhist_top; ! 455: for (i = 0; i < 32; i++) { ! 456: m68kbrhist& h = cpu->brhist[t--]; ! 457: int x = (i / 16) * 36; ! 458: int y = i % 16; ! 459: if (h.count == 0) { ! 460: continue; ! 461: } ! 462: monitor.Print(x, y, "%02d:$%08x->$%08x", i, ! 463: h.from, h.to); ! 464: if (h.count > 1) { ! 465: monitor.Print(x + 24, y, "x%9u", h.count); ! 466: } ! 467: } ! 468: return true; ! 469: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.