fpu_emulate.c revision 1.1 1 1.1 gwr /* $NetBSD: fpu_emulate.c,v 1.1 1995/03/01 04:56:27 gwr Exp $ */
2 1.1 gwr
3 1.1 gwr /*
4 1.1 gwr * Copyright (c) 1995 Gordon W. Ross
5 1.1 gwr * All rights reserved.
6 1.1 gwr *
7 1.1 gwr * Redistribution and use in source and binary forms, with or without
8 1.1 gwr * modification, are permitted provided that the following conditions
9 1.1 gwr * are met:
10 1.1 gwr * 1. Redistributions of source code must retain the above copyright
11 1.1 gwr * notice, this list of conditions and the following disclaimer.
12 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 gwr * notice, this list of conditions and the following disclaimer in the
14 1.1 gwr * documentation and/or other materials provided with the distribution.
15 1.1 gwr * 3. The name of the author may not be used to endorse or promote products
16 1.1 gwr * derived from this software without specific prior written permission.
17 1.1 gwr * 4. All advertising materials mentioning features or use of this software
18 1.1 gwr * must display the following acknowledgement:
19 1.1 gwr * This product includes software developed by Gordon Ross
20 1.1 gwr *
21 1.1 gwr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 1.1 gwr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 1.1 gwr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 1.1 gwr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 1.1 gwr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 1.1 gwr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 1.1 gwr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 1.1 gwr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 1.1 gwr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 1.1 gwr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 1.1 gwr */
32 1.1 gwr
33 1.1 gwr /*
34 1.1 gwr * mc68881 emulator
35 1.1 gwr * XXX - Just a start at it for now...
36 1.1 gwr */
37 1.1 gwr
38 1.1 gwr #include <sys/types.h>
39 1.1 gwr #include <sys/signal.h>
40 1.1 gwr #include <machine/frame.h>
41 1.1 gwr
42 1.1 gwr #define DEBUG 1 /* XXX */
43 1.1 gwr
44 1.1 gwr /*
45 1.1 gwr * Internal info about a decoded effective address.
46 1.1 gwr */
47 1.1 gwr struct insn_ea {
48 1.1 gwr int regnum;
49 1.1 gwr int immed;
50 1.1 gwr int flags;
51 1.1 gwr #define EA_DIRECT 0x01
52 1.1 gwr #define EA_PREDECR 0x02
53 1.1 gwr #define EA_POSTINCR 0x04
54 1.1 gwr #define EA_OFFSET 0x08 /* mode 5: base+offset */
55 1.1 gwr #define EA_INDEXED 0x10 /* mode 6: complicated */
56 1.1 gwr #define EA_ABS 0x20 /* mode 7: reg 0 or 1 */
57 1.1 gwr #define EA_PC_REL 0x40 /* mode 7: reg 2 or 3 */
58 1.1 gwr #define EA_IMMED 0x80 /* mode 7: reg 4 */
59 1.1 gwr };
60 1.1 gwr
61 1.1 gwr struct instruction {
62 1.1 gwr int advance; /* length of instruction */
63 1.1 gwr int datasize; /* byte, word, long, float, double, ... */
64 1.1 gwr int opcode;
65 1.1 gwr int word1;
66 1.1 gwr struct insn_ea ea0;
67 1.1 gwr struct insn_ea ea1;
68 1.1 gwr };
69 1.1 gwr
70 1.1 gwr int fpu_emul_fmovm(struct frame *frame,
71 1.1 gwr struct fpframe *fpf,
72 1.1 gwr struct instruction *insn);
73 1.1 gwr int fpu_emul_type0(struct frame *frame,
74 1.1 gwr struct fpframe *fpf,
75 1.1 gwr struct instruction *insn);
76 1.1 gwr int fpu_emul_type1(struct frame *frame,
77 1.1 gwr struct fpframe *fpf,
78 1.1 gwr struct instruction *insn);
79 1.1 gwr int fpu_emul_brcc(struct frame *frame,
80 1.1 gwr struct fpframe *fpf,
81 1.1 gwr struct instruction *insn);
82 1.1 gwr
83 1.1 gwr static int decode_ea(struct frame *frame,
84 1.1 gwr struct instruction *insn,
85 1.1 gwr struct insn_ea *ea,
86 1.1 gwr int modreg);
87 1.1 gwr static int load_ea(struct frame *frame,
88 1.1 gwr struct instruction *insn,
89 1.1 gwr struct insn_ea *ea,
90 1.1 gwr char *cpureg);
91 1.1 gwr static int store_ea(struct frame *frame,
92 1.1 gwr struct instruction *insn,
93 1.1 gwr struct insn_ea *ea,
94 1.1 gwr char *cpureg);
95 1.1 gwr
96 1.1 gwr
97 1.1 gwr /*
98 1.1 gwr * Emulate a floating-point instruction.
99 1.1 gwr * Return zero for success, else signal number.
100 1.1 gwr * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
101 1.1 gwr */
102 1.1 gwr int fpu_emulate(struct frame *frame, struct fpframe *fpf)
103 1.1 gwr {
104 1.1 gwr struct instruction insn;
105 1.1 gwr int word, optype, sig;
106 1.1 gwr
107 1.1 gwr word = fusword(frame->f_pc);
108 1.1 gwr if (word < 0) {
109 1.1 gwr #ifdef DEBUG
110 1.1 gwr printf("fpu_emulate: fault reading opcode\n");
111 1.1 gwr #endif
112 1.1 gwr return SIGSEGV;
113 1.1 gwr }
114 1.1 gwr
115 1.1 gwr if ((word & 0xF000) != 0xF000) {
116 1.1 gwr #ifdef DEBUG
117 1.1 gwr printf("fpu_emulate: not coproc. insn.: opcode=0x%x\n", word);
118 1.1 gwr #endif
119 1.1 gwr return SIGILL;
120 1.1 gwr }
121 1.1 gwr
122 1.1 gwr if ((word & 0x0E00) != 0x0200) {
123 1.1 gwr #ifdef DEBUG
124 1.1 gwr printf("fpu_emulate: bad coproc. id: opcode=0x%x\n", word);
125 1.1 gwr #endif
126 1.1 gwr return SIGILL;
127 1.1 gwr }
128 1.1 gwr
129 1.1 gwr insn.opcode = word;
130 1.1 gwr optype = (word & 0x01C0);
131 1.1 gwr
132 1.1 gwr word = fusword(frame->f_pc + 2);
133 1.1 gwr if (word < 0) {
134 1.1 gwr #ifdef DEBUG
135 1.1 gwr printf("fpu_emulate: fault reading word1\n");
136 1.1 gwr #endif
137 1.1 gwr return SIGSEGV;
138 1.1 gwr }
139 1.1 gwr insn.word1 = word;
140 1.1 gwr
141 1.1 gwr /*
142 1.1 gwr * Which family (or type) of opcode is it?
143 1.1 gwr * Tests ordered by likelihood (hopefully).
144 1.1 gwr * Certainly, type 0 is the most common.
145 1.1 gwr */
146 1.1 gwr if (optype == 0x0000) {
147 1.1 gwr /* type=0: generic */
148 1.1 gwr if (insn.word1 & 0x8000) {
149 1.1 gwr sig = fpu_emul_fmovm(frame, fpf, &insn);
150 1.1 gwr } else {
151 1.1 gwr sig = fpu_emul_type0(frame, fpf, &insn);
152 1.1 gwr }
153 1.1 gwr }
154 1.1 gwr else if (optype == 0x0080) {
155 1.1 gwr /* type=2: fbcc, short disp. */
156 1.1 gwr sig = fpu_emul_brcc(frame, fpf, &insn);
157 1.1 gwr }
158 1.1 gwr else if (optype == 0x00C0) {
159 1.1 gwr /* type=3: fbcc, long disp. */
160 1.1 gwr sig = fpu_emul_brcc(frame, fpf, &insn);
161 1.1 gwr }
162 1.1 gwr else if (optype == 0x0040) {
163 1.1 gwr /* type=1: fdbcc, fscc, ftrapcc */
164 1.1 gwr sig = fpu_emul_type1(frame, fpf, &insn);
165 1.1 gwr }
166 1.1 gwr else {
167 1.1 gwr /* type=4: fsave (privileged) */
168 1.1 gwr /* type=5: frestore (privileged) */
169 1.1 gwr /* type=6: reserved */
170 1.1 gwr /* type=7: reserved */
171 1.1 gwr #ifdef DEBUG
172 1.1 gwr printf("fpu_emulate: bad opcode type: opcode=0x%x\n", insn.opcode);
173 1.1 gwr #endif
174 1.1 gwr sig = SIGILL;
175 1.1 gwr }
176 1.1 gwr
177 1.1 gwr if (sig == 0) {
178 1.1 gwr frame->f_pc += insn.advance;
179 1.1 gwr }
180 1.1 gwr #if defined(DDB) && defined(DEBUG)
181 1.1 gwr else kdb_trap(-1, frame);
182 1.1 gwr #endif
183 1.1 gwr
184 1.1 gwr return (sig);
185 1.1 gwr }
186 1.1 gwr
187 1.1 gwr /*
188 1.1 gwr * type 0: fmovem, fmove <cr>
189 1.1 gwr * Separated out of fpu_emul_type0 for efficiency.
190 1.1 gwr * In this function, we know:
191 1.1 gwr * (opcode & 0x01C0) == 0
192 1.1 gwr * (word1 & 0x8000) == 0x8000
193 1.1 gwr *
194 1.1 gwr * No conversion or rounding is done by this instruction,
195 1.1 gwr * and the FPSR is not affected.
196 1.1 gwr */
197 1.1 gwr int fpu_emul_fmovm(struct frame *frame,
198 1.1 gwr struct fpframe *fpf,
199 1.1 gwr struct instruction *insn)
200 1.1 gwr {
201 1.1 gwr int word1, sig;
202 1.1 gwr int reglist, regmask, regnum;
203 1.1 gwr int fpu_to_mem, order;
204 1.1 gwr int w1_post_incr; /* XXX - FP regs order? */
205 1.1 gwr int *fpregs;
206 1.1 gwr
207 1.1 gwr insn->advance = 4;
208 1.1 gwr insn->datasize = 12;
209 1.1 gwr word1 = insn->word1;
210 1.1 gwr
211 1.1 gwr /* Bit 14 selects FPn or FP control regs. */
212 1.1 gwr if (word1 & 0x4000) {
213 1.1 gwr /*
214 1.1 gwr * Bits 12,11 select register list mode:
215 1.1 gwr * 0,0: Static reg list, pre-decr.
216 1.1 gwr * 0,1: Dynamic reg list, pre-decr.
217 1.1 gwr * 1,0: Static reg list, post-incr.
218 1.1 gwr * 1,1: Dynamic reg list, post-incr
219 1.1 gwr */
220 1.1 gwr w1_post_incr = word1 & 0x1000;
221 1.1 gwr if (word1 & 0x0800) {
222 1.1 gwr /* dynamic reg list */
223 1.1 gwr reglist = frame->f_regs[(word1 & 0x70) >> 4];
224 1.1 gwr } else
225 1.1 gwr reglist = word1;
226 1.1 gwr reglist &= 0xFF;
227 1.1 gwr } else {
228 1.1 gwr /* XXX: move to/from control registers */
229 1.1 gwr reglist = word1 & 0x1C00;
230 1.1 gwr return SIGILL;
231 1.1 gwr }
232 1.1 gwr
233 1.1 gwr /* Bit 13 selects direction (FPU to/from Mem) */
234 1.1 gwr fpu_to_mem = word1 & 0x2000;
235 1.1 gwr
236 1.1 gwr /* Get effective address. (modreg=opcode&077) */
237 1.1 gwr sig = decode_ea(frame, insn, &insn->ea0, insn->opcode);
238 1.1 gwr if (sig) return sig;
239 1.1 gwr
240 1.1 gwr /* Get address of soft coprocessor regs. */
241 1.1 gwr fpregs = &fpf->fpf_regs[0];
242 1.1 gwr
243 1.1 gwr if (insn->ea0.flags & EA_PREDECR) {
244 1.1 gwr regnum = 7;
245 1.1 gwr order = -1;
246 1.1 gwr } else {
247 1.1 gwr regnum = 0;
248 1.1 gwr order = 1;
249 1.1 gwr }
250 1.1 gwr
251 1.1 gwr while ((0 <= regnum) && (regnum < 8)) {
252 1.1 gwr regmask = 1 << regnum;
253 1.1 gwr if (regmask & reglist) {
254 1.1 gwr if (fpu_to_mem)
255 1.1 gwr sig = store_ea(frame, insn, &insn->ea0,
256 1.1 gwr (char*) &fpregs[regnum]);
257 1.1 gwr else /* mem to fpu */
258 1.1 gwr sig = load_ea(frame, insn, &insn->ea0,
259 1.1 gwr (char*) &fpregs[regnum]);
260 1.1 gwr if (sig) break;
261 1.1 gwr }
262 1.1 gwr regnum += order;
263 1.1 gwr }
264 1.1 gwr
265 1.1 gwr return 0;
266 1.1 gwr }
267 1.1 gwr
268 1.1 gwr int fpu_emul_type0(struct frame *frame,
269 1.1 gwr struct fpframe *fpf,
270 1.1 gwr struct instruction *insn)
271 1.1 gwr {
272 1.1 gwr int sig;
273 1.1 gwr
274 1.1 gwr /* Get effective address */
275 1.1 gwr /* XXX */
276 1.1 gwr
277 1.1 gwr switch(insn->word1 & 0x3F) {
278 1.1 gwr
279 1.1 gwr case 0x00: /* fmove */
280 1.1 gwr
281 1.1 gwr case 0x01: /* fint */
282 1.1 gwr case 0x02: /* fsinh */
283 1.1 gwr case 0x03: /* fintrz */
284 1.1 gwr case 0x04: /* fsqrt */
285 1.1 gwr case 0x06: /* flognp1 */
286 1.1 gwr
287 1.1 gwr case 0x09: /* ftanh */
288 1.1 gwr case 0x0A: /* fatan */
289 1.1 gwr case 0x0C: /* fasin */
290 1.1 gwr case 0x0D: /* fatanh */
291 1.1 gwr case 0x0E: /* fsin */
292 1.1 gwr case 0x0F: /* ftan */
293 1.1 gwr
294 1.1 gwr case 0x10: /* fetox */
295 1.1 gwr case 0x11: /* ftwotox */
296 1.1 gwr case 0x12: /* ftentox */
297 1.1 gwr case 0x14: /* flogn */
298 1.1 gwr case 0x15: /* flog10 */
299 1.1 gwr case 0x16: /* flog2 */
300 1.1 gwr
301 1.1 gwr case 0x18: /* fabs */
302 1.1 gwr case 0x19: /* fcosh */
303 1.1 gwr case 0x1A: /* fneg */
304 1.1 gwr case 0x1C: /* facos */
305 1.1 gwr case 0x1D: /* fcos */
306 1.1 gwr case 0x1E: /* fgetexp */
307 1.1 gwr case 0x1F: /* fgetman */
308 1.1 gwr
309 1.1 gwr case 0x20: /* fdiv */
310 1.1 gwr case 0x21: /* fmod */
311 1.1 gwr case 0x22: /* fadd */
312 1.1 gwr case 0x23: /* fmul */
313 1.1 gwr case 0x24: /* fsgldiv */
314 1.1 gwr case 0x25: /* frem */
315 1.1 gwr case 0x26: /* fscale */
316 1.1 gwr case 0x27: /* fsglmul */
317 1.1 gwr
318 1.1 gwr case 0x28: /* fsub */
319 1.1 gwr case 0x38: /* fcmp */
320 1.1 gwr case 0x3A: /* ftst */
321 1.1 gwr
322 1.1 gwr default:
323 1.1 gwr #ifdef DEBUG
324 1.1 gwr printf("fpu_emul_type0: unknown: opcode=0x%x, word1=0x%x\n",
325 1.1 gwr insn->opcode, insn->word1);
326 1.1 gwr #endif
327 1.1 gwr sig = SIGILL;
328 1.1 gwr
329 1.1 gwr } /* switch */
330 1.1 gwr return (sig);
331 1.1 gwr }
332 1.1 gwr
333 1.1 gwr /*
334 1.1 gwr * type 1: fdbcc, fscc, ftrapcc
335 1.1 gwr * In this function, we know:
336 1.1 gwr * (opcode & 0x01C0) == 0x0040
337 1.1 gwr */
338 1.1 gwr int fpu_emul_type1(struct frame *frame,
339 1.1 gwr struct fpframe *fpf,
340 1.1 gwr struct instruction *insn)
341 1.1 gwr {
342 1.1 gwr int sig;
343 1.1 gwr
344 1.1 gwr /* Get effective address */
345 1.1 gwr /* XXX */
346 1.1 gwr
347 1.1 gwr switch (insn->opcode & 070) {
348 1.1 gwr
349 1.1 gwr case 010: /* fdbcc */
350 1.1 gwr /* XXX: If not CC { Decrement Dn; if (Dn >= 0) branch; } */
351 1.1 gwr
352 1.1 gwr case 070: /* fscc or ftrapcc */
353 1.1 gwr if ((insn->opcode & 07) > 1) {
354 1.1 gwr /* ftrapcc */
355 1.1 gwr /* XXX: If CC, advance and return SIGFPE */
356 1.1 gwr break;
357 1.1 gwr }
358 1.1 gwr /* fallthrough */
359 1.1 gwr default: /* fscc */
360 1.1 gwr /* XXX: If CC, store ones, else store zero */
361 1.1 gwr sig = SIGILL;
362 1.1 gwr break;
363 1.1 gwr
364 1.1 gwr }
365 1.1 gwr return (sig);
366 1.1 gwr }
367 1.1 gwr
368 1.1 gwr /*
369 1.1 gwr * Type 2 or 3: fbcc (also fnop)
370 1.1 gwr * In this function, we know:
371 1.1 gwr * (opcode & 0x0180) == 0x0080
372 1.1 gwr */
373 1.1 gwr int fpu_emul_brcc(struct frame *frame,
374 1.1 gwr struct fpframe *fpf,
375 1.1 gwr struct instruction *insn)
376 1.1 gwr {
377 1.1 gwr int displ, word2;
378 1.1 gwr int sig, advance;
379 1.1 gwr
380 1.1 gwr /*
381 1.1 gwr * Get branch displacement.
382 1.1 gwr */
383 1.1 gwr advance = 4;
384 1.1 gwr displ = insn->word1;
385 1.1 gwr if (displ & 0x8000)
386 1.1 gwr displ |= 0xFFFF0000;
387 1.1 gwr
388 1.1 gwr if (insn->opcode & 0x40) {
389 1.1 gwr word2 = fusword(frame->f_pc + 4);
390 1.1 gwr if (word2 < 0) {
391 1.1 gwr #ifdef DEBUG
392 1.1 gwr printf("fpu_emul_brcc: fault reading word2\n");
393 1.1 gwr #endif
394 1.1 gwr return SIGSEGV;
395 1.1 gwr }
396 1.1 gwr displ << 16;
397 1.1 gwr displ |= word2;
398 1.1 gwr advance += 2;
399 1.1 gwr }
400 1.1 gwr
401 1.1 gwr /* XXX: If CC, frame->f_pc += displ */
402 1.1 gwr return SIGILL;
403 1.1 gwr }
404 1.1 gwr
405 1.1 gwr /*
406 1.1 gwr * Helper routines for dealing with "effective address" values.
407 1.1 gwr */
408 1.1 gwr
409 1.1 gwr /*
410 1.1 gwr * Decode an effective address into internal form.
411 1.1 gwr * Returns zero on success, else signal number.
412 1.1 gwr */
413 1.1 gwr static int decode_ea(struct frame *frame,
414 1.1 gwr struct instruction *insn,
415 1.1 gwr struct insn_ea *ea,
416 1.1 gwr int modreg)
417 1.1 gwr {
418 1.1 gwr int immed_bytes = 0;
419 1.1 gwr int data;
420 1.1 gwr
421 1.1 gwr /* Set the most common value here. */
422 1.1 gwr ea->regnum = 8 + (modreg & 7);
423 1.1 gwr
424 1.1 gwr switch (modreg & 070) {
425 1.1 gwr
426 1.1 gwr case 0: /* Dn */
427 1.1 gwr ea->regnum = (modreg & 7);
428 1.1 gwr ea->flags = EA_DIRECT;
429 1.1 gwr break;
430 1.1 gwr
431 1.1 gwr case 010: /* An */
432 1.1 gwr ea->flags = EA_DIRECT;
433 1.1 gwr break;
434 1.1 gwr
435 1.1 gwr case 020: /* (An) */
436 1.1 gwr ea->flags = 0;
437 1.1 gwr break;
438 1.1 gwr
439 1.1 gwr case 030: /* (An)+ */
440 1.1 gwr ea->flags = EA_POSTINCR;
441 1.1 gwr break;
442 1.1 gwr
443 1.1 gwr case 040: /* -(An) */
444 1.1 gwr ea->flags = EA_PREDECR;
445 1.1 gwr break;
446 1.1 gwr
447 1.1 gwr case 050: /* (d16,An) */
448 1.1 gwr ea->flags = EA_OFFSET;
449 1.1 gwr immed_bytes = 2;
450 1.1 gwr break;
451 1.1 gwr
452 1.1 gwr case 060: /* (d8,An,Xn) */
453 1.1 gwr ea->flags = EA_INDEXED;
454 1.1 gwr immed_bytes = 2;
455 1.1 gwr
456 1.1 gwr case 070: /* misc. */
457 1.1 gwr ea->regnum = (modreg & 7);
458 1.1 gwr switch (modreg & 7) {
459 1.1 gwr
460 1.1 gwr case 0: /* (xxxx).W */
461 1.1 gwr ea->flags = EA_ABS;
462 1.1 gwr immed_bytes = 2;
463 1.1 gwr break;
464 1.1 gwr
465 1.1 gwr case 1: /* (xxxxxxxx).L */
466 1.1 gwr ea->flags = EA_ABS;
467 1.1 gwr immed_bytes = 4;
468 1.1 gwr break;
469 1.1 gwr
470 1.1 gwr case 2: /* (d16,PC) */
471 1.1 gwr ea->flags = EA_PC_REL | EA_OFFSET;
472 1.1 gwr immed_bytes = 2;
473 1.1 gwr break;
474 1.1 gwr
475 1.1 gwr case 3: /* (d8,PC,Xn) */
476 1.1 gwr ea->flags = EA_PC_REL | EA_INDEXED;
477 1.1 gwr immed_bytes = 2;
478 1.1 gwr break;
479 1.1 gwr
480 1.1 gwr case 4: /* #data */
481 1.1 gwr ea->flags = EA_IMMED;
482 1.1 gwr immed_bytes = insn->datasize;
483 1.1 gwr break;
484 1.1 gwr
485 1.1 gwr default:
486 1.1 gwr return SIGILL;
487 1.1 gwr } /* switch for mode 7 */
488 1.1 gwr break;
489 1.1 gwr } /* switch mode */
490 1.1 gwr
491 1.1 gwr /* Now fetch any immediate data and advance. */
492 1.1 gwr if (immed_bytes > 0) {
493 1.1 gwr data = fusword(frame->f_pc + insn->advance);
494 1.1 gwr if (data < 0)
495 1.1 gwr return SIGSEGV;
496 1.1 gwr insn->advance += 2;
497 1.1 gwr if (data & 0x8000)
498 1.1 gwr data |= 0xFFFF0000;
499 1.1 gwr ea->immed = data;
500 1.1 gwr }
501 1.1 gwr if (immed_bytes > 2) {
502 1.1 gwr data = fusword(frame->f_pc + insn->advance);
503 1.1 gwr if (data < 0)
504 1.1 gwr return SIGSEGV;
505 1.1 gwr insn->advance += 2;
506 1.1 gwr ea->immed <<= 16;
507 1.1 gwr ea->immed |= data;
508 1.1 gwr }
509 1.1 gwr return 0;
510 1.1 gwr }
511 1.1 gwr
512 1.1 gwr
513 1.1 gwr /*
514 1.1 gwr * Load a value from an effective address.
515 1.1 gwr * Returns zero on success, else signal number.
516 1.1 gwr */
517 1.1 gwr static int load_ea(struct frame *frame,
518 1.1 gwr struct instruction *insn,
519 1.1 gwr struct insn_ea *ea,
520 1.1 gwr char *dst)
521 1.1 gwr {
522 1.1 gwr int *reg;
523 1.1 gwr char *src;
524 1.1 gwr int len;
525 1.1 gwr
526 1.1 gwr #ifdef DIAGNOSTIC
527 1.1 gwr if (ea->regnum & ~0xF)
528 1.1 gwr panic("load_ea: bad regnum");
529 1.1 gwr #endif
530 1.1 gwr
531 1.1 gwr /* The dst is always int or larger. */
532 1.1 gwr len = insn->datasize;
533 1.1 gwr if (len < 4)
534 1.1 gwr dst += (4 - len);
535 1.1 gwr
536 1.1 gwr /* point to the register */
537 1.1 gwr if (ea->flags & EA_PC_REL)
538 1.1 gwr reg = &frame->f_pc;
539 1.1 gwr else
540 1.1 gwr reg = &frame->f_regs[ea->regnum];
541 1.1 gwr
542 1.1 gwr if (ea->flags & (EA_DIRECT | EA_IMMED)) {
543 1.1 gwr if (ea->flags & EA_DIRECT)
544 1.1 gwr src = (char*) reg;
545 1.1 gwr if (ea->flags & EA_IMMED)
546 1.1 gwr src = (char*) &ea->immed;
547 1.1 gwr if (len > 4)
548 1.1 gwr return SIGILL;
549 1.1 gwr /* The source is an int. */
550 1.1 gwr if (len < 4)
551 1.1 gwr src += (4 - len);
552 1.1 gwr bcopy(src, dst, len);
553 1.1 gwr } else {
554 1.1 gwr /* One of MANY indirect forms... */
555 1.1 gwr
556 1.1 gwr /* do pre-decrement */
557 1.1 gwr if (ea->flags & EA_PREDECR)
558 1.1 gwr *reg -= len;
559 1.1 gwr
560 1.1 gwr /* Grab the register contents. */
561 1.1 gwr src = (char*) *reg;
562 1.1 gwr
563 1.1 gwr /* apply the signed offset */
564 1.1 gwr if (ea->flags & EA_OFFSET)
565 1.1 gwr src += ea->immed;
566 1.1 gwr
567 1.1 gwr /* XXX - Don't know how to handle this yet. */
568 1.1 gwr if (ea->flags & EA_INDEXED)
569 1.1 gwr return SIGILL;
570 1.1 gwr
571 1.1 gwr copyin(src, dst, len);
572 1.1 gwr
573 1.1 gwr /* do post-increment */
574 1.1 gwr if (ea->flags & EA_POSTINCR)
575 1.1 gwr *reg += len;
576 1.1 gwr }
577 1.1 gwr
578 1.1 gwr return 0;
579 1.1 gwr }
580 1.1 gwr
581 1.1 gwr /*
582 1.1 gwr * Store a value at the effective address.
583 1.1 gwr * Returns zero on success, else signal number.
584 1.1 gwr */
585 1.1 gwr static int store_ea(struct frame *frame,
586 1.1 gwr struct instruction *insn,
587 1.1 gwr struct insn_ea *ea,
588 1.1 gwr char *src)
589 1.1 gwr {
590 1.1 gwr int *reg;
591 1.1 gwr char *dst;
592 1.1 gwr int len;
593 1.1 gwr
594 1.1 gwr #ifdef DIAGNOSTIC
595 1.1 gwr if (ea->regnum & ~0xF)
596 1.1 gwr panic("load_ea: bad regnum");
597 1.1 gwr #endif
598 1.1 gwr
599 1.1 gwr /* The src is always int or larger. */
600 1.1 gwr len = insn->datasize;
601 1.1 gwr if (len < 4)
602 1.1 gwr src += (4 - len);
603 1.1 gwr
604 1.1 gwr /* point to the register */
605 1.1 gwr if (ea->flags & EA_PC_REL)
606 1.1 gwr reg = &frame->f_pc;
607 1.1 gwr else
608 1.1 gwr reg = &frame->f_regs[ea->regnum];
609 1.1 gwr
610 1.1 gwr if (ea->flags & EA_IMMED)
611 1.1 gwr return SIGILL;
612 1.1 gwr
613 1.1 gwr if (ea->flags & EA_DIRECT) {
614 1.1 gwr dst = (char*) reg;
615 1.1 gwr if (len > 4)
616 1.1 gwr return SIGILL;
617 1.1 gwr /* The destination is an int. */
618 1.1 gwr if (len < 4)
619 1.1 gwr dst += (4 - len);
620 1.1 gwr bcopy(src, dst, len);
621 1.1 gwr } else {
622 1.1 gwr /* One of MANY indirect forms... */
623 1.1 gwr
624 1.1 gwr /* do pre-decrement */
625 1.1 gwr if (ea->flags & EA_PREDECR)
626 1.1 gwr *reg -= len;
627 1.1 gwr
628 1.1 gwr /* Grab the register contents. */
629 1.1 gwr dst = (char*) *reg;
630 1.1 gwr
631 1.1 gwr /* apply the signed offset */
632 1.1 gwr if (ea->flags & EA_OFFSET)
633 1.1 gwr dst += ea->immed;
634 1.1 gwr
635 1.1 gwr /* XXX - Don't know how to handle this yet. */
636 1.1 gwr if (ea->flags & EA_INDEXED)
637 1.1 gwr return SIGILL;
638 1.1 gwr
639 1.1 gwr copyout(src, dst, len);
640 1.1 gwr
641 1.1 gwr /* do post-increment */
642 1.1 gwr if (ea->flags & EA_POSTINCR)
643 1.1 gwr *reg += len;
644 1.1 gwr }
645 1.1 gwr
646 1.1 gwr return 0;
647 1.1 gwr }
648