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