3bf57d21 |
1 | /* Print m68k instructions for GDB, the GNU debugger. |
2 | Copyright (C) 1986, 1987 Free Software Foundation, Inc. |
3 | |
4 | GDB is distributed in the hope that it will be useful, but WITHOUT ANY |
5 | WARRANTY. No author or distributor accepts responsibility to anyone |
6 | for the consequences of using it or for whether it serves any |
7 | particular purpose or works at all, unless he says so in writing. |
8 | Refer to the GDB General Public License for full details. |
9 | |
10 | Everyone is granted permission to copy, modify and redistribute GDB, |
11 | but only under the conditions described in the GDB General Public |
12 | License. A copy of this license is supposed to have been given to you |
13 | along with GDB so you can know your rights and responsibilities. It |
14 | should be in a file named COPYING. Among other things, the copyright |
15 | notice and this notice must be preserved on all copies. |
16 | |
17 | In other words, go ahead and share GDB, but don't try to stop |
18 | anyone else from sharing it farther. Help stamp out software hoarding! |
19 | */ |
20 | |
21 | #include <stdio.h> |
22 | |
23 | #include "defs.h" |
24 | #include "param.h" |
25 | #include "symtab.h" |
26 | #include "opcode.h" |
27 | |
28 | /* 68k instructions are never longer than this many bytes. */ |
29 | #define MAXLEN 22 |
30 | |
31 | /* Number of elements in the opcode table. */ |
32 | #define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0]) |
33 | |
34 | extern char *reg_names[]; |
35 | char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", |
36 | "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"}; |
37 | |
38 | static unsigned char *print_insn_arg (); |
39 | static unsigned char *print_indexed (); |
40 | static void print_base (); |
41 | static int fetch_arg (); |
42 | |
43 | #define NEXTBYTE(p) (p += 2, ((char *)p)[-1]) |
44 | |
45 | #define NEXTWORD(p) \ |
46 | (p += 2, ((((char *)p)[-2]) << 8) + p[-1]) |
47 | |
48 | #define NEXTLONG(p) \ |
49 | (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) |
50 | |
51 | #define NEXTSINGLE(p) \ |
52 | (p += 4, *((float *)(p - 4))) |
53 | |
54 | #define NEXTDOUBLE(p) \ |
55 | (p += 8, *((double *)(p - 8))) |
56 | |
57 | #define NEXTEXTEND(p) \ |
58 | (p += 12, 0.0) /* Need a function to convert from extended to double |
59 | precision... */ |
60 | |
61 | #define NEXTPACKED(p) \ |
62 | (p += 12, 0.0) /* Need a function to convert from packed to double |
63 | precision. Actually, it's easier to print a |
64 | packed number than a double anyway, so maybe |
65 | there should be a special case to handle this... */ |
66 | \f |
67 | /* Print the m68k instruction at address MEMADDR in debugged memory, |
68 | on STREAM. Returns length of the instruction, in bytes. */ |
69 | |
70 | int |
71 | print_insn (memaddr, stream) |
72 | CORE_ADDR memaddr; |
73 | FILE *stream; |
74 | { |
75 | unsigned char buffer[MAXLEN]; |
76 | register int i; |
77 | register unsigned char *p; |
78 | register char *d; |
79 | register int bestmask; |
80 | int best; |
81 | |
82 | read_memory (memaddr, buffer, MAXLEN); |
83 | |
84 | bestmask = 0; |
85 | best = -1; |
86 | for (i = 0; i < NOPCODES; i++) |
87 | { |
88 | register unsigned int opcode = m68k_opcodes[i].opcode; |
89 | register unsigned int match = m68k_opcodes[i].match; |
90 | if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) |
91 | && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) |
92 | && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) |
93 | && ((0xff & buffer[3] & match) == (0xff & opcode))) |
94 | { |
95 | /* Don't use for printout the variants of divul and divsl |
96 | that have the same register number in two places. |
97 | The more general variants will match instead. */ |
98 | for (d = m68k_opcodes[i].args; *d; d += 2) |
99 | if (d[1] == 'D') |
100 | break; |
101 | |
102 | /* Don't use for printout the variants of most floating |
103 | point coprocessor instructions which use the same |
104 | register number in two places, as above. */ |
105 | if (*d == 0) |
106 | for (d = m68k_opcodes[i].args; *d; d += 2) |
107 | if (d[1] == 't') |
108 | break; |
109 | |
110 | if (*d == 0 && match > bestmask) |
111 | { |
112 | best = i; |
113 | bestmask = match; |
114 | } |
115 | } |
116 | } |
117 | |
118 | /* Handle undefined instructions. */ |
119 | if (best < 0) |
120 | { |
121 | fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]); |
122 | return 2; |
123 | } |
124 | |
125 | fprintf (stream, "%s", m68k_opcodes[best].name); |
126 | |
127 | /* Point at first word of argument data, |
128 | and at descriptor for first argument. */ |
129 | p = buffer + 2; |
130 | |
131 | /* Why do this this way? -MelloN */ |
132 | for (d = m68k_opcodes[best].args; *d; d += 2) |
133 | { |
134 | if (d[0] == '#') |
135 | { |
136 | if (d[1] == 'l' && p - buffer < 6) |
137 | p = buffer + 6; |
138 | else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) |
139 | p = buffer + 4; |
140 | } |
141 | if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4) |
142 | p = buffer + 4; |
143 | if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6) |
144 | p = buffer + 6; |
145 | } |
146 | |
147 | d = m68k_opcodes[best].args; |
148 | |
149 | if (*d) |
150 | fputc (' ', stream); |
151 | |
152 | while (*d) |
153 | { |
154 | p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream); |
155 | d += 2; |
156 | if (*d && *(d - 2) != 'I' && *d != 'k') |
157 | fprintf (stream, ","); |
158 | } |
159 | return p - buffer; |
160 | } |
161 | |
162 | static unsigned char * |
163 | print_insn_arg (d, buffer, p, addr, stream) |
164 | char *d; |
165 | unsigned char *buffer; |
166 | register unsigned char *p; |
167 | CORE_ADDR addr; /* PC for this arg to be relative to */ |
168 | FILE *stream; |
169 | { |
170 | register int val; |
171 | register int place = d[1]; |
172 | int regno; |
173 | register char *regname; |
174 | register unsigned char *p1; |
175 | register double flval; |
176 | int flt_p; |
177 | |
178 | switch (*d) |
179 | { |
180 | case 'C': |
181 | fprintf (stream, "ccr"); |
182 | break; |
183 | |
184 | case 'S': |
185 | fprintf (stream, "sr"); |
186 | break; |
187 | |
188 | case 'U': |
189 | fprintf (stream, "usp"); |
190 | break; |
191 | |
192 | case 'J': |
193 | { |
194 | static struct { char *name; int value; } names[] |
195 | = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, |
196 | {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, |
197 | {"msp", 0x803}, {"isp", 0x804}}; |
198 | |
199 | val = fetch_arg (buffer, place, 12); |
200 | for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) |
201 | if (names[regno].value == val) |
202 | { |
203 | fprintf (stream, names[regno].name); |
204 | break; |
205 | } |
206 | if (regno < 0) |
207 | fprintf (stream, "%d", val); |
208 | } |
209 | break; |
210 | |
211 | case 'Q': |
212 | val = fetch_arg (buffer, place, 3); |
213 | if (val == 0) val = 8; |
214 | fprintf (stream, "#%d", val); |
215 | break; |
216 | |
217 | case 'M': |
218 | val = fetch_arg (buffer, place, 8); |
219 | if (val & 0x80) |
220 | val = val - 0x100; |
221 | fprintf (stream, "#%d", val); |
222 | break; |
223 | |
224 | case 'T': |
225 | val = fetch_arg (buffer, place, 4); |
226 | fprintf (stream, "#%d", val); |
227 | break; |
228 | |
229 | case 'D': |
230 | fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); |
231 | break; |
232 | |
233 | case 'A': |
234 | fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]); |
235 | break; |
236 | |
237 | case 'R': |
238 | fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); |
239 | break; |
240 | |
241 | case 'F': |
242 | fprintf (stream, "fp%d", fetch_arg (buffer, place, 3)); |
243 | break; |
244 | |
245 | case 'O': |
246 | val = fetch_arg (buffer, place, 6); |
247 | if (val & 0x20) |
248 | fprintf (stream, "%s", reg_names [val & 7]); |
249 | else |
250 | fprintf (stream, "%d", val); |
251 | break; |
252 | |
253 | case '+': |
254 | fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]); |
255 | break; |
256 | |
257 | case '-': |
258 | fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]); |
259 | break; |
260 | |
261 | case 'k': |
262 | if (place == 'k') |
263 | fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]); |
264 | else if (place == 'C') |
265 | { |
266 | val = fetch_arg (buffer, place, 7); |
267 | if ( val > 63 ) /* This is a signed constant. */ |
268 | val -= 128; |
269 | fprintf (stream, "{#%d}", val); |
270 | } |
271 | else |
272 | error ("Invalid arg format in opcode table: \"%c%c\".", |
273 | *d, place); |
274 | break; |
275 | |
276 | case '#': |
277 | p1 = buffer + 2; |
278 | if (place == 's') |
279 | val = fetch_arg (buffer, place, 4); |
280 | else if (place == 'C') |
281 | val = fetch_arg (buffer, place, 7); |
282 | else if (place == '8') |
283 | val = fetch_arg (buffer, place, 3); |
284 | else if (place == '3') |
285 | val = fetch_arg (buffer, place, 8); |
286 | else if (place == 'b') |
287 | val = NEXTBYTE (p1); |
288 | else if (place == 'w') |
289 | val = NEXTWORD (p1); |
290 | else if (place == 'l') |
291 | val = NEXTLONG (p1); |
292 | else |
293 | error ("Invalid arg format in opcode table: \"%c%c\".", |
294 | *d, place); |
295 | fprintf (stream, "#%d", val); |
296 | break; |
297 | |
298 | case '^': |
299 | if (place == 's') |
300 | val = fetch_arg (buffer, place, 4); |
301 | else if (place == 'C') |
302 | val = fetch_arg (buffer, place, 7); |
303 | else if (place == '8') |
304 | val = fetch_arg (buffer, place, 3); |
305 | else if (place == 'b') |
306 | val = NEXTBYTE (p); |
307 | else if (place == 'w') |
308 | val = NEXTWORD (p); |
309 | else if (place == 'l') |
310 | val = NEXTLONG (p); |
311 | else |
312 | error ("Invalid arg format in opcode table: \"%c%c\".", |
313 | *d, place); |
314 | fprintf (stream, "#%d", val); |
315 | break; |
316 | |
317 | case 'B': |
318 | if (place == 'b') |
319 | val = NEXTBYTE (p); |
320 | else if (place == 'w') |
321 | val = NEXTWORD (p); |
322 | else if (place == 'l') |
323 | val = NEXTLONG (p); |
324 | else if (place == 'g') |
325 | { |
326 | val = ((char *)buffer)[1]; |
327 | if (val == 0) |
328 | val = NEXTWORD (p); |
329 | else if (val == -1) |
330 | val = NEXTLONG (p); |
331 | } |
332 | else if (place == 'c') |
333 | { |
334 | if (buffer[1] & 0x40) /* If bit six is one, long offset */ |
335 | val = NEXTLONG (p); |
336 | else |
337 | val = NEXTWORD (p); |
338 | } |
339 | else |
340 | error ("Invalid arg format in opcode table: \"%c%c\".", |
341 | *d, place); |
342 | |
343 | print_address (addr + val, stream); |
344 | break; |
345 | |
346 | case 'd': |
347 | val = NEXTWORD (p); |
348 | fprintf (stream, "%d(%s)", val, reg_names[fetch_arg (buffer, place, 3)]); |
349 | break; |
350 | |
351 | case 's': |
352 | fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]); |
353 | break; |
354 | |
355 | case 'I': |
356 | val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */ |
357 | if (val != 1) /* Unusual coprocessor ID? */ |
358 | fprintf (stream, "(cpid=%d) ", val); |
359 | if (place == 'i') |
360 | p += 2; /* Skip coprocessor extended operands */ |
361 | break; |
362 | |
363 | case '*': |
364 | case '~': |
365 | case '%': |
366 | case ';': |
367 | case '@': |
368 | case '!': |
369 | case '$': |
370 | case '?': |
371 | case '/': |
372 | case '&': |
373 | |
374 | if (place == 'd') |
375 | { |
376 | val = fetch_arg (buffer, 'x', 6); |
377 | val = ((val & 7) << 3) + ((val >> 3) & 7); |
378 | } |
379 | else |
380 | val = fetch_arg (buffer, 's', 6); |
381 | |
382 | /* Get register number assuming address register. */ |
383 | regno = (val & 7) + 8; |
384 | regname = reg_names[regno]; |
385 | switch (val >> 3) |
386 | { |
387 | case 0: |
388 | fprintf (stream, "%s", reg_names[val]); |
389 | break; |
390 | |
391 | case 1: |
392 | fprintf (stream, "%s", regname); |
393 | break; |
394 | |
395 | case 2: |
396 | fprintf (stream, "(%s)", regname); |
397 | break; |
398 | |
399 | case 3: |
400 | fprintf (stream, "(%s)+", regname); |
401 | break; |
402 | |
403 | case 4: |
404 | fprintf (stream, "-(%s)", regname); |
405 | break; |
406 | |
407 | case 5: |
408 | val = NEXTWORD (p); |
409 | fprintf (stream, "%d(%s)", val, regname); |
410 | break; |
411 | |
412 | case 6: |
413 | p = print_indexed (regno, p, addr, stream); |
414 | break; |
415 | |
416 | case 7: |
417 | switch (val & 7) |
418 | { |
419 | case 0: |
420 | val = NEXTWORD (p); |
421 | fprintf (stream, "@#"); |
422 | print_address (val, stream); |
423 | break; |
424 | |
425 | case 1: |
426 | val = NEXTLONG (p); |
427 | fprintf (stream, "@#"); |
428 | print_address (val, stream); |
429 | break; |
430 | |
431 | case 2: |
432 | val = NEXTWORD (p); |
433 | print_address (addr + val, stream); |
434 | break; |
435 | |
436 | case 3: |
437 | p = print_indexed (-1, p, addr, stream); |
438 | break; |
439 | |
440 | case 4: |
441 | flt_p = 1; /* Assume it's a float... */ |
442 | switch( place ) |
443 | { |
444 | case 'b': |
445 | val = NEXTBYTE (p); |
446 | flt_p = 0; |
447 | break; |
448 | |
449 | case 'w': |
450 | val = NEXTWORD (p); |
451 | flt_p = 0; |
452 | break; |
453 | |
454 | case 'l': |
455 | val = NEXTLONG (p); |
456 | flt_p = 0; |
457 | break; |
458 | |
459 | case 'f': |
460 | flval = NEXTSINGLE(p); |
461 | break; |
462 | |
463 | case 'F': |
464 | flval = NEXTDOUBLE(p); |
465 | break; |
466 | |
467 | case 'x': |
468 | flval = NEXTEXTEND(p); |
469 | break; |
470 | |
471 | case 'p': |
472 | flval = NEXTPACKED(p); |
473 | break; |
474 | |
475 | default: |
476 | error ("Invalid arg format in opcode table: \"%c%c\".", |
477 | *d, place); |
478 | } |
479 | if ( flt_p ) /* Print a float? */ |
480 | fprintf (stream, "#%g", flval); |
481 | else |
482 | fprintf (stream, "#%d", val); |
483 | break; |
484 | |
485 | default: |
486 | fprintf (stream, "<invalid address mode 0%o>", val); |
487 | } |
488 | } |
489 | break; |
490 | |
491 | default: |
492 | error ("Invalid arg format in opcode table: \"%c\".", *d); |
493 | } |
494 | |
495 | return (unsigned char *) p; |
496 | } |
497 | |
498 | /* Fetch BITS bits from a position in the instruction specified by CODE. |
499 | CODE is a "place to put an argument", or 'x' for a destination |
500 | that is a general address (mode and register). |
501 | BUFFER contains the instruction. */ |
502 | |
503 | static int |
504 | fetch_arg (buffer, code, bits) |
505 | unsigned char *buffer; |
506 | char code; |
507 | int bits; |
508 | { |
509 | register int val; |
510 | switch (code) |
511 | { |
512 | case 's': |
513 | val = buffer[1]; |
514 | break; |
515 | |
516 | case 'd': /* Destination, for register or quick. */ |
517 | val = (buffer[0] << 8) + buffer[1]; |
518 | val >>= 9; |
519 | break; |
520 | |
521 | case 'x': /* Destination, for general arg */ |
522 | val = (buffer[0] << 8) + buffer[1]; |
523 | val >>= 6; |
524 | break; |
525 | |
526 | case 'k': |
527 | val = (buffer[3] >> 4); |
528 | break; |
529 | |
530 | case 'C': |
531 | val = buffer[3]; |
532 | break; |
533 | |
534 | case '1': |
535 | val = (buffer[2] << 8) + buffer[3]; |
536 | val >>= 12; |
537 | break; |
538 | |
539 | case '2': |
540 | val = (buffer[2] << 8) + buffer[3]; |
541 | val >>= 6; |
542 | break; |
543 | |
544 | case '3': |
545 | case 'j': |
546 | val = (buffer[2] << 8) + buffer[3]; |
547 | break; |
548 | |
549 | case '4': |
550 | val = (buffer[4] << 8) + buffer[5]; |
551 | val >>= 12; |
552 | break; |
553 | |
554 | case '5': |
555 | val = (buffer[4] << 8) + buffer[5]; |
556 | val >>= 6; |
557 | break; |
558 | |
559 | case '6': |
560 | val = (buffer[4] << 8) + buffer[5]; |
561 | break; |
562 | |
563 | case '7': |
564 | val = (buffer[2] << 8) + buffer[3]; |
565 | val >>= 7; |
566 | break; |
567 | |
568 | case '8': |
569 | val = (buffer[2] << 8) + buffer[3]; |
570 | val >>= 10; |
571 | break; |
572 | |
573 | default: |
574 | abort (); |
575 | } |
576 | |
577 | switch (bits) |
578 | { |
579 | case 3: |
580 | return val & 7; |
581 | case 4: |
582 | return val & 017; |
583 | case 5: |
584 | return val & 037; |
585 | case 6: |
586 | return val & 077; |
587 | case 7: |
588 | return val & 0177; |
589 | case 8: |
590 | return val & 0377; |
591 | case 12: |
592 | return val & 07777; |
593 | default: |
594 | abort (); |
595 | } |
596 | } |
597 | |
598 | /* Print an indexed argument. The base register is BASEREG (-1 for pc). |
599 | P points to extension word, in buffer. |
600 | ADDR is the nominal core address of that extension word. */ |
601 | |
602 | static unsigned char * |
603 | print_indexed (basereg, p, addr, stream) |
604 | int basereg; |
605 | unsigned char *p; |
606 | FILE *stream; |
607 | CORE_ADDR addr; |
608 | { |
609 | register int word; |
610 | static char *scales[] = {"", "*2", "*4", "*8"}; |
611 | register int base_disp; |
612 | register int outer_disp; |
613 | char buf[40]; |
614 | |
615 | word = NEXTWORD (p); |
616 | |
617 | /* Generate the text for the index register. |
618 | Where this will be output is not yet determined. */ |
619 | sprintf (buf, "[%s.%c%s]", |
620 | reg_names[(word >> 12) & 0xf], |
621 | (word & 0x800) ? 'l' : 'w', |
622 | scales[(word >> 9) & 3]); |
623 | |
624 | /* Handle the 68000 style of indexing. */ |
625 | |
626 | if ((word & 0x100) == 0) |
627 | { |
628 | print_base (basereg, |
629 | ((word & 0x80) ? word | 0xff00 : word & 0xff) |
630 | + ((basereg == -1) ? addr : 0), |
631 | stream); |
632 | fprintf (stream, "%s", buf); |
633 | return p; |
634 | } |
635 | |
636 | /* Handle the generalized kind. */ |
637 | /* First, compute the displacement to add to the base register. */ |
638 | |
639 | if (word & 0200) |
640 | basereg = -2; |
641 | if (word & 0100) |
642 | buf[0] = 0; |
643 | base_disp = 0; |
644 | switch ((word >> 4) & 3) |
645 | { |
646 | case 2: |
647 | base_disp = NEXTWORD (p); |
648 | break; |
649 | case 3: |
650 | base_disp = NEXTLONG (p); |
651 | } |
652 | if (basereg == -1) |
653 | base_disp += addr; |
654 | |
655 | /* Handle single-level case (not indirect) */ |
656 | |
657 | if ((word & 7) == 0) |
658 | { |
659 | print_base (basereg, base_disp, stream); |
660 | fprintf (stream, "%s", buf); |
661 | return p; |
662 | } |
663 | |
664 | /* Two level. Compute displacement to add after indirection. */ |
665 | |
666 | outer_disp = 0; |
667 | switch (word & 3) |
668 | { |
669 | case 2: |
670 | outer_disp = NEXTWORD (p); |
671 | break; |
672 | case 3: |
673 | outer_disp = NEXTLONG (p); |
674 | } |
675 | |
676 | fprintf (stream, "%d(", outer_disp); |
677 | print_base (basereg, base_disp, stream); |
678 | |
679 | /* If postindexed, print the closeparen before the index. */ |
680 | if (word & 4) |
681 | fprintf (stream, ")%s", buf); |
682 | /* If preindexed, print the closeparen after the index. */ |
683 | else |
684 | fprintf (stream, "%s)", buf); |
685 | |
686 | return p; |
687 | } |
688 | |
689 | /* Print a base register REGNO and displacement DISP, on STREAM. |
690 | REGNO = -1 for pc, -2 for none (suppressed). */ |
691 | |
692 | static void |
693 | print_base (regno, disp, stream) |
694 | int regno; |
695 | int disp; |
696 | FILE *stream; |
697 | { |
698 | if (regno == -2) |
699 | fprintf (stream, "%d", disp); |
700 | else if (regno == -1) |
701 | fprintf (stream, "0x%x", disp); |
702 | else |
703 | fprintf (stream, "%d(%s)", disp, reg_names[regno]); |
704 | } |
705 | \f |
706 | /* This is not part of insn printing, but it is machine-specific, |
707 | so this is a convenient place to put it. |
708 | |
709 | Convert a 68881 extended float to a double. |
710 | FROM is the address of the extended float. |
711 | Store the double in *TO. */ |
712 | |
713 | convert_from_68881 (from, to) |
714 | char *from; |
715 | double *to; |
716 | { |
717 | #ifdef HPUX_ASM |
718 | asm ("mov.l 8(%a6),%a0"); |
719 | asm ("mov.l 12(%a6),%a1"); |
720 | asm ("fmove.x (%a0),%fp0"); |
721 | asm ("fmove.d %fp0,(%a1)"); |
722 | #else /* not HPUX_ASM */ |
723 | #if 0 |
724 | asm ("movl a6@(8),a0"); |
725 | asm ("movl a6@(12),a1"); |
726 | asm ("fmovex a0@,fp0"); |
727 | asm ("fmoved fp0,a1@"); |
728 | #else |
729 | /* Hand-assemble those insns since some assemblers lose |
730 | and some have different syntax. */ |
731 | asm (".word 020156"); |
732 | asm (".word 8"); |
733 | asm (".word 021156"); |
734 | asm (".word 12"); |
735 | asm (".long 0xf2104800"); |
736 | asm (".long 0xf2117400"); |
737 | #endif |
738 | #endif /* not HPUX_ASM */ |
739 | } |
740 | |
741 | /* The converse: convert the double *FROM to an extended float |
742 | and store where TO points. */ |
743 | |
744 | convert_to_68881 (from, to) |
745 | double *from; |
746 | char *to; |
747 | { |
748 | #ifdef HPUX_ASM |
749 | asm ("mov.l 8(%a6),%a0"); |
750 | asm ("mov.l 12(%a6),%a1"); |
751 | asm ("fmove.d (%a0),%fp0"); |
752 | asm ("fmove.x %fp0,(%a1)"); |
753 | #else /* not HPUX_ASM */ |
754 | #if 0 |
755 | asm ("movl a6@(8),a0"); |
756 | asm ("movl a6@(12),a1"); |
757 | asm ("fmoved a0@,fp0"); |
758 | asm ("fmovex fp0,a1@"); |
759 | #else |
760 | /* Hand-assemble those insns since some assemblers lose. */ |
761 | asm (".word 020156"); |
762 | asm (".word 8"); |
763 | asm (".word 021156"); |
764 | asm (".word 12"); |
765 | asm (".long 0xf2105400"); |
766 | asm (".long 0xf2116800"); |
767 | #endif |
768 | #endif /* not HPUX_ASM */ |
769 | } |