|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2022 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // HD647180 コア ! 9: // ! 10: ! 11: #include "mpu64180.h" ! 12: #include "debugger.h" ! 13: #include "hd64180.h" ! 14: #include "hd647180.h" ! 15: #include "scheduler.h" ! 16: ! 17: #define OP_DEF(name) void __CONCAT(MPU64180Device::op_,name)() ! 18: #define OP_FUNC(name) __CONCAT(op_,name)() ! 19: #include "hd64180ops.cpp" ! 20: ! 21: void ! 22: MPU64180Device::ExecNormal(Event& ev) ! 23: { ! 24: uint64 cycle_start = used_cycle; ! 25: ! 26: ppc = reg.pc; ! 27: ixiy = USE_HL; ! 28: ixd = -1; ! 29: ops.clear(); ! 30: intcheck = true; ! 31: ! 32: // R レジスタは命令ごとにカウント。7bit マスクは読み出し時に行う。 ! 33: // 命令の前か後かは分からないが。 ! 34: reg_r++; ! 35: ! 36: // 1バイト目処理 ! 37: op = Fetch8(); ! 38: if (__predict_false(opmode == OpMode::Halt)) { ! 39: // ホールトモードなら PC を戻し続けるだけ ! 40: reg.pc--; ! 41: CYCLE(3); ! 42: } else { ! 43: switch (op) { ! 44: #include "hd64180switch_00.inc" ! 45: default: ! 46: __unreachable(); ! 47: } ! 48: } ! 49: ! 50: // 割り込みチェック。 ! 51: if (__predict_true(intcheck)) { ! 52: // intmap が非ゼロなら割り込み発生中。 ! 53: if (GetIEF1() == true && __predict_false(intmap != 0)) { ! 54: DoInterrupt(); ! 55: } ! 56: } else { ! 57: // この命令境界での割り込みチェックを飛ばす。次からは行う。 ! 58: intcheck = true; ! 59: } ! 60: ! 61: int cycle = used_cycle - cycle_start; ! 62: ev.time = cycle * clock_nsec; ! 63: scheduler->StartEvent(ev); ! 64: } ! 65: ! 66: // 不当命令。 ! 67: // pos は不当命令になったバイト位置。2バイト目なら2。 ! 68: void ! 69: MPU64180Device::op_illegal(int pos) ! 70: { ! 71: // ログ表示 ! 72: std::string str; ! 73: for (auto o : ops) { ! 74: str += string_format(" %02x", o); ! 75: } ! 76: putlog(1, "Undefined opcode%s", str.c_str()); ! 77: ! 78: itc_trap = true; ! 79: // 3バイト目なら UFO ビットをセット。 ! 80: itc_ufo = (pos == 3); ! 81: ! 82: // XXX CYCLE ! 83: ! 84: // TRAP 割り込みはマスク不可能。 ! 85: // IEF[12] not affected ! 86: ! 87: // (1) ITC の TRAP ビットを 1 にする ! 88: // (2) 未定義 opcode 位置の PC をスタックに保存する ! 89: // (3) ベクタを 0000H にする ! 90: ! 91: // PC は未定義命令の先頭番地ではなく、未定義 opcode だった位置? ! 92: // nono の実装ではフェッチと同時にインクリメントしているので、 ! 93: // 1つ前でいい? HD64180.pdf p38-39 ! 94: Push16(reg.pc - 1); ! 95: ExceptionDirect(HD647180::IntmapTRAP, 0x0000); ! 96: } ! 97: ! 98: // 分岐 ! 99: void ! 100: MPU64180Device::Jump(uint16 addr) ! 101: { ! 102: reg.pc = addr; ! 103: ! 104: // 命令本体(オペランドを含まない)を16ビット左詰めにする。 ! 105: // 分岐命令は1バイト命令か ED XX か DD/FD XX の2バイト命令しかないはず。 ! 106: //上位ワードは $0000。 ! 107: uint32 inst; ! 108: if (ops[0] == 0xed || ops[0] == 0xdd || ops[0] == 0xfd) { ! 109: inst = (ops[0] << 8) | ops[1]; ! 110: } else { ! 111: inst = (ops[0] << 8); ! 112: } ! 113: ! 114: brhist.AddEntry(GetPPC(), addr, inst); ! 115: } ! 116: ! 117: // ! 118: // 割り込み。 ! 119: // ! 120: // TRAP 0000H ! 121: // NMI 0066H ! 122: // INT0 mode0 命令をデータバスからフェッチ ! 123: // INT0 mode1 0038H ! 124: // INT0 mode2 Vectored (上位8bit が I レジスタ、下位8bit はデータバス) ! 125: // INT1 Vectored (I + IL + 固定コード) ! 126: // INT2 Vectored (〃) ! 127: // 内蔵割り込み Vectored (〃) ! 128: ! 129: // 内部の割り込みマップ (Intmap) をアサートする。 ! 130: void ! 131: MPU64180Device::AssertIntmap(int source) ! 132: { ! 133: uint32 oldmap; ! 134: uint32 srcmap; ! 135: ! 136: oldmap = intmap; ! 137: srcmap = 1U << (31 - source); ! 138: intmap |= srcmap; ! 139: ! 140: if ((oldmap ^ intmap) != 0) { ! 141: // 立ち上がりエッジでカウント ! 142: int_counter[source]++; ! 143: ! 144: // ホールトモード、スリープモードなら解除 ! 145: if (__predict_false((int)opmode >= (int)OpMode::Halt)) { ! 146: if (opmode == OpMode::Halt) { ! 147: // ホールトモードなら解除するだけ。 ! 148: // XXX 割り込みは一つ次の命令境界で処理されるけど、いいか? ! 149: opmode = OpMode::Normal; ! 150: } else { ! 151: // スリープモードなら通常モードに戻す。 ! 152: EnterWakeup(); ! 153: } ! 154: } ! 155: } ! 156: } ! 157: ! 158: // 内部の割り込みマップ (Intmap) をネゲートする。 ! 159: void ! 160: MPU64180Device::NegateIntmap(int source) ! 161: { ! 162: uint32 oldmap; ! 163: uint32 srcmap; ! 164: ! 165: oldmap = intmap; ! 166: srcmap = 1U << (31 - source); ! 167: intmap &= ~srcmap; ! 168: ! 169: if ((oldmap ^ intmap) != 0) { ! 170: // 今は立ち下がりで何もすることはない。 ! 171: } ! 172: } ! 173: ! 174: // INT0 信号線をアサートする。(PIO1 から呼ばれる) ! 175: void ! 176: MPU64180Device::AssertINT0() ! 177: { ! 178: AssertIntmap(HD647180::IntmapINT0); ! 179: } ! 180: ! 181: // INT0 信号線をネゲートする。 ! 182: void ! 183: MPU64180Device::NegateINT0() ! 184: { ! 185: NegateIntmap(HD647180::IntmapINT0); ! 186: } ! 187: ! 188: // マスカブル割り込みを処理する。(命令境界で呼ばれる) ! 189: void ! 190: MPU64180Device::DoInterrupt() ! 191: { ! 192: // まず割り込み禁止。 ! 193: ief1 = false; ! 194: ief2 = false; ! 195: ! 196: // 優先順位の最も高い割り込みを一つ選択。 ! 197: assert(intmap != 0); ! 198: int source = __builtin_clz(intmap); ! 199: ! 200: // TRAP はここに来ない。NMI は LUNA では未接続のため未実装。 ! 201: assert(source != HD647180::IntmapTRAP); ! 202: assert(source != HD647180::IntmapNMI); ! 203: ! 204: if (source == HD647180::IntmapINT0) { ! 205: // INT0 はモードによって分岐方法が異なる。 ! 206: ! 207: // ただし mode0 と mode2 は使われてないので未対応。 ! 208: if (int0mode != 1) { ! 209: PANIC("INT0 on mode%d (NOT IMPLEMENTED)", int0mode); ! 210: } ! 211: ! 212: // mode1 は固定番地へ ! 213: Push16(reg.pc); ! 214: ExceptionDirect(source, 0x0038); ! 215: } else { ! 216: // 残りはすべてベクタ方式。 ! 217: ! 218: Push16(reg.pc); ! 219: ExceptionVector(source); ! 220: } ! 221: ! 222: // XXX あとで見る ! 223: // HD64180.pdf, p45. Figure 2.7.7 ! 224: CYCLE(11); ! 225: } ! 226: ! 227: // 例外によって new_addr に直接ジャンプする。 ! 228: // (HD64180 系の用語では例外ではなくて割り込みだが) ! 229: // source は Intmap*。 ! 230: void ! 231: MPU64180Device::ExceptionDirect(int source, uint32 new_addr) ! 232: { ! 233: // 例外発生とジャンプを記録。 ! 234: brhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source); ! 235: exhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source); ! 236: ! 237: reg.pc = new_addr; ! 238: ! 239: debugger->NotifyExceptionXP(source); ! 240: } ! 241: ! 242: // 例外ごとに固有のベクタにジャンプする。 ! 243: // (HD64180 系の用語では例外ではなくて割り込みだが) ! 244: // source は Intmap*。 ! 245: void ! 246: MPU64180Device::ExceptionVector(int source) ! 247: { ! 248: // 固定コード ! 249: static uint16 vector_offset[] = { ! 250: 0, // 0:TRAP ! 251: 0, // 1:NMI ! 252: 0, // 2:INT0 ! 253: ! 254: 0x00, // 3:INT1 ! 255: 0x02, // 4:INT2 ! 256: 0x12, // 5:Input Capture ! 257: 0x14, // 6:Output Compare ! 258: 0x16, // 7:Timer Overflow ! 259: 0x04, // 8:Timer0 (PRT0) ! 260: 0x06, // 9:Timer1 (PRT1) ! 261: 0x08, // 10:DMA0 ! 262: 0x0a, // 11:DMA1 ! 263: 0x0c, // 12:CSIO ! 264: 0x0e, // 13:ASCI0 ! 265: 0x10, // 14:ASCI1 ! 266: }; ! 267: ! 268: // 例外からベクタアドレスを求める。ベクタアドレスは以下の構成。 ! 269: // ! 270: // F E D C B A 9 8 7 6 5 4 3 2 1 0 ! 271: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ ! 272: // | I レジスタ | IL | 固定コード | ! 273: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ ! 274: assert(source < countof(vector_offset)); ! 275: uint32 vec_addr = (reg_i << 8) | intvec_low | vector_offset[source]; ! 276: ! 277: // 例外発生を記録。 ! 278: brhist.AddEntry(GetPPC(), -1, 0x80000000 | source); ! 279: exhist.AddEntry(GetPPC(), -1, 0x80000000 | source); ! 280: ! 281: // ジャンプ先を読み込む ! 282: uint32 new_addr = Read16(vec_addr); ! 283: ! 284: // ベクタジャンプを記録。 ! 285: brhist.AddEntry(vec_addr, new_addr, -1); ! 286: ! 287: reg.pc = new_addr; ! 288: ! 289: debugger->NotifyExceptionXP(source); ! 290: } ! 291: ! 292: ! 293: // ! 294: // hd64180flag ! 295: // ! 296: ! 297: // F レジスタの値を取得する ! 298: uint8 ! 299: hd64180flag::Get() const ! 300: { ! 301: uint8 f = 0; ! 302: ! 303: if (IsS()) f |= HD64180::FlagS; ! 304: if (IsZ()) f |= HD64180::FlagZ; ! 305: if (b5) f |= 0x20; ! 306: if (IsH()) f |= HD64180::FlagH; ! 307: if (b3) f |= 0x08; ! 308: if (IsPV()) f |= HD64180::FlagPV; ! 309: if (IsN()) f |= HD64180::FlagN; ! 310: if (IsC()) f |= HD64180::FlagC; ! 311: ! 312: return f; ! 313: } ! 314: ! 315: // F レジスタに代入する ! 316: void ! 317: hd64180flag::Set(uint8 val) ! 318: { ! 319: SetS(val & HD64180::FlagS); ! 320: SetZ(val & HD64180::FlagZ); ! 321: b5 = (val & 0x20); ! 322: SetH(val & HD64180::FlagH); ! 323: b3 = (val & 0x08); ! 324: SetPV(val & HD64180::FlagPV); ! 325: SetN(val & HD64180::FlagN); ! 326: SetC(val & HD64180::FlagC); ! 327: } ! 328: ! 329: // fff (0..7) の条件が成立すれば true を返す。 ! 330: bool ! 331: hd64180flag::IsCond(uint fff) const ! 332: { ! 333: switch (fff) { ! 334: case 0: return !IsZ(); // NZ ! 335: case 1: return IsZ(); // Z ! 336: case 2: return !IsC(); // NC ! 337: case 3: return IsC(); // C ! 338: case 4: return !IsPV(); // PO ! 339: case 5: return IsPV(); // PE ! 340: case 6: return !IsS(); // P ! 341: case 7: return IsS(); // M ! 342: default: ! 343: PANIC("invalid cond = %u", fff); ! 344: } ! 345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.