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