Wed Jul 31 11:45:15 1996 Martin M. Hunt <hunt@pizza.cygnus.com>
[deliverable/binutils-gdb.git] / gas / config / tc-d10v.c
CommitLineData
7be9a312
MH
1/* tc-d10v.c -- Assembler code for the Mitsubishi D10V
2
3 Copyright (C) 1996 Free Software Foundation.
4
5 This file is part of GAS, the GNU Assembler.
6
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22#include <stdio.h>
23#include <ctype.h>
24#include "as.h"
25#include "subsegs.h"
26#include "opcode/d10v.h"
27#include "elf/ppc.h"
28
29const char comment_chars[] = "#;";
30const char line_comment_chars[] = "#";
31const char line_separator_chars[] = "";
32const char *md_shortopts = "";
33const char EXP_CHARS[] = "eE";
34const char FLT_CHARS[] = "dD";
35
0ef32559
MH
36
37/* fixups */
38#define MAX_INSN_FIXUPS (5)
39struct d10v_fixup
40{
41 expressionS exp;
42 bfd_reloc_code_real_type reloc;
43};
44
45typedef struct _fixups
46{
47 int fc;
48 struct d10v_fixup fix[MAX_INSN_FIXUPS];
49 struct _fixups *next;
50} Fixups;
51
52static Fixups FixUps[2];
53static Fixups *fixups;
54
7be9a312
MH
55/* local functions */
56static int reg_name_search PARAMS ((char *name));
0ef32559 57static int register_name PARAMS ((expressionS *expressionP));
a40d3589 58static int check_range PARAMS ((unsigned long num, int bits, int flags));
7be9a312
MH
59static int postfix PARAMS ((char *p));
60static bfd_reloc_code_real_type get_reloc PARAMS ((struct d10v_operand *op));
61static int get_operands PARAMS ((expressionS exp[]));
ab48956f 62static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers, unsigned long insn));
0ef32559
MH
63static void write_long PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
64static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
7be9a312 65static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
0ef32559 66 struct d10v_opcode *opcode2, unsigned long insn2, int exec_type, Fixups *fx));
7be9a312 67static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode));
0ef32559
MH
68static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type,
69 offsetT value, int left));
7be9a312 70
7be9a312
MH
71
72struct option md_longopts[] = {
73 {NULL, no_argument, NULL, 0}
74};
75size_t md_longopts_size = sizeof(md_longopts);
76
77/* The target specific pseudo-ops which we support. */
78const pseudo_typeS md_pseudo_table[] =
79{
7be9a312
MH
80 { NULL, NULL, 0 }
81};
82
83/* Opcode hash table. */
84static struct hash_control *d10v_hash;
85
7be9a312
MH
86/* reg_name_search does a binary search of the pre_defined_registers
87 array to see if "name" is a valid regiter name. Returns the register
88 number from the array on success, or -1 on failure. */
89
90static int
91reg_name_search (name)
92 char *name;
93{
94 int middle, low, high;
95 int cmp;
96
97 low = 0;
0ef32559 98 high = reg_name_cnt() - 1;
7be9a312
MH
99
100 do
101 {
102 middle = (low + high) / 2;
103 cmp = strcasecmp (name, pre_defined_registers[middle].name);
104 if (cmp < 0)
105 high = middle - 1;
106 else if (cmp > 0)
107 low = middle + 1;
108 else
109 return pre_defined_registers[middle].value;
110 }
111 while (low <= high);
112 return -1;
113}
114
0ef32559
MH
115/* register_name() checks the string at input_line_pointer
116 to see if it is a valid register name */
7be9a312 117
0ef32559 118static int
7be9a312
MH
119register_name (expressionP)
120 expressionS *expressionP;
121{
122 int reg_number;
0ef32559
MH
123 char c, *p = input_line_pointer;
124
125 while (*p && *p!='\n' && *p!='\r' && *p !=',' && *p!=' ' && *p!=')')
126 p++;
7be9a312 127
0ef32559
MH
128 c = *p;
129 if (c)
130 *p++ = 0;
7be9a312 131
0ef32559
MH
132 /* look to see if it's in the register table */
133 reg_number = reg_name_search (input_line_pointer);
134 if (reg_number >= 0)
135 {
136 expressionP->X_op = O_register;
137 /* temporarily store a pointer to the string here */
138 expressionP->X_op_symbol = (struct symbol *)input_line_pointer;
139 expressionP->X_add_number = reg_number;
140 input_line_pointer = p;
141 return 1;
7be9a312 142 }
0ef32559
MH
143 if (c)
144 *(p-1) = c;
145 return 0;
7be9a312
MH
146}
147
ab48956f
MH
148
149static int
a40d3589 150check_range (num, bits, flags)
ab48956f
MH
151 unsigned long num;
152 int bits;
a40d3589 153 int flags;
ab48956f
MH
154{
155 long min, max;
156 int retval=0;
157
a40d3589
MH
158 if (flags & OPERAND_SHIFT)
159 {
160 /* all special shift operands are unsigned */
161 /* and <= 16. We allow 0 for now. */
162 if (num>16)
163 return 1;
164 else
165 return 0;
166 }
167
168 if (flags & OPERAND_SIGNED)
ab48956f
MH
169 {
170 max = (1 << (bits - 1)) - 1;
171 min = - (1 << (bits - 1));
172 if (((long)num > max) || ((long)num < min))
173 retval = 1;
174 }
175 else
176 {
177 max = (1 << bits) - 1;
178 min = 0;
179 if ((num > max) || (num < min))
180 retval = 1;
181 }
182
183 return retval;
184}
185
186
7be9a312
MH
187void
188md_show_usage (stream)
189 FILE *stream;
190{
191 fprintf(stream, "D10V options:\n\
192none yet\n");
193}
194
195int
196md_parse_option (c, arg)
197 int c;
198 char *arg;
199{
200 return 0;
201}
202
203symbolS *
204md_undefined_symbol (name)
205 char *name;
206{
207 return 0;
208}
209
210char *
211md_atof (type, litp, sizep)
212 int type;
213char *litp;
214int *sizep;
215{
216 return "";
217}
218
219void
220md_convert_frag (abfd, sec, fragP)
221 bfd *abfd;
222 asection *sec;
223 fragS *fragP;
224{
0ef32559 225 printf ("call to md_convert_frag \n");
7be9a312
MH
226 abort ();
227}
228
229valueT
230md_section_align (seg, addr)
231 asection *seg;
232 valueT addr;
233{
234 int align = bfd_get_section_alignment (stdoutput, seg);
235 return ((addr + (1 << align) - 1) & (-1 << align));
236}
237
0ef32559 238
7be9a312
MH
239void
240md_begin ()
241{
242 char *prev_name = "";
243 struct d10v_opcode *opcode;
244 d10v_hash = hash_new();
245
246 /* Insert unique names into hash table. The D10v instruction set
247 has many identical opcode names that have different opcodes based
248 on the operands. This hash table then provides a quick index to
249 the first opcode with a particular name in the opcode table. */
250
251 for (opcode = (struct d10v_opcode *)d10v_opcodes; opcode->name; opcode++)
252 {
253 if (strcmp (prev_name, opcode->name))
254 {
255 prev_name = (char *)opcode->name;
256 hash_insert (d10v_hash, opcode->name, (char *) opcode);
257 }
258 }
0ef32559
MH
259
260 fixups = &FixUps[0];
261 FixUps[0].next = &FixUps[1];
262 FixUps[1].next = &FixUps[0];
7be9a312
MH
263}
264
265
266/* this function removes the postincrement or postdecrement
267 operator ( '+' or '-' ) from an expression */
268
269static int postfix (p)
270 char *p;
271{
272 while (*p != '-' && *p != '+')
273 {
274 if (*p==0 || *p=='\n' || *p=='\r')
275 break;
276 p++;
277 }
278
279 if (*p == '-')
280 {
281 *p = ' ';
282 return (-1);
283 }
284 if (*p == '+')
285 {
286 *p = ' ';
287 return (1);
288 }
289
290 return (0);
291}
292
293
294static bfd_reloc_code_real_type
295get_reloc (op)
296 struct d10v_operand *op;
297{
298 int bits = op->bits;
299
300 /* printf("get_reloc: bits=%d address=%d\n",bits,op->flags & OPERAND_ADDR); */
301 if (bits <= 4)
302 return (0);
303
304 if (op->flags & OPERAND_ADDR)
305 {
0ef32559
MH
306 if (bits == 8)
307 return (BFD_RELOC_D10V_10_PCREL_R);
7be9a312
MH
308 else
309 return (BFD_RELOC_D10V_18_PCREL);
310 }
311
312 return (BFD_RELOC_16);
313}
314
315/* get_operands parses a string of operands and returns
316 an array of expressions */
317
318static int
319get_operands (exp)
320 expressionS exp[];
321{
322 char *p = input_line_pointer;
323 int numops = 0;
324 int post = 0;
325
326 while (*p)
327 {
328 while (*p == ' ' || *p == '\t' || *p == ',')
329 p++;
330 if (*p==0 || *p=='\n' || *p=='\r')
331 break;
332
333 if (*p == '@')
334 {
335 p++;
336 exp[numops].X_op = O_absent;
337 if (*p == '(')
338 {
339 p++;
340 exp[numops].X_add_number = OPERAND_ATPAR;
341 }
342 else if (*p == '-')
343 {
344 p++;
345 exp[numops].X_add_number = OPERAND_ATMINUS;
346 }
347 else
348 {
349 exp[numops].X_add_number = OPERAND_ATSIGN;
350 post = postfix (p);
351 }
352 numops++;
353 continue;
354 }
355
356 if (*p == ')')
357 {
358 /* just skip the trailing paren */
359 p++;
360 continue;
361 }
362
363 input_line_pointer = p;
0ef32559
MH
364
365
7be9a312 366 /* check to see if it might be a register name */
0ef32559
MH
367 if (!register_name (&exp[numops]))
368 {
369 /* parse as an expression */
370 expression (&exp[numops]);
371 }
7be9a312
MH
372
373 if (exp[numops].X_op == O_illegal)
374 as_bad ("illegal operand");
375 else if (exp[numops].X_op == O_absent)
376 as_bad ("missing operand");
377
378 numops++;
379 p = input_line_pointer;
380 }
381
382 switch (post)
383 {
384 case -1: /* postdecrement mode */
385 exp[numops].X_op = O_absent;
386 exp[numops++].X_add_number = OPERAND_MINUS;
387 break;
388 case 1: /* postincrement mode */
389 exp[numops].X_op = O_absent;
390 exp[numops++].X_add_number = OPERAND_PLUS;
391 break;
392 }
393
394 exp[numops].X_op = 0;
395 return (numops);
396}
397
398static unsigned long
0ef32559 399d10v_insert_operand (insn, op_type, value, left)
7be9a312
MH
400 unsigned long insn;
401 int op_type;
402 offsetT value;
0ef32559 403 int left;
7be9a312
MH
404{
405 int shift, bits;
406
407 shift = d10v_operands[op_type].shift;
0ef32559
MH
408 if (left)
409 shift += 15;
410
7be9a312 411 bits = d10v_operands[op_type].bits;
93050391 412
7be9a312 413 /* truncate to the proper number of bits */
a40d3589 414 if (check_range (value, bits, d10v_operands[op_type].flags))
ab48956f
MH
415 as_bad("operand out of range: %d",value);
416
7be9a312
MH
417 value &= 0x7FFFFFFF >> (31 - bits);
418 insn |= (value << shift);
419
420 return insn;
421}
422
423
424/* build_insn takes a pointer to the opcode entry in the opcode table
425 and the array of operand expressions and returns the instruction */
426
427static unsigned long
ab48956f 428build_insn (opcode, opers, insn)
7be9a312
MH
429 struct d10v_opcode *opcode;
430 expressionS *opers;
ab48956f 431 unsigned long insn;
7be9a312 432{
ab48956f 433 int i, bits, shift, flags, format;
7be9a312 434 unsigned int number;
ab48956f
MH
435
436 /* the insn argument is only used for the DIVS kludge */
437 if (insn)
438 format = LONG_R;
439 else
440 {
441 insn = opcode->opcode;
442 format = opcode->format;
443 }
444
7be9a312
MH
445 for (i=0;opcode->operands[i];i++)
446 {
447 flags = d10v_operands[opcode->operands[i]].flags;
448 bits = d10v_operands[opcode->operands[i]].bits;
449 shift = d10v_operands[opcode->operands[i]].shift;
450 number = opers[i].X_add_number;
451
452 if (flags & OPERAND_REG)
453 {
454 number &= REGISTER_MASK;
ab48956f 455 if (format == LONG_L)
7be9a312
MH
456 shift += 15;
457 }
458
459 if (opers[i].X_op != O_register && opers[i].X_op != O_constant)
460 {
461 /* now create a fixup */
462
463 /*
464 printf("need a fixup: ");
465 print_expr_1(stdout,&opers[i]);
466 printf("\n");
467 */
468
0ef32559 469 if (fixups->fc >= MAX_INSN_FIXUPS)
7be9a312 470 as_fatal ("too many fixups");
0ef32559 471 fixups->fix[fixups->fc].exp = opers[i];
7be9a312
MH
472
473 /* put the operand number here for now. We can look up
474 the reloc type and/or fixup the instruction in md_apply_fix() */
0ef32559
MH
475 fixups->fix[fixups->fc].reloc = opcode->operands[i];
476 (fixups->fc)++;
7be9a312
MH
477 }
478
479 /* truncate to the proper number of bits */
a40d3589 480 if ((opers[i].X_op == O_constant) && check_range (number, bits, flags))
ab48956f 481 as_bad("operand out of range: %d",number);
7be9a312
MH
482 number &= 0x7FFFFFFF >> (31 - bits);
483 insn = insn | (number << shift);
484 }
ab48956f
MH
485
486 /* kludge: for DIVS, we need to put the operands in twice */
487 /* on the second pass, format is changed to LONG_R to force */
488 /* the second set of operands to not be shifted over 15 */
489 if ((opcode->opcode == OPCODE_DIVS) && (format==LONG_L))
490 insn = build_insn (opcode, opers, insn);
491
7be9a312
MH
492 return insn;
493}
494
495/* write out a long form instruction */
496static void
0ef32559 497write_long (opcode, insn, fx)
7be9a312
MH
498 struct d10v_opcode *opcode;
499 unsigned long insn;
0ef32559 500 Fixups *fx;
7be9a312
MH
501{
502 int i;
503 char *f = frag_more(4);
504
505 insn |= FM11;
0ef32559 506 /* printf("INSN: %08x\n",insn); */
7be9a312
MH
507 number_to_chars_bigendian (f, insn, 4);
508
0ef32559 509 for (i=0; i < fx->fc; i++)
7be9a312 510 {
0ef32559 511 if (get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].reloc]))
7be9a312
MH
512 {
513 /*
514 printf("fix_new_exp: where:%x size:4\n ",f - frag_now->fr_literal);
0ef32559 515 print_expr_1(stdout,&(fx->fix[i].exp));
7be9a312
MH
516 printf("\n");
517 */
0ef32559 518
7be9a312
MH
519 fix_new_exp (frag_now,
520 f - frag_now->fr_literal,
521 4,
0ef32559 522 &(fx->fix[i].exp),
7be9a312 523 1,
0ef32559 524 fx->fix[i].reloc);
7be9a312
MH
525 }
526 }
0ef32559 527 fx->fc = 0;
7be9a312
MH
528}
529
0ef32559 530
7be9a312
MH
531/* write out a short form instruction by itself */
532static void
0ef32559 533write_1_short (opcode, insn, fx)
7be9a312
MH
534 struct d10v_opcode *opcode;
535 unsigned long insn;
0ef32559 536 Fixups *fx;
7be9a312
MH
537{
538 char *f = frag_more(4);
539 int i;
540
a40d3589
MH
541 if (opcode->exec_type == PARONLY)
542 as_fatal ("Instruction must be executed in parallel with another instruction.");
543
ab48956f
MH
544 /* the other container needs to be NOP */
545 /* according to 4.3.1: for FM=00, sub-instructions performed only
546 by IU cannot be encoded in L-container. */
547 if (opcode->unit == IU)
548 insn |= FM00 | (NOP << 15); /* right container */
549 else
550 insn = FM00 | (insn << 15) | NOP; /* left container */
551
0ef32559 552 /* printf("INSN: %08x\n",insn); */
7be9a312 553 number_to_chars_bigendian (f, insn, 4);
0ef32559 554 for (i=0; i < fx->fc; i++)
7be9a312 555 {
0ef32559 556 if (get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].reloc]))
7be9a312
MH
557 {
558 /*
559 printf("fix_new_exp: where:%x size:4\n ",f - frag_now->fr_literal);
0ef32559 560 print_expr_1(stdout,&(fx->fix[i].exp));
7be9a312
MH
561 printf("\n");
562 */
563
564 fix_new_exp (frag_now,
565 f - frag_now->fr_literal,
566 4,
0ef32559 567 &(fx->fix[i].exp),
7be9a312 568 1,
0ef32559 569 fx->fix[i].reloc);
7be9a312
MH
570 }
571 }
0ef32559 572 fx->fc = 0;
7be9a312
MH
573}
574
575/* write out a short form instruction if possible */
576/* return number of instructions not written out */
577static int
0ef32559 578write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
7be9a312
MH
579 struct d10v_opcode *opcode1, *opcode2;
580 unsigned long insn1, insn2;
581 int exec_type;
0ef32559 582 Fixups *fx;
7be9a312
MH
583{
584 unsigned long insn;
0ef32559
MH
585 char *f;
586 int i,j;
7be9a312 587
a40d3589
MH
588 if ( (exec_type != 1) && ((opcode1->exec_type == PARONLY)
589 || (opcode2->exec_type == PARONLY)))
590 as_fatal("Instruction must be executed in parallel");
591
592 if ( (opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
593 as_fatal ("Long instructions may not be combined.");
594
7be9a312
MH
595 if(opcode1->exec_type == BRANCH_LINK)
596 {
597 /* subroutines must be called from 32-bit boundaries */
598 /* so the return address will be correct */
0ef32559 599 write_1_short (opcode1, insn1, fx->next);
7be9a312
MH
600 return (1);
601 }
602
603 switch (exec_type)
604 {
605 case 0:
606 if (opcode1->unit == IU)
607 {
0ef32559 608 /* reverse sequential */
7be9a312
MH
609 insn = FM10 | (insn2 << 15) | insn1;
610 }
611 else
612 {
0ef32559
MH
613 insn = FM01 | (insn1 << 15) | insn2;
614 fx = fx->next;
7be9a312
MH
615 }
616 break;
617 case 1: /* parallel */
a40d3589
MH
618 if (opcode1->exec_type == SEQ || opcode2->exec_type == SEQ)
619 as_fatal ("One of these instructions may not be executed in parallel.");
620
621 if (opcode1->unit == IU)
622 {
623 if (opcode2->unit == IU)
624 as_fatal ("Two IU instructions may not be executed in parallel");
625 as_warn ("Swapping instruction order");
626 insn = FM00 | (insn2 << 15) | insn1;
627 }
628 else if (opcode2->unit == MU)
629 {
630 if (opcode1->unit == MU)
631 as_fatal ("Two MU instructions may not be executed in parallel");
632 as_warn ("Swapping instruction order");
633 insn = FM00 | (insn2 << 15) | insn1;
634 }
635 else
636 insn = FM00 | (insn1 << 15) | insn2;
637 fx = fx->next;
7be9a312
MH
638 break;
639 case 2: /* sequential */
a40d3589
MH
640 if (opcode1->unit == IU)
641 as_fatal ("IU instruction may not be in the left container");
642 insn = FM01 | (insn1 << 15) | insn2;
643 fx = fx->next;
7be9a312
MH
644 break;
645 case 3: /* reverse sequential */
a40d3589
MH
646 if (opcode2->unit == MU)
647 as_fatal ("MU instruction may not be in the right container");
648 insn = FM10 | (insn1 << 15) | insn2;
7be9a312
MH
649 break;
650 default:
651 as_fatal("unknown execution type passed to write_2_short()");
652 }
653
654 /* printf("INSN: %08x\n",insn); */
0ef32559
MH
655 f = frag_more(4);
656 number_to_chars_bigendian (f, insn, 4);
657
658for (j=0; j<2; j++)
659 {
660 bfd_reloc_code_real_type reloc;
661 for (i=0; i < fx->fc; i++)
662 {
663 reloc = get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].reloc]);
664 if (reloc)
665 {
666 if ( (reloc == BFD_RELOC_D10V_10_PCREL_R) && (j == 0) )
667 fx->fix[i].reloc |= 1024;
668
669 /*
670 printf("fix_new_exp: where:%x reloc:%d\n ",f - frag_now->fr_literal,fx->fix[i].reloc);
671 print_expr_1(stdout,&(fx->fix[i].exp));
672 printf("\n");
673 */
674 fix_new_exp (frag_now,
675 f - frag_now->fr_literal,
676 4,
677 &(fx->fix[i].exp),
678 1,
679 fx->fix[i].reloc);
680 }
681 }
682 fx->fc = 0;
683 fx = fx->next;
684 }
685
7be9a312
MH
686 return (0);
687}
688
689
690/* This is the main entry point for the machine-dependent assembler. str points to a
691 machine-dependent instruction. This function is supposed to emit the frags/bytes
692 it assembles to. For the D10V, it mostly handles the special VLIW parsing and packing
693 and leaves the difficult stuff to do_assemble().
694 */
695
696static unsigned long prev_insn;
697static struct d10v_opcode *prev_opcode = 0;
0ef32559
MH
698static subsegT prev_subseg;
699static segT prev_seg;
7be9a312
MH
700
701void
702md_assemble (str)
703 char *str;
704{
705 struct d10v_opcode *opcode;
706 unsigned long insn;
ef5a4085
MH
707 int extype=0; /* execution type; parallel, etc */
708 static int etype=0; /* saved extype. used for multiline instructions */
7be9a312
MH
709 char *str2;
710
711 /* printf("md_assemble: str=%s\n",str); */
0ef32559 712
ef5a4085 713 if (etype == 0)
7be9a312 714 {
ef5a4085
MH
715 /* look for the special multiple instruction separators */
716 str2 = strstr (str, "||");
7be9a312 717 if (str2)
ef5a4085 718 extype = 1;
7be9a312
MH
719 else
720 {
ef5a4085 721 str2 = strstr (str, "->");
7be9a312 722 if (str2)
ef5a4085
MH
723 extype = 2;
724 else
725 {
726 str2 = strstr (str, "<-");
727 if (str2)
728 extype = 3;
729 }
730 }
731 /* str2 points to the separator, if one */
732 if (str2)
733 {
734 *str2 = 0;
735
736 /* if two instructions are present and we already have one saved
737 then first write it out */
738 if (prev_opcode)
739 write_1_short (prev_opcode, prev_insn, fixups->next);
740
741 /* assemble first instruction and save it */
742 prev_insn = do_assemble (str, &prev_opcode);
743 if (prev_insn == -1)
744 as_fatal ("can't find opcode ");
745 fixups = fixups->next;
746 str = str2 + 2;
7be9a312
MH
747 }
748 }
749
ef5a4085
MH
750 insn = do_assemble (str, &opcode);
751 if (insn == -1)
7be9a312 752 {
ef5a4085
MH
753 if (extype)
754 {
755 etype = extype;
756 return;
757 }
758 as_fatal ("can't find opcode ");
7be9a312
MH
759 }
760
ef5a4085
MH
761 if (etype)
762 {
763 extype = etype;
764 etype = 0;
765 }
7be9a312
MH
766
767 /* if this is a long instruction, write it and any previous short instruction */
768 if (opcode->format & LONG_OPCODE)
769 {
ef5a4085 770 if (extype)
7be9a312
MH
771 as_fatal("Unable to mix instructions as specified");
772 if (prev_opcode)
773 {
0ef32559 774 write_1_short (prev_opcode, prev_insn, fixups->next);
7be9a312
MH
775 prev_opcode = NULL;
776 }
0ef32559 777 write_long (opcode, insn, fixups);
7be9a312
MH
778 prev_opcode = NULL;
779 return;
780 }
781
ef5a4085 782 if (prev_opcode && (write_2_short (prev_opcode, prev_insn, opcode, insn, extype, fixups) == 0))
7be9a312
MH
783 {
784 /* no instructions saved */
785 prev_opcode = NULL;
786 }
787 else
788 {
ef5a4085 789 if (extype)
7be9a312
MH
790 as_fatal("Unable to mix instructions as specified");
791 /* save off last instruction so it may be packed on next pass */
792 prev_opcode = opcode;
793 prev_insn = insn;
0ef32559
MH
794 prev_seg = now_seg;
795 prev_subseg = now_subseg;
796 fixups = fixups->next;
7be9a312
MH
797 }
798}
799
800
ef5a4085
MH
801/* do_assemble assembles a single instruction and returns an opcode */
802/* it returns -1 (an invalid opcode) on error */
803
7be9a312
MH
804static unsigned long
805do_assemble (str, opcode)
806 char *str;
807 struct d10v_opcode **opcode;
808{
809 struct d10v_opcode *next_opcode;
810 unsigned char *op_start, *save;
811 unsigned char *op_end;
812 char name[20];
813 int nlen = 0, i, match, numops;
814 expressionS myops[6];
815 unsigned long insn;
816
0ef32559 817 /* printf("do_assemble: str=%s\n",str); */
7be9a312
MH
818
819 /* Drop leading whitespace */
820 while (*str == ' ')
821 str++;
822
823 /* find the opcode end */
824 for (op_start = op_end = (unsigned char *) (str);
825 *op_end
826 && nlen < 20
827 && !is_end_of_line[*op_end] && *op_end != ' ';
828 op_end++)
829 {
830 name[nlen] = op_start[nlen];
831 nlen++;
832 }
833 name[nlen] = 0;
834
835 if (nlen == 0)
ef5a4085 836 return (-1);
7be9a312
MH
837
838 /* find the first opcode with the proper name */
839 *opcode = (struct d10v_opcode *)hash_find (d10v_hash, name);
840 if (*opcode == NULL)
ab48956f 841 as_fatal ("unknown opcode: %s",name);
7be9a312
MH
842
843 save = input_line_pointer;
844 input_line_pointer = op_end;
845
846 /* get all the operands and save them as expressions */
847 numops = get_operands (myops);
848
ab48956f
MH
849 /* now see if the operand is a fake. If so, find the correct size */
850 /* instruction, if possible */
851 match = 0;
852 if ((*opcode)->format == OPCODE_FAKE)
7be9a312 853 {
ab48956f
MH
854 int opnum = (*opcode)->operands[0];
855 if (myops[opnum].X_op == O_constant)
7be9a312 856 {
ab48956f
MH
857 next_opcode=(*opcode)+1;
858 for (i=0; (*opcode)->operands[i+1]; i++)
7be9a312 859 {
ab48956f
MH
860 int bits = d10v_operands[next_opcode->operands[opnum]].bits;
861 int flags = d10v_operands[next_opcode->operands[opnum]].flags;
a40d3589 862 if (!check_range (myops[opnum].X_add_number, bits, flags))
ab48956f
MH
863 {
864 match = 1;
865 break;
866 }
867 next_opcode++;
7be9a312 868 }
ab48956f
MH
869 }
870 else
871 {
872 /* not a constant, so use a long instruction */
873 next_opcode = (*opcode)+2;
874 match = 1;
875 }
876 if (match)
877 *opcode = next_opcode;
878 else
879 as_fatal ("value out of range");
880 }
881 else
882 {
883 /* now search the opcode table table for one with operands */
ef5a4085 884 /* that matches what we've got */
ab48956f
MH
885 while (!match)
886 {
887 match = 1;
888 for (i = 0; (*opcode)->operands[i]; i++)
7be9a312 889 {
ab48956f
MH
890 int flags = d10v_operands[(*opcode)->operands[i]].flags;
891 int X_op = myops[i].X_op;
892 int num = myops[i].X_add_number;
893
894 if (X_op==0)
7be9a312
MH
895 {
896 match=0;
897 break;
ab48956f
MH
898 }
899
900 if (flags & OPERAND_REG)
901 {
902 if ((X_op != O_register) ||
903 ((flags & OPERAND_ACC) != (num & OPERAND_ACC)) ||
904 ((flags & OPERAND_FLAG) != (num & OPERAND_FLAG)) ||
905 ((flags & OPERAND_CONTROL) != (num & OPERAND_CONTROL)))
906 {
907 match=0;
908 break;
909 }
910 }
911
912 if (((flags & OPERAND_MINUS) && ((X_op != O_absent) || (num != OPERAND_MINUS))) ||
913 ((flags & OPERAND_PLUS) && ((X_op != O_absent) || (num != OPERAND_PLUS))) ||
914 ((flags & OPERAND_ATMINUS) && ((X_op != O_absent) || (num != OPERAND_ATMINUS))) ||
915 ((flags & OPERAND_ATPAR) && ((X_op != O_absent) || (num != OPERAND_ATPAR))) ||
916 ((flags & OPERAND_ATSIGN) && ((X_op != O_absent) || (num != OPERAND_ATSIGN))))
917 {
918 match=0;
919 break;
920 }
921
7be9a312 922 }
ab48956f
MH
923
924 /* we're only done if the operands matched AND there
925 are no more to check */
926 if (match && myops[i].X_op==0)
927 break;
928
929 next_opcode = (*opcode)+1;
930 if (next_opcode->opcode == 0)
931 break;
932 if (strcmp(next_opcode->name, (*opcode)->name))
933 break;
934 (*opcode) = next_opcode;
7be9a312 935 }
ab48956f 936 }
7be9a312
MH
937
938 if (!match)
939 {
940 as_bad ("bad opcode or operands");
941 return (0);
942 }
943
944 /* Check that all registers that are required to be even are. */
945 /* Also, if any operands were marked as registers, but were really symbols */
946 /* fix that here. */
947 for (i=0; (*opcode)->operands[i]; i++)
948 {
949 if ((d10v_operands[(*opcode)->operands[i]].flags & OPERAND_EVEN) &&
950 (myops[i].X_add_number & 1))
951 as_fatal("Register number must be EVEN");
952 if (myops[i].X_op == O_register)
953 {
954 if (!(d10v_operands[(*opcode)->operands[i]].flags & OPERAND_REG))
955 {
956 myops[i].X_op = O_symbol;
0ef32559 957 myops[i].X_add_symbol = symbol_find_or_make ((char *)myops[i].X_op_symbol);
7be9a312 958 myops[i].X_add_number = 0;
0ef32559 959 myops[i].X_op_symbol = NULL;
7be9a312
MH
960 }
961 }
962 }
963
964 input_line_pointer = save;
965
966 /* at this point, we have "opcode" pointing to the opcode entry in the
967 d10v opcode table, with myops filled out with the operands. */
ab48956f
MH
968 insn = build_insn ((*opcode), myops, 0);
969 /* printf("sub-insn = %lx\n",insn); */
7be9a312
MH
970
971 return (insn);
972}
973
974
975/* if while processing a fixup, a reloc really needs to be created */
976/* then it is done here */
977
978arelent *
979tc_gen_reloc (seg, fixp)
980 asection *seg;
981 fixS *fixp;
982{
983 arelent *reloc;
984 reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
985 reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
986 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
987 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
988 if (reloc->howto == (reloc_howto_type *) NULL)
989 {
990 as_bad_where (fixp->fx_file, fixp->fx_line,
991 "reloc %d not supported by object file format", (int)fixp->fx_r_type);
992 return NULL;
993 }
994 reloc->addend = fixp->fx_addnumber;
995 /* printf("tc_gen_reloc: addr=%x addend=%x\n", reloc->address, reloc->addend); */
996 return reloc;
997}
998
999int
1000md_estimate_size_before_relax (fragp, seg)
1001 fragS *fragp;
1002 asection *seg;
1003{
1004 abort ();
1005 return 0;
1006}
1007
1008long
1009md_pcrel_from_section (fixp, sec)
1010 fixS *fixp;
1011 segT sec;
1012{
1013 return 0;
1014 /* return fixp->fx_frag->fr_address + fixp->fx_where; */
1015}
1016
1017int
1018md_apply_fix3 (fixp, valuep, seg)
1019 fixS *fixp;
1020 valueT *valuep;
1021 segT seg;
1022{
7be9a312
MH
1023 char *where;
1024 unsigned long insn;
93050391 1025 long value;
7be9a312 1026 int op_type;
0ef32559 1027 int left=0;
7be9a312
MH
1028
1029 if (fixp->fx_addsy == (symbolS *) NULL)
1030 {
1031 value = *valuep;
1032 fixp->fx_done = 1;
1033 }
1034 else if (fixp->fx_pcrel)
1035 value = *valuep;
1036 else
1037 {
1038 value = fixp->fx_offset;
1039 if (fixp->fx_subsy != (symbolS *) NULL)
1040 {
1041 if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
1042 value -= S_GET_VALUE (fixp->fx_subsy);
1043 else
1044 {
1045 /* We don't actually support subtracting a symbol. */
1046 as_bad_where (fixp->fx_file, fixp->fx_line,
1047 "expression too complex");
1048 }
1049 }
1050 }
1051
0ef32559 1052 /* printf("md_apply_fix: value=0x%x type=%d\n", value, fixp->fx_r_type); */
7be9a312
MH
1053
1054 op_type = fixp->fx_r_type;
0ef32559
MH
1055 if (op_type & 1024)
1056 {
1057 op_type -= 1024;
1058 fixp->fx_r_type = BFD_RELOC_D10V_10_PCREL_L;
1059 left = 1;
1060 }
1061 else
1062 fixp->fx_r_type = get_reloc((struct d10v_operand *)&d10v_operands[op_type]);
7be9a312
MH
1063
1064 /* Fetch the instruction, insert the fully resolved operand
1065 value, and stuff the instruction back again. */
1066 where = fixp->fx_frag->fr_literal + fixp->fx_where;
1067 insn = bfd_getb32 ((unsigned char *) where);
7be9a312 1068
93050391
MH
1069 switch (fixp->fx_r_type)
1070 {
1071 case BFD_RELOC_D10V_10_PCREL_L:
1072 case BFD_RELOC_D10V_10_PCREL_R:
1073 case BFD_RELOC_D10V_18_PCREL:
1074 /* instruction addresses are always right-shifted by 2
1075 and pc-relative */
1076 if (!fixp->fx_pcrel)
1077 value -= fixp->fx_where;
1078 value >>= 2;
1079 default:
1080 break;
1081 }
1082 /* printf(" insn=%x value=%x where=%x pcrel=%x\n",insn,value,fixp->fx_where,fixp->fx_pcrel); */
1083
1084 insn = d10v_insert_operand (insn, op_type, (offsetT)value, left);
7be9a312
MH
1085
1086 /* printf(" new insn=%x\n",insn); */
1087
1088 bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
1089
1090 if (fixp->fx_done)
1091 return 1;
1092
1093 fixp->fx_addnumber = value;
1094 return 1;
1095}
1096
7be9a312 1097
0ef32559
MH
1098/* d10v_cleanup() is called after the assembler has finished parsing the input
1099 file or after a label is defined. Because the D10V assembler sometimes saves short
1100 instructions to see if it can package them with the next instruction, there may
1101 be a short instruction that still needs written. */
7be9a312 1102int
ab48956f
MH
1103d10v_cleanup (done)
1104 int done;
7be9a312 1105{
0ef32559
MH
1106 segT seg;
1107 subsegT subseg;
1108
ab48956f 1109 if ( prev_opcode && (done || (now_seg == prev_seg) && (now_subseg == prev_subseg)))
7be9a312 1110 {
0ef32559
MH
1111 seg = now_seg;
1112 subseg = now_subseg;
1113 subseg_set (prev_seg, prev_subseg);
1114 write_1_short (prev_opcode, prev_insn, fixups);
1115 subseg_set (seg, subseg);
7be9a312
MH
1116 prev_opcode = NULL;
1117 }
1118 return 1;
1119}
This page took 0.171903 seconds and 4 git commands to generate.