home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / cctools / as / m88k.c < prev    next >
C/C++ Source or Header  |  1997-01-24  |  34KB  |  1,675 lines

  1. /* m88k.c -- Assemble for the 88100
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.  
  4. This file is not yet part of GAS, the GNU Assembler.
  5.  
  6. GAS 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. GAS 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 GAS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <ctype.h>
  21. #include <string.h>
  22. #include <mach-o/m88k/reloc.h>
  23. #include "m88k-opcode.h"
  24. #include "as.h"
  25. #include "flonum.h"
  26. #include "expr.h"
  27. #include "hash.h"
  28. #include "frags.h"
  29. #include "fixes.h"
  30. #include "read.h"
  31. #include "md.h"
  32. #include "obstack.h"
  33. #include "symbols.h"
  34. #include "messages.h"
  35. #include "input-scrub.h"
  36. #include "sections.h"
  37.  
  38. /*
  39.  * These are the default cputype and cpusubtype for the m88k architecture.
  40.  */
  41. const cpu_type_t md_cputype = CPU_TYPE_MC88000;
  42. cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_MC88000_ALL;
  43.  
  44. /* This is the byte sex for the m88k architecture */
  45. const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX;
  46.  
  47. #ifdef NeXT
  48. static long in_delay_slot = 0;
  49. #endif
  50.  
  51. static char *cmpslot[] = { "**", "**", "eq", "ne", "gt", "le", "lt", "ge",
  52.                "hi", "ls", "lo", "hs",
  53. #ifdef m88110
  54.                "be", "nb", "he", "nh",
  55. #endif m88110
  56.                 NULL };
  57.  
  58. static struct {
  59.     char *name;
  60.     unsigned int num;
  61.  
  62. } cndmsk[] = {
  63.         { "eq0", 0x02},
  64.         { "ne0", 0x0d},
  65.         { "gt0", 0x01},
  66.         { "lt0", 0x0c},
  67.         { "ge0", 0x03},
  68.         { "le0", 0x0e},
  69.         { NULL,  0x00},
  70.           };
  71.  
  72. struct m88k_insn {
  73.         unsigned long opcode;
  74.         expressionS exp;
  75. #ifdef NeXT
  76.         enum reloc_type_m88k reloc;
  77. #else
  78.         enum reloc_type reloc;
  79. #endif
  80. };
  81.  
  82. static struct hash_control *op_hash = NULL;
  83.  
  84. /* These chars start a comment anywhere in a source file (except inside
  85.    another comment */
  86. const char md_comment_chars[] = ";";
  87.  
  88. /* These chars only start a comment at the beginning of a line. */
  89. const char md_line_comment_chars[] = "#";
  90.  
  91. /* Chars that can be used to separate mant from exp in floating point nums */
  92. const char md_EXP_CHARS[] = "eE";
  93.  
  94. /* Chars that mean this number is a floating point constant */
  95. /* as in 0f123.456 */
  96. /* or    0H1.234E-12 (see exp chars above) */
  97. const char md_FLT_CHARS[] = "dDfF";
  98.  
  99. static int calcop(
  100.     struct m88k_opcode *format,
  101.     char *param,
  102.     struct m88k_insn *insn);
  103. static char * parse_reg(
  104.     char *param,
  105.     struct m88k_insn *insn,
  106.     struct m88k_opcode *format,
  107.     int parcnt);
  108. #ifdef m88110
  109. static char *parse_ereg(
  110.     char *param,
  111.     struct m88k_insn *insn,
  112.     struct m88k_opcode *format,
  113.     int parcnt);
  114. static char *parse_e4rot(
  115.     char *param,
  116.     struct m88k_insn *insn,
  117.     struct m88k_opcode *format,
  118.     int parcnt);
  119. static char *parse_xreg(
  120.     char *param,
  121.     struct m88k_insn *insn,
  122.     struct m88k_opcode *format,
  123.     int parcnt);
  124. #endif m88110
  125. static char *parse_pcr(
  126.     char *param,
  127.     struct m88k_insn *insn,
  128.     struct m88k_opcode *format,
  129.     int parcnt);
  130. static char *parse_cmp(
  131.     char *param,
  132.     struct m88k_insn *insn,
  133.     struct m88k_opcode *format,
  134.     int parcnt);
  135. static char *parse_cnd(
  136.     char *param,
  137.     struct m88k_insn *insn,
  138.     struct m88k_opcode *format,
  139.     int parcnt);
  140. static char *parse_bf(
  141.     char *param,
  142.     struct m88k_insn *insn,
  143.     struct m88k_opcode *format,
  144.     int parcnt);
  145. static char *parse_rot(
  146.     char *param,
  147.     struct m88k_insn *insn,
  148.     struct m88k_opcode *format,
  149.     int parcnt);
  150. static char *parse_rsc(
  151.     char *param,
  152.     struct m88k_insn *insn,
  153.     struct m88k_opcode *format,
  154.     int parcnt);
  155. static char *parse_cr(
  156.     char *param,
  157.     struct m88k_insn *insn,
  158.     struct m88k_opcode *format,
  159.     int parcnt);
  160. static char *parse_fcr(
  161.     char *param,
  162.     struct m88k_insn *insn,
  163.     struct m88k_opcode *format,
  164.     int parcnt);
  165. static char *parse_cst(
  166.     char *param,
  167.     struct m88k_insn *insn,
  168.     struct m88k_opcode *format,
  169.     int parcnt);
  170. static char *getval(
  171.     char *param,
  172.     unsigned int *val);
  173. #ifdef NeXT
  174. static void s_reg(
  175.     int reg);
  176. static void s_scaled(
  177.     int value);
  178. static void s_m88k_abs(
  179.     int value);
  180. static void s_no_delay(
  181.     int value);
  182. static void s_dot(
  183.     int value);
  184. #endif /* NeXT */
  185.  
  186. const pseudo_typeS md_pseudo_table[] =
  187. {
  188. #ifdef NeXT
  189.     {"greg", s_reg, 'r' },
  190.     {"xreg", s_reg, 'x' },
  191.     {"scaled", s_scaled, 0},
  192.     {"abs", s_m88k_abs, 0},
  193.     {"no_delay", s_no_delay, 0},
  194.     {"dot", s_dot, 0},
  195. #endif
  196. #ifndef NeXT
  197.       /* At NeXT we don't allow these */
  198.     {"dfloat", float_cons, 'd'},
  199.     {"ffloat", float_cons, 'f'},
  200.     {"global", s_globl, 0},
  201.     {"half", cons, 2 },
  202.     {"ln", s_line, 0},
  203.     {"zero", s_space, 0},
  204.     {"word", cons, 4 },
  205. #endif
  206.     {0}
  207. };
  208.  
  209. #ifdef NeXT
  210. static
  211. void
  212. s_dot(
  213. int value)
  214. {
  215.     char *name, *end_name, delim;
  216.     symbolS *symbolP;
  217.  
  218.     if( * input_line_pointer == '"')
  219.       name = input_line_pointer + 1;
  220.     else
  221.       name = input_line_pointer;
  222.     delim = get_symbol_end();
  223.     end_name = input_line_pointer;
  224.     *end_name = 0;
  225.  
  226.     symbolP = symbol_find_or_make (name);
  227.     symbolP -> sy_type = N_ABS;
  228.     symbolP -> sy_other = 0; /* NO_SECT */
  229.     symbolP -> sy_value = obstack_next_free(&frags) - frag_now->fr_literal;
  230.     symbolP -> sy_frag = &zero_address_frag;
  231.  
  232.     *end_name = delim;
  233.     totally_ignore_line();
  234. }
  235. /*
  236.  * s_reg() is used to implement ".greg symbol,exp" and ".xreg symbol,exp"
  237.  * which set symbol to 1 or 0 depending on if the expression is a general
  238.  * register or extended register respectfully.  These are intended for use in
  239.  * macros.
  240.  */
  241. static
  242. void
  243. s_reg(
  244. int reg)
  245. {
  246.     char *name, *end_name, delim;
  247.     symbolS *symbolP;
  248.     unsigned long n_value, val;
  249.  
  250.     if( * input_line_pointer == '"')
  251.       name = input_line_pointer + 1;
  252.     else
  253.       name = input_line_pointer;
  254.     delim = get_symbol_end();
  255.     end_name = input_line_pointer;
  256.     *end_name = delim;
  257.     SKIP_WHITESPACE();
  258.     if ( * input_line_pointer != ',' ) {
  259.         *end_name = 0;
  260.         as_warn("Expected comma after name \"%s\"", name);
  261.         *end_name = delim;
  262.         ignore_rest_of_line();
  263.         return;
  264.     }
  265.     input_line_pointer ++;
  266.     *end_name = 0;
  267.  
  268.     SKIP_WHITESPACE();
  269.     n_value = 0;
  270.     if (*input_line_pointer == reg || *input_line_pointer == toupper(reg)){
  271.         input_line_pointer++;
  272.         if(isdigit(*input_line_pointer)){
  273.         val = 0;
  274.         while (isdigit(*input_line_pointer)){
  275.             if ((val = val * 10 + *input_line_pointer++ - '0') > 31)
  276.             break;
  277.         }
  278.         SKIP_WHITESPACE();
  279.         if(val <= 31 &&
  280.            (*input_line_pointer == '\n' || *input_line_pointer == '@'))
  281.             n_value = 1;
  282.         }
  283.     }
  284.  
  285.     symbolP = symbol_find_or_make (name);
  286.     symbolP -> sy_type = N_ABS;
  287.     symbolP -> sy_other = 0; /* NO_SECT */
  288.     symbolP -> sy_value = n_value;
  289.     symbolP -> sy_frag = &zero_address_frag;
  290.  
  291.     *end_name = delim;
  292.     totally_ignore_line();
  293. }
  294.  
  295. /*
  296.  * s_scaled() is used to implement ".scaled symbol,exp" which sets symbol to 1
  297.  * or 0 depending on if the expression is a scaled general register expression
  298.  * "r1[r2]" or not respectfully.  This is intended for use in macros.
  299.  */
  300. static
  301. void
  302. s_scaled(
  303. int value)
  304. {
  305.     char *name, *end_name, delim;
  306.     symbolS *symbolP;
  307.     unsigned long n_value, val;
  308.  
  309.     if( * input_line_pointer == '"')
  310.       name = input_line_pointer + 1;
  311.     else
  312.       name = input_line_pointer;
  313.     delim = get_symbol_end();
  314.     end_name = input_line_pointer;
  315.     *end_name = delim;
  316.     SKIP_WHITESPACE();
  317.     if ( * input_line_pointer != ',' ) {
  318.         *end_name = 0;
  319.         as_warn("Expected comma after name \"%s\"", name);
  320.         *end_name = delim;
  321.         ignore_rest_of_line();
  322.         return;
  323.     }
  324.     input_line_pointer ++;
  325.     *end_name = 0;
  326.  
  327.     SKIP_WHITESPACE();
  328.     n_value = 0;
  329.     if (*input_line_pointer == 'r' || *input_line_pointer == 'R'){
  330.         input_line_pointer++;
  331.         if(isdigit(*input_line_pointer)){
  332.         val = 0;
  333.         while (isdigit(*input_line_pointer)){
  334.             if ((val = val * 10 + *input_line_pointer++ - '0') > 31)
  335.             break;
  336.         }
  337.         SKIP_WHITESPACE();
  338.         if(val <= 31 && *input_line_pointer == '['){
  339.             input_line_pointer++;
  340.             if (*input_line_pointer == 'r' ||
  341.             *input_line_pointer == 'R'){
  342.             input_line_pointer++;
  343.             if(isdigit(*input_line_pointer)){
  344.                 val = 0;
  345.                 while (isdigit(*input_line_pointer)){
  346.                 if ((val = val * 10 +
  347.                        *input_line_pointer++ - '0') > 31)
  348.                     break;
  349.                 }
  350.                 if(val <= 31 && *input_line_pointer == ']'){
  351.                 input_line_pointer++;
  352.                 SKIP_WHITESPACE();
  353.                 if(*input_line_pointer == '\n' ||
  354.                    *input_line_pointer == '@')
  355.                         n_value = 1;
  356.                 }
  357.             }
  358.             }
  359.         }
  360.         }
  361.     }
  362.  
  363.     symbolP = symbol_find_or_make (name);
  364.     symbolP -> sy_type = N_ABS;
  365.     symbolP -> sy_other = 0; /* NO_SECT */
  366.     symbolP -> sy_value = n_value;
  367.     symbolP -> sy_frag = & zero_address_frag;
  368.  
  369.     *end_name = delim;
  370.     totally_ignore_line();
  371. }
  372.  
  373. /*
  374.  * s_m88k_abs() is used to implement ".abs symbol,exp" which sets symbol to 1
  375.  * or 0 depending on if the expression is an absolute expression or not
  376.  * respectfully.  This is intended for use in macros.
  377.  */
  378. static
  379. void
  380. s_m88k_abs(
  381. int value)
  382. {
  383.     char *name, *end_name, delim, *start;
  384.     symbolS *symbolP;
  385.     unsigned long n_value, val, is_reg_exp;
  386.  
  387.     start = input_line_pointer;
  388.     if( * input_line_pointer == '"')
  389.       name = input_line_pointer + 1;
  390.     else
  391.       name = input_line_pointer;
  392.     delim = get_symbol_end();
  393.     end_name = input_line_pointer;
  394.     *end_name = delim;
  395.     SKIP_WHITESPACE();
  396.     if ( * input_line_pointer != ',' ) {
  397.         *end_name = 0;
  398.         as_warn("Expected comma after name \"%s\"", name);
  399.         *end_name = delim;
  400.         ignore_rest_of_line();
  401.         return;
  402.     }
  403.     input_line_pointer ++;
  404.     *end_name = 0;
  405.  
  406.     SKIP_WHITESPACE();
  407.     is_reg_exp = 0;
  408.     n_value = 0;
  409.     if(*input_line_pointer == 'r' || *input_line_pointer == 'R'){
  410.         input_line_pointer++;
  411.         if(isdigit(*input_line_pointer)){
  412.         val = 0;
  413.         while (isdigit(*input_line_pointer)){
  414.             if ((val = val * 10 + *input_line_pointer++ - '0') > 31)
  415.             break;
  416.         }
  417.         SKIP_WHITESPACE();
  418.         if(val <= 31)
  419.             is_reg_exp = 1;
  420.         }
  421.     }
  422.     if(is_reg_exp == 0){
  423.         *end_name = delim;
  424.         input_line_pointer = start;
  425.         s_abs(value);
  426.         return;
  427.     }
  428.  
  429.     symbolP = symbol_find_or_make (name);
  430.     symbolP -> sy_type = N_ABS;
  431.     symbolP -> sy_other = 0; /* NO_SECT */
  432.     symbolP -> sy_value = n_value;
  433.     symbolP -> sy_frag = & zero_address_frag;
  434.     *end_name = delim;
  435.  
  436.     totally_ignore_line();
  437. }
  438.  
  439. /*
  440.  * s_no_delay() is used to implement ".no_delay string" which will abort and
  441.  * print the string if the last instruction assembled has a delay slot.
  442.  * This is intended for use in macros that expand to more than one instruction
  443.  * that could be put in delay slots.  This is not really correct in it's
  444.  * operation in that it is not per-section and does not take into account
  445.  * anything other than assembled instructions.
  446.  */
  447. static
  448. void
  449. s_no_delay(
  450. int value)
  451. {
  452.     char *p, c;
  453.  
  454.     p = input_line_pointer;
  455.     while(*p != '\n' && *p != '@' && *p != '\0')
  456.         p++;
  457.     c = *p;
  458.     *p = '\0';
  459.     
  460.     if(in_delay_slot)
  461.         as_fatal("delay slot abort %s detected.  Assembly stopping.",
  462.              input_line_pointer);
  463.     input_line_pointer = p;
  464.     *p = c;
  465. }
  466. #endif /* NeXT */
  467.  
  468. void
  469. md_begin(
  470. void)
  471. {
  472.     register char *retval = NULL;
  473.     register unsigned int i = 0;
  474.  
  475.     /* initialize hash table */
  476.  
  477.     op_hash = hash_new();
  478.     if (op_hash == NULL)
  479.         as_fatal("Could not initialize hash table");
  480.  
  481.     /* loop until you see the end of the list */
  482.  
  483.     while (*m88k_opcodes[i].name) {
  484.         char *name = m88k_opcodes[i].name;
  485.  
  486.         /* hash each mnemonic and record its position */
  487.  
  488.         retval = hash_insert(op_hash, name, (char *)&m88k_opcodes[i]);
  489.  
  490.         if (retval != NULL && *retval != '\0')
  491.             as_fatal("Can't hash instruction '%s':%s",
  492.                     m88k_opcodes[i].name, retval);
  493.  
  494.         /* skip to next unique mnemonic or end of list */
  495.  
  496.         for (i++; !strcmp(m88k_opcodes[i].name, name); i++);
  497.     }
  498. }
  499.  
  500. int
  501. md_parse_option(
  502. char **argP,
  503. int *cntP,
  504. char ***vecP)
  505. {
  506.     return (1);
  507. }
  508.  
  509. void
  510. md_assemble(
  511. char *op)
  512. {
  513.     char *param, *thisfrag;
  514.     struct m88k_opcode *format;
  515.     struct m88k_insn insn;
  516. #ifdef NeXT
  517.     long pcrel_reloc;
  518. #endif
  519.  
  520.     assert(op);
  521.  
  522.     /* skip over instruction to find parameters */
  523.  
  524.     /* *param != '\0' is need for instructions that have no parameters
  525.        like rte */
  526.     for (param = op; !isspace(*param) && *param != '\0' ; param++);
  527.     *param++ = '\0';
  528.  
  529.     /* try to find the instruction in the hash table */
  530.  
  531.     if ((format = (struct m88k_opcode *) hash_find(op_hash, op)) == NULL) {
  532.         as_warn("Invalid mnemonic '%s'", op);
  533.         return;
  534.     }
  535.  
  536.     /* try parsing this instruction into insn */
  537.  
  538.     while (!calcop(format,param,&insn))
  539.  
  540.         /* if it doesn't parse try the next instruction */
  541.  
  542.         if (!strcmp(format->name, format[1].name))
  543.             format++;
  544.         else {
  545.             as_warn("Parameter syntax error");
  546.             return;
  547.         }
  548.  
  549.     /* grow the current frag and plop in the opcode */
  550.  
  551.     thisfrag = frag_more(4);
  552.     md_number_to_chars(thisfrag, insn.opcode, 4);
  553. #ifdef NeXT
  554.     in_delay_slot = format->delay_slot;
  555. #endif
  556. #ifdef NeXT    /* generate stabs for debugging assembly code */
  557.     /*
  558.      * If the -g flag is present generate a line number stab for the
  559.      * instruction.
  560.      * 
  561.      * See the detailed comments about stabs in read_a_source_file() for a
  562.      * description of what is going on here.
  563.      */
  564.     if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
  565.         (void)symbol_new(
  566.           "",
  567.           68 /* N_SLINE */,
  568.           text_nsect,
  569.           logical_input_line /* n_desc, line number */,
  570.           obstack_next_free(&frags) - frag_now->fr_literal,
  571.           frag_now);
  572.     }
  573. #endif /* NeXT */
  574.  
  575. #ifdef NeXT    /* mark sections containing instructions */
  576.     /*
  577.      * We are putting a machine instruction in this section so mark it as
  578.      * containg some machine instructions.
  579.      */
  580.     frchain_now->frch_section.flags |= S_ATTR_SOME_INSTRUCTIONS;
  581. #endif /* NeXT */
  582.  
  583. #ifdef NeXT
  584.     pcrel_reloc = 0;
  585.     if (insn.reloc == M88K_RELOC_PC16 || insn.reloc == M88K_RELOC_PC26){
  586.         /*
  587.          * The NeXT linker has the ability to scatter blocks of
  588.          * sections between labels.  This requires that brances to
  589.          * labels that survive to the link phase must be able to
  590.          * be relocated.
  591.          */
  592.         if(insn.exp.X_add_symbol != NULL &&
  593.            (insn.exp.X_add_symbol->sy_name[0] != 'L' || flagseen ['L']))
  594.         pcrel_reloc = 1;
  595.         else
  596.         pcrel_reloc = 0;
  597.     }
  598. #endif /* NeXT */
  599.  
  600.     /* if this instruction requires labels mark it for later */
  601.     switch (insn.reloc) {
  602.  
  603.         case NO_RELOC:
  604.                 break;
  605.  
  606.         case M88K_RELOC_LO16:
  607.         case M88K_RELOC_HI16:
  608.                 fix_new(
  609.                     frag_now,
  610. #ifdef NeXT
  611.                     thisfrag - frag_now->fr_literal,
  612.                     4,
  613. #else
  614.                     thisfrag - frag_now->fr_literal + 2,
  615.                     2,
  616. #endif
  617.                     insn.exp.X_add_symbol,
  618.                     insn.exp.X_subtract_symbol,
  619.                     insn.exp.X_add_number,
  620.                     0, 0,
  621.                     insn.reloc
  622.                 );
  623.                 break;
  624.  
  625. #ifndef NeXT
  626.         case M88K_RELOC_IW16:
  627.                 fix_new(
  628.                     frag_now,
  629.                     thisfrag - frag_now->fr_literal,
  630.                     4,
  631.                     insn.exp.X_add_symbol,
  632.                     insn.exp.X_subtract_symbol,
  633.                     insn.exp.X_add_number,
  634.                     0, 0,
  635.                     insn.reloc
  636.                 );
  637.                 break;
  638. #endif /* !defined(NeXT) */
  639.  
  640.         case M88K_RELOC_PC16:
  641.                 fix_new(
  642.                     frag_now,
  643. #ifdef NeXT
  644.                     thisfrag - frag_now->fr_literal,
  645.                     4,
  646. #else
  647.                     thisfrag - frag_now->fr_literal + 2,
  648.                     2,
  649. #endif
  650.                     insn.exp.X_add_symbol,
  651.                     insn.exp.X_subtract_symbol,
  652.                     insn.exp.X_add_number,
  653.                     1, pcrel_reloc,
  654.                     insn.reloc
  655.                 );
  656.                 break;
  657.  
  658.         case M88K_RELOC_PC26:
  659.                 fix_new(
  660.                     frag_now,
  661.                     thisfrag - frag_now->fr_literal,
  662.                     4,
  663.                     insn.exp.X_add_symbol,
  664.                     insn.exp.X_subtract_symbol,
  665.                     insn.exp.X_add_number,
  666.                     1, pcrel_reloc,
  667.                     insn.reloc
  668.                 );
  669.                 break;
  670.  
  671.         default:
  672.                 as_warn("Unknown relocation type");
  673.                 break;
  674.     }
  675. }
  676.  
  677. static
  678. int
  679. calcop(
  680. struct m88k_opcode *format,
  681. char *param,
  682. struct m88k_insn *insn)
  683. {
  684.     int parcnt;
  685.  
  686.     /* initial the passed structure */
  687.  
  688.     memset(insn, '\0', sizeof(*insn));
  689.     insn->reloc = NO_RELOC;
  690.     insn->opcode = format->opcode;
  691.  
  692.     /* parse all parameters */
  693.  
  694.     for (parcnt=0; parcnt<3 && format->op[parcnt].type != NIL; parcnt++) {
  695.  
  696.         switch (format->op[parcnt].type) {
  697.  
  698.             case CNST:
  699.                 param = parse_cst(param, insn, format, parcnt);
  700.                 break;
  701.  
  702.             case REG:
  703.                 param = parse_reg(param, insn, format, parcnt);
  704.                 break;
  705. #ifdef m88110
  706.             case EREG:
  707.                 param = parse_ereg(param, insn, format, parcnt);
  708.                 break;
  709.  
  710.             case E4ROT:
  711.                 param = parse_e4rot(param, insn, format,parcnt);
  712.                 break;
  713.  
  714.             case XREG:
  715.                 param = parse_xreg(param, insn, format, parcnt);
  716.                 break;
  717. #endif m88110
  718.             case BF:
  719.                 param = parse_bf(param, insn, format, parcnt);
  720.                 break;
  721.  
  722.             case ROT:
  723.                 param = parse_rot(param, insn, format, parcnt);
  724.                 break;
  725.  
  726.             case REGSC:
  727.                 param = parse_rsc(param, insn, format, parcnt);
  728.                 break;
  729.  
  730.             case CRREG:
  731.                 param = parse_cr(param, insn, format, parcnt);
  732.                 break;
  733.  
  734.             case FCRREG:
  735.                 param = parse_fcr(param, insn, format, parcnt);
  736.                 break;
  737.  
  738.             case PCREL:
  739.                 param = parse_pcr(param, insn, format, parcnt);
  740.                 break;
  741.  
  742.             case CONDMASK:
  743.                 param = parse_cnd(param, insn, format, parcnt);
  744.                 break;
  745.  
  746.             case CMPRSLT:
  747.                 param = parse_cmp(param, insn, format, parcnt);
  748.                 break;
  749.  
  750.             default:
  751.                 as_fatal("Unknown parameter type");
  752.         }
  753.  
  754.         /* see if parser failed or not */
  755.  
  756.         if (param == NULL)
  757.             return 0;
  758.     }
  759.  
  760.     return 1;
  761. }
  762.  
  763. static
  764. char *
  765. parse_pcr(
  766. char *param,
  767. struct m88k_insn *insn,
  768. struct m88k_opcode *format,
  769. int parcnt)
  770. {
  771.     char *saveptr, *saveparam;
  772.     segT seg;
  773.  
  774.     saveptr = input_line_pointer;
  775.     input_line_pointer = param;
  776.  
  777.     seg = expression(&insn->exp);
  778.  
  779.     saveparam = input_line_pointer;
  780.     input_line_pointer = saveptr;
  781.  
  782.     switch (format->op[parcnt].width) {
  783.  
  784.         case 16: insn->reloc = M88K_RELOC_PC16;
  785.              break;
  786.  
  787.         case 26: insn->reloc = M88K_RELOC_PC26;
  788.              break;
  789.  
  790.         default: as_warn("Strange PC relative width %d",
  791.                         format->op[parcnt].width);
  792.              break;
  793.     }
  794.  
  795.     return saveparam;
  796. }
  797.  
  798. static
  799. char *
  800. parse_reg(
  801. char *param,
  802. struct m88k_insn *insn,
  803. struct m88k_opcode *format,
  804. int parcnt)
  805. {
  806.     unsigned int val = 0;
  807.  
  808.     if (*param != 'r' && *param != 'R')
  809.         return NULL;
  810.  
  811.     param++;
  812.  
  813.     if (!isdigit(*param))
  814.         return NULL;
  815.  
  816.     while (isdigit(*param))
  817.         if ((val = val * 10 + *param++ - '0') > 31)
  818.             return NULL;
  819.  
  820.     insn->opcode |= val << format->op[parcnt].offset;
  821.  
  822.     switch (*param) {
  823.  
  824.         case '\0' :
  825.             if (parcnt == 2 || format->op[parcnt+1].type == NIL)
  826.                 return param;
  827.             else
  828.                 return NULL;
  829.  
  830.         case '['  :
  831.             if (parcnt != 2 && format->op[parcnt+1].type == REGSC)
  832.                 return param+1;
  833.             else
  834.                 return NULL;
  835.  
  836.         case ','  :
  837.             if (parcnt != 2 && format->op[parcnt+1].type != NIL)
  838.                 return param+1;
  839.             else
  840.                 return NULL;
  841.     }
  842.  
  843.     return NULL;
  844. }
  845.  
  846. #ifdef m88110
  847. static
  848. char *
  849. parse_ereg(
  850. char *param,
  851. struct m88k_insn *insn,
  852. struct m88k_opcode *format,
  853. int parcnt)
  854. {
  855.     unsigned int val = 0;
  856.  
  857.     if (*param != 'r' && *param != 'R')
  858.         return NULL;
  859.  
  860.     param++;
  861.  
  862.     if (!isdigit(*param))
  863.         return NULL;
  864.  
  865.     while (isdigit(*param))
  866.         if ((val = val * 10 + *param++ - '0') > 31)
  867.             return NULL;
  868.  
  869.     if((val & 0x1) != 0)
  870.         return NULL;
  871.  
  872.     insn->opcode |= val << format->op[parcnt].offset;
  873.  
  874.     switch (*param) {
  875.  
  876.         case '\0' :
  877.             if (parcnt == 2 || format->op[parcnt+1].type == NIL)
  878.                 return param;
  879.             else
  880.                 return NULL;
  881.  
  882.         case '['  :
  883.             if (parcnt != 2 && format->op[parcnt+1].type == REGSC)
  884.                 return param+1;
  885.             else
  886.                 return NULL;
  887.  
  888.         case ','  :
  889.             if (parcnt != 2 && format->op[parcnt+1].type != NIL)
  890.                 return param+1;
  891.             else
  892.                 return NULL;
  893.     }
  894.  
  895.     return NULL;
  896. }
  897.  
  898. static
  899. char *
  900. parse_e4rot(
  901. char *param,
  902. struct m88k_insn *insn,
  903. struct m88k_opcode *format,
  904. int parcnt)
  905. {
  906.     int val;
  907.     char *saveptr, save_c, *offset_ptr;
  908.         expressionS exp;
  909.     segT seg;
  910.  
  911.     /* Now step over the '<' and look for the offset expression before a
  912.        '>' and the end of line (which is a '\0' when we get here).  We
  913.        know there is a '\0' where the end of line was because that is
  914.        what parse_a_buffer() in read.c does before calling md_assemble */
  915.     if (*param++ != '<')
  916.         return NULL;
  917.     offset_ptr = param;
  918.     while(*param != '\0')
  919.         param++;
  920.     if(param == offset_ptr || param[-1] != '>')
  921.         return NULL;
  922.     param--;
  923.     save_c = *param;
  924.     *param = '\0';
  925.     saveptr = input_line_pointer;
  926.     input_line_pointer = offset_ptr;
  927.     seg = expression(&exp);
  928.     *param = save_c;
  929.     input_line_pointer = saveptr;
  930.     val = exp.X_add_number;
  931.     if(seg != SEG_ABSOLUTE || val > 60 || (val & 0x3) != 0)
  932.         return NULL;
  933.  
  934.     val >>= 2;
  935.     insn->opcode |= val << format->op[parcnt].offset;
  936.  
  937.     return param+1;
  938. }
  939.  
  940. static
  941. char *
  942. parse_xreg(
  943. char *param,
  944. struct m88k_insn *insn,
  945. struct m88k_opcode *format,
  946. int parcnt)
  947. {
  948.     unsigned int val = 0;
  949.  
  950.     if (*param != 'x' && *param != 'X')
  951.         return NULL;
  952.  
  953.     param++;
  954.  
  955.     if (!isdigit(*param))
  956.         return NULL;
  957.  
  958.     while (isdigit(*param))
  959.         if ((val = val * 10 + *param++ - '0') > 31)
  960.             return NULL;
  961.  
  962.     insn->opcode |= val << format->op[parcnt].offset;
  963.  
  964.     switch (*param) {
  965.  
  966.         case '\0' :
  967.             if (parcnt == 2 || format->op[parcnt+1].type == NIL)
  968.                 return param;
  969.             else
  970.                 return NULL;
  971.  
  972.         case '['  :
  973.             if (parcnt != 2 && format->op[parcnt+1].type == REGSC)
  974.                 return param+1;
  975.             else
  976.                 return NULL;
  977.  
  978.         case ','  :
  979.             if (parcnt != 2 && format->op[parcnt+1].type != NIL)
  980.                 return param+1;
  981.             else
  982.                 return NULL;
  983.     }
  984.  
  985.     return NULL;
  986. }
  987. #endif m88110
  988.  
  989. static
  990. char *
  991. parse_cmp(
  992. char *param,
  993. struct m88k_insn *insn,
  994. struct m88k_opcode *format,
  995. int parcnt)
  996. {
  997.     int val;
  998.     char *saveptr, save_c, *offset_ptr, c;
  999.         expressionS exp;
  1000.     segT seg;
  1001.  
  1002.     /* look for the offset expression before a ',' */
  1003.     c = *param;
  1004.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1005.         c == '~'){
  1006.         offset_ptr = param;
  1007.         while(*param != ',')
  1008.             param++;
  1009.         if(param == offset_ptr || *param != ',')
  1010.             return NULL;
  1011.         save_c = *param;
  1012.         *param = '\0';
  1013.         saveptr = input_line_pointer;
  1014.         input_line_pointer = offset_ptr;
  1015.         seg = expression(&exp);
  1016.         *param = save_c;
  1017.         input_line_pointer = saveptr;
  1018.         val = exp.X_add_number;
  1019.         if(seg != SEG_ABSOLUTE ||
  1020.            val > (1 << format->op[parcnt].width) || val < 0)
  1021.             return NULL;
  1022.     } else {
  1023.         if (isupper(*param))
  1024.             *param = tolower(*param);
  1025.  
  1026.         if (isupper(*(param+1)))
  1027.             *(param+1) = tolower(*(param+1));
  1028.  
  1029.         for (val=0; cmpslot[val] != NULL; val++)
  1030.             if (!strncmp(param,cmpslot[val],2))
  1031.                 break;
  1032.  
  1033.         if (cmpslot[val] == NULL)
  1034.             return NULL;
  1035.  
  1036.         param += 2;
  1037.     }
  1038.  
  1039.     if (*param++ != ',')
  1040.         return NULL;
  1041.  
  1042.     insn->opcode |= val << format->op[parcnt].offset;
  1043.  
  1044.     return param;
  1045. }
  1046.  
  1047. static
  1048. char *
  1049. parse_cnd(
  1050. char *param,
  1051. struct m88k_insn *insn,
  1052. struct m88k_opcode *format,
  1053. int parcnt)
  1054. {
  1055.     int val;
  1056.     char *saveptr, save_c, *offset_ptr, c;
  1057.         expressionS exp;
  1058.     segT seg;
  1059.  
  1060.     /* look for the offset expression before a ',' */
  1061.     c = *param;
  1062.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1063.         c == '~'){
  1064.         offset_ptr = param;
  1065.         while(*param != ',')
  1066.             param++;
  1067.         if(param == offset_ptr || *param != ',')
  1068.             return NULL;
  1069.         save_c = *param;
  1070.         *param = '\0';
  1071.         saveptr = input_line_pointer;
  1072.         input_line_pointer = offset_ptr;
  1073.         seg = expression(&exp);
  1074.         *param = save_c;
  1075.         input_line_pointer = saveptr;
  1076.         val = exp.X_add_number;
  1077.         if(seg != SEG_ABSOLUTE ||
  1078.            val > (1 << format->op[parcnt].width) || val < 0)
  1079.             return NULL;
  1080.     } else {
  1081.         if (isupper(*param))
  1082.             *param = tolower(*param);
  1083.  
  1084.         if (isupper(*(param+1)))
  1085.             *(param+1) = tolower(*(param+1));
  1086.  
  1087.         for (val=0; cndmsk[val].name != NULL; val++)
  1088.             if (!strncmp(param,cndmsk[val].name,3))
  1089.                 break;
  1090.  
  1091.         if (cndmsk[val].name == NULL)
  1092.             return NULL;
  1093.  
  1094.         val = cndmsk[val].num;
  1095.  
  1096.         param += 3;
  1097.     }
  1098.  
  1099.     if (*param++ != ',')
  1100.         return NULL;
  1101.  
  1102.     insn->opcode |= val << format->op[parcnt].offset;
  1103.  
  1104.     return param;
  1105. }
  1106.  
  1107. static
  1108. char *
  1109. parse_bf(
  1110. char *param,
  1111. struct m88k_insn *insn,
  1112. struct m88k_opcode *format,
  1113. int parcnt)
  1114. {
  1115.     int val, width;
  1116.     char *saveptr, save_c, *offset_ptr, c;
  1117.         expressionS exp;
  1118.     segT seg;
  1119.  
  1120.     /* We know there is a '\0' where the end of line was because that is
  1121.        what parse_a_buffer() in read.c does before calling md_assemble */
  1122.  
  1123.     /* First look for the width expression before a '<' */
  1124.     saveptr = input_line_pointer;
  1125.     input_line_pointer = param;
  1126.     while(*param != '<' && *param != '\0')
  1127.         param++;
  1128.     if(*param == '\0'){
  1129.         input_line_pointer = saveptr;
  1130.         return NULL;
  1131.     }
  1132.     save_c = *param;
  1133.     *param = '\0';
  1134.     seg = expression(&exp);
  1135.     *param = save_c;
  1136.     input_line_pointer = saveptr;
  1137.     width = exp.X_add_number;
  1138.     if(seg != SEG_ABSOLUTE || width > 32 || width < 0)
  1139.         return NULL;
  1140.  
  1141.     /* Now step over the '<' and look for the offset expression before a
  1142.        '>' and the end of line (which is a '\0' when we get here) */
  1143.     param++;
  1144.     c = *param;
  1145.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1146.         c == '~'){
  1147.         offset_ptr = param;
  1148.         while(*param != '\0')
  1149.             param++;
  1150.         if(param != offset_ptr && param[-1] != '>')
  1151.             return NULL;
  1152.         param--;
  1153.         save_c = *param;
  1154.         *param = '\0';
  1155.         saveptr = input_line_pointer;
  1156.         input_line_pointer = offset_ptr;
  1157.         seg = expression(&exp);
  1158.         *param = save_c;
  1159.         input_line_pointer = saveptr;
  1160.         val = exp.X_add_number;
  1161.         if(seg != SEG_ABSOLUTE || val > 32 || val < 0)
  1162.             return NULL;
  1163.     }
  1164.     else {
  1165.         if (isupper(*param))
  1166.             *param = tolower(*param);
  1167.  
  1168.         if (isupper(*(param+1)))
  1169.             *(param+1) = tolower(*(param+1));
  1170.  
  1171.         for (val=0; cmpslot[val] != NULL; val++)
  1172.             if (!strncmp(param,cmpslot[val],2))
  1173.                 break;
  1174.  
  1175.         if (cmpslot[val] == NULL)
  1176.             return NULL;
  1177.  
  1178.         param += 2;
  1179.     }
  1180.     if (*param != '>')
  1181.         return NULL;
  1182.     insn->opcode |= width << 5;
  1183.     insn->opcode |= val;
  1184.  
  1185.     return param+1;
  1186. }
  1187.  
  1188. static
  1189. char *
  1190. parse_rot(
  1191. char *param,
  1192. struct m88k_insn *insn,
  1193. struct m88k_opcode *format,
  1194. int parcnt)
  1195. {
  1196.     int val;
  1197.     char *saveptr, save_c, *offset_ptr;
  1198.         expressionS exp;
  1199.     segT seg;
  1200.  
  1201.     /* Now step over the '<' and look for the offset expression before a
  1202.        '>' and the end of line (which is a '\0' when we get here).  We
  1203.        know there is a '\0' where the end of line was because that is
  1204.        what parse_a_buffer() in read.c does before calling md_assemble */
  1205.     if (*param++ != '<')
  1206.         return NULL;
  1207.     offset_ptr = param;
  1208.     while(*param != '\0')
  1209.         param++;
  1210.     if(param != offset_ptr && param[-1] != '>')
  1211.         return NULL;
  1212.     param--;
  1213.     save_c = *param;
  1214.     *param = '\0';
  1215.     saveptr = input_line_pointer;
  1216.     input_line_pointer = offset_ptr;
  1217.     seg = expression(&exp);
  1218.     *param = save_c;
  1219.     input_line_pointer = saveptr;
  1220.     val = exp.X_add_number;
  1221.     if(seg != SEG_ABSOLUTE && (val > 32 || val < 0))
  1222.         return NULL;
  1223.  
  1224.     insn->opcode |= val;
  1225.  
  1226.     return param+1;
  1227. }
  1228.  
  1229. static
  1230. char *
  1231. parse_rsc(
  1232. char *param,
  1233. struct m88k_insn *insn,
  1234. struct m88k_opcode *format,
  1235. int parcnt)
  1236. {
  1237.     unsigned int val = 0;
  1238.  
  1239.     if (*param != 'r' && *param != 'R')
  1240.         return NULL;
  1241.  
  1242.     param++;
  1243.  
  1244.     if (!isdigit(*param))
  1245.         return NULL;
  1246.  
  1247.     while (isdigit(*param))
  1248.         if ((val = val * 10 + *param++ - '0') > 31)
  1249.             return NULL;
  1250.  
  1251.     insn->opcode |= val << format->op[parcnt].offset;
  1252.  
  1253.     if (*param != ']' || *(param+1) != '\0')
  1254.         return NULL;
  1255.  
  1256.     return param+1;
  1257. }
  1258.  
  1259. static
  1260. char *
  1261. parse_cr(
  1262. char *param,
  1263. struct m88k_insn *insn,
  1264. struct m88k_opcode *format,
  1265. int parcnt)
  1266. {
  1267.     unsigned int val = 0;
  1268.  
  1269.     if (strncmp(param, "cr", 2))
  1270.         return NULL;
  1271.  
  1272.     param += 2;
  1273.  
  1274.     if (!isdigit(*param))
  1275.         return NULL;
  1276.  
  1277.     while (isdigit(*param))
  1278.         if ((val = val * 10 + *param++ - '0') > 63)
  1279.             return NULL;
  1280.  
  1281.     /*
  1282.      * the following fix is not as generic as I'd like, but the
  1283.      * hardware is real picky about this.    - bowen@cs.buffalo.edu
  1284.      * This fix is to make sure the S1 and S2 fields are the same.
  1285.      */
  1286.     insn->opcode |= (insn->opcode & 0x001f0000) >> 16;
  1287.  
  1288.     insn->opcode |= val << format->op[parcnt].offset;
  1289.  
  1290.     if (*param != '\0')
  1291.         return NULL;
  1292.  
  1293.     return param;
  1294. }
  1295.  
  1296. static
  1297. char *
  1298. parse_fcr(
  1299. char *param,
  1300. struct m88k_insn *insn,
  1301. struct m88k_opcode *format,
  1302. int parcnt)
  1303. {
  1304.     unsigned int val = 0;
  1305.  
  1306.     if (strncmp(param, "fcr", 3))
  1307.         return NULL;
  1308.  
  1309.     param += 3;
  1310.  
  1311.     if (!isdigit(*param))
  1312.         return NULL;
  1313.  
  1314.     while (isdigit(*param))
  1315.         if ((val = val * 10 + *param++ - '0') > 63)
  1316.             return NULL;
  1317.  
  1318.     /*
  1319.      * This is to make sure the S1 and S2 fields are the same.
  1320.      */
  1321.     insn->opcode |= (insn->opcode & 0x001f0000) >> 16;
  1322.  
  1323.     insn->opcode |= val << format->op[parcnt].offset;
  1324.  
  1325.     if (*param != '\0')
  1326.         return NULL;
  1327.  
  1328.     return param;
  1329. }
  1330.  
  1331. static
  1332. char *
  1333. parse_cst(
  1334. char *param,
  1335. struct m88k_insn *insn,
  1336. struct m88k_opcode *format,
  1337. int parcnt)
  1338. {
  1339.     char c, *saveptr, *saveparam;
  1340.     unsigned int val, nohilo = 0;
  1341.     segT seg;
  1342.         expressionS exp;
  1343.  
  1344.     c = *param;
  1345.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1346.         c == '~'){
  1347.         saveptr = input_line_pointer;
  1348.         input_line_pointer = param;
  1349.         while(*param != '\0')
  1350.             param++;
  1351.         seg = expression(&exp);
  1352.         input_line_pointer = saveptr;
  1353.         val = exp.X_add_number;
  1354.         if(seg != SEG_ABSOLUTE || val > (1 << format->op[parcnt].width))
  1355.             return NULL;
  1356.     }
  1357.     else if (!strncmp(param,"hi16(",5))
  1358.  
  1359.         if (isdigit(*(param+5))) {
  1360.             param = getval(param+5,&val);
  1361.             val = (val & 0xffff0000) >> 16;
  1362.             if (*param++ != ')')
  1363.                 return NULL;
  1364.  
  1365.         } else
  1366.             insn->reloc = M88K_RELOC_HI16;
  1367.     else if (!strncmp(param,"lo16(",5))
  1368.  
  1369.         if (isdigit(*(param+5))) {
  1370.             param = getval(param+5,&val);
  1371.             val &= 0x0000ffff;
  1372.             if (*param++ != ')')
  1373.                 return NULL;
  1374.  
  1375.         } else
  1376.             insn->reloc = M88K_RELOC_LO16;
  1377.  
  1378. #ifndef NeXT
  1379.     else if (!strncmp(param,"iw16(",5))
  1380.  
  1381.         if (isdigit(*(param+5))) {
  1382.             param = getval(param+5,&val);
  1383.             val &= 0x0000ffff;
  1384.             if (*param++ != ')')
  1385.                 return NULL;
  1386.  
  1387.         } else
  1388.             insn->reloc = M88K_RELOC_IW16;
  1389. #endif /* !defined(NeXT) */
  1390.  
  1391.     else if (*param == 'r' && isdigit(*(param+1)))
  1392.  
  1393.         return NULL;
  1394.  
  1395.     else {
  1396.         insn->reloc = M88K_RELOC_LO16;
  1397.         nohilo = 1;
  1398.     }
  1399.  
  1400.     if (insn->reloc != NO_RELOC) {
  1401.  
  1402.         saveptr = input_line_pointer;
  1403.         input_line_pointer = param + (nohilo ? 0 : 5);
  1404.  
  1405.         seg = expression(&insn->exp);
  1406.  
  1407.         saveparam = input_line_pointer;
  1408.         input_line_pointer = saveptr;
  1409.  
  1410.         if (nohilo) {
  1411.  
  1412.             if (*saveparam != '\0')
  1413.                 return NULL;
  1414.  
  1415.             return saveparam;
  1416.         }
  1417.  
  1418.         if (*saveparam != ')')
  1419.             return NULL;
  1420.  
  1421.         return saveparam+1;
  1422.     }
  1423.  
  1424.     if ((1 << format->op[parcnt].width) <= val)
  1425.         return NULL;
  1426.  
  1427.     insn->opcode |= val << format->op[parcnt].offset;
  1428.  
  1429.     if (*param != '\0')
  1430.         return NULL;
  1431.  
  1432.     return param;
  1433. }
  1434.  
  1435. #define isoct(z) (z >= '0' && z <= '7')
  1436. #define ishex(z) ((z >= '0' && z <= '9') || (z >= 'a' && z <= 'f') || (z >= 'A' && z <= 'F'))
  1437. #define hexval(z) \
  1438.   (isdigit(z) ? (z) - '0' :        \
  1439.    islower(z) ? (z) - 'a' + 10 :    \
  1440.    (z) - 'A' + 10)
  1441.  
  1442. static
  1443. char *
  1444. getval(
  1445. char *param,
  1446. unsigned int *val)
  1447. {
  1448.     *val = 0;
  1449.  
  1450.     if (*param == '0' && (*(param+1) == 'x' || *(param+1) == 'X'))
  1451.  
  1452.         for (param += 2; ishex(*param); param++)
  1453.  
  1454.             if (*val > 0x0fffffff)
  1455.                 return param;
  1456.             else
  1457.                 *val = *val * 16 + hexval(*param);
  1458.  
  1459.     else if (*param == '0')
  1460.  
  1461.         for (param++; isoct(*param); param++)
  1462.  
  1463.             if (*val > 0x1fffffff)
  1464.                 return param;
  1465.             else
  1466.                 *val = *val * 8 + *param - '0';
  1467.  
  1468.     else
  1469.  
  1470.         for (; isdigit(*param); param++)
  1471.  
  1472.             *val = *val * 10 + *param - '0';
  1473.  
  1474.     return param;
  1475. }
  1476.  
  1477. void
  1478. md_number_to_chars(
  1479. char *buf,
  1480. long val,
  1481. int nbytes)
  1482. {
  1483.     switch(nbytes) {
  1484.  
  1485.         case 4:
  1486.             *buf++ = val >> 24;
  1487.             *buf++ = val >> 16;
  1488.         case 2:
  1489.             *buf++ = val >> 8;
  1490.         case 1:
  1491.             *buf = val;
  1492.             break;
  1493.  
  1494.         default:
  1495.             abort();
  1496.     }
  1497. }
  1498.  
  1499. void
  1500. md_number_to_imm(
  1501. unsigned char *buf,
  1502. long val,
  1503. int nbytes,
  1504. fixS *fixP,
  1505. int nsect)
  1506. {
  1507.     if(fixP->fx_r_type == NO_RELOC ||
  1508.        fixP->fx_r_type == M88K_RELOC_VANILLA) {
  1509.         switch (nbytes) {
  1510.             case 4:
  1511.                 *buf++ = val >> 24;
  1512.                 *buf++ = val >> 16;
  1513.             case 2:
  1514.                 *buf++ = val >> 8;
  1515.             case 1:
  1516.                 *buf = val;
  1517.                 break;
  1518.  
  1519.             default:
  1520.                 abort();
  1521.         }
  1522.         return;
  1523.     }
  1524.  
  1525.     switch (fixP->fx_r_type) {
  1526. #ifdef NeXT
  1527.             case M88K_RELOC_LO16:
  1528.                 buf[2] = val >> 8;
  1529.                 buf[3] = val;
  1530.                 break;
  1531.             case M88K_RELOC_HI16:
  1532.                 buf[2] = val >> 24;
  1533.                 buf[3] = val >> 16;
  1534.                 break;
  1535.  
  1536.             case M88K_RELOC_PC16:
  1537.                 val += 4;
  1538.                 buf[2] = val >> 10;
  1539.                 buf[3] = val >> 2;
  1540.                 break;
  1541.  
  1542.             case M88K_RELOC_PC26:
  1543.                 val += 4;
  1544.                 buf[0] |= (val >> 26) & 0x03;
  1545.                 buf[1] = val >> 18;
  1546.                 buf[2] = val >> 10;
  1547.                 buf[3] = val >> 2;
  1548.                 break;
  1549. #else /* !defined NeXT */
  1550.             case M88K_RELOC_LO16:
  1551.                 buf[0] = val >> 8;
  1552.                 buf[1] = val;
  1553.                 break;
  1554.  
  1555.             case M88K_RELOC_IW16:
  1556.                 buf[2] = val >> 8;
  1557.                 buf[3] = val;
  1558.                 break;
  1559.  
  1560.             case M88K_RELOC_HI16:
  1561.                 buf[0] = val >> 24;
  1562.                 buf[1] = val >> 16;
  1563.                 break;
  1564.  
  1565.             case M88K_RELOC_PC16:
  1566.                 val += 4;
  1567.                 buf[0] = val >> 10;
  1568.                 buf[1] = val >> 2;
  1569.                 break;
  1570.  
  1571.             case M88K_RELOC_PC26:
  1572.                 val += 4;
  1573.                 buf[0] |= (val >> 26) & 0x03;
  1574.                 buf[1] = val >> 18;
  1575.                 buf[2] = val >> 10;
  1576.                 buf[3] = val >> 2;
  1577.                 break;
  1578.  
  1579.             case M88K_RELOC_32:
  1580.                 buf[0] = val >> 24;
  1581.                 buf[1] = val >> 16;
  1582.                 buf[2] = val >> 8;
  1583.                 buf[3] = val;
  1584.                 break;
  1585. #endif /* !defined(NeXT) */
  1586.  
  1587.             default:
  1588.                 as_warn("Bad relocation type");
  1589.                 break;
  1590.     }
  1591. }
  1592.  
  1593. #define MAX_LITTLENUMS 6
  1594.  
  1595. /* Turn a string in input_line_pointer into a floating point constant of type
  1596.    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
  1597.    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
  1598.  */
  1599. char *
  1600. md_atof(
  1601. int type,
  1602. char *litP,
  1603. int *sizeP)
  1604. {
  1605.     int    prec;
  1606.     LITTLENUM_TYPE words[MAX_LITTLENUMS];
  1607.     LITTLENUM_TYPE *wordP;
  1608.     char    *t;
  1609.     char    *atof_ieee();
  1610.  
  1611.     switch(type) {
  1612.     case 'f':
  1613.     case 'F':
  1614.     case 's':
  1615.     case 'S':
  1616.         prec = 2;
  1617.         break;
  1618.  
  1619.     case 'd':
  1620.     case 'D':
  1621.     case 'r':
  1622.     case 'R':
  1623.         prec = 4;
  1624.         break;
  1625.  
  1626.     case 'x':
  1627.     case 'X':
  1628.         prec = 6;
  1629.         break;
  1630.  
  1631.     case 'p':
  1632.     case 'P':
  1633.         prec = 6;
  1634.         break;
  1635.  
  1636.     default:
  1637.         *sizeP=0;
  1638.         return "Bad call to MD_ATOF()";
  1639.     }
  1640.     t=atof_ieee(input_line_pointer,type,words);
  1641.     if(t)
  1642.         input_line_pointer=t;
  1643.  
  1644.     *sizeP=prec * sizeof(LITTLENUM_TYPE);
  1645.     for(wordP=words;prec--;) {
  1646.         md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
  1647.         litP+=sizeof(LITTLENUM_TYPE);
  1648.     }
  1649.     return "";    /* Someone should teach Dean about null pointers */
  1650. }
  1651.  
  1652. const relax_typeS md_relax_table[] = { {0} };
  1653.  
  1654. int
  1655. md_estimate_size_before_relax(
  1656. fragS *fragP,
  1657. int segment_type)
  1658. {
  1659.     as_fatal("internal error: Relaxation should never occur");
  1660.     return(0);
  1661. }
  1662.  
  1663. void
  1664. md_convert_frag(
  1665. fragS *fragP)
  1666. {
  1667.     as_fatal("internal error: Relaxation should never occur");
  1668. }
  1669.  
  1670. void
  1671. md_end(
  1672. void)
  1673. {
  1674. }
  1675.