|
|
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:
1.1.1.2 ! root 280: case 0xf200 ... 0xf3ff: // FPU
1.1 root 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.