Update year range in copyright notice of binutils files
[binutils-gdb.git] / gas / config / tc-kvx.c
blobcfd9c682982124be8073fb08b349905412bde8cc
1 /* tc-kvx.c -- Assemble for the KVX ISA
3 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 Contributed by Kalray SA.
6 This file is part of GAS.
8 GAS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the license, or
11 (at your option) any later version.
13 GAS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING3. If not,
20 see <http://www.gnu.org/licenses/>. */
22 #include "as.h"
23 #include "obstack.h"
24 #include "subsegs.h"
25 #include "tc-kvx.h"
26 #include "libiberty.h"
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <ctype.h>
34 #ifdef OBJ_ELF
35 #include "elf/kvx.h"
36 #include "dwarf2dbg.h"
37 #include "dw2gencfi.h"
38 #endif
40 #define D(args...) do { if(debug) fprintf(args); } while(0)
42 static void supported_cores (char buf[], size_t buflen);
44 #define NELEMS(a) ((int) (sizeof (a)/sizeof ((a)[0])))
46 #define STREQ(x,y) !strcmp(((x) ? (x) : ""), ((y) ? (y) : ""))
47 #define STRNEQ(x,y,n) !strncmp(((x) ? (x) : ""), ((y) ? (y) : ""),(n))
49 /* The PARALLEL_BIT is set to 0 when an instruction is the last of a bundle. */
50 #define PARALLEL_BIT (1u << 31)
52 /*TB begin*/
53 int size_type_function = 1;
54 /*TB end */
56 struct kvx_as_env env = {
57 .params = {
58 .abi = ELF_KVX_ABI_UNDEF,
59 .osabi = ELFOSABI_NONE,
60 .core = -1,
61 .core_set = 0,
62 .abi_set = 0,
63 .osabi_set = 0,
64 .pic_flags = 0,
65 .arch_size = 64
67 .opts = {
68 .march = NULL,
69 .check_resource_usage = 1,
70 .generate_illegal_code = 0,
71 .dump_table = 0,
72 .dump_insn = 0,
73 .diagnostics = 1,
74 .more = 1,
75 .allow_all_sfr = 0
79 /* This string should contain position in string where error occured. */
81 /* Default kvx_registers array. */
82 const struct kvx_Register *kvx_registers = NULL;
83 /* Default kvx_modifiers array. */
84 const char ***kvx_modifiers = NULL;
85 /* Default kvx_regfiles array. */
86 const int *kvx_regfiles = NULL;
87 /* Default values used if no assume directive is given */
88 const struct kvx_core_info *kvx_core_info = NULL;
90 /***********************************************/
91 /* Generic Globals for GAS */
92 /***********************************************/
94 const char comment_chars[] = "#";
95 const char line_comment_chars[] = "#";
96 const char line_separator_chars[] = ";";
97 const char EXP_CHARS[] = "eE";
98 const char FLT_CHARS[] = "dD";
99 const int md_short_jump_size = 0;
100 const int md_long_jump_size = 0;
102 /***********************************************/
103 /* Local Types */
104 /***********************************************/
106 /* a fix up record */
108 struct kvx_fixup
110 /* The expression used. */
111 expressionS exp;
112 /* The place in the frag where this goes. */
113 int where;
114 /* The relocation. */
115 bfd_reloc_code_real_type reloc;
118 /* a single assembled instruction record */
119 /* may include immediate extension words */
120 struct kvxinsn
122 /* written out? */
123 int written;
124 /* Opcode table entry for this insn */
125 const struct kvxopc *opdef;
126 /* length of instruction in words (1 or 2) */
127 int len;
128 /* insn is extended */
129 int immx0;
130 /* insn has two immx */
131 int immx1;
132 /* order to stabilize sort */
133 int order;
134 /* instruction words */
135 uint32_t words[KVXMAXBUNDLEWORDS];
136 /* the number of fixups [0,2] */
137 int nfixups;
138 /* the actual fixups */
139 struct kvx_fixup fixup[2];
142 typedef void (*print_insn_t) (struct kvxopc * op);
143 static print_insn_t print_insn = NULL;
145 /* Set to TRUE when we assemble instructions. */
146 static bool assembling_insn = false;
148 #define NOIMMX -1
150 /* Was KVXMAXBUNDLEISSUE, changed because of NOPs */
151 static struct kvxinsn insbuf[KVXMAXBUNDLEWORDS];
152 static int insncnt = 0;
153 static struct kvxinsn immxbuf[KVXMAXBUNDLEWORDS];
154 static int immxcnt = 0;
156 static void
157 incr_immxcnt (void)
159 immxcnt++;
160 if (immxcnt >= KVXMAXBUNDLEWORDS)
161 as_bad ("Max immx number exceeded: %d", immxcnt);
164 static void set_byte_counter (asection * sec, int value);
165 static void
166 set_byte_counter (asection * sec, int value)
168 sec->target_index = value;
171 static int get_byte_counter (asection * sec);
173 get_byte_counter (asection * sec)
175 return sec->target_index;
178 const char *
179 kvx_target_format (void)
181 return env.params.arch_size == 64 ? "elf64-kvx" : "elf32-kvx";
184 /****************************************************/
185 /* ASSEMBLER Pseudo-ops. Some of this just */
186 /* extends the default definitions */
187 /* others are KVX specific */
188 /****************************************************/
190 static void kvx_check_resources (int);
191 static void kvx_proc (int start);
192 static void kvx_endp (int start);
193 static void kvx_type (int start);
195 const pseudo_typeS md_pseudo_table[] = {
196 /* override default 2-bytes */
197 { "word", cons, 4 },
199 /* KVX specific */
200 { "dword", cons, 8 },
202 /* Override align directives to have a boundary as argument (and not the
203 power of two as in p2align) */
204 { "align", s_align_bytes, 0 },
206 { "checkresources", kvx_check_resources, 1 },
207 { "nocheckresources", kvx_check_resources, 0 },
209 { "proc", kvx_proc, 1 },
210 { "endp", kvx_endp, 0 },
212 { "type", kvx_type, 0 },
214 #ifdef OBJ_ELF
215 { "file", dwarf2_directive_file, 0 },
216 { "loc", dwarf2_directive_loc, 0 },
217 #endif
218 { NULL, 0, 0 }
222 static int inside_bundle = 0;
224 /* Stores the labels inside bundles (typically debug labels) that need
225 to be postponed to the next bundle. */
226 struct label_fix
228 struct label_fix *next;
229 symbolS *sym;
230 } *label_fixes = 0;
232 /*****************************************************/
233 /* OPTIONS PROCESSING */
234 /*****************************************************/
236 const char *md_shortopts = "hV"; /* catted to std short options */
238 /* added to std long options */
240 #define OPTION_HEXFILE (OPTION_MD_BASE + 0)
241 #define OPTION_MARCH (OPTION_MD_BASE + 4)
242 #define OPTION_CHECK_RESOURCES (OPTION_MD_BASE + 5)
243 #define OPTION_NO_CHECK_RESOURCES (OPTION_MD_BASE + 6)
244 #define OPTION_GENERATE_ILLEGAL_CODE (OPTION_MD_BASE + 7)
245 #define OPTION_DUMP_TABLE (OPTION_MD_BASE + 8)
246 #define OPTION_PIC (OPTION_MD_BASE + 9)
247 #define OPTION_BIGPIC (OPTION_MD_BASE + 10)
248 #define OPTION_NOPIC (OPTION_MD_BASE + 12)
249 #define OPTION_32 (OPTION_MD_BASE + 13)
250 #define OPTION_DUMPINSN (OPTION_MD_BASE + 15)
251 #define OPTION_ALL_SFR (OPTION_MD_BASE + 16)
252 #define OPTION_DIAGNOSTICS (OPTION_MD_BASE + 17)
253 #define OPTION_NO_DIAGNOSTICS (OPTION_MD_BASE + 18)
254 #define OPTION_MORE (OPTION_MD_BASE + 19)
255 #define OPTION_NO_MORE (OPTION_MD_BASE + 20)
257 struct option md_longopts[] = {
258 { "march", required_argument, NULL, OPTION_MARCH },
259 { "check-resources", no_argument, NULL, OPTION_CHECK_RESOURCES },
260 { "no-check-resources", no_argument, NULL, OPTION_NO_CHECK_RESOURCES },
261 { "generate-illegal-code", no_argument, NULL, OPTION_GENERATE_ILLEGAL_CODE },
262 { "dump-table", no_argument, NULL, OPTION_DUMP_TABLE },
263 { "mpic", no_argument, NULL, OPTION_PIC },
264 { "mPIC", no_argument, NULL, OPTION_BIGPIC },
265 { "mnopic", no_argument, NULL, OPTION_NOPIC },
266 { "m32", no_argument, NULL, OPTION_32 },
267 { "dump-insn", no_argument, NULL, OPTION_DUMPINSN },
268 { "all-sfr", no_argument, NULL, OPTION_ALL_SFR },
269 { "diagnostics", no_argument, NULL, OPTION_DIAGNOSTICS },
270 { "no-diagnostics", no_argument, NULL, OPTION_NO_DIAGNOSTICS },
271 { "more", no_argument, NULL, OPTION_MORE },
272 { "no-more", no_argument, NULL, OPTION_NO_MORE },
273 { NULL, no_argument, NULL, 0 }
276 size_t md_longopts_size = sizeof (md_longopts);
279 md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
281 int find_core = 0;
283 switch (c)
285 case 'h':
286 md_show_usage (stdout);
287 exit (EXIT_SUCCESS);
288 break;
290 /* -V: SVR4 argument to print version ID. */
291 case 'V':
292 print_version_id ();
293 exit (EXIT_SUCCESS);
294 break;
295 case OPTION_MARCH:
296 env.opts.march = strdup (arg);
297 for (int i = 0; i < KVXNUMCORES && !find_core; ++i)
298 if (!strcasecmp (env.opts.march, kvx_core_info_table[i]->name))
300 kvx_core_info = kvx_core_info_table[i];
301 kvx_registers = kvx_registers_table[i];
302 kvx_modifiers = kvx_modifiers_table[i];
303 kvx_regfiles = kvx_regfiles_table[i];
305 find_core = 1;
306 break;
308 if (!find_core)
310 char buf[100];
311 supported_cores (buf, sizeof (buf));
312 as_fatal ("Specified arch not supported [%s]", buf);
314 break;
315 case OPTION_CHECK_RESOURCES:
316 env.opts.check_resource_usage = 1;
317 break;
318 case OPTION_NO_CHECK_RESOURCES:
319 env.opts.check_resource_usage = 0;
320 break;
321 case OPTION_GENERATE_ILLEGAL_CODE:
322 env.opts.generate_illegal_code = 1;
323 break;
324 case OPTION_DUMP_TABLE:
325 env.opts.dump_table = 1;
326 break;
327 case OPTION_DUMPINSN:
328 env.opts.dump_insn = 1;
329 break;
330 case OPTION_ALL_SFR:
331 env.opts.allow_all_sfr = 1;
332 break;
333 case OPTION_DIAGNOSTICS:
334 env.opts.diagnostics = 1;
335 break;
336 case OPTION_NO_DIAGNOSTICS:
337 env.opts.diagnostics = 0;
338 break;
339 case OPTION_MORE:
340 env.opts.more = 1;
341 break;
342 case OPTION_NO_MORE:
343 env.opts.more = 0;
344 break;
345 case OPTION_PIC:
346 /* fallthrough, for now the same on KVX */
347 case OPTION_BIGPIC:
348 env.params.pic_flags |= ELF_KVX_ABI_PIC_BIT;
349 break;
350 case OPTION_NOPIC:
351 env.params.pic_flags &= ~(ELF_KVX_ABI_PIC_BIT);
352 break;
353 case OPTION_32:
354 env.params.arch_size = 32;
355 break;
357 default:
358 return 0;
360 return 1;
363 void
364 md_show_usage (FILE * stream)
366 char buf[100];
367 supported_cores (buf, sizeof (buf));
369 fprintf (stream, "\n"
370 "KVX specific options:\n\n"
371 " --check-resources\t Perform minimal resource checking\n"
372 " --march [%s]\t Select architecture\n"
373 " -V \t\t\t Print assembler version number\n\n"
374 " The options -M, --mri and -f are not supported in this assembler.\n", buf);
377 /**************************************************/
378 /* UTILITIES */
379 /**************************************************/
382 * Read a value from to the object file
385 static valueT md_chars_to_number (char *buf, int n);
386 valueT
387 md_chars_to_number (char *buf, int n)
389 valueT val = 0;
391 if (n > (int) sizeof (val) || n <= 0)
392 abort ();
394 while (n--)
396 val <<= 8;
397 val |= (buf[n] & 0xff);
400 return val;
403 /* Returns the corresponding pseudo function matching SYM and to be
404 used for data section */
405 static struct pseudo_func *
406 kvx_get_pseudo_func_data_scn (symbolS * sym)
408 for (int i = 0; i < kvx_core_info->nb_pseudo_funcs; i++)
409 if (sym == kvx_core_info->pseudo_funcs[i].sym
410 && kvx_core_info->pseudo_funcs[i].pseudo_relocs.single != BFD_RELOC_UNUSED)
411 return &kvx_core_info->pseudo_funcs[i];
412 return NULL;
415 /* Returns the corresponding pseudo function matching SYM and operand
416 format OPND */
417 static struct pseudo_func *
418 kvx_get_pseudo_func2 (symbolS *sym, struct kvx_operand * opnd)
420 for (int i = 0; i < kvx_core_info->nb_pseudo_funcs; i++)
421 if (sym == kvx_core_info->pseudo_funcs[i].sym)
422 for (int relidx = 0; relidx < opnd->reloc_nb; relidx++)
423 if (opnd->relocs[relidx] == kvx_core_info->pseudo_funcs[i].pseudo_relocs.kreloc
424 && (env.params.arch_size == (int) kvx_core_info->pseudo_funcs[i].pseudo_relocs.avail_modes
425 || kvx_core_info->pseudo_funcs[i].pseudo_relocs.avail_modes == PSEUDO_ALL))
426 return &kvx_core_info->pseudo_funcs[i];
428 return NULL;
431 static void
432 supported_cores (char buf[], size_t buflen)
434 buf[0] = '\0';
435 for (int i = 0; i < KVXNUMCORES; i++)
437 if (buf[0] == '\0')
438 strcpy (buf, kvx_core_info_table[i]->name);
439 else
440 if ((strlen (buf) + 1 + strlen (kvx_core_info_table[i]->name) + 1) < buflen)
442 strcat (buf, "|");
443 strcat (buf, kvx_core_info_table[i]->name);
448 /***************************************************/
449 /* ASSEMBLE AN INSTRUCTION */
450 /***************************************************/
453 * Insert ARG into the operand described by OPDEF in instruction INSN
454 * Returns 1 if the immediate extension (IMMX) has been
455 * handled along with relocation, 0 if not.
457 static int
458 insert_operand (struct kvxinsn *insn, struct kvx_operand *opdef,
459 struct token_list *tok)
461 uint64_t op = 0;
462 struct kvx_bitfield *bfields = opdef->bfield;
463 int bf_nb = opdef->bitfields;
464 int immx_ready = 0;
466 if (opdef->width == 0)
467 return 0;
469 #define add_fixup(insn_, reloc_, exp_) \
470 do { \
471 (insn_)->fixup[(insn_)->nfixups].reloc = (reloc_); \
472 (insn_)->fixup[(insn_)->nfixups].exp = (exp_); \
473 (insn_)->fixup[(insn_)->nfixups].where = 0; \
474 (insn_)->nfixups++; \
475 } while (0)
477 #define add_immx(insn_, words_, reloc_, exp_, nfixups_, len_) \
478 do { \
479 immxbuf[immxcnt].words[0] = (words_); \
480 immxbuf[immxcnt].fixup[0].reloc = (reloc_); \
481 immxbuf[immxcnt].fixup[0].exp = (exp_); \
482 immxbuf[immxcnt].fixup[0].where = 0; \
483 immxbuf[immxcnt].nfixups = (nfixups_); \
484 immxbuf[immxcnt].len = (len_); \
485 /* decrement insn->len: immx part handled separately \
486 from insn and must not be emited twice. */ \
487 (insn_)->len -= 1; \
488 incr_immxcnt (); \
489 } while (0)
491 #define chk_imm(core_, imm_) \
492 (env.params.core == ELF_KVX_CORE_## core_ && opdef->type == (imm_))
494 /* try to resolve the value */
496 switch (tok->category)
498 case CAT_REGISTER:
499 op = S_GET_VALUE (str_hash_find (env.reg_hash, tok->tok));
500 op -= opdef->bias;
501 op >>= opdef->shift;
502 break;
503 case CAT_MODIFIER:
504 op = tok->val;
505 op -= opdef->bias;
506 op >>= opdef->shift;
507 break;
508 case CAT_IMMEDIATE:
510 char *ilp_save = input_line_pointer;
511 input_line_pointer = tok->tok;
512 expressionS exp = { 0 };
513 expression (&exp);
514 input_line_pointer = ilp_save;
516 /* We are dealing with a pseudo-function. */
517 if (tok->tok[0] == '@')
519 if (insn->nfixups == 0)
521 expressionS reloc_arg;
522 reloc_arg = exp;
523 reloc_arg.X_op = O_symbol;
524 struct pseudo_func *pf =
525 kvx_get_pseudo_func2 (exp.X_op_symbol, opdef);
526 /* S64 uses LO10/UP27/EX27 format (3 words), with one reloc in each words (3) */
527 /* S43 uses LO10/EX6/UP27 format (2 words), with 2 relocs in main syllabes and 1 in extra word */
528 /* S37 uses LO10/UP27 format (2 words), with one reloc in each word (2) */
530 /* Beware that immxbuf must be filled in the same order as relocs should be emitted. */
532 if (pf->pseudo_relocs.reloc_type == S64_LO10_UP27_EX27
533 || pf->pseudo_relocs.reloc_type == S43_LO10_UP27_EX6
534 || pf->pseudo_relocs.reloc_type == S37_LO10_UP27)
536 add_fixup (insn, pf->pseudo_relocs.reloc_lo10, reloc_arg);
538 insn->immx0 = immxcnt;
539 add_immx (insn, 0, pf->pseudo_relocs.reloc_up27,
540 reloc_arg, 1, 1);
541 immx_ready = 1;
543 else if (pf->pseudo_relocs.reloc_type == S32_LO5_UP27)
545 add_fixup (insn, pf->pseudo_relocs.reloc_lo5, reloc_arg);
547 insn->immx0 = immxcnt;
548 add_immx (insn, 0, pf->pseudo_relocs.reloc_up27,
549 reloc_arg, 1, 1);
550 immx_ready = 1;
552 else if (pf->pseudo_relocs.reloc_type == S16)
553 add_fixup (insn, pf->pseudo_relocs.single, reloc_arg);
554 else
555 as_fatal ("Unexpected fixup");
557 if (pf->pseudo_relocs.reloc_type == S64_LO10_UP27_EX27)
559 insn->immx1 = immxcnt;
560 add_immx (insn, 0, pf->pseudo_relocs.reloc_ex, reloc_arg,
561 1, 1);
563 else if (pf->pseudo_relocs.reloc_type == S43_LO10_UP27_EX6)
564 add_fixup (insn, pf->pseudo_relocs.reloc_ex, reloc_arg);
567 else
569 if (exp.X_op == O_constant)
571 /* This is a immediate: either a regular immediate, or an
572 immediate that was saved in a variable through `.equ'. */
573 uint64_t sval = (int64_t) tok->val;
574 op = opdef->flags & kvxSIGNED ? sval : tok->val;
575 op >>= opdef->shift;
577 else if (exp.X_op == O_subtract)
578 as_fatal ("O_subtract not supported.");
579 else
582 /* This is a symbol which needs a relocation. */
583 if (insn->nfixups == 0)
585 if (chk_imm (KV3_1, Immediate_kv3_v1_pcrel17)
586 || chk_imm (KV3_2, Immediate_kv3_v2_pcrel17)
587 || chk_imm (KV4_1, Immediate_kv4_v1_pcrel17))
588 add_fixup (insn, BFD_RELOC_KVX_PCREL17, exp);
589 else if (chk_imm (KV3_1, Immediate_kv3_v1_pcrel27)
590 || chk_imm (KV3_2, Immediate_kv3_v2_pcrel27)
591 || chk_imm (KV4_1, Immediate_kv4_v1_pcrel27))
592 add_fixup (insn, BFD_RELOC_KVX_PCREL27, exp);
593 else if (chk_imm (KV3_1, Immediate_kv3_v1_wrapped32)
594 || chk_imm (KV3_2, Immediate_kv3_v2_wrapped32)
595 || chk_imm (KV4_1, Immediate_kv4_v1_wrapped32))
597 add_fixup (insn, BFD_RELOC_KVX_S32_LO5, exp);
599 insn->immx0 = immxcnt;
600 add_immx (insn, 0, BFD_RELOC_KVX_S32_UP27, exp, 1, 1);
602 immx_ready = 1;
604 else if (chk_imm (KV3_1, Immediate_kv3_v1_signed10)
605 || chk_imm (KV3_2, Immediate_kv3_v2_signed10)
606 || chk_imm (KV4_1, Immediate_kv4_v1_signed10))
607 add_fixup (insn, BFD_RELOC_KVX_S37_LO10, exp);
608 else if (chk_imm (KV3_1, Immediate_kv3_v1_signed37)
609 || chk_imm (KV3_2, Immediate_kv3_v2_signed37)
610 || chk_imm (KV4_1, Immediate_kv4_v1_signed37))
612 add_fixup (insn, BFD_RELOC_KVX_S37_LO10, exp);
614 insn->immx0 = immxcnt;
615 add_immx (insn, 0, BFD_RELOC_KVX_S37_UP27, exp, 1, 1);
617 immx_ready = 1;
619 else if (chk_imm (KV3_1, Immediate_kv3_v1_signed43)
620 || chk_imm (KV3_2, Immediate_kv3_v2_signed43)
621 || chk_imm (KV4_1, Immediate_kv4_v1_signed43))
623 add_fixup (insn, BFD_RELOC_KVX_S43_LO10, exp);
624 add_fixup (insn, BFD_RELOC_KVX_S43_EX6, exp);
626 insn->immx0 = immxcnt;
627 add_immx (insn, insn->words[1],
628 BFD_RELOC_KVX_S43_UP27, exp, 1, 1);
630 immx_ready = 1;
632 else if (chk_imm (KV3_1, Immediate_kv3_v1_wrapped64)
633 || chk_imm (KV3_2, Immediate_kv3_v2_wrapped64)
634 || chk_imm (KV4_1, Immediate_kv4_v1_wrapped64))
636 add_fixup (insn, BFD_RELOC_KVX_S64_LO10, exp);
638 insn->immx0 = immxcnt;
639 add_immx (insn, insn->words[1],
640 BFD_RELOC_KVX_S64_UP27, exp, 1, 1);
642 insn->immx1 = immxcnt;
643 add_immx (insn, insn->words[2],
644 BFD_RELOC_KVX_S64_EX27, exp, 1, 1);
646 immx_ready = 1;
648 else
649 as_fatal ("don't know how to generate a fixup record");
650 return immx_ready;
652 else
653 as_fatal ("No room for fixup ");
657 break;
658 default:
659 break;
662 for (int bf_idx = 0; bf_idx < bf_nb; bf_idx++)
664 uint64_t value =
665 ((uint64_t) op >> bfields[bf_idx].from_offset);
666 int j = 0;
667 int to_offset = bfields[bf_idx].to_offset;
668 value &= (1LL << bfields[bf_idx].size) - 1;
669 j = to_offset / 32;
670 to_offset = to_offset % 32;
671 insn->words[j] |= (value << to_offset) & 0xffffffff;
674 return immx_ready;
676 #undef chk_imm
677 #undef add_immx
678 #undef add_fixup
682 * Given a set of operands and a matching instruction,
683 * assemble it
686 static void
687 assemble_insn (const struct kvxopc * opcode, struct token_list *tok, struct kvxinsn *insn)
689 unsigned immx_ready = 0;
691 memset (insn, 0, sizeof (*insn));
692 insn->opdef = opcode;
693 for (int i = 0; i < opcode->wordcount; i++)
695 insn->words[i] = opcode->codewords[i].opcode;
696 insn->len += 1;
699 insn->immx0 = NOIMMX;
700 insn->immx1 = NOIMMX;
702 struct token_list *tok_ = tok;
703 struct kvx_operand **format = (struct kvx_operand **) opcode->format;
705 while (tok_)
707 int ret = insert_operand (insn, *format, tok_);
708 immx_ready |= ret;
709 while ((tok_ = tok_->next) && tok_->category == CAT_SEPARATOR);
710 format++;
713 // Handle immx if insert_operand did not already take care of that
714 if (!immx_ready)
716 for (int i = 0; i < opcode->wordcount; i++)
718 if (opcode->codewords[i].flags & kvxOPCODE_FLAG_IMMX0)
720 insn->immx0 = immxcnt;
721 immxbuf[immxcnt].words[0] = insn->words[i];
722 immxbuf[immxcnt].nfixups = 0;
723 immxbuf[immxcnt].len = 1;
724 insn->len -= 1;
725 incr_immxcnt ();
727 if (opcode->codewords[i].flags & kvxOPCODE_FLAG_IMMX1)
729 insn->immx1 = immxcnt;
730 immxbuf[immxcnt].words[0] = insn->words[i];
731 immxbuf[immxcnt].nfixups = 0;
732 immxbuf[immxcnt].len = 1;
733 insn->len -= 1;
734 incr_immxcnt ();
740 /* Emit an instruction from the instruction array into the object
741 * file. INSN points to an element of the instruction array. STOPFLAG
742 * is true if this is the last instruction in the bundle.
744 * Only handles main syllables of bundle. Immediate extensions are
745 * handled by insert_operand.
747 static void
748 emit_insn (struct kvxinsn * insn, int insn_pos, int stopflag)
750 char *f;
751 unsigned int image;
753 /* if we are listing, attach frag to previous line. */
754 if (listing)
755 listing_prev_line ();
757 /* Update text size for lane parity checking. */
758 set_byte_counter (now_seg, (get_byte_counter (now_seg) + (insn->len * 4)));
760 /* allocate space in the fragment. */
761 f = frag_more (insn->len * 4);
763 /* spit out bits. */
764 for (int i = 0; i < insn->len; i++)
766 image = insn->words[i];
768 /* Handle bundle parallel bit. */ ;
769 if ((i == insn->len - 1) && stopflag)
770 image &= ~PARALLEL_BIT;
771 else
772 image |= PARALLEL_BIT;
774 /* Emit the instruction image. */
775 md_number_to_chars (f + (i * 4), image, 4);
778 /* generate fixup records */
780 for (int i = 0; i < insn->nfixups; i++)
782 int size, pcrel;
783 reloc_howto_type *reloc_howto =
784 bfd_reloc_type_lookup (stdoutput, insn->fixup[i].reloc);
785 assert (reloc_howto);
786 size = bfd_get_reloc_size (reloc_howto);
787 pcrel = reloc_howto->pc_relative;
789 /* In case the PCREL relocation is not for the first insn in the
790 bundle, we have to offset it. The pc used by the hardware
791 references a bundle and not separate insn.
793 assert (!(insn_pos == -1 && pcrel));
794 if (pcrel && insn_pos > 0)
795 insn->fixup[i].exp.X_add_number += insn_pos * 4;
797 fixS *fixup = fix_new_exp (frag_now,
798 f - frag_now->fr_literal +
799 insn->fixup[i].where,
800 size,
801 &(insn->fixup[i].exp),
802 pcrel,
803 insn->fixup[i].reloc);
805 * Set this bit so that large value can still be
806 * handled. Without it, assembler will fail in fixup_segment
807 * when it checks there is enough bits to store the value. As we
808 * usually split our reloc across different words, it may think
809 * that 4 bytes are not enough for large value. This simply
810 * skips the tests
812 fixup->fx_no_overflow = 1;
817 /* Called for any expression that can not be recognized. When the
818 * function is called, `input_line_pointer' will point to the start of
819 * the expression. */
820 /* FIXME: Should be done by the parser */
821 void
822 md_operand (expressionS * e)
824 /* enum pseudo_type pseudo_type; */
825 /* char *name = NULL; */
826 size_t len;
827 int ch, i;
829 switch (*input_line_pointer)
831 case '@':
832 /* Find what relocation pseudo-function we're dealing with. */
833 /* pseudo_type = 0; */
834 ch = *++input_line_pointer;
835 for (i = 0; i < kvx_core_info->nb_pseudo_funcs; ++i)
836 if (kvx_core_info->pseudo_funcs[i].name && kvx_core_info->pseudo_funcs[i].name[0] == ch)
838 len = strlen (kvx_core_info->pseudo_funcs[i].name);
839 if (strncmp (kvx_core_info->pseudo_funcs[i].name + 1,
840 input_line_pointer + 1, len - 1) == 0
841 && !is_part_of_name (input_line_pointer[len]))
843 input_line_pointer += len;
844 break;
847 SKIP_WHITESPACE ();
848 if (*input_line_pointer != '(')
850 as_bad ("Expected '('");
851 goto err;
853 /* Skip '('. */
854 ++input_line_pointer;
855 if (!kvx_core_info->pseudo_funcs[i].pseudo_relocs.has_no_arg)
856 expression (e);
857 if (*input_line_pointer++ != ')')
859 as_bad ("Missing ')'");
860 goto err;
862 if (!kvx_core_info->pseudo_funcs[i].pseudo_relocs.has_no_arg)
864 if (e->X_op != O_symbol)
865 as_fatal ("Illegal combination of relocation functions");
867 /* Make sure gas doesn't get rid of local symbols that are used
868 in relocs. */
869 e->X_op = O_pseudo_fixup;
870 e->X_op_symbol = kvx_core_info->pseudo_funcs[i].sym;
871 break;
873 default:
874 break;
876 return;
878 err:
879 ignore_rest_of_line ();
883 * Return the Bundling type for an insn.
885 static int
886 find_bundling (const struct kvxinsn * insn)
888 return insn->opdef->bundling;
891 static int
892 find_reservation (const struct kvxinsn * insn)
894 return insn->opdef->reservation;
897 static struct kvxopc *
898 assemble_tokens (struct token_list *tok_list)
900 assert (tok_list != NULL);
901 struct token_list *toks = tok_list;
903 /* make sure there is room in instruction buffer */
904 /* Was KVXMAXBUNDLEISSUE, changed because of NOPs */
905 if (insncnt >= KVXMAXBUNDLEWORDS)
906 as_fatal ("[assemble_tokens]: too many instructions in bundle.");
908 /* TODO: Merge */
909 struct kvxinsn *insn;
910 insn = insbuf + insncnt;
912 /* The formats table registers the modifier into the opcode, therefore we need
913 to fuse both before looking up the opcodes hashtable. */
914 char *opcode = NULL;
916 opcode = toks->tok;
917 toks = toks->next;
919 while (toks && toks->category == CAT_SEPARATOR)
920 toks = toks->next;
922 /* Find the format requested by the instruction. */
923 struct kvxopc *format_tbl = str_hash_find (env.opcode_hash, opcode);
924 struct kvxopc *format = NULL;
926 struct token_list *toks_ = toks;
928 while (!format && format_tbl && STREQ (opcode, format_tbl->as_op))
930 for (int i = 0 ; toks_ && format_tbl->format[i]
931 && toks_->class_id == format_tbl->format[i]->type ;)
933 toks_ = toks_->next;
934 while (toks_ && toks_->category == CAT_SEPARATOR)
935 toks_ = toks_->next;
936 i += 1;
939 if (!toks_)
940 format = format_tbl;
941 else
943 toks_ = toks;
944 format_tbl++;
948 assert (format != NULL);
950 assemble_insn (format, toks, insn);
951 insncnt++;
953 return NULL;
957 * Write in buf at most buf_size.
958 * Returns the number of writen characters.
960 static int ATTRIBUTE_UNUSED
961 insn_syntax (struct kvxopc * op, char *buf, int buf_size)
963 int chars = snprintf (buf, buf_size, "%s ", op->as_op);
964 const char *fmtp = op->fmtstring;
965 char ch = 0;
967 for (int i = 0; op->format[i]; i++)
969 int type = op->format[i]->type;
970 const char *type_name = TOKEN_NAME (type);
971 int offset = 0;
973 for (int j = 0 ; type_name[j] ; ++j)
974 if (type_name[j] == '_')
975 offset = j + 1;
977 /* Print characters in the format string up to the following * % or nul. */
978 while ((chars < buf_size) && (ch = *fmtp) && ch != '%')
980 buf[chars++] = ch;
981 fmtp++;
984 /* Skip past %s */
985 if (ch == '%')
987 ch = *fmtp++;
988 fmtp++;
991 chars += snprintf (&buf[chars], buf_size - chars, "%s", type_name + offset);
994 /* Print trailing characters in the format string, if any */
995 while ((chars < buf_size) && (ch = *fmtp))
997 buf[chars++] = ch;
998 fmtp++;
1001 if (chars < buf_size)
1002 buf[chars++] = '\0';
1003 else
1004 buf[buf_size - 1] = '\0';
1006 return chars;
1009 #define ASM_CHARS_MAX (71)
1011 static void
1012 kvx_print_insn (struct kvxopc * op ATTRIBUTE_UNUSED)
1014 char asm_str[ASM_CHARS_MAX];
1015 int chars = insn_syntax (op, asm_str, ASM_CHARS_MAX);
1016 const char *insn_type = "UNKNOWN";
1017 const char *insn_mode = "";
1019 for (int i = chars - 1; i < ASM_CHARS_MAX - 1; i++)
1020 asm_str[i] = '-';
1022 /* This is a hack which works because the Bundling is the same for all cores
1023 for now. */
1024 switch ((int) op->bundling)
1026 case Bundling_kv3_v1_ALL:
1027 insn_type = "ALL ";
1028 break;
1029 case Bundling_kv3_v1_BCU:
1030 insn_type = "BCU ";
1031 break;
1032 case Bundling_kv3_v1_TCA:
1033 insn_type = "TCA ";
1034 break;
1035 case Bundling_kv3_v1_FULL:
1036 case Bundling_kv3_v1_FULL_X:
1037 case Bundling_kv3_v1_FULL_Y:
1038 insn_type = "FULL ";
1039 break;
1040 case Bundling_kv3_v1_LITE:
1041 case Bundling_kv3_v1_LITE_X:
1042 case Bundling_kv3_v1_LITE_Y:
1043 insn_type = "LITE ";
1044 break;
1045 case Bundling_kv3_v1_TINY:
1046 case Bundling_kv3_v1_TINY_X:
1047 case Bundling_kv3_v1_TINY_Y:
1048 insn_type = "TINY ";
1049 break;
1050 case Bundling_kv3_v1_MAU:
1051 case Bundling_kv3_v1_MAU_X:
1052 case Bundling_kv3_v1_MAU_Y:
1053 insn_type = "MAU ";
1054 break;
1055 case Bundling_kv3_v1_LSU:
1056 case Bundling_kv3_v1_LSU_X:
1057 case Bundling_kv3_v1_LSU_Y:
1058 insn_type = "LSU ";
1059 break;
1060 case Bundling_kv3_v1_NOP:
1061 insn_type = "NOP ";
1062 break;
1063 default:
1064 as_fatal ("Unhandled Bundling class %d", op->bundling);
1067 if (op->codewords[0].flags & kvxOPCODE_FLAG_MODE64
1068 && op->codewords[0].flags & kvxOPCODE_FLAG_MODE32)
1069 insn_mode = "32 and 64";
1070 else if (op->codewords[0].flags & kvxOPCODE_FLAG_MODE64)
1071 insn_mode = "64";
1072 else if (op->codewords[0].flags & kvxOPCODE_FLAG_MODE32)
1073 insn_mode = "32";
1074 else
1075 as_fatal ("Unknown instruction mode.");
1077 printf ("%s | syllables: %d | type: %s | mode: %s bits\n", asm_str,
1078 op->wordcount, insn_type, insn_mode);
1081 /* Comparison function compatible with qsort. This is used to sort the issues
1082 into the right order. */
1083 static int
1084 kvxinsn_compare (const void *a, const void *b)
1086 struct kvxinsn *kvxinsn_a = *(struct kvxinsn **) a;
1087 struct kvxinsn *kvxinsn_b = *(struct kvxinsn **) b;
1088 int bundling_a = find_bundling (kvxinsn_a);
1089 int bundling_b = find_bundling (kvxinsn_b);
1090 int order_a = kvxinsn_a->order;
1091 int order_b = kvxinsn_b->order;
1092 if (bundling_a != bundling_b)
1093 return (bundling_b < bundling_a) - (bundling_a < bundling_b);
1094 return (order_b < order_a) - (order_a < order_b);
1097 static void
1098 kvx_reorder_bundle (struct kvxinsn *bundle_insn[], int bundle_insncnt)
1100 enum
1101 { EXU_BCU, EXU_TCA, EXU_ALU0, EXU_ALU1, EXU_MAU, EXU_LSU, EXU__ };
1102 struct kvxinsn *issued[EXU__];
1103 int tag, exu;
1105 memset (issued, 0, sizeof (issued));
1106 for (int i = 0; i < bundle_insncnt; i++)
1108 struct kvxinsn *kvxinsn = bundle_insn[i];
1109 tag = -1, exu = -1;
1110 /* This is a hack. It works because all the Bundling are the same for all
1111 cores for now. */
1112 switch ((int) find_bundling (kvxinsn))
1114 case Bundling_kv3_v1_ALL:
1115 if (bundle_insncnt > 1)
1116 as_fatal ("Too many ops in a single op bundle");
1117 issued[0] = kvxinsn;
1118 break;
1119 case Bundling_kv3_v1_BCU:
1120 if (!issued[EXU_BCU])
1121 issued[EXU_BCU] = kvxinsn;
1122 else
1123 as_fatal ("More than one BCU instruction in bundle");
1124 break;
1125 case Bundling_kv3_v1_TCA:
1126 if (!issued[EXU_TCA])
1127 issued[EXU_TCA] = kvxinsn;
1128 else
1129 as_fatal ("More than one TCA instruction in bundle");
1130 break;
1131 case Bundling_kv3_v1_FULL:
1132 case Bundling_kv3_v1_FULL_X:
1133 case Bundling_kv3_v1_FULL_Y:
1134 if (!issued[EXU_ALU0])
1136 issued[EXU_ALU0] = kvxinsn;
1137 tag = Modifier_kv3_v1_exunum_ALU0;
1138 exu = EXU_ALU0;
1140 else
1141 as_fatal ("More than one ALU FULL instruction in bundle");
1142 break;
1143 case Bundling_kv3_v1_LITE:
1144 case Bundling_kv3_v1_LITE_X:
1145 case Bundling_kv3_v1_LITE_Y:
1146 if (!issued[EXU_ALU0])
1148 issued[EXU_ALU0] = kvxinsn;
1149 tag = Modifier_kv3_v1_exunum_ALU0;
1150 exu = EXU_ALU0;
1152 else if (!issued[EXU_ALU1])
1154 issued[EXU_ALU1] = kvxinsn;
1155 tag = Modifier_kv3_v1_exunum_ALU1;
1156 exu = EXU_ALU1;
1158 else
1159 as_fatal ("Too many ALU FULL or LITE instructions in bundle");
1160 break;
1161 case Bundling_kv3_v1_MAU:
1162 case Bundling_kv3_v1_MAU_X:
1163 case Bundling_kv3_v1_MAU_Y:
1164 if (!issued[EXU_MAU])
1166 issued[EXU_MAU] = kvxinsn;
1167 tag = Modifier_kv3_v1_exunum_MAU;
1168 exu = EXU_MAU;
1170 else
1171 as_fatal ("More than one MAU instruction in bundle");
1172 break;
1173 case Bundling_kv3_v1_LSU:
1174 case Bundling_kv3_v1_LSU_X:
1175 case Bundling_kv3_v1_LSU_Y:
1176 if (!issued[EXU_LSU])
1178 issued[EXU_LSU] = kvxinsn;
1179 tag = Modifier_kv3_v1_exunum_LSU;
1180 exu = EXU_LSU;
1182 else
1183 as_fatal ("More than one LSU instruction in bundle");
1184 break;
1185 case Bundling_kv3_v1_TINY:
1186 case Bundling_kv3_v1_TINY_X:
1187 case Bundling_kv3_v1_TINY_Y:
1188 case Bundling_kv3_v1_NOP:
1189 if (!issued[EXU_ALU0])
1191 issued[EXU_ALU0] = kvxinsn;
1192 tag = Modifier_kv3_v1_exunum_ALU0;
1193 exu = EXU_ALU0;
1195 else if (!issued[EXU_ALU1])
1197 issued[EXU_ALU1] = kvxinsn;
1198 tag = Modifier_kv3_v1_exunum_ALU1;
1199 exu = EXU_ALU1;
1201 else if (!issued[EXU_MAU])
1203 issued[EXU_MAU] = kvxinsn;
1204 tag = Modifier_kv3_v1_exunum_MAU;
1205 exu = EXU_MAU;
1207 else if (!issued[EXU_LSU])
1209 issued[EXU_LSU] = kvxinsn;
1210 tag = Modifier_kv3_v1_exunum_LSU;
1211 exu = EXU_LSU;
1213 else
1214 as_fatal ("Too many ALU instructions in bundle");
1215 break;
1216 default:
1217 as_fatal ("Unhandled Bundling class %d", find_bundling (kvxinsn));
1219 if (tag >= 0)
1221 if (issued[exu]->immx0 != NOIMMX)
1222 immxbuf[issued[exu]->immx0].words[0] |= (tag << 27);
1223 if (issued[exu]->immx1 != NOIMMX)
1224 immxbuf[issued[exu]->immx1].words[0] |= (tag << 27);
1228 int i;
1229 for (i = 0, exu = 0; exu < EXU__; exu++)
1231 if (issued[exu])
1232 bundle_insn[i++] = issued[exu];
1234 if (i != bundle_insncnt)
1235 as_fatal ("Mismatch between bundle and issued instructions");
1238 static void
1239 kvx_check_resource_usage (struct kvxinsn **bundle_insn, int bundle_insncnt)
1241 const int reservation_table_len =
1242 (kvx_core_info->reservation_table_lines * kvx_core_info->resource_max);
1243 const int *resources = kvx_core_info->resources;
1244 int *resources_used =
1245 malloc (reservation_table_len * sizeof (int));
1246 memset (resources_used, 0, reservation_table_len * sizeof (int));
1248 for (int i = 0; i < bundle_insncnt; i++)
1250 int insn_reservation = find_reservation (bundle_insn[i]);
1251 int reservation = insn_reservation & 0xff;
1252 const int *reservation_table = kvx_core_info->reservation_table_table[reservation];
1253 for (int j = 0; j < reservation_table_len; j++)
1254 resources_used[j] += reservation_table[j];
1257 for (int i = 0; i < kvx_core_info->reservation_table_lines; i++)
1259 for (int j = 0; j < kvx_core_info->resource_max; j++)
1260 if (resources_used[(i * kvx_core_info->resource_max) + j] > resources[j])
1262 int v = resources_used[(i * kvx_core_info->resource_max) + j];
1263 free (resources_used);
1264 as_fatal ("Resource %s over-used in bundle: %d used, %d available",
1265 kvx_core_info->resource_names[j], v, resources[j]);
1268 free (resources_used);
1272 * Called by core to assemble a single line
1274 void
1275 md_assemble (char *line)
1277 char *line_cursor = line;
1279 if (get_byte_counter (now_seg) & 3)
1280 as_fatal ("code segment not word aligned in md_assemble");
1282 while (line_cursor && line_cursor[0] && (line_cursor[0] == ' '))
1283 line_cursor++;
1285 /* ;; was converted to "be" by line hook */
1286 /* here we look for the bundle end */
1287 /* and actually output any instructions in bundle */
1288 /* also we need to implement the stop bit */
1289 /* check for bundle end */
1290 if (strncmp (line_cursor, "be", 2) == 0)
1292 inside_bundle = 0;
1293 //int sec_align = bfd_get_section_alignment(stdoutput, now_seg);
1294 /* Was KVXMAXBUNDLEISSUE, changed because of NOPs */
1295 struct kvxinsn *bundle_insn[KVXMAXBUNDLEWORDS];
1296 int bundle_insncnt = 0;
1297 int syllables = 0;
1298 int entry;
1300 #ifdef OBJ_ELF
1301 /* Emit Dwarf debug line information */
1302 dwarf2_emit_insn (0);
1303 #endif
1304 for (int j = 0; j < insncnt; j++)
1306 insbuf[j].order = j;
1307 bundle_insn[bundle_insncnt++] = &insbuf[j];
1308 syllables += insbuf[j].len;
1311 if (syllables + immxcnt > KVXMAXBUNDLEWORDS)
1312 as_fatal ("Bundle has too many syllables : %d instead of %d",
1313 syllables + immxcnt, KVXMAXBUNDLEWORDS);
1315 if (env.opts.check_resource_usage)
1316 kvx_check_resource_usage (bundle_insn, bundle_insncnt);
1318 /* Reorder and check the bundle. */
1319 if (!env.opts.generate_illegal_code)
1321 /* Sort the bundle_insn in order of bundling. */
1322 qsort (bundle_insn, bundle_insncnt, sizeof (struct kvxinsn *), kvxinsn_compare);
1324 kvx_reorder_bundle (bundle_insn, bundle_insncnt);
1327 /* The ordering of the insns has been set correctly in bundle_insn. */
1328 for (int i = 0; i < bundle_insncnt; i++)
1330 emit_insn (bundle_insn[i], i, (i == bundle_insncnt + immxcnt - 1));
1331 bundle_insn[i]->written = 1;
1334 // Emit immx, ordering them by EXU tags, 0 to 3
1335 entry = 0;
1336 for (int tag = 0; tag < 4; tag++)
1338 for (int j = 0; j < immxcnt; j++)
1340 #define kv3_exunum2_fld(x) (int)(((unsigned int)(x) >> 27) & 0x3)
1341 if (kv3_exunum2_fld (immxbuf[j].words[0]) == tag)
1343 assert (immxbuf[j].written == 0);
1344 int insn_pos = bundle_insncnt + entry;
1345 emit_insn (&(immxbuf[j]), insn_pos, entry == immxcnt - 1);
1346 immxbuf[j].written = 1;
1347 entry++;
1349 #undef kv3_exunum2_fld
1352 if (entry != immxcnt)
1353 as_fatal ("%d IMMX produced, only %d emitted.", immxcnt, entry);
1355 /* The debug label that appear in the middle of bundles
1356 had better appear to be attached to the next
1357 bundle. This is because usually these labels point to
1358 the first instruction where some condition is met. If
1359 the label isn't handled this way it will be attached to
1360 the current bundle which is wrong as the corresponding
1361 instruction wasn't executed yet. */
1362 while (label_fixes)
1364 struct label_fix *fix = label_fixes;
1366 label_fixes = fix->next;
1367 symbol_set_value_now (fix->sym);
1368 free (fix);
1371 insncnt = 0;
1372 immxcnt = 0;
1373 memset (immxbuf, 0, sizeof (immxbuf));
1375 return;
1378 char *buf = NULL;
1379 sscanf (line_cursor, "%m[^\n]", &buf);
1380 struct token_s my_tok = { .insn = buf, .begin = 0, .end = 0, .class_id = -1 , .val = 0 };
1381 struct token_list *tok_lst = parse (my_tok);
1382 free (buf);
1384 if (!tok_lst)
1385 return;
1387 /* Skip opcode */
1388 line_cursor += strlen (tok_lst->tok);
1390 assembling_insn = true;
1392 inside_bundle = 1;
1393 assemble_tokens (tok_lst);
1394 free_token_list (tok_lst);
1395 assembling_insn = false;
1398 static void
1399 kvx_set_cpu (void)
1401 if (!kvx_core_info)
1402 kvx_core_info = &kvx_kv3_v1_core_info;
1404 if (!kvx_registers)
1405 kvx_registers = kvx_kv3_v1_registers;
1407 if (!kvx_regfiles)
1408 kvx_regfiles = kvx_kv3_v1_regfiles;
1410 if (!kvx_modifiers)
1411 kvx_modifiers = kvx_kv3_v1_modifiers;
1413 if (env.params.core == -1)
1414 env.params.core = kvx_core_info->elf_core;
1416 int kvx_bfd_mach;
1417 print_insn = kvx_print_insn;
1419 switch (kvx_core_info->elf_core)
1421 case ELF_KVX_CORE_KV3_1:
1422 kvx_bfd_mach = env.params.arch_size == 32 ? bfd_mach_kv3_1 : bfd_mach_kv3_1_64;
1423 setup (ELF_KVX_CORE_KV3_1);
1424 break;
1425 case ELF_KVX_CORE_KV3_2:
1426 kvx_bfd_mach = env.params.arch_size == 32 ? bfd_mach_kv3_2 : bfd_mach_kv3_2_64;
1427 setup (ELF_KVX_CORE_KV3_2);
1428 break;
1429 case ELF_KVX_CORE_KV4_1:
1430 kvx_bfd_mach = env.params.arch_size == 32 ? bfd_mach_kv4_1 : bfd_mach_kv4_1_64;
1431 setup (ELF_KVX_CORE_KV4_1);
1432 break;
1433 default:
1434 as_fatal ("Unknown elf core: 0x%x", kvx_core_info->elf_core);
1437 if (!bfd_set_arch_mach (stdoutput, TARGET_ARCH, kvx_bfd_mach))
1438 as_warn (_("could not set architecture and machine"));
1441 static int
1442 kvxop_compar (const void *a, const void *b)
1444 const struct kvxopc *opa = (const struct kvxopc *) a;
1445 const struct kvxopc *opb = (const struct kvxopc *) b;
1446 int res = strcmp (opa->as_op, opb->as_op);
1448 if (res)
1449 return res;
1450 else
1452 for (int i = 0; opa->format[i] && opb->format[i]; ++i)
1453 if (opa->format[i]->width != opb->format[i]->width)
1454 return opa->format[i]->width - opb->format[i]->width;
1455 return 0;
1459 /***************************************************/
1460 /* INITIALIZE ASSEMBLER */
1461 /***************************************************/
1463 static int
1464 print_hash (void **slot, void *arg ATTRIBUTE_UNUSED)
1466 string_tuple_t *tuple = *((string_tuple_t **) slot);
1467 printf ("%s\n", tuple->key);
1468 return 1;
1471 static void
1472 declare_register (const char *name, int number)
1474 symbolS *regS = symbol_create (name, reg_section,
1475 &zero_address_frag, number);
1477 if (str_hash_insert (env.reg_hash, S_GET_NAME (regS), regS, 0) != NULL)
1478 as_fatal (_("duplicate %s"), name);
1481 void
1482 md_begin ()
1484 kvx_set_cpu ();
1487 * Declare register names with symbols
1490 env.reg_hash = str_htab_create ();
1492 for (int i = 0; i < kvx_regfiles[KVX_REGFILE_REGISTERS]; i++)
1493 declare_register (kvx_registers[i].name, kvx_registers[i].id);
1495 /* Sort optab, so that identical mnemonics appear consecutively */
1497 int nel;
1498 for (nel = 0; !STREQ ("", kvx_core_info->optab[nel].as_op); nel++)
1500 qsort (kvx_core_info->optab, nel, sizeof (kvx_core_info->optab[0]),
1501 kvxop_compar);
1504 /* The '?' is an operand separator */
1505 lex_type['?'] = 0;
1507 /* Create the opcode hash table */
1508 /* Each name should appear only once */
1510 env.opcode_hash = str_htab_create ();
1511 env.reloc_hash = str_htab_create ();
1514 struct kvxopc *op;
1515 const char *name = 0;
1516 for (op = kvx_core_info->optab; !(STREQ ("", op->as_op)); op++)
1518 /* enter in hash table if this is a new name */
1519 if (!(STREQ (name, op->as_op)))
1521 name = op->as_op;
1522 if (str_hash_insert (env.opcode_hash, name, op, 0))
1523 as_fatal ("internal error: can't hash opcode `%s'", name);
1527 for (int i = 0 ; op->format[i] ; ++i)
1529 const char *reloc_name = TOKEN_NAME (op->format[i]->type);
1530 void *relocs = op->format[i]->relocs;
1531 if (op->format[i]->relocs[0] != 0
1532 && !str_hash_find (env.reloc_hash, reloc_name))
1533 if (str_hash_insert (env.reloc_hash, reloc_name, relocs, 0))
1534 as_fatal ("internal error: can't hash type `%s'", reloc_name);
1539 if (env.opts.dump_table)
1541 htab_traverse (env.opcode_hash, print_hash, NULL);
1542 exit (0);
1545 if (env.opts.dump_insn)
1547 for (struct kvxopc *op = kvx_core_info->optab; !(STREQ ("", op->as_op)); op++)
1548 print_insn (op);
1549 exit (0);
1552 /* Here we enforce the minimum section alignment. Remember, in
1553 * the linker we can make the boudaries between the linked sections
1554 * on larger boundaries. The text segment is aligned to long words
1555 * because of the odd/even constraint on immediate extensions
1558 bfd_set_section_alignment (text_section, 3); /* -- 8 bytes */
1559 bfd_set_section_alignment (data_section, 2); /* -- 4 bytes */
1560 bfd_set_section_alignment (bss_section, 2); /* -- 4 bytes */
1561 subseg_set (text_section, 0);
1563 symbolS *gotoff_sym = symbol_create (".<gotoff>", undefined_section, &zero_address_frag, 0);
1564 symbolS *got_sym = symbol_create (".<got>", undefined_section, &zero_address_frag, 0);
1565 symbolS *plt_sym = symbol_create (".<plt>", undefined_section, &zero_address_frag, 0);
1566 symbolS *tlsgd_sym = symbol_create (".<tlsgd>", undefined_section, &zero_address_frag, 0);
1567 symbolS *tlsie_sym = symbol_create (".<tlsie>", undefined_section, &zero_address_frag, 0);
1568 symbolS *tlsle_sym = symbol_create (".<tlsle>", undefined_section, &zero_address_frag, 0);
1569 symbolS *tlsld_sym = symbol_create (".<tlsld>", undefined_section, &zero_address_frag, 0);
1570 symbolS *dtpoff_sym = symbol_create (".<dtpoff>", undefined_section, &zero_address_frag, 0);
1571 symbolS *plt64_sym = symbol_create (".<plt64>", undefined_section, &zero_address_frag, 0);
1572 symbolS *gotaddr_sym = symbol_create (".<gotaddr>", undefined_section, &zero_address_frag, 0);
1573 symbolS *pcrel16_sym = symbol_create (".<pcrel16>", undefined_section, &zero_address_frag, 0);
1574 symbolS *pcrel_sym = symbol_create (".<pcrel>", undefined_section, &zero_address_frag, 0);
1575 symbolS *signed32_sym = symbol_create (".<signed32>", undefined_section, &zero_address_frag, 0);
1577 for (int i = 0; i < kvx_core_info->nb_pseudo_funcs; ++i)
1579 symbolS *sym;
1580 if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "gotoff"))
1581 sym = gotoff_sym;
1582 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "got"))
1583 sym = got_sym;
1584 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "plt"))
1585 sym = plt_sym;
1586 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "tlsgd"))
1587 sym = tlsgd_sym;
1588 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "tlsle"))
1589 sym = tlsle_sym;
1590 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "tlsld"))
1591 sym = tlsld_sym;
1592 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "dtpoff"))
1593 sym = dtpoff_sym;
1594 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "tlsie"))
1595 sym = tlsie_sym;
1596 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "plt64"))
1597 sym = plt64_sym;
1598 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "pcrel16"))
1599 sym = pcrel16_sym;
1600 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "pcrel"))
1601 sym = pcrel_sym;
1602 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "gotaddr"))
1603 sym = gotaddr_sym;
1604 else if (!strcmp (kvx_core_info->pseudo_funcs[i].name, "signed32"))
1605 sym = signed32_sym;
1606 else
1607 as_fatal ("internal error: Unknown pseudo func `%s'",
1608 kvx_core_info->pseudo_funcs[i].name);
1610 kvx_core_info->pseudo_funcs[i].sym = sym;
1614 /***************************************************/
1615 /* ASSEMBLER CLEANUP STUFF */
1616 /***************************************************/
1618 /* Return non-zero if the indicated VALUE has overflowed the maximum
1619 range expressible by a signed number with the indicated number of
1620 BITS.
1622 This is from tc-aarch64.c
1625 static bfd_boolean
1626 signed_overflow (offsetT value, unsigned bits)
1628 offsetT lim;
1629 if (bits >= sizeof (offsetT) * 8)
1630 return FALSE;
1631 lim = (offsetT) 1 << (bits - 1);
1632 return (value < -lim || value >= lim);
1635 /***************************************************/
1636 /* ASSEMBLER FIXUP STUFF */
1637 /***************************************************/
1639 void
1640 md_apply_fix (fixS * fixP, valueT * valueP, segT segmentP ATTRIBUTE_UNUSED)
1642 char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
1643 valueT value = *valueP;
1644 valueT image;
1645 arelent *rel;
1647 rel = (arelent *) xmalloc (sizeof (arelent));
1649 rel->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
1650 if (rel->howto == NULL)
1652 as_fatal
1653 ("[md_apply_fix] unsupported relocation type (can't find howto)");
1656 /* Note whether this will delete the relocation. */
1657 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
1658 fixP->fx_done = 1;
1660 if (fixP->fx_size > 0)
1661 image = md_chars_to_number (fixpos, fixP->fx_size);
1662 else
1663 image = 0;
1664 if (fixP->fx_addsy != NULL)
1666 switch (fixP->fx_r_type)
1668 case BFD_RELOC_KVX_S37_TLS_LE_UP27:
1669 case BFD_RELOC_KVX_S37_TLS_LE_LO10:
1671 case BFD_RELOC_KVX_S43_TLS_LE_EX6:
1672 case BFD_RELOC_KVX_S43_TLS_LE_UP27:
1673 case BFD_RELOC_KVX_S43_TLS_LE_LO10:
1675 case BFD_RELOC_KVX_S37_TLS_GD_LO10:
1676 case BFD_RELOC_KVX_S37_TLS_GD_UP27:
1678 case BFD_RELOC_KVX_S43_TLS_GD_LO10:
1679 case BFD_RELOC_KVX_S43_TLS_GD_UP27:
1680 case BFD_RELOC_KVX_S43_TLS_GD_EX6:
1682 case BFD_RELOC_KVX_S37_TLS_IE_LO10:
1683 case BFD_RELOC_KVX_S37_TLS_IE_UP27:
1685 case BFD_RELOC_KVX_S43_TLS_IE_LO10:
1686 case BFD_RELOC_KVX_S43_TLS_IE_UP27:
1687 case BFD_RELOC_KVX_S43_TLS_IE_EX6:
1689 case BFD_RELOC_KVX_S37_TLS_LD_LO10:
1690 case BFD_RELOC_KVX_S37_TLS_LD_UP27:
1692 case BFD_RELOC_KVX_S43_TLS_LD_LO10:
1693 case BFD_RELOC_KVX_S43_TLS_LD_UP27:
1694 case BFD_RELOC_KVX_S43_TLS_LD_EX6:
1696 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1697 break;
1698 default:
1699 break;
1703 /* If relocation has been marked for deletion, apply remaining changes */
1704 if (fixP->fx_done)
1706 switch (fixP->fx_r_type)
1708 case BFD_RELOC_8:
1709 case BFD_RELOC_16:
1710 case BFD_RELOC_32:
1711 case BFD_RELOC_64:
1713 case BFD_RELOC_KVX_GLOB_DAT:
1714 case BFD_RELOC_KVX_32_GOT:
1715 case BFD_RELOC_KVX_64_GOT:
1716 case BFD_RELOC_KVX_64_GOTOFF:
1717 case BFD_RELOC_KVX_32_GOTOFF:
1718 image = value;
1719 md_number_to_chars (fixpos, image, fixP->fx_size);
1720 break;
1722 case BFD_RELOC_KVX_PCREL17:
1723 if (signed_overflow (value, 17 + 2))
1724 as_bad_where (fixP->fx_file, fixP->fx_line,
1725 _("branch out of range"));
1726 goto pcrel_common;
1728 case BFD_RELOC_KVX_PCREL27:
1729 if (signed_overflow (value, 27 + 2))
1730 as_bad_where (fixP->fx_file, fixP->fx_line,
1731 _("branch out of range"));
1732 goto pcrel_common;
1734 case BFD_RELOC_KVX_S16_PCREL:
1735 if (signed_overflow (value, 16))
1736 as_bad_where (fixP->fx_file, fixP->fx_line,
1737 _("signed16 PCREL value out of range"));
1738 goto pcrel_common;
1740 case BFD_RELOC_KVX_S43_PCREL_LO10:
1741 case BFD_RELOC_KVX_S43_PCREL_UP27:
1742 case BFD_RELOC_KVX_S43_PCREL_EX6:
1743 if (signed_overflow (value, 10 + 27 + 6))
1744 as_bad_where (fixP->fx_file, fixP->fx_line,
1745 _("signed43 PCREL value out of range"));
1746 goto pcrel_common;
1748 case BFD_RELOC_KVX_S37_PCREL_LO10:
1749 case BFD_RELOC_KVX_S37_PCREL_UP27:
1750 if (signed_overflow (value, 10 + 27))
1751 as_bad_where (fixP->fx_file, fixP->fx_line,
1752 _("signed37 PCREL value out of range"));
1753 goto pcrel_common;
1755 case BFD_RELOC_KVX_S64_PCREL_LO10:
1756 case BFD_RELOC_KVX_S64_PCREL_UP27:
1757 case BFD_RELOC_KVX_S64_PCREL_EX27:
1759 pcrel_common:
1760 if (fixP->fx_pcrel || fixP->fx_addsy)
1761 return;
1762 value =
1763 (((value >> rel->howto->rightshift) << rel->howto->bitpos) & rel->
1764 howto->dst_mask);
1765 image = (image & ~(rel->howto->dst_mask)) | value;
1766 md_number_to_chars (fixpos, image, fixP->fx_size);
1767 break;
1769 case BFD_RELOC_KVX_S64_GOTADDR_LO10:
1770 case BFD_RELOC_KVX_S64_GOTADDR_UP27:
1771 case BFD_RELOC_KVX_S64_GOTADDR_EX27:
1773 case BFD_RELOC_KVX_S43_GOTADDR_LO10:
1774 case BFD_RELOC_KVX_S43_GOTADDR_UP27:
1775 case BFD_RELOC_KVX_S43_GOTADDR_EX6:
1777 case BFD_RELOC_KVX_S37_GOTADDR_LO10:
1778 case BFD_RELOC_KVX_S37_GOTADDR_UP27:
1779 value = 0;
1780 /* Fallthrough */
1782 case BFD_RELOC_KVX_S32_UP27:
1784 case BFD_RELOC_KVX_S37_UP27:
1786 case BFD_RELOC_KVX_S43_UP27:
1788 case BFD_RELOC_KVX_S64_UP27:
1789 case BFD_RELOC_KVX_S64_EX27:
1790 case BFD_RELOC_KVX_S64_LO10:
1792 case BFD_RELOC_KVX_S43_TLS_LE_UP27:
1793 case BFD_RELOC_KVX_S43_TLS_LE_EX6:
1795 case BFD_RELOC_KVX_S37_TLS_LE_UP27:
1797 case BFD_RELOC_KVX_S37_GOTOFF_UP27:
1799 case BFD_RELOC_KVX_S43_GOTOFF_UP27:
1800 case BFD_RELOC_KVX_S43_GOTOFF_EX6:
1802 case BFD_RELOC_KVX_S43_GOT_UP27:
1803 case BFD_RELOC_KVX_S43_GOT_EX6:
1805 case BFD_RELOC_KVX_S37_GOT_UP27:
1807 case BFD_RELOC_KVX_S32_LO5:
1808 case BFD_RELOC_KVX_S37_LO10:
1810 case BFD_RELOC_KVX_S43_LO10:
1811 case BFD_RELOC_KVX_S43_EX6:
1813 case BFD_RELOC_KVX_S43_TLS_LE_LO10:
1814 case BFD_RELOC_KVX_S37_TLS_LE_LO10:
1816 case BFD_RELOC_KVX_S37_GOTOFF_LO10:
1817 case BFD_RELOC_KVX_S43_GOTOFF_LO10:
1819 case BFD_RELOC_KVX_S43_GOT_LO10:
1820 case BFD_RELOC_KVX_S37_GOT_LO10:
1822 default:
1823 as_fatal ("[md_apply_fix]:"
1824 "unsupported relocation type (type not handled : %d)",
1825 fixP->fx_r_type);
1831 * Warning: Can be called only in fixup_segment() after fx_addsy field
1832 * has been updated by calling symbol_get_value_expression(...->X_add_symbol)
1835 kvx_validate_sub_fix (fixS * fixP)
1837 segT add_symbol_segment, sub_symbol_segment;
1839 switch (fixP->fx_r_type)
1841 case BFD_RELOC_8:
1842 case BFD_RELOC_16:
1843 case BFD_RELOC_32:
1844 if (fixP->fx_addsy != NULL)
1845 add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy);
1846 else
1847 return 0;
1848 if (fixP->fx_subsy != NULL)
1849 sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy);
1850 else
1851 return 0;
1853 if ((strcmp (S_GET_NAME (fixP->fx_addsy),
1854 S_GET_NAME (fixP->fx_subsy)) == 0) &&
1855 (add_symbol_segment == sub_symbol_segment))
1856 return 1;
1857 break;
1858 default:
1859 break;
1862 return 0;
1865 /* This is called whenever some data item (not an instruction) needs a
1866 * fixup. */
1867 void
1868 kvx_cons_fix_new (fragS * f, int where, int nbytes, expressionS * exp,
1869 bfd_reloc_code_real_type code)
1871 if (exp->X_op == O_pseudo_fixup)
1873 exp->X_op = O_symbol;
1874 struct pseudo_func *pf =
1875 kvx_get_pseudo_func_data_scn (exp->X_op_symbol);
1876 assert (pf != NULL);
1877 code = pf->pseudo_relocs.single;
1879 if (code == BFD_RELOC_UNUSED)
1880 as_fatal ("Unsupported relocation");
1882 else
1884 switch (nbytes)
1886 case 1:
1887 code = BFD_RELOC_8;
1888 break;
1889 case 2:
1890 code = BFD_RELOC_16;
1891 break;
1892 case 4:
1893 code = BFD_RELOC_32;
1894 break;
1895 case 8:
1896 code = BFD_RELOC_64;
1897 break;
1898 default:
1899 as_fatal ("unsupported BFD relocation size %u", nbytes);
1900 break;
1903 fix_new_exp (f, where, nbytes, exp, 0, code);
1907 * generate a relocation record
1910 arelent *
1911 tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
1913 arelent *reloc;
1914 bfd_reloc_code_real_type code;
1916 reloc = (arelent *) xmalloc (sizeof (arelent));
1918 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
1919 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1920 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1922 code = fixp->fx_r_type;
1923 if (code == BFD_RELOC_32 && fixp->fx_pcrel)
1924 code = BFD_RELOC_32_PCREL;
1925 reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
1927 if (reloc->howto == NULL)
1929 as_bad_where (fixp->fx_file, fixp->fx_line,
1930 "cannot represent `%s' relocation in object file",
1931 bfd_get_reloc_code_name (code));
1932 return NULL;
1935 // if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
1936 // {
1937 // as_fatal ("internal error? cannot generate `%s' relocation",
1938 // bfd_get_reloc_code_name (code));
1939 // }
1940 // assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
1942 reloc->addend = fixp->fx_offset;
1945 * Ohhh, this is ugly. The problem is that if this is a local global
1946 * symbol, the relocation will entirely be performed at link time, not
1947 * at assembly time. bfd_perform_reloc doesn't know about this sort
1948 * of thing, and as a result we need to fake it out here.
1951 /* GD I'm not sure what this is used for in the kvx case but it sure */
1952 /* messes up the relocs when emit_all_relocs is used as they are not */
1953 /* resolved with respect to a global sysmbol (e.g. .text), and hence */
1954 /* they are ALWAYS resolved at link time */
1955 /* FIXME FIXME */
1957 /* clarkes: 030827: This code (and the other half of the fix in write.c)
1958 * have caused problems with the PIC relocations.
1959 * The root problem is that bfd_install_relocation adds in to the reloc
1960 * addend the section offset of a symbol defined in the current object.
1961 * This causes problems on numerous other targets too, and there are
1962 * several different methods used to get around it:
1963 * 1. In tc_gen_reloc, subtract off the value that bfd_install_relocation
1964 * added. That is what we do here, and it is also done the
1965 * same way for alpha.
1966 * 2. In md_apply_fix, subtract off the value that bfd_install_relocation
1967 * will add. This is done on SH (non-ELF) and sparc targets.
1968 * 3. In the howto structure for the relocations, specify a
1969 * special function that does not return bfd_reloc_continue.
1970 * This causes bfd_install_relocaion to terminate before it
1971 * adds in the symbol offset. This is done on SH ELF targets.
1972 * Note that on ST200 we specify bfd_elf_generic_reloc as
1973 * the special function. This will return bfd_reloc_continue
1974 * only in some circumstances, but in particular if the reloc
1975 * is marked as partial_inplace in the bfd howto structure, then
1976 * bfd_elf_generic_reloc will return bfd_reloc_continue.
1977 * Some ST200 relocations are marked as partial_inplace
1978 * (this is an error in my opinion because ST200 always uses
1979 * a separate addend), but some are not. The PIC relocations
1980 * are not marked as partial_inplace, so for them,
1981 * bfd_elf_generic_reloc returns bfd_reloc_ok, and the addend
1982 * is not modified by bfd_install_relocation. The relocations
1983 * R_KVX_16 and R_KVX_32 are marked partial_inplace, and so for
1984 * these we need to correct the addend.
1985 * In the code below, the condition in the emit_all_relocs branch
1986 * (now moved to write.c) is the inverse of the condition that
1987 * bfd_elf_generic_reloc uses to short-circuit the code in
1988 * bfd_install_relocation that modifies the addend. The condition
1989 * in the else branch match the condition used in the alpha version
1990 * of tc_gen_reloc (see tc-alpha.c).
1991 * I do not know why we need to use different conditions in these
1992 * two branches, it seems to me that the condition should be the same
1993 * whether or not emit_all_relocs is true.
1994 * I also do not understand why it was necessary to move the emit_all_relocs
1995 * condition to write.c.
1998 if (S_IS_EXTERNAL (fixp->fx_addsy) &&
1999 !S_IS_COMMON (fixp->fx_addsy) && reloc->howto->partial_inplace)
2000 reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
2002 return reloc;
2005 /* Round up segment to appropriate boundary */
2007 valueT
2008 md_section_align (asection * seg ATTRIBUTE_UNUSED, valueT size)
2010 #ifndef OBJ_ELF
2011 /* This is not right for ELF; a.out wants it, and COFF will force
2012 * the alignment anyways. */
2013 int align = bfd_get_section_alignment (stdoutput, seg);
2014 valueT mask = ((valueT) 1 << align) - 1;
2015 return (size + mask) & ~mask;
2016 #else
2017 return size;
2018 #endif
2022 md_estimate_size_before_relax (register fragS * fragP ATTRIBUTE_UNUSED,
2023 segT segtype ATTRIBUTE_UNUSED)
2025 as_fatal ("estimate_size_before_relax called");
2028 void
2029 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
2030 asection * sec ATTRIBUTE_UNUSED,
2031 fragS * fragp ATTRIBUTE_UNUSED)
2033 as_fatal ("kvx convert_frag");
2036 symbolS *
2037 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
2039 return 0;
2042 const char *
2043 md_atof (int type ATTRIBUTE_UNUSED,
2044 char *litp ATTRIBUTE_UNUSED, int *sizep ATTRIBUTE_UNUSED)
2046 return ieee_md_atof (type, litp, sizep, TARGET_BYTES_BIG_ENDIAN);
2050 * calculate the base for a pcrel fixup
2051 * -- for relocation, we might need to add addend ?
2054 long
2055 md_pcrel_from (fixS * fixP)
2057 return (fixP->fx_where + fixP->fx_frag->fr_address);
2060 /************************************************************/
2061 /* Hooks into standard processing -- we hook into label */
2062 /* handling code to detect double ':' and we hook before */
2063 /* a line of code is processed to do some simple sed style */
2064 /* edits. */
2065 /************************************************************/
2067 static symbolS *last_proc_sym = NULL;
2068 static int update_last_proc_sym = 0;
2070 void
2071 kvx_frob_label (symbolS *sym)
2073 if (update_last_proc_sym)
2075 last_proc_sym = sym;
2076 update_last_proc_sym = 0;
2079 if (inside_bundle)
2081 struct label_fix *fix;
2082 fix = malloc (sizeof (*fix));
2083 fix->next = label_fixes;
2084 fix->sym = sym;
2085 label_fixes = fix;
2088 dwarf2_emit_label (sym);
2091 void
2092 kvx_check_label (symbolS *sym)
2094 /* Labels followed by a second semi-colon are considered external symbols. */
2095 if (*input_line_pointer == ':')
2097 S_SET_EXTERNAL (sym);
2098 input_line_pointer++;
2102 /* Emit single bundle nop. This is needed by .nop asm directive
2103 * Have to manage end of bundle done usually by start_line_hook
2104 * using BE pseudo op
2106 void
2107 kvx_emit_single_noop (void)
2109 char *nop;
2110 char *end_of_bundle;
2112 if (asprintf (&nop, "nop") < 0)
2113 as_fatal ("%s", xstrerror (errno));
2115 if (asprintf (&end_of_bundle, "be") < 0)
2116 as_fatal ("%s", xstrerror (errno));
2118 char *saved_ilp = input_line_pointer;
2119 md_assemble (nop);
2120 md_assemble (end_of_bundle);
2121 input_line_pointer = saved_ilp;
2122 free (nop);
2123 free (end_of_bundle);
2126 /* edit out some syntactic sugar that confuses GAS */
2127 /* input_line_pointer is guaranteed to point to the */
2128 /* the current line but may include text from following */
2129 /* lines. Thus, '\n' must be scanned for as well as '\0' */
2131 void
2132 kvx_md_start_line_hook (void)
2134 char *t;
2136 for (t = input_line_pointer; t && t[0] == ' '; t++);
2138 /* Detect illegal syntax patterns:
2139 * - two bundle ends on the same line: ;; ;;
2140 * - illegal token: ;;;
2142 if (t && (t[0] == ';') && (t[1] == ';'))
2144 char *tmp_t;
2145 bool newline_seen = false;
2147 if (t[2] == ';')
2148 as_fatal ("Syntax error: Illegal ;;; token");
2150 tmp_t = t + 2;
2152 while (tmp_t && tmp_t[0])
2154 while (tmp_t && tmp_t[0] &&
2155 ((tmp_t[0] == ' ') || (tmp_t[0] == '\n')))
2157 if (tmp_t[0] == '\n')
2158 newline_seen = true;
2159 tmp_t++;
2161 if (tmp_t[0] == ';' && tmp_t[1] == ';')
2163 /* if there's no newline between the two bundle stops
2164 * then raise a syntax error now, otherwise a strange error
2165 * message from read.c will be raised: "junk at end of line..."
2167 if (tmp_t[2] == ';')
2168 as_fatal ("Syntax error: Illegal ;;; token");
2170 if (!newline_seen)
2171 as_fatal ("Syntax error: More than one bundle stop on a line");
2172 newline_seen = false; /* reset */
2174 /* this is an empty bundle, transform it into an
2175 * empty statement */
2176 tmp_t[0] = ';';
2177 tmp_t[1] = ' ';
2179 tmp_t += 2;
2181 else
2182 break;
2186 /* check for bundle end */
2187 /* we transform these into a special opcode BE */
2188 /* because gas has ';' hardwired as a statement end */
2189 if (t && (t[0] == ';') && (t[1] == ';'))
2191 t[0] = 'B';
2192 t[1] = 'E';
2193 return;
2197 static void
2198 kvx_check_resources (int f)
2200 env.opts.check_resource_usage = f;
2203 /** called before write_object_file */
2204 void
2205 kvx_end (void)
2207 int newflags;
2209 if (!env.params.core_set)
2210 env.params.core = kvx_core_info->elf_core;
2212 /* (pp) the flags must be set at once */
2213 newflags = env.params.core | env.params.abi | env.params.pic_flags;
2215 if (env.params.arch_size == 64)
2216 newflags |= ELF_KVX_ABI_64B_ADDR_BIT;
2218 bfd_set_private_flags (stdoutput, newflags);
2220 cleanup ();
2222 if (inside_bundle && insncnt != 0)
2223 as_bad ("unexpected end-of-file while processing a bundle."
2224 " Please check that ;; is on its own line.");
2227 static void
2228 kvx_type (int start ATTRIBUTE_UNUSED)
2230 char *name;
2231 char c;
2232 int type;
2233 char *typename = NULL;
2234 symbolS *sym;
2235 elf_symbol_type *elfsym;
2237 c = get_symbol_name (&name);
2238 sym = symbol_find_or_make (name);
2239 elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
2240 *input_line_pointer = c;
2242 if (!*S_GET_NAME (sym))
2243 as_bad (_("Missing symbol name in directive"));
2245 SKIP_WHITESPACE ();
2246 if (*input_line_pointer == ',')
2247 ++input_line_pointer;
2250 SKIP_WHITESPACE ();
2251 if (*input_line_pointer == '#'
2252 || *input_line_pointer == '@'
2253 || *input_line_pointer == '"' || *input_line_pointer == '%')
2254 ++input_line_pointer;
2256 /* typename = input_line_pointer; */
2257 /* c = get_symbol_end(); */
2258 c = get_symbol_name (&typename);
2260 type = 0;
2261 if (strcmp (typename, "function") == 0
2262 || strcmp (typename, "STT_FUNC") == 0)
2263 type = BSF_FUNCTION;
2264 else if (strcmp (typename, "object") == 0
2265 || strcmp (typename, "STT_OBJECT") == 0)
2266 type = BSF_OBJECT;
2267 else if (strcmp (typename, "tls_object") == 0
2268 || strcmp (typename, "STT_TLS") == 0)
2269 type = BSF_OBJECT | BSF_THREAD_LOCAL;
2270 else if (strcmp (typename, "common") == 0
2271 || strcmp (typename, "STT_COMMON") == 0)
2272 type = BSF_ELF_COMMON;
2273 else if (strcmp (typename, "gnu_unique_object") == 0
2274 || strcmp (typename, "STB_GNU_UNIQUE") == 0)
2276 elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_unique;
2277 type = BSF_OBJECT | BSF_GNU_UNIQUE;
2279 else if (strcmp (typename, "notype") == 0
2280 || strcmp (typename, "STT_NOTYPE") == 0)
2282 #ifdef md_elf_symbol_type
2283 else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
2285 #endif
2286 else
2287 as_bad (_("unrecognized symbol type \"%s\""), typename);
2289 *input_line_pointer = c;
2291 if (*input_line_pointer == '"')
2292 ++input_line_pointer;
2294 elfsym->symbol.flags |= type;
2295 symbol_get_bfdsym (sym)->flags |= type;
2297 demand_empty_rest_of_line ();
2300 #define ENDPROCEXTENSION "$endproc"
2301 #define MINUSEXPR ".-"
2303 static int proc_endp_status = 0;
2305 static void
2306 kvx_endp (int start ATTRIBUTE_UNUSED)
2308 char c;
2309 char *name;
2311 if (inside_bundle)
2312 as_warn (".endp directive inside a bundle.");
2313 /* function name is optionnal and is ignored */
2314 /* there may be several names separated by commas... */
2315 while (1)
2317 SKIP_WHITESPACE ();
2318 c = get_symbol_name (&name);
2319 (void) restore_line_pointer (c);
2320 SKIP_WHITESPACE ();
2321 if (*input_line_pointer != ',')
2322 break;
2323 ++input_line_pointer;
2325 demand_empty_rest_of_line ();
2327 if (!proc_endp_status)
2329 as_warn (".endp directive doesn't follow .proc -- ignoring ");
2330 return;
2333 proc_endp_status = 0;
2335 /* TB begin : add BSF_FUNCTION attribute to last_proc_sym symbol */
2336 if (size_type_function)
2338 if (!last_proc_sym)
2340 as_bad ("Cannot set function attributes (bad symbol)");
2341 return;
2344 /* last_proc_sym->symbol.flags |= BSF_FUNCTION; */
2345 symbol_get_bfdsym (last_proc_sym)->flags |= BSF_FUNCTION;
2346 /* Add .size funcname,.-funcname in order to add size
2347 * attribute to the current function */
2349 const int newdirective_sz =
2350 strlen (S_GET_NAME (last_proc_sym)) + strlen (MINUSEXPR) + 1;
2351 char *newdirective = malloc (newdirective_sz);
2352 char *savep = input_line_pointer;
2353 expressionS exp;
2355 memset (newdirective, 0, newdirective_sz);
2357 /* BUILD :".-funcname" expression */
2358 strcat (newdirective, MINUSEXPR);
2359 strcat (newdirective, S_GET_NAME (last_proc_sym));
2360 input_line_pointer = newdirective;
2361 expression (&exp);
2363 if (exp.X_op == O_constant)
2365 S_SET_SIZE (last_proc_sym, exp.X_add_number);
2366 if (symbol_get_obj (last_proc_sym)->size)
2368 xfree (symbol_get_obj (last_proc_sym)->size);
2369 symbol_get_obj (last_proc_sym)->size = NULL;
2372 else
2374 symbol_get_obj (last_proc_sym)->size =
2375 (expressionS *) xmalloc (sizeof (expressionS));
2376 *symbol_get_obj (last_proc_sym)->size = exp;
2379 /* just restore the real input pointer */
2380 input_line_pointer = savep;
2381 free (newdirective);
2384 /* TB end */
2386 last_proc_sym = NULL;
2389 static void
2390 kvx_proc (int start ATTRIBUTE_UNUSED)
2392 char c;
2393 char *name;
2394 /* there may be several names separated by commas... */
2395 while (1)
2397 SKIP_WHITESPACE ();
2398 c = get_symbol_name (&name);
2399 (void) restore_line_pointer (c);
2401 SKIP_WHITESPACE ();
2402 if (*input_line_pointer != ',')
2403 break;
2404 ++input_line_pointer;
2406 demand_empty_rest_of_line ();
2408 if (proc_endp_status)
2410 as_warn (".proc follows .proc -- ignoring");
2411 return;
2414 proc_endp_status = 1;
2416 /* this code emit a global symbol to mark the end of each function */
2417 /* the symbol emitted has a name formed by the original function name */
2418 /* concatenated with $endproc so if _foo is a function name the symbol */
2419 /* marking the end of it is _foo$endproc */
2420 /* It is also required for generation of .size directive in kvx_endp() */
2422 if (size_type_function)
2423 update_last_proc_sym = 1;
2427 kvx_force_reloc (fixS * fixP)
2429 symbolS *sym;
2430 asection *symsec;
2432 if (generic_force_reloc (fixP))
2433 return 1;
2435 switch (fixP->fx_r_type)
2437 case BFD_RELOC_KVX_32_GOTOFF:
2438 case BFD_RELOC_KVX_S37_GOTOFF_UP27:
2439 case BFD_RELOC_KVX_S37_GOTOFF_LO10:
2441 case BFD_RELOC_KVX_64_GOTOFF:
2442 case BFD_RELOC_KVX_S43_GOTOFF_UP27:
2443 case BFD_RELOC_KVX_S43_GOTOFF_LO10:
2444 case BFD_RELOC_KVX_S43_GOTOFF_EX6:
2446 case BFD_RELOC_KVX_32_GOT:
2447 case BFD_RELOC_KVX_64_GOT:
2448 case BFD_RELOC_KVX_S37_GOT_UP27:
2449 case BFD_RELOC_KVX_S37_GOT_LO10:
2451 case BFD_RELOC_KVX_GLOB_DAT:
2452 return 1;
2453 default:
2454 return 0;
2457 sym = fixP->fx_addsy;
2458 if (sym)
2460 symsec = S_GET_SEGMENT (sym);
2461 /* if (bfd_is_abs_section (symsec)) return 0; */
2462 if (!SEG_NORMAL (symsec))
2463 return 0;
2465 return 1;
2469 kvx_force_reloc_sub_same (fixS * fixP, segT sec)
2471 symbolS *sym;
2472 asection *symsec;
2473 const char *sec_name = NULL;
2475 if (generic_force_reloc (fixP))
2476 return 1;
2478 switch (fixP->fx_r_type)
2480 case BFD_RELOC_KVX_32_GOTOFF:
2481 case BFD_RELOC_KVX_S37_GOTOFF_UP27:
2482 case BFD_RELOC_KVX_S37_GOTOFF_LO10:
2484 case BFD_RELOC_KVX_64_GOTOFF:
2485 case BFD_RELOC_KVX_S43_GOTOFF_UP27:
2486 case BFD_RELOC_KVX_S43_GOTOFF_LO10:
2487 case BFD_RELOC_KVX_S43_GOTOFF_EX6:
2489 case BFD_RELOC_KVX_32_GOT:
2490 case BFD_RELOC_KVX_64_GOT:
2491 case BFD_RELOC_KVX_S37_GOT_UP27:
2492 case BFD_RELOC_KVX_S37_GOT_LO10:
2494 case BFD_RELOC_KVX_S37_LO10:
2495 case BFD_RELOC_KVX_S37_UP27:
2497 case BFD_RELOC_KVX_GLOB_DAT:
2498 return 1;
2500 default:
2501 return 0;
2504 sym = fixP->fx_addsy;
2505 if (sym)
2507 symsec = S_GET_SEGMENT (sym);
2508 /* if (bfd_is_abs_section (symsec)) return 0; */
2509 if (!SEG_NORMAL (symsec))
2510 return 0;
2513 * for .debug_arrange, .debug_frame, .eh_frame sections, containing
2514 * expressions of the form "sym2 - sym1 + addend", solve them even when
2515 * --emit-all-relocs is set. Otherwise, a relocation on two symbols
2516 * is necessary and fails at elf level. Binopt should not be impacted by
2517 * the resolution of this relocatable expression on symbols inside a
2518 * function.
2520 sec_name = segment_name (sec);
2521 if ((strcmp (sec_name, ".eh_frame") == 0) ||
2522 (strcmp (sec_name, ".except_table") == 0) ||
2523 (strncmp (sec_name, ".debug_", sizeof (".debug_")) == 0))
2524 return 0;
2526 return 1;
2529 /* Implement HANDLE_ALIGN. */
2531 static void
2532 kvx_make_nops (char *buf, bfd_vma bytes)
2534 bfd_vma i = 0;
2535 unsigned int j;
2537 static unsigned int nop_single = 0;
2539 if (!nop_single)
2541 const struct kvxopc *opcode =
2542 (struct kvxopc *) str_hash_find (env.opcode_hash, "nop");
2544 if (opcode == NULL)
2545 as_fatal
2546 ("internal error: could not find opcode for 'nop' during padding");
2548 nop_single = opcode->codewords[0].opcode;
2551 /* KVX instructions are always 4-bytes aligned. If we are at a position */
2552 /* that is not 4 bytes aligned, it means this is not part of an instruction, */
2553 /* so it is safe to use a zero byte for padding. */
2555 for (j = bytes % 4; j > 0; j--)
2556 buf[i++] = 0;
2558 for (j = 0; j < (bytes - i); j += 4)
2560 unsigned nop = nop_single;
2562 // nop has bundle end only if #4 nop or last padding nop.
2563 // Sets the parallel bit when neither conditions are matched.
2564 // 4*4 = biggest nop bundle we can get
2565 // 12 = offset when writting the last nop possible in a 4 nops bundle
2566 // bytes-i-4 = offset for the last 4-words in the padding
2567 if (j % (4 * 4) != 12 && j != (bytes - i - 4))
2568 nop |= PARALLEL_BIT;
2570 memcpy (buf + i + j, &nop, sizeof (nop));
2574 /* Pads code section with bundle of nops when possible, 0 if not. */
2575 void
2576 kvx_handle_align (fragS *fragP)
2578 switch (fragP->fr_type)
2580 case rs_align_code:
2582 bfd_signed_vma bytes = (fragP->fr_next->fr_address
2583 - fragP->fr_address - fragP->fr_fix);
2584 char *p = fragP->fr_literal + fragP->fr_fix;
2586 if (bytes <= 0)
2587 break;
2589 /* Insert zeros or nops to get 4 byte alignment. */
2590 kvx_make_nops (p, bytes);
2591 fragP->fr_fix += bytes;
2593 break;
2595 default:
2596 break;
2600 * This is just used for debugging
2603 ATTRIBUTE_UNUSED
2604 static void
2605 print_operand (expressionS * e, FILE * out)
2607 if (e)
2609 switch (e->X_op)
2611 case O_register:
2612 fprintf (out, "%s", kvx_registers[e->X_add_number].name);
2613 break;
2615 case O_constant:
2616 if (e->X_add_symbol)
2618 if (e->X_add_number)
2619 fprintf (out, "(%s + %d)", S_GET_NAME (e->X_add_symbol),
2620 (int) e->X_add_number);
2621 else
2622 fprintf (out, "%s", S_GET_NAME (e->X_add_symbol));
2624 else
2625 fprintf (out, "%d", (int) e->X_add_number);
2626 break;
2628 case O_symbol:
2629 if (e->X_add_symbol)
2631 if (e->X_add_number)
2632 fprintf (out, "(%s + %d)", S_GET_NAME (e->X_add_symbol),
2633 (int) e->X_add_number);
2634 else
2635 fprintf (out, "%s", S_GET_NAME (e->X_add_symbol));
2637 else
2638 fprintf (out, "%d", (int) e->X_add_number);
2639 break;
2641 default:
2642 fprintf (out, "o,ptype-%d", e->X_op);
2647 void
2648 kvx_cfi_frame_initial_instructions (void)
2650 cfi_add_CFA_def_cfa (KVX_SP_REGNO, 0);
2654 kvx_regname_to_dw2regnum (const char *regname)
2656 unsigned int regnum = -1;
2657 const char *p;
2658 char *q;
2660 if (regname[0] == 'r')
2662 p = regname + 1;
2663 regnum = strtoul (p, &q, 10);
2664 if (p == q || *q || regnum >= 64)
2665 return -1;
2667 return regnum;