|
|
1.1 ! root 1: // vi:set ts=4: ! 2: ! 3: // ! 4: // nono ! 5: // Copyright (C) 2024 nono project ! 6: // Licensed under nono-license.txt ! 7: // ! 8: ! 9: #include "runx.h" ! 10: ! 11: #define CCR_X (0x0010) ! 12: #define CCR_N (0x0008) ! 13: #define CCR_Z (0x0004) ! 14: #define CCR_V (0x0002) ! 15: #define CCR_C (0x0001) ! 16: ! 17: #define SUPERVISOR_OP() do { \ ! 18: if ((emul.sr & 0x2000) == 0) \ ! 19: goto unpriv; \ ! 20: } while (0) ! 21: ! 22: #define push2(data) do { \ ! 23: RegA(7) -= 2; \ ! 24: writemem2(RegA(7), (data)); \ ! 25: } while (0) ! 26: ! 27: #define push4(data) do { \ ! 28: RegA(7) -= 4; \ ! 29: writemem4(RegA(7), (data)); \ ! 30: } while (0) ! 31: ! 32: static uint32 exception_common(struct reg *, uint32, uint32, uint32); ! 33: ! 34: #define pop2() ({ \ ! 35: uint32 data_ = readmem2(RegA(7)); \ ! 36: RegA(7) += 2; \ ! 37: data_; \ ! 38: }) ! 39: #define pop4() ({ \ ! 40: uint32 data_ = readmem4(RegA(7)); \ ! 41: RegA(7) += 4; \ ! 42: data_; \ ! 43: }) ! 44: ! 45: // MOVE.* 系の CCR をセットする共通部分。 ! 46: static void ! 47: acc_move(struct reg *reg, bool z, bool n) ! 48: { ! 49: RegCCR &= ~(CCR_N | CCR_Z | CCR_V | CCR_C); ! 50: if (z) ! 51: RegCCR |= CCR_Z; ! 52: if (n) ! 53: RegCCR |= CCR_N; ! 54: } ! 55: ! 56: // MOVE.B 系の CCR をセットする。 ! 57: static void ! 58: acc_move_1(struct reg *reg, uint32 data) ! 59: { ! 60: bool z = ((data & 0xff) == 0); ! 61: bool n = (data & 0x80); ! 62: acc_move(reg, z, n); ! 63: } ! 64: ! 65: // MOVE.L 系の CCR をセットする。 ! 66: static void ! 67: acc_move_4(struct reg *reg, uint32 data) ! 68: { ! 69: bool z = (data == 0); ! 70: bool n = (data & 0x8000'0000); ! 71: acc_move(reg, z, n); ! 72: } ! 73: ! 74: // スタックフレームフォーマット0 の例外を起こす。 ! 75: // pc はスタックに積む PC (例外ごとにこの命令か次の命令かが違う)。 ! 76: uint32 ! 77: exception_format0(struct reg *reg, uint32 vector, uint32 pc) ! 78: { ! 79: return exception_common(reg, 0, vector, pc); ! 80: } ! 81: ! 82: // スタックフレームフォーマット2 の例外を起こす。 ! 83: uint32 ! 84: exception_format2(struct reg *reg, uint32 vector) ! 85: { ! 86: // XXX ここに積む INSTRUCTION ADDRESS は今の所取り出す方法がない。 ! 87: // たぶん見てないのでへーきへーき。 ! 88: push4(RegPC - 2); ! 89: return exception_common(reg, 2, vector, RegPC); ! 90: } ! 91: ! 92: static uint32 ! 93: exception_common(struct reg *reg, uint32 frame, uint32 vector, uint32 pc) ! 94: { ! 95: // 本当はスタックに積む前だが、ここでは影響ない。 ! 96: SetSR(GetSR | 0x2000); ! 97: ! 98: push2((frame << 12) | (vector << 2)); ! 99: push4(pc); ! 100: push2(GetSR); ! 101: ! 102: uint32 addr = readmem4(emul.vbr + (vector << 2)); ! 103: return addr; ! 104: } ! 105: ! 106: // inst は命令の1ワード目 (16bit 下詰め)。 ! 107: // 戻り値は更新した nextpc。 ! 108: uint32 ! 109: exec_op(pid_t pid, struct reg *reg, int signo, uint32 inst) ! 110: { ! 111: uint32 inst2; ! 112: uint32 addr; ! 113: uint32 data; ! 114: uint n; ! 115: uint m; ! 116: uint oplen; ! 117: ! 118: oplen = 2; ! 119: switch (inst) { ! 120: case 0x007c: // ori.w #imm,sr ! 121: SUPERVISOR_OP(); ! 122: ! 123: data = readmem2(RegPC + 2); ! 124: TRACE(RegPC, "ori.w #$%04x,sr", data); ! 125: data |= GetSR; ! 126: SetSR(data); ! 127: oplen = 4; ! 128: break; ! 129: ! 130: case 0x06fa: // callm ! 131: TRACE(RegPC, "callm"); ! 132: return exception_format0(reg, 4, RegPC); ! 133: ! 134: case 0x21c9: // move.l an,abs.w ! 135: n = inst & 7; ! 136: addr = (int32)(int16)readmem2(RegPC + 2); ! 137: TRACE(RegPC, "move.l a%u,$%04x.w", n, addr); ! 138: data = RegA(n); ! 139: acc_move_4(reg, data); ! 140: writemem4(addr, data); ! 141: oplen = 4; ! 142: break; ! 143: ! 144: case 0x21df: // move.l (an)+,abs.w ! 145: n = inst & 7; ! 146: addr = (int32)(int16)readmem2(RegPC + 2); ! 147: TRACE(RegPC, "move.l (a%u)+,$%04x.w", n, addr); ! 148: data = readmem4(RegA(n)); ! 149: acc_move_4(reg, data); ! 150: writemem4(addr, data); ! 151: RegA(n) += 4; ! 152: oplen = 4; ! 153: break; ! 154: ! 155: case 0x2855: // movea.l (an),am ! 156: n = inst & 7; ! 157: m = (inst >> 9) & 7; ! 158: TRACE(RegPC, "move.l (a%u),a%u", n, m); ! 159: data = readmem4(RegA(n)); ! 160: RegA(m) = data; ! 161: break; ! 162: ! 163: case 0x2a88: // move.l an,(am) ! 164: case 0x2a89: ! 165: case 0x2a8a: ! 166: case 0x2a8b: ! 167: case 0x2a8c: ! 168: case 0x2a8d: ! 169: case 0x2a8e: ! 170: case 0x2a8f: ! 171: n = inst & 7; ! 172: m = (inst >> 9) & 7; ! 173: TRACE(RegPC, "move.l a%u,(a%u)", n, m); ! 174: data = RegA(n); ! 175: acc_move_4(reg, data); ! 176: writemem4(RegA(m), data); ! 177: break; ! 178: ! 179: case 0x2f38: // move.l abs.w,-(an) ! 180: n = (inst >> 9) & 7; ! 181: addr = (int32)(int16)readmem2(RegPC + 2); ! 182: TRACE(RegPC, "move.l $%04x.w,-(a%u)", addr, n); ! 183: data = readmem4(addr); ! 184: acc_move_4(reg, data); ! 185: RegA(n) -= 4; ! 186: writemem4(RegA(n), data); ! 187: oplen = 4; ! 188: break; ! 189: ! 190: case 0x40c0: // move.w sr,dn ! 191: n = inst & 7; ! 192: if ((GetSR & 0x2000)) { ! 193: TRACE(RegPC, "move.w sr,d%u", n); ! 194: data = GetSR; ! 195: RegD(n) = (RegD(n) & 0xffff0000) | data; ! 196: } else { ! 197: // Human68k が move from sr を move from ccr に書き換えて ! 198: // この命令から再実行。 ! 199: TRACE(RegPC, "Patch move.w sr,d%u -> move.w ccr,d%u", n, n); ! 200: writemem2(RegPC, inst | 0x0200); ! 201: oplen = 0; ! 202: } ! 203: break; ! 204: ! 205: case 0x40e0: ! 206: case 0x40e1: ! 207: case 0x40e2: ! 208: case 0x40e3: ! 209: case 0x40e4: ! 210: case 0x40e5: ! 211: case 0x40e6: ! 212: case 0x40e7: // move.w sr,(a7) ! 213: SUPERVISOR_OP(); ! 214: ! 215: n = inst & 7; ! 216: TRACE(RegPC, "move.w sr,(a%u)", n); ! 217: addr = RegA(n); ! 218: data = GetSR; ! 219: writemem2(addr, data); ! 220: break; ! 221: ! 222: case 0x46df: // move.w (a7)+,sr ! 223: SUPERVISOR_OP(); ! 224: ! 225: n = inst & 7; ! 226: TRACE(RegPC, "move.w (a%u)+,sr", n); ! 227: addr = RegA(n); ! 228: RegA(n) += 2; ! 229: data = readmem2(addr); ! 230: SetSR(data); ! 231: break; ! 232: ! 233: case 0x4e73: // rte ! 234: { ! 235: uint32 sr = pop2(); ! 236: uint32 pc = pop4(); ! 237: uint32 frame = pop2(); ! 238: TRACE(RegPC, "rte (frame=$%x, retpc=$%06x)", frame, pc); ! 239: switch (frame >> 12) { ! 240: case 0: ! 241: SetSR(sr); ! 242: return pc; ! 243: ! 244: case 2: ! 245: // +08.L INSTRUCTION ADDRESS を読み捨てる ! 246: RegA(7) += 4; ! 247: SetSR(sr); ! 248: return pc; ! 249: ! 250: default: ! 251: errx(1, "%06x: rte: Unimplemented format $%x", RegPC, frame); ! 252: break; ! 253: } ! 254: break; ! 255: } ! 256: ! 257: case 0x4e7a: ! 258: inst2 = readmem2(RegPC + 2); ! 259: n = inst2 >> 12; ! 260: switch (inst2 & 0xfff) { ! 261: case 0x0801: ! 262: // movec.l vbr,d0 ! 263: TRACE(RegPC, "movec.l vbr,%c%u", (n < 8) ? 'd' : 'a', n & 7); ! 264: RegR(n) = emul.vbr; ! 265: break; ! 266: ! 267: case 0x0802: ! 268: // movec.l caar,d0 ! 269: TRACE(RegPC, "movec.l caar,%c%u", (n < 8) ? 'd' : 'a', n & 7); ! 270: RegR(n) = emul.caar; ! 271: break; ! 272: ! 273: default: ! 274: warnx("%06x: Illegal instruction %04x %04x", RegPC, inst, inst2); ! 275: return -1; ! 276: } ! 277: oplen = 4; ! 278: break; ! 279: ! 280: case 0xf200 ... 0xf23f: // FPU ! 281: if (signo == SIGILL) { ! 282: inst2 = readmem2(RegPC + 2); ! 283: TRACE(RegPC, "Illegal FP instruction %04x %04x", inst, inst2); ! 284: return exception_format0(reg, 11, RegPC); ! 285: } else { ! 286: // default へ ! 287: } ! 288: // FALLTHROUGH ! 289: ! 290: default: ! 291: if (signo == SIGILL) { ! 292: warnx("%06x: Illegal instruction %04x", RegPC, inst); ! 293: } else { ! 294: // SIGSEGV なら fault address を取り出して表示。 ! 295: struct ptrace_siginfo psi; ! 296: if (ptrace(PT_GET_SIGINFO, pid, &psi, sizeof(psi)) < 0) { ! 297: warn("ptrace(PT_GET_SIGINFO)"); ! 298: } ! 299: warnx("%06x: SIGSEGV caught (instruction %04x, address $%06x)", ! 300: RegPC, inst, (uint)(uintptr_t)psi.psi_siginfo.si_addr); ! 301: } ! 302: return -1; ! 303: } ! 304: ! 305: return RegPC + oplen; ! 306: ! 307: unpriv: ! 308: warnx("%06x: Unprivledged instruction %04x", RegPC, inst); ! 309: return -1; ! 310: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.