|
|
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 (m88xx0)
8:
9: #include "mpu88xx0.h"
10: #include "config.h"
1.1.1.2 root 11: #include "sysctlr.h"
12:
1.1 root 13: // コンストラクタ
1.1.1.7 root 14: MPU88xx0Device::MPU88xx0Device()
1.1.1.8 root 15: : inherited("MPU(88xx0)")
1.1 root 16: {
1.1.1.7 root 17: cpu.reset(new m88kcpu());
1.1.1.4 root 18:
1.1.1.2 root 19: // LUNA88K では CMMU の ID は次のように割り振ってあるようだ。
20: // OpenBSD の sys/arch/luna68k/include/board.h より。
21: //
22: // Inst Data
23: // CPU#0 ID=7 ID=6
24: // CPU#1 ID=5 ID=4
25: // CPU#2 ID=3 ID=2
26: // CPU#3 ID=1 ID=0
27: //
28: // 厳密にはこれは LUNA88K のハードウェアがどういうコンフィグレーションで
29: // m88200 を使うかなので、ここではなくて vm_luna あたりのほうがいいかも
30: // しれんけど、あまり遠いのも面倒なので、とりあえずこの辺に。
31: // あとマルチプロセッサになったらまたその時考える。
32: cpu->cmmu[0].SetID(7);
33: cpu->cmmu[1].SetID(6);
34:
1.1.1.8 root 35: // レジスタモニター
36: monitor.func = (MonitorCallback_t)&MPU88xx0Device::MonitorUpdate;
1.1.1.10! root 37: monitor.SetSize(79, 28);
1.1.1.8 root 38: monitor.Regist(ID_MONITOR_MPUREG);
1.1 root 39: }
40:
41: // デストラクタ
42: MPU88xx0Device::~MPU88xx0Device()
43: {
44: }
45:
1.1.1.5 root 46: bool
47: MPU88xx0Device::Init()
48: {
49: // 親クラス
50: if (inherited::Init() == false) {
51: return false;
52: }
53: // MPU クロックは親 Init() で読み込んで、ここで cpu にセットする
54: cpu->SetClockSpeed(clock_khz);
55:
1.1.1.8 root 56: const ConfigItem& item = gConfig->Find("mpu-pseudo-stop");
57: cpu->pseudo_stop_enable = (bool)item.AsInt();
58:
1.1.1.5 root 59: return true;
60: }
61:
1.1.1.7 root 62: bool
63: MPU88xx0Device::PowerOn()
64: {
65: cpu->PowerOn();
66: return true;
67: }
68:
1.1 root 69: void
1.1.1.7 root 70: MPU88xx0Device::ResetHard()
1.1 root 71: {
1.1.1.5 root 72: cpu->RequestReset();
1.1 root 73: }
74:
1.1.1.6 root 75: // アクセス中の論理アドレスを取得
76: uint32
77: MPU88xx0Device::GetLaddr() const
78: {
79: m88200 *cmmu = m88200::GetBusMaster();
80: assert(cmmu);
81: return cmmu->GetLaddr();
82: }
83:
84: // アクセス中の物理アドレスを取得
85: uint32
86: MPU88xx0Device::GetPaddr() const
87: {
88: m88200 *cmmu = m88200::GetBusMaster();
89: assert(cmmu);
90: return cmmu->GetPaddr();
91: }
92:
1.1.1.4 root 93: // アクセスウェイトを加算
94: void
1.1.1.5 root 95: MPU88xx0Device::AddCycle(int32 cycle)
1.1.1.4 root 96: {
97: // 今アクセスしてきている(= バスマスターの) CMMU に対して加算する
98: m88200 *cmmu = m88200::GetBusMaster();
99: assert(cmmu);
100: cmmu->AddCycle(cycle);
101: }
102:
1.1.1.2 root 103: // Interrupt
104: void
1.1.1.5 root 105: MPU88xx0Device::Interrupt(int level)
1.1.1.2 root 106: {
1.1.1.5 root 107: cpu->Interrupt(level);
1.1.1.2 root 108: }
109:
1.1.1.9 root 110: // DOS call エミュレーションのコールバックを指定
111: void
112: MPU88xx0Device::SetFLineCallback(bool (*callback)(m88kcpu *, void *), void *arg)
113: {
114: cpu->SetFLineCallback(callback, arg);
115: }
116:
117: // MPU からのアクセスをエミュレート
118: uint64
119: MPU88xx0Device::Read8(uint32 addr)
120: {
121: return cpu->cmmu[1].load_8(addr);
122: }
123:
124: uint64
125: MPU88xx0Device::Read16(uint32 addr)
126: {
127: if ((addr & 1) == 0) {
128: return cpu->cmmu[1].load_16(addr);
129: } else {
130: uint64 h, l;
131: h = Read8(addr);
132: if ((int64)h < 0) {
133: return h;
134: }
135: l = Read8(addr + 1);
136: if ((int64)l < 0) {
137: return l;
138: }
139: return (h << 8) | l;
140: }
141: }
142:
143: uint64
144: MPU88xx0Device::Read32(uint32 addr)
145: {
146: if ((addr & 3) == 0) {
147: return cpu->cmmu[1].load_32(addr);
148: } else if ((addr & 1) == 0) {
149: uint64 h, l;
150: h = Read16(addr);
151: if ((int64)h < 0) {
152: return h;
153: }
154: l = Read16(addr + 2);
155: if ((int64)l < 0) {
156: return l;
157: }
158: return (h << 16) | l;
159: } else {
160: uint64 h, m, l;
161: h = Read8(addr);
162: if ((int64)h < 0) {
163: return h;
164: }
165: m = Read16(addr + 1);
166: if ((int64)m < 0) {
167: return m;
168: }
169: l = Read8(addr + 3);
170: if ((int64)l < 0) {
171: return l;
172: }
173: return (h << 24) | (m << 8) | l;
174: }
175: }
176:
177: uint64
178: MPU88xx0Device::Write8(uint32 addr, uint32 data)
179: {
180: return cpu->cmmu[1].store_8(addr, data & 0xff);
181: }
182:
183: uint64
184: MPU88xx0Device::Write16(uint32 addr, uint32 data)
185: {
186: if ((addr & 1) == 0) {
187: return cpu->cmmu[1].store_16(addr, data & 0xffff);
188: } else {
189: uint64 r;
190: r = Write8(addr, data >> 8);
191: if ((int64)r < 0) {
192: return r;
193: }
194: return Write8(addr + 1, data);
195: }
196: }
197:
198: uint64
199: MPU88xx0Device::Write32(uint32 addr, uint32 data)
200: {
201: if ((addr & 3) == 0) {
202: return cpu->cmmu[1].store_32(addr, data);
203: } else if ((addr & 1) == 0) {
204: uint64 r;
205: r = Write16(addr, data >> 16);
206: if ((int64)r < 0) {
207: return r;
208: }
209: return Write16(addr + 2, data);
210: } else {
211: uint64 r;
212: r = Write8(addr, data >> 24);
213: if ((int64)r < 0) {
214: return r;
215: }
216: r = Write16(addr + 1, data >> 8);
217: if ((int64)r < 0) {
218: return r;
219: }
220: return Write8(addr + 3, data);
221: }
222: }
223:
1.1.1.10! root 224: #define FA(val, bit) TA::OnOff((val) & m88100reg::bit)
! 225:
1.1 root 226: // モニター更新
1.1.1.3 root 227: void
1.1.1.8 root 228: MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 229: {
230: m88100reg reg;
231: int x;
232: int y;
233:
1.1.1.8 root 234: screen.Clear();
1.1 root 235:
236: // ローカルにコピー
237: reg = *cpu;
238:
239: //
240: for (int i = 0; i < countof(reg.r); i++) {
1.1.1.8 root 241: screen.Print((i / 8) * 14, i % 8, "r%-2d:%08x", i, reg.r[i]);
1.1 root 242: }
243:
244: // 制御レジスタ
245: x = 0;
246: y = 9;
1.1.1.8 root 247: screen.Print(x, y++, "pid (cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)",
1.1 root 248: reg.pid,
249: (reg.pid >> 8) & 0xff,
1.1.1.2 root 250: (reg.pid >> 1) & 0x7f,
251: (reg.pid & 1) ? "Master" : "Checker");
1.1.1.8 root 252: screen.Print(x, y, "psr (cr1):%08x(", reg.psr);
1.1.1.10! root 253: screen.Puts(x + 19, y, FA(reg.psr, PSR_SUPER), "S");
1.1.1.8 root 254: screen.Puts(x + 21, y,
1.1.1.2 root 255: ((reg.psr & m88100reg::PSR_BO_LE) ? "BO=LE" : "BO=BE"));
1.1.1.10! root 256: screen.Puts(x + 27, y, FA(reg.psr, PSR_SER), "SER");
! 257: screen.Puts(x + 31, y, FA(reg.psr, PSR_C), "Cy");
! 258: screen.Puts(x + 34, y, FA(reg.psr, PSR_SFD1), "SFD1");
! 259: screen.Puts(x + 39, y, FA(reg.psr, PSR_MXM), "MXM");
! 260: screen.Puts(x + 43, y, FA(reg.psr, PSR_IND), "IND");
! 261: screen.Puts(x + 47, y, FA(reg.psr, PSR_SFRZ), "SFRZ");
1.1.1.8 root 262: screen.Puts(x + 51, y, ")");
1.1.1.2 root 263: y++;
1.1.1.8 root 264: screen.Print(x, y, "epsr(cr2):%08x(", reg.epsr);
1.1.1.10! root 265: screen.Puts(x + 19, y, FA(reg.epsr, PSR_SUPER), "S");
1.1.1.8 root 266: screen.Puts(x + 21, y,
1.1.1.2 root 267: ((reg.epsr& m88100reg::PSR_BO_LE) ? "BO=LE" : "BO=BE"));
1.1.1.10! root 268: screen.Puts(x + 27, y, FA(reg.epsr, PSR_SER), "SER");
! 269: screen.Puts(x + 31, y, FA(reg.epsr, PSR_C), "Cy");
! 270: screen.Puts(x + 34, y, FA(reg.epsr, PSR_SFD1), "SFD1");
! 271: screen.Puts(x + 39, y, FA(reg.epsr, PSR_MXM), "MXM");
! 272: screen.Puts(x + 43, y, FA(reg.epsr, PSR_IND), "IND");
! 273: screen.Puts(x + 47, y, FA(reg.epsr, PSR_SFRZ), "SFRZ");
1.1.1.8 root 274: screen.Puts(x + 51, y, ")");
1.1 root 275:
1.1.1.2 root 276: // 制御レジスタ(左中; *IP)
1.1 root 277: x = 0;
278: y = 12;
1.1.1.8 root 279: screen.Print(x, y + 0, "xip:%08x opX:%08x(%c%c)",
1.1 root 280: reg.xip, (uint32)reg.opX,
281: cpu->OpIsBusErr(reg.opX) ? 'B' : '-',
282: cpu->OpIsDelay(reg.opX) ? 'D' : '-');
1.1.1.8 root 283: screen.Print(x, y + 1, "nip:%08x opF:%08x(%c%c)",
1.1 root 284: reg.nip, (uint32)reg.opF,
285: cpu->OpIsBusErr(reg.opF) ? 'B' : '-',
286: cpu->OpIsDelay(reg.opF) ? 'D' : '-');
1.1.1.8 root 287: screen.Print(x, y + 2, "fip:%08x", reg.fip);
1.1 root 288:
289: // 制御レジスタ (S*IP)
290: x = 32;
291: for (int i = 0; i < 3; i++) {
1.1.1.8 root 292: screen.Print(x, y + i, "%s(cr%d):%08x:%c%c",
1.1 root 293: m88100reg::sipname[i], 4 + i,
294: (reg.cr[4 + i] & m88100reg::SIP_MASK),
295: (reg.cr[4 + i] & m88100reg::SIP_V) ? 'V' : '-',
296: (reg.cr[4 + i] & m88100reg::SIP_E) ? 'E' : '-');
297: }
298:
1.1.1.2 root 299: // 制御レジスタ(右中)
1.1 root 300: x = 55;
301: y = 9;
302: for (int i = 0; i < 4; i++) {
303: int rn = 17 + i;
1.1.1.8 root 304: screen.Print(x, y++, "sr%d(cr%d):%08x", i, rn, reg.cr[rn]);
1.1 root 305: }
1.1.1.8 root 306: screen.Print(x, y++, "ssbr(cr3):%08x", reg.ssbr);
307: screen.Print(x, y++, "vbr (cr7):%08x", reg.vbr);
1.1 root 308:
1.1.1.10! root 309: // MMU レジスタ(次段)
1.1.1.2 root 310: y = 15;
311: for (int i = 0; i <= 2; i++) {
312: int dt = 8 + i * 3;
313: int dd = 9 + i * 3;
314: int da = 10 + i * 3;
315:
1.1.1.8 root 316: screen.Print(0, y, "dmt%d(cr%-2d):%04x",
1.1.1.2 root 317: i, dt, (reg.cr[dt] & 0xffff));
1.1.1.8 root 318: screen.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)");
319: screen.Puts(16, y, (reg.cr[dt] & m88100reg::DM_BO) ? "B" : "-");
320: screen.Puts(18, y, (reg.cr[dt] & m88100reg::DM_DAS) ? "S" : "U");
321: screen.Puts(20, y, (reg.cr[dt] & m88100reg::DM_DOUB1) ? "D" : "-");
322: screen.Puts(22, y, (reg.cr[dt] & m88100reg::DM_LOCK) ? "L" : "-");
1.1.1.2 root 323: // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力
1.1.1.8 root 324: screen.Print(25, y, "%d,",
1.1.1.2 root 325: (reg.cr[dt] & m88100reg::DM_DREG_MASK) >> 7);
1.1.1.8 root 326: screen.Puts(28, y, (reg.cr[dt] & m88100reg::DM_SIGNED) ? "S" : "-");
1.1.1.2 root 327: uint32 en = (reg.cr[dt] & m88100reg::DM_EN_MASK) >> 2;
1.1.1.8 root 328: screen.Puts(30, y, m88100reg::dmt_en_str[en]);
329: screen.Puts(35, y, (reg.cr[dt] & m88100reg::DM_WRITE) ? "W" : "-");
330: screen.Puts(37, y, (reg.cr[dt] & m88100reg::DM_VALID) ? "V" : "-");
1.1.1.2 root 331:
1.1.1.8 root 332: screen.Print(40, y, "dmd%d(cr%-2d):%08x", i, dd, reg.cr[dd]);
333: screen.Print(60, y, "dma%d(cr%2d):%08x", i, da, reg.cr[da]);
1.1.1.2 root 334: y++;
335: }
1.1.1.10! root 336: y++;
! 337:
! 338: // FPU レジスタ (下段)
! 339: screen.Print(0, y, "fpecr(fcr0):%08x(", reg.fpecr);
! 340: x = 21;
! 341: screen.Puts(x + 0, y, FA(reg.fpecr, FPECR_FIOV), "FIOV");
! 342: screen.Puts(x + 5, y, FA(reg.fpecr, FPECR_FUNIMP), "FUNIMP");
! 343: screen.Puts(x + 12, y, FA(reg.fpecr, FPECR_FPRV), "FPRV");
! 344: screen.Puts(x + 17, y, FA(reg.fpecr, FPECR_FROP), "FROP");
! 345: screen.Puts(x + 22, y, FA(reg.fpecr, FPECR_FDVZ), "FDVZ");
! 346: screen.Puts(x + 27, y, FA(reg.fpecr, FPECR_FUNF), "FUNF");
! 347: screen.Puts(x + 32, y, FA(reg.fpecr, FPECR_FOVF), "FOVF");
! 348: screen.Puts(x + 37, y, FA(reg.fpecr, FPECR_FINX), "FINX");
! 349: screen.Puts(x + 41, y, ")");
! 350: y++;
! 351:
! 352: screen.Print(0, y++,
! 353: "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%d T2=%d TD=%d Dest=r%d)",
! 354: reg.fppt,
! 355: ((reg.fppt >> 15) & 1) + '0',
! 356: ((reg.fppt >> 14) & 1) + '0',
! 357: ((reg.fppt >> 13) & 1) + '0',
! 358: ((reg.fppt >> 12) & 1) + '0',
! 359: ((reg.fppt >> 11) & 1) + '0',
! 360: ((reg.fppt >> 9) & 3),
! 361: ((reg.fppt >> 7) & 3),
! 362: ((reg.fppt >> 5) & 3),
! 363: (reg.fppt & m88100reg::FPPT_DEST));
! 364:
! 365: screen.Print(0, y++, "fphs1(fcr1)/fpls1(fcr2): %08x'%08x",
! 366: reg.fphs1, reg.fpls1);
! 367: screen.Print(0, y++, "fphs2(fcr3)/fpls2(fcr4): %08x'%08x",
! 368: reg.fphs2, reg.fpls2);
! 369:
! 370: screen.Print(0, y, "fprh(fcr6) /fprl(fcr7): %08x'%08x(",
! 371: reg.fprh, reg.fprl);
! 372: x = 43;
! 373: screen.Puts(x + 0, y, FA(reg.fprh, FPRH_ADDONE), "ADDONE");
! 374: screen.Print(x + 7, y, "RM=%s)", rmstr[(reg.fprh >> 29) & 3]);
! 375: y++;
! 376:
! 377: x = 21;
! 378: screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%d",
! 379: reg.fpit,
! 380: ((reg.fpit >> 15) & 1) + '0',
! 381: ((reg.fpit >> 14) & 1) + '0',
! 382: ((reg.fpit >> 13) & 1) + '0',
! 383: ((reg.fpit >> 12) & 1) + '0',
! 384: ((reg.fpit >> 11) & 1) + '0',
! 385: ((reg.fpit >> 10) & 1));
! 386: screen.Puts(x + 19, y, FA(reg.fpit, FPIT_EFINV), "EINV");
! 387: screen.Puts(x + 24, y, FA(reg.fpit, FPIT_EFDVZ), "EDVZ");
! 388: screen.Puts(x + 29, y, FA(reg.fpit, FPIT_EFUNF), "EUNF");
! 389: screen.Puts(x + 34, y, FA(reg.fpit, FPIT_EFOVF), "EOVF");
! 390: screen.Puts(x + 39, y, FA(reg.fpit, FPIT_EFINX), "EINX");
! 391: screen.Print(x + 44, y, "Dest=r%d)", reg.fpit & m88100reg::FPIT_DEST);
! 392: y++;
! 393:
! 394: uint32 sign = (reg.fprh & m88100reg::FPRH_SIGN);
! 395: uint32 exp = (int32)reg.fpit >> 20;
! 396: uint32 mant_h = (reg.fprh & 0x000fffff);
! 397: uint32 mant_l = reg.fprl;
! 398: screen.Print(12, y, "result: %c%1x.%05x'%08x'grs e%+d",
! 399: (sign ? '-' : '+'),
! 400: ((reg.fprh >> 20) & 1),
! 401: mant_h,
! 402: mant_l,
! 403: exp - 0x3ff);
! 404: screen.Puts(38, y, FA(reg.fprh, FPRH_GUARD), "G");
! 405: screen.Puts(39, y, FA(reg.fprh, FPRH_ROUND), "R");
! 406: screen.Puts(40, y, FA(reg.fprh, FPRH_STICKY), "S");
! 407: screen.Print(48, y, "($%03x)", exp & 0x7ff);
! 408: // Inf と NAN はこの形式だけからでは分かりづらいので別途追加で表示。
! 409: // exp は符号拡張しているので指数部 $7ff は exp == -1。
! 410: if (exp == 0xffffffff) {
! 411: x = 55;
! 412: if ((mant_h | mant_l) == 0) {
! 413: if (sign == 0) {
! 414: screen.Puts(x, y, "= +Inf");
! 415: } else {
! 416: screen.Puts(x, y, "= -Inf");
! 417: }
! 418: } else {
! 419: if (sign == 0) {
! 420: screen.Puts(x, y, "= +NAN");
! 421: } else {
! 422: screen.Puts(x, y, "= -NAN");
! 423: }
! 424: }
! 425: }
! 426: y++;
! 427:
! 428: screen.Print(0, y, "fpsr(fcr62):%08x(", reg.fpsr);
! 429: x = 21;
! 430: screen.Puts(x + 0, y, FA(reg.fpsr, FPSR_AFINV), "AFINV");
! 431: screen.Puts(x + 6, y, FA(reg.fpsr, FPSR_AFDVZ), "AFDVZ");
! 432: screen.Puts(x + 12, y, FA(reg.fpsr, FPSR_AFUNF), "AFUNF");
! 433: screen.Puts(x + 18, y, FA(reg.fpsr, FPSR_AFOVF), "AFOVF");
! 434: screen.Puts(x + 24, y, FA(reg.fpsr, FPSR_AFINX), "AFINX");
! 435: screen.Puts(x + 29, y, ")");
! 436: y++;
! 437:
! 438: screen.Print(0, y, "fpcr(fcr63):%08x(", reg.fpcr);
! 439: screen.Puts(x + 0, y, FA(reg.fpcr, FPCR_EFINV), "EFINV");
! 440: screen.Puts(x + 6, y, FA(reg.fpcr, FPCR_EFDVZ), "EFDVZ");
! 441: screen.Puts(x + 12, y, FA(reg.fpcr, FPCR_EFUNF), "EFUNF");
! 442: screen.Puts(x + 18, y, FA(reg.fpcr, FPCR_EFOVF), "EFOVF");
! 443: screen.Puts(x + 24, y, FA(reg.fpcr, FPCR_EFINX), "EFINX");
! 444: screen.Print(x + 30, y, "RM=%s)", rmstr[(reg.fpcr >> 14) & 3]);
1.1 root 445: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.