home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Atari / Gnu / gdb36p4s.zoo / m68k-pinsn.c < prev    next >
C/C++ Source or Header  |  1993-09-04  |  21KB  |  909 lines

  1. /* Print m68k instructions for GDB, the GNU debugger.
  2.    Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
  3.  
  4. This file is part of GDB.
  5.  
  6. GDB is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GDB is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GDB; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <stdio.h>
  21.  
  22. #include <setjmp.h>
  23. #include <signal.h>
  24.  
  25. #include "defs.h"
  26. #include "param.h"
  27. #include "symtab.h"
  28. #include "opcode.h"
  29.  
  30. /* 68k instructions are never longer than this many bytes.  */
  31. #define MAXLEN 22
  32.  
  33. /* Number of elements in the opcode table.  */
  34. #define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
  35.  
  36. extern char *reg_names[];
  37. char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
  38.              "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
  39.  
  40. static unsigned char *print_insn_arg ();
  41. static unsigned char *print_indexed ();
  42. static void print_base ();
  43. static int fetch_arg ();
  44.  
  45. #define NEXTBYTE(p)  (p += 2, ((char *)p)[-1])
  46.  
  47. #define NEXTWORD(p)  \
  48.   (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
  49.  
  50. #define NEXTLONG(p)  \
  51.   (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
  52.  
  53. #define NEXTSINGLE(p) \
  54.   (p += 4, *((float *)(p - 4)))
  55.  
  56. #define NEXTDOUBLE(p) \
  57.   (p += 8, *((double *)(p - 8)))
  58.  
  59. #if defined (atarist) && defined (__M68881__)
  60. #define NEXTEXTEND(p) \
  61.   (p += 12, *(long double *) (p - 12))
  62. #else
  63. #define NEXTEXTEND(p) \
  64.   (p += 12, 0.0)    /* Need a function to convert from extended to double
  65.                precision... */
  66. #endif
  67.  
  68. #define NEXTPACKED(p) \
  69.   (p += 12, 0.0)    /* Need a function to convert from packed to double
  70.                precision.   Actually, it's easier to print a
  71.                packed number than a double anyway, so maybe
  72.                there should be a special case to handle this... */
  73.  
  74. /* Print the m68k instruction at address MEMADDR in debugged memory,
  75.    on STREAM.  Returns length of the instruction, in bytes.  */
  76.  
  77. int
  78. print_insn (memaddr, stream)
  79.      CORE_ADDR memaddr;
  80.      FILE *stream;
  81. {
  82.   unsigned char buffer[MAXLEN];
  83.   register int i;
  84.   register unsigned char *p;
  85.   register const char *d;
  86.   register int bestmask;
  87.   int best;
  88.  
  89.   read_memory (memaddr, buffer, MAXLEN);
  90.  
  91.   bestmask = 0;
  92.   best = -1;
  93.   for (i = 0; i < NOPCODES; i++)
  94.     {
  95.       register unsigned int opcode = m68k_opcodes[i].opcode;
  96.       register unsigned int match = m68k_opcodes[i].match;
  97.       if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
  98.       && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
  99.       && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
  100.       && ((0xff & buffer[3] & match) == (0xff & opcode)))
  101.     {
  102.       /* Don't use for printout the variants of divul and divsl
  103.          that have the same register number in two places.
  104.          The more general variants will match instead.  */
  105.       for (d = m68k_opcodes[i].args; *d; d += 2)
  106.         if (d[1] == 'D')
  107.           break;
  108.  
  109.       /* Don't use for printout the variants of most floating
  110.          point coprocessor instructions which use the same
  111.          register number in two places, as above. */
  112.       if (*d == 0)
  113.         for (d = m68k_opcodes[i].args; *d; d += 2)
  114.           if (d[1] == 't')
  115.         break;
  116.  
  117.       if (*d == 0 && match > bestmask)
  118.         {
  119.           best = i;
  120.           bestmask = match;
  121.         }
  122.     }
  123.     }
  124.  
  125.   /* Handle undefined instructions.  */
  126.   if (best < 0)
  127.     {
  128.       fprintf_filtered (stream, "0%o", (buffer[0] << 8) + buffer[1]);
  129.       return 2;
  130.     }
  131.  
  132.   fprintf_filtered (stream, "%s", m68k_opcodes[best].name);
  133.  
  134.   /* Point at first word of argument data,
  135.      and at descriptor for first argument.  */
  136.   p = buffer + 2;
  137.   
  138.   /* Why do this this way? -MelloN */
  139.   for (d = m68k_opcodes[best].args; *d; d += 2)
  140.     {
  141.       if (d[0] == '#')
  142.     {
  143.       if (d[1] == 'l' && p - buffer < 6)
  144.         p = buffer + 6;
  145.       else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
  146.         p = buffer + 4;
  147.     }
  148.       if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
  149.     p = buffer + 4;
  150.       if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
  151.     p = buffer + 6;
  152.       if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
  153.     p = buffer + 4;
  154.     }
  155.  
  156.   d = m68k_opcodes[best].args;
  157.  
  158.   if (*d)
  159.     fputs_filtered (" ", stream);
  160.  
  161.   while (*d)
  162.     {
  163.       p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream);
  164.       d += 2;
  165.       if (*d && *(d - 2) != 'I' && *d != 'k')
  166.     fputs_filtered (",", stream);
  167.     }
  168.   return p - buffer;
  169. }
  170.  
  171. static unsigned char *
  172. print_insn_arg (d, buffer, p, addr, stream)
  173.      const char *d;
  174.      unsigned char *buffer;
  175.      register unsigned char *p;
  176.      CORE_ADDR addr;        /* PC for this arg to be relative to */
  177.      FILE *stream;
  178. {
  179.   register int val;
  180.   register int place = d[1];
  181.   int regno;
  182.   register char *regname;
  183.   register unsigned char *p1;
  184.   register double flval;
  185.   int flt_p;
  186.  
  187.   switch (*d)
  188.     {
  189.     case 'C':
  190.       fprintf_filtered (stream, "ccr");
  191.       break;
  192.  
  193.     case 'S':
  194.       fprintf_filtered (stream, "sr");
  195.       break;
  196.  
  197.     case 'U':
  198.       fprintf_filtered (stream, "usp");
  199.       break;
  200.  
  201.     case 'J':
  202.       {
  203.     static const struct { const char *name; int value; } names[]
  204.       = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
  205.          {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
  206.          {"msp", 0x803}, {"isp", 0x804}};
  207.  
  208.     val = fetch_arg (buffer, place, 12);
  209.     for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
  210.       if (names[regno].value == val)
  211.         {
  212.           fprintf_filtered (stream, names[regno].name);
  213.           break;
  214.         }
  215.     if (regno < 0)
  216.       fprintf_filtered (stream, "%d", val);
  217.       }
  218.       break;
  219.  
  220.     case 'Q':
  221.       val = fetch_arg (buffer, place, 3);
  222.       if (val == 0) val = 8;
  223.       fprintf_filtered (stream, "#%d", val);
  224.       break;
  225.  
  226.     case 'M':
  227.       val = fetch_arg (buffer, place, 8);
  228.       if (val & 0x80)
  229.     val = val - 0x100;
  230.       fprintf_filtered (stream, "#%d", val);
  231.       break;
  232.  
  233.     case 'T':
  234.       val = fetch_arg (buffer, place, 4);
  235.       fprintf_filtered (stream, "#%d", val);
  236.       break;
  237.  
  238.     case 'D':
  239.       fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
  240.       break;
  241.  
  242.     case 'A':
  243.       fprintf_filtered (stream, "%s",
  244.             reg_names[fetch_arg (buffer, place, 3) + 010]);
  245.       break;
  246.  
  247.     case 'R':
  248.       fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
  249.       break;
  250.  
  251.     case 'F':
  252.       fprintf_filtered (stream, "fp%d", fetch_arg (buffer, place, 3));
  253.       break;
  254.  
  255.     case 'O':
  256.       val = fetch_arg (buffer, place, 6);
  257.       if (val & 0x20)
  258.     fprintf_filtered (stream, "%s", reg_names [val & 7]);
  259.       else
  260.     fprintf_filtered (stream, "%d", val);
  261.       break;
  262.  
  263.     case '+':
  264.       fprintf_filtered (stream, "%s@+",
  265.             reg_names[fetch_arg (buffer, place, 3) + 8]);
  266.       break;
  267.  
  268.     case '-':
  269.       fprintf_filtered (stream, "%s@-",
  270.            reg_names[fetch_arg (buffer, place, 3) + 8]);
  271.       break;
  272.  
  273.     case 'k':
  274.       if (place == 'k')
  275.     fprintf_filtered (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
  276.       else if (place == 'C')
  277.     {
  278.       val = fetch_arg (buffer, place, 7);
  279.       if ( val > 63 )        /* This is a signed constant. */
  280.         val -= 128;
  281.       fprintf_filtered (stream, "{#%d}", val);
  282.     }
  283.       else
  284.     error ("Invalid arg format in opcode table: \"%c%c\".",
  285.            *d, place);
  286.       break;
  287.  
  288.     case '#':
  289.     case '^':
  290.       p1 = buffer + (*d == '#' ? 2 : 4);
  291.       if (place == 's')
  292.     val = fetch_arg (buffer, place, 4);
  293.       else if (place == 'C')
  294.     val = fetch_arg (buffer, place, 7);
  295.       else if (place == '8')
  296.     val = fetch_arg (buffer, place, 3);
  297.       else if (place == '3')
  298.     val = fetch_arg (buffer, place, 8);
  299.       else if (place == 'b')
  300.     val = NEXTBYTE (p1);
  301.       else if (place == 'w')
  302.     val = NEXTWORD (p1);
  303.       else if (place == 'l')
  304.     val = NEXTLONG (p1);
  305.       else
  306.     error ("Invalid arg format in opcode table: \"%c%c\".",
  307.            *d, place);
  308.       fprintf_filtered (stream, "#%d", val);
  309.       break;
  310.  
  311.     case 'B':
  312.       if (place == 'b')
  313.     val = NEXTBYTE (p);
  314.       else if (place == 'w')
  315.     val = NEXTWORD (p);
  316.       else if (place == 'l')
  317.     val = NEXTLONG (p);
  318.       else if (place == 'g')
  319.     {
  320.       val = ((char *)buffer)[1];
  321.       if (val == 0)
  322.         val = NEXTWORD (p);
  323.       else if (val == -1)
  324.         val = NEXTLONG (p);
  325.     }
  326.       else if (place == 'c')
  327.     {
  328.       if (buffer[1] & 0x40)        /* If bit six is one, long offset */
  329.         val = NEXTLONG (p);
  330.       else
  331.         val = NEXTWORD (p);
  332.     }
  333.       else
  334.     error ("Invalid arg format in opcode table: \"%c%c\".",
  335.            *d, place);
  336.  
  337.       print_address (addr + val, stream);
  338.       break;
  339.  
  340.     case 'd':
  341.       val = NEXTWORD (p);
  342.       fprintf_filtered (stream, "%s@(%d)",
  343.             reg_names[fetch_arg (buffer, place, 3)], val);
  344.       break;
  345.  
  346.     case 's':
  347.       fprintf_filtered (stream, "%s",
  348.             fpcr_names[fetch_arg (buffer, place, 3)]);
  349.       break;
  350.  
  351.     case 'I':
  352.       val = fetch_arg (buffer, 'd', 3);          /* Get coprocessor ID... */
  353.       if (val != 1)                /* Unusual coprocessor ID? */
  354.     fprintf_filtered (stream, "(cpid=%d) ", val);
  355.       if (place == 'i')
  356.     p += 2;                 /* Skip coprocessor extended operands */
  357.       break;
  358.  
  359.     case '*':
  360.     case '~':
  361.     case '%':
  362.     case ';':
  363.     case '@':
  364.     case '!':
  365.     case '$':
  366.     case '?':
  367.     case '/':
  368.     case '&':
  369.  
  370.       if (place == 'd')
  371.     {
  372.       val = fetch_arg (buffer, 'x', 6);
  373.       val = ((val & 7) << 3) + ((val >> 3) & 7);
  374.     }
  375.       else
  376.     val = fetch_arg (buffer, 's', 6);
  377.  
  378.       /* Get register number assuming address register.  */
  379.       regno = (val & 7) + 8;
  380.       regname = reg_names[regno];
  381.       switch (val >> 3)
  382.     {
  383.     case 0:
  384.       fprintf_filtered (stream, "%s", reg_names[val]);
  385.       break;
  386.  
  387.     case 1:
  388.       fprintf_filtered (stream, "%s", regname);
  389.       break;
  390.  
  391.     case 2:
  392.       fprintf_filtered (stream, "%s@", regname);
  393.       break;
  394.  
  395.     case 3:
  396.       fprintf_filtered (stream, "%s@+", regname);
  397.       break;
  398.  
  399.     case 4:
  400.       fprintf_filtered (stream, "%s@-", regname);
  401.       break;
  402.  
  403.     case 5:
  404.       val = NEXTWORD (p);
  405.       fprintf_filtered (stream, "%s@(%d)", regname, val);
  406.       break;
  407.  
  408.     case 6:
  409.       p = print_indexed (regno, p, addr, stream);
  410.       break;
  411.  
  412.     case 7:
  413.       switch (val & 7)
  414.         {
  415.         case 0:
  416.           val = NEXTWORD (p);
  417.           fprintf_filtered (stream, "@#");
  418.           print_address (val, stream);
  419.           break;
  420.  
  421.         case 1:
  422.           val = NEXTLONG (p);
  423.           fprintf_filtered (stream, "@#");
  424.           print_address (val, stream);
  425.           break;
  426.  
  427.         case 2:
  428.           val = NEXTWORD (p);
  429.           print_address (addr + val, stream);
  430.           break;
  431.  
  432.         case 3:
  433.           p = print_indexed (-1, p, addr, stream);
  434.           break;
  435.  
  436.         case 4:
  437.           flt_p = 1;    /* Assume it's a float... */
  438.           switch( place )
  439.           {
  440.         case 'b':
  441.           val = NEXTBYTE (p);
  442.           flt_p = 0;
  443.           break;
  444.  
  445.         case 'w':
  446.           val = NEXTWORD (p);
  447.           flt_p = 0;
  448.           break;
  449.  
  450.         case 'l':
  451.           val = NEXTLONG (p);
  452.           flt_p = 0;
  453.           break;
  454.  
  455.         case 'f':
  456.           flval = NEXTSINGLE(p);
  457.           break;
  458.  
  459.         case 'F':
  460.           flval = NEXTDOUBLE(p);
  461.           break;
  462.  
  463.         case 'x':
  464.           flval = NEXTEXTEND(p);
  465.           break;
  466.  
  467.         case 'p':
  468.           flval = NEXTPACKED(p);
  469.           break;
  470.  
  471.         default:
  472.           error ("Invalid arg format in opcode table: \"%c%c\".",
  473.                *d, place);
  474.           }
  475.           if ( flt_p )    /* Print a float? */
  476.         fprintf_filtered (stream, "#%g", flval);
  477.           else
  478.         fprintf_filtered (stream, "#%d", val);
  479.           break;
  480.  
  481.         default:
  482.           fprintf_filtered (stream, "<invalid address mode 0%o>", val);
  483.         }
  484.     }
  485.       break;
  486.  
  487.     case 'L':
  488.     case 'l':
  489.     if (place == 'w')
  490.       {
  491.         char doneany;
  492.         p1 = buffer + 2;
  493.         val = NEXTWORD (p1);
  494.         /* Move the pointer ahead if this point is farther ahead
  495.            than the last.  */
  496.         p = p1 > p ? p1 : p;
  497.         if (val == 0)
  498.           {
  499.         fputs_filtered ("#0", stream);
  500.         break;
  501.           }
  502.         if (*d == 'l')
  503.           {
  504.         register int newval = 0;
  505.         for (regno = 0; regno < 16; ++regno)
  506.           if (val & (0x8000 >> regno))
  507.             newval |= 1 << regno;
  508.         val = newval;
  509.           }
  510.         val &= 0xffff;
  511.         doneany = 0;
  512.         for (regno = 0; regno < 16; ++regno)
  513.           if (val & (1 << regno))
  514.         {
  515.           int first_regno;
  516.           if (doneany)
  517.             fputs_filtered ("/", stream);
  518.           doneany = 1;
  519.           fprintf_filtered (stream, "%s", reg_names[regno]);
  520.           first_regno = regno;
  521.           while (val & (1 << (regno + 1)))
  522.             ++regno;
  523.           if (regno > first_regno)
  524.             fprintf_filtered (stream, "-%s", reg_names[regno]);
  525.         }
  526.       }
  527.     else if (place == '3')
  528.       {
  529.         /* `fmovem' insn.  */
  530.         char doneany;
  531.         val = fetch_arg (buffer, place, 8);
  532.         if (val == 0)
  533.           {
  534.         fputs_filtered ("#0", stream);
  535.         break;
  536.           }
  537.         if (*d == 'l')
  538.           {
  539.         register int newval = 0;
  540.         for (regno = 0; regno < 8; ++regno)
  541.           if (val & (0x80 >> regno))
  542.             newval |= 1 << regno;
  543.         val = newval;
  544.           }
  545.         val &= 0xff;
  546.         doneany = 0;
  547.         for (regno = 0; regno < 8; ++regno)
  548.           if (val & (1 << regno))
  549.         {
  550.           int first_regno;
  551.           if (doneany)
  552.             fputs_filtered ("/", stream);
  553.           doneany = 1;
  554.           fprintf_filtered (stream, "fp%d", regno);
  555.           first_regno = regno;
  556.           while (val & (1 << (regno + 1)))
  557.             ++regno;
  558.           if (regno > first_regno)
  559.             fprintf_filtered (stream, "-fp%d", regno);
  560.         }
  561.       }
  562.     else
  563.       abort ();
  564.       break;
  565.  
  566.     default:
  567.       error ("Invalid arg format in opcode table: \"%c\".", *d);
  568.     }
  569.  
  570.   return (unsigned char *) p;
  571. }
  572.  
  573. /* Fetch BITS bits from a position in the instruction specified by CODE.
  574.    CODE is a "place to put an argument", or 'x' for a destination
  575.    that is a general address (mode and register).
  576.    BUFFER contains the instruction.  */
  577.  
  578. static int
  579. fetch_arg (buffer, code, bits)
  580.      unsigned char *buffer;
  581.      char code;
  582.      int bits;
  583. {
  584.   register int val;
  585.   switch (code)
  586.     {
  587.     case 's':
  588.       val = buffer[1];
  589.       break;
  590.  
  591.     case 'd':            /* Destination, for register or quick.  */
  592.       val = (buffer[0] << 8) + buffer[1];
  593.       val >>= 9;
  594.       break;
  595.  
  596.     case 'x':            /* Destination, for general arg */
  597.       val = (buffer[0] << 8) + buffer[1];
  598.       val >>= 6;
  599.       break;
  600.  
  601.     case 'k':
  602.       val = (buffer[3] >> 4);
  603.       break;
  604.  
  605.     case 'C':
  606.       val = buffer[3];
  607.       break;
  608.  
  609.     case '1':
  610.       val = (buffer[2] << 8) + buffer[3];
  611.       val >>= 12;
  612.       break;
  613.  
  614.     case '2':
  615.       val = (buffer[2] << 8) + buffer[3];
  616.       val >>= 6;
  617.       break;
  618.  
  619.     case '3':
  620.     case 'j':
  621.       val = (buffer[2] << 8) + buffer[3];
  622.       break;
  623.  
  624.     case '4':
  625.       val = (buffer[4] << 8) + buffer[5];
  626.       val >>= 12;
  627.       break;
  628.  
  629.     case '5':
  630.       val = (buffer[4] << 8) + buffer[5];
  631.       val >>= 6;
  632.       break;
  633.  
  634.     case '6':
  635.       val = (buffer[4] << 8) + buffer[5];
  636.       break;
  637.  
  638.     case '7':
  639.       val = (buffer[2] << 8) + buffer[3];
  640.       val >>= 7;
  641.       break;
  642.       
  643.     case '8':
  644.       val = (buffer[2] << 8) + buffer[3];
  645.       val >>= 10;
  646.       break;
  647.  
  648.     default:
  649.       abort ();
  650.     }
  651.  
  652.   switch (bits)
  653.     {
  654.     case 3:
  655.       return val & 7;
  656.     case 4:
  657.       return val & 017;
  658.     case 5:
  659.       return val & 037;
  660.     case 6:
  661.       return val & 077;
  662.     case 7:
  663.       return val & 0177;
  664.     case 8:
  665.       return val & 0377;
  666.     case 12:
  667.       return val & 07777;
  668.     default:
  669.       abort ();
  670.     }
  671. }
  672.  
  673. /* Print an indexed argument.  The base register is BASEREG (-1 for pc).
  674.    P points to extension word, in buffer.
  675.    ADDR is the nominal core address of that extension word.  */
  676.  
  677. static unsigned char *
  678. print_indexed (basereg, p, addr, stream)
  679.      int basereg;
  680.      unsigned char *p;
  681.      FILE *stream;
  682.      CORE_ADDR addr;
  683. {
  684.   register int word;
  685.   static char *scales[] = {"", "*2", "*4", "*8"};
  686.   register int base_disp;
  687.   register int outer_disp;
  688.   char buf[40];
  689.  
  690.   word = NEXTWORD (p);
  691.  
  692.   /* Generate the text for the index register.
  693.      Where this will be output is not yet determined.  */
  694.   sprintf (buf, "[%s.%c%s]",
  695.        reg_names[(word >> 12) & 0xf],
  696.        (word & 0x800) ? 'l' : 'w',
  697.        scales[(word >> 9) & 3]);
  698.  
  699.   /* Handle the 68000 style of indexing.  */
  700.  
  701.   if ((word & 0x100) == 0)
  702.     {
  703.       print_base (basereg,
  704.           ((word & 0x80) ? word | 0xff00 : word & 0xff)
  705.           + ((basereg == -1) ? addr : 0),
  706.           stream);
  707.       fputs_filtered (buf, stream);
  708.       return p;
  709.     }
  710.  
  711.   /* Handle the generalized kind.  */
  712.   /* First, compute the displacement to add to the base register.  */
  713.  
  714.   if (word & 0200)
  715.     basereg = -2;
  716.   if (word & 0100)
  717.     buf[0] = 0;
  718.   base_disp = 0;
  719.   switch ((word >> 4) & 3)
  720.     {
  721.     case 2:
  722.       base_disp = NEXTWORD (p);
  723.       break;
  724.     case 3:
  725.       base_disp = NEXTLONG (p);
  726.     }
  727.   if (basereg == -1)
  728.     base_disp += addr;
  729.  
  730.   /* Handle single-level case (not indirect) */
  731.  
  732.   if ((word & 7) == 0)
  733.     {
  734.       print_base (basereg, base_disp, stream);
  735.       fputs_filtered (buf, stream);
  736.       return p;
  737.     }
  738.  
  739.   /* Two level.  Compute displacement to add after indirection.  */
  740.  
  741.   outer_disp = 0;
  742.   switch (word & 3)
  743.     {
  744.     case 2:
  745.       outer_disp = NEXTWORD (p);
  746.       break;
  747.     case 3:
  748.       outer_disp = NEXTLONG (p);
  749.     }
  750.  
  751.   fprintf_filtered (stream, "%d(", outer_disp);
  752.   print_base (basereg, base_disp, stream);
  753.  
  754.   /* If postindexed, print the closeparen before the index.  */
  755.   if (word & 4)
  756.     fprintf_filtered (stream, ")%s", buf);
  757.   /* If preindexed, print the closeparen after the index.  */
  758.   else
  759.     fprintf_filtered (stream, "%s)", buf);
  760.  
  761.   return p;
  762. }
  763.  
  764. /* Print a base register REGNO and displacement DISP, on STREAM.
  765.    REGNO = -1 for pc, -2 for none (suppressed).  */
  766.  
  767. static void
  768. print_base (regno, disp, stream)
  769.      int regno;
  770.      int disp;
  771.      FILE *stream;
  772. {
  773.   if (regno == -2)
  774.     fprintf_filtered (stream, "%d", disp);
  775.   else if (regno == -1)
  776.     fprintf_filtered (stream, "0x%x", disp);
  777.   else
  778.     fprintf_filtered (stream, "%d(%s)", disp, reg_names[regno]);
  779. }
  780.  
  781. /* Nonzero if the host system has a 68881 (or compatible)
  782.    floating-point unit.  This does *not* indicate whether the target
  783.    system has a co-processor, just whether the host system does.
  784.    There might be a difference in the case of remote debugging.  */
  785. static int have_fpu = 1;
  786.  
  787. /* This is not part of insn printing, but it is machine-specific,
  788.    so this is a convenient place to put it.
  789.  
  790.    Convert a 68881 extended float to a double.
  791.    FROM is the address of the extended float.
  792.    Store the double in *TO.  */
  793.  
  794. convert_from_68881 (from, to)
  795.      char *from;
  796.      double *to;
  797. {
  798.   if (!have_fpu)
  799.     {
  800.       *to = 0.0;
  801.       return;
  802.     }
  803.   else
  804.     {
  805. #ifdef HPUX_ASM
  806.       asm ("mov.l 8(%a6),%a0");
  807.       asm ("mov.l 12(%a6),%a1");
  808.       asm ("fmove.x (%a0),%fp0");
  809.       asm ("fmove.d %fp0,(%a1)");
  810. #else /* not HPUX_ASM */
  811. #if defined (atarist) && defined (__GNUC__)
  812.       /* allow -fomit-frame-pointer */
  813.       asm volatile ("fmovex %1@,fp0; fmoved fp0,%0@" : "=a" (to) : "a" (from));
  814. #else
  815. #if 0
  816.       asm ("movl a6@(8),a0");
  817.       asm ("movl a6@(12),a1");
  818.       asm ("fmovex a0@,fp0");
  819.       asm ("fmoved fp0,a1@");
  820. #else
  821.       /* Hand-assemble those insns since some assemblers lose
  822.      and some have different syntax.  */
  823.       asm (".word 020156");
  824.       asm (".word 8");
  825.       asm (".word 021156");
  826.       asm (".word 12");
  827.       asm (".long 0xf2104800");
  828.       asm (".long 0xf2117400");
  829. #endif
  830. #endif /* not atarist */
  831. #endif /* not HPUX_ASM */
  832.     }
  833. }
  834.  
  835. /* The converse: convert the double *FROM to an extended float
  836.    and store where TO points.  */
  837.  
  838. convert_to_68881 (from, to)
  839.      double *from;
  840.      char *to;
  841. {
  842.   if (!have_fpu)
  843.       return;
  844.   else
  845.     {
  846. #ifdef HPUX_ASM
  847.       asm ("mov.l 8(%a6),%a0");
  848.       asm ("mov.l 12(%a6),%a1");
  849.       asm ("fmove.d (%a0),%fp0");
  850.       asm ("fmove.x %fp0,(%a1)");
  851. #else /* not HPUX_ASM */
  852. #if defined (atarist) && defined (__GNUC__)
  853.       asm volatile ("fmoved %1@,fp0; fmovex fp0,%0@" : : "a" (to), "a" (from));
  854. #else
  855. #if 0
  856.       asm ("movl a6@(8),a0");
  857.       asm ("movl a6@(12),a1");
  858.       asm ("fmoved a0@,fp0");
  859.       asm ("fmovex fp0,a1@");
  860. #else
  861.       /* Hand-assemble those insns since some assemblers lose.  */
  862.       asm (".word 020156");
  863.       asm (".word 8");
  864.       asm (".word 021156");
  865.       asm (".word 12");
  866.       asm (".long 0xf2105400");
  867.       asm (".long 0xf2116800");
  868. #endif
  869. #endif /* not atarist */
  870. #endif /* not HPUX_ASM */
  871.     }
  872. }
  873.  
  874. static jmp_buf    fpu_check;
  875.  
  876. void
  877. sigemt()
  878. {
  879.     have_fpu = 0;
  880.     longjmp (fpu_check, 1);
  881. }
  882.  
  883. void
  884. _initialize_pinsn()
  885. {
  886. #ifdef atarist
  887.   have_fpu = check_fpu ();
  888. #else
  889.   /* Want to figure out if we've got a coprocessor. The idea is to catch the
  890.      signal that gets delivered if no coprocessor is around (SIGEMT) then
  891.      execute a coprocessor instruction and see what happens. have_fpu is set
  892.      to zero if the EMT signal arrives. Else it is left at 1.  */
  893.   /* If this turns out not to be portable to all 68k machines, we'll
  894.      have to move it to the dep files.  */
  895.   void (*emthandler) ();
  896.  
  897.   emthandler = (void (*) ()) signal (SIGEMT, sigemt);
  898.   if (!setjmp (fpu_check))
  899.     {
  900. #if defined(HPUX_ASM)
  901.       asm (" long       0xf2000600");   /* fmovel fp0, d0 */
  902. #else
  903.       asm(".long    0xf2000600");    /* fmovel fp0, d0 */
  904. #endif
  905.     }
  906.   signal(SIGEMT, emthandler);
  907. #endif /* not atarist */
  908. }
  909.