tc-kvx.c revision 1.1.1.3 1 /* tc-kvx.c -- Assemble for the KVX ISA
2
3 Copyright (C) 2009-2026 Free Software Foundation, Inc.
4 Contributed by Kalray SA.
5
6 This file is part of GAS.
7
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.
12
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.
17
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/>. */
21
22 #include "as.h"
23 #include "obstack.h"
24 #include "subsegs.h"
25 #include "tc-kvx.h"
26 #include "libiberty.h"
27
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #ifdef OBJ_ELF
35 #include "elf/kvx.h"
36 #include "dwarf2dbg.h"
37 #include "dw2gencfi.h"
38 #endif
39
40 #define D(args...) do { if(debug) fprintf(args); } while(0)
41
42 static void supported_cores (char buf[], size_t buflen);
43
44 #define NELEMS(a) ((int) (sizeof (a)/sizeof ((a)[0])))
45
46 #define STREQ(x,y) !strcmp(((x) ? (x) : ""), ((y) ? (y) : ""))
47 #define STRNEQ(x,y,n) !strncmp(((x) ? (x) : ""), ((y) ? (y) : ""),(n))
48
49 /* The PARALLEL_BIT is set to 0 when an instruction is the last of a bundle. */
50 #define PARALLEL_BIT (1u << 31)
51
52 /*TB begin*/
53 int size_type_function = 1;
54 /*TB end */
55
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
66 },
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
76 }
77 };
78
79 /* This string should contain position in string where error occured. */
80
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;
89
90 /***********************************************/
91 /* Generic Globals for GAS */
92 /***********************************************/
93
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;
101
102 /***********************************************/
103 /* Local Types */
104 /***********************************************/
105
106 /* a fix up record */
107
108 struct kvx_fixup
109 {
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;
116 };
117
118 /* a single assembled instruction record */
119 /* may include immediate extension words */
120 struct kvxinsn
121 {
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];
140 };
141
142 typedef void (*print_insn_t) (struct kvxopc * op);
143 static print_insn_t print_insn = NULL;
144
145 /* Set to TRUE when we assemble instructions. */
146 static bool assembling_insn = false;
147
148 #define NOIMMX -1
149
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;
155
156 static void
157 incr_immxcnt (void)
158 {
159 immxcnt++;
160 if (immxcnt >= KVXMAXBUNDLEWORDS)
161 as_bad ("Max immx number exceeded: %d", immxcnt);
162 }
163
164 static void set_byte_counter (asection * sec, int value);
165 static void
166 set_byte_counter (asection * sec, int value)
167 {
168 sec->target_index = value;
169 }
170
171 static int get_byte_counter (asection * sec);
172 int
173 get_byte_counter (asection * sec)
174 {
175 return sec->target_index;
176 }
177
178 const char *
179 kvx_target_format (void)
180 {
181 return env.params.arch_size == 64 ? "elf64-kvx" : "elf32-kvx";
182 }
183
184 /****************************************************/
185 /* ASSEMBLER Pseudo-ops. Some of this just */
186 /* extends the default definitions */
187 /* others are KVX specific */
188 /****************************************************/
189
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);
194
195 const pseudo_typeS md_pseudo_table[] = {
196 /* override default 2-bytes */
197 { "word", cons, 4 },
198
199 /* KVX specific */
200 { "dword", cons, 8 },
201
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 },
205
206 { "checkresources", kvx_check_resources, 1 },
207 { "nocheckresources", kvx_check_resources, 0 },
208
209 { "proc", kvx_proc, 1 },
210 { "endp", kvx_endp, 0 },
211
212 { "type", kvx_type, 0 },
213
214 #ifdef OBJ_ELF
215 { "file", dwarf2_directive_file, 0 },
216 { "loc", dwarf2_directive_loc, 0 },
217 #endif
218 { NULL, 0, 0 }
219 };
220
221
222 static int inside_bundle = 0;
223
224 /* Stores the labels inside bundles (typically debug labels) that need
225 to be postponed to the next bundle. */
226 struct label_fix
227 {
228 struct label_fix *next;
229 symbolS *sym;
230 } *label_fixes = 0;
231
232 /*****************************************************/
233 /* OPTIONS PROCESSING */
234 /*****************************************************/
235
236 const char md_shortopts[] = "hV"; /* catted to std short options */
237
238 /* added to std long options */
239
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)
256
257 const 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 }
274 };
275
276 const size_t md_longopts_size = sizeof (md_longopts);
277
278 int
279 md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
280 {
281 int find_core = 0;
282
283 switch (c)
284 {
285 case 'h':
286 md_show_usage (stdout);
287 exit (EXIT_SUCCESS);
288 break;
289
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))
299 {
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];
304
305 find_core = 1;
306 break;
307 }
308 if (!find_core)
309 {
310 char buf[100];
311 supported_cores (buf, sizeof (buf));
312 as_fatal ("Specified arch not supported [%s]", buf);
313 }
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;
356
357 default:
358 return 0;
359 }
360 return 1;
361 }
362
363 void
364 md_show_usage (FILE * stream)
365 {
366 char buf[100];
367 supported_cores (buf, sizeof (buf));
368
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);
375 }
376
377 /**************************************************/
378 /* UTILITIES */
379 /**************************************************/
380
381 /*
382 * Read a value from to the object file
383 */
384
385 static valueT md_chars_to_number (char *buf, int n);
386 valueT
387 md_chars_to_number (char *buf, int n)
388 {
389 valueT val = 0;
390
391 if (n > (int) sizeof (val) || n <= 0)
392 abort ();
393
394 while (n--)
395 {
396 val <<= 8;
397 val |= (buf[n] & 0xff);
398 }
399
400 return val;
401 }
402
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)
407 {
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;
413 }
414
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)
419 {
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];
427
428 return NULL;
429 }
430
431 static void
432 supported_cores (char buf[], size_t buflen)
433 {
434 buf[0] = '\0';
435 for (int i = 0; i < KVXNUMCORES; i++)
436 {
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)
441 {
442 strcat (buf, "|");
443 strcat (buf, kvx_core_info_table[i]->name);
444 }
445 }
446 }
447
448 /***************************************************/
449 /* ASSEMBLE AN INSTRUCTION */
450 /***************************************************/
451
452 /*
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.
456 */
457 static int
458 insert_operand (struct kvxinsn *insn, struct kvx_operand *opdef,
459 struct token_list *tok)
460 {
461 uint64_t op = 0;
462 struct kvx_bitfield *bfields = opdef->bfield;
463 int bf_nb = opdef->bitfields;
464 int immx_ready = 0;
465
466 if (opdef->width == 0)
467 return 0;
468
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)
476
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)
490
491 #define chk_imm(core_, imm_) \
492 (env.params.core == ELF_KVX_CORE_## core_ && opdef->type == (imm_))
493
494 /* try to resolve the value */
495
496 switch (tok->category)
497 {
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:
509 {
510 char *ilp_save = input_line_pointer;
511 input_line_pointer = tok->tok;
512 expressionS exp;
513 expression (&exp);
514 input_line_pointer = ilp_save;
515
516 /* We are dealing with a pseudo-function. */
517 if (tok->tok[0] == '@')
518 {
519 if (insn->nfixups == 0)
520 {
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) */
529
530 /* Beware that immxbuf must be filled in the same order as relocs should be emitted. */
531
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)
535 {
536 add_fixup (insn, pf->pseudo_relocs.reloc_lo10, reloc_arg);
537
538 insn->immx0 = immxcnt;
539 add_immx (insn, 0, pf->pseudo_relocs.reloc_up27,
540 reloc_arg, 1, 1);
541 immx_ready = 1;
542 }
543 else if (pf->pseudo_relocs.reloc_type == S32_LO5_UP27)
544 {
545 add_fixup (insn, pf->pseudo_relocs.reloc_lo5, reloc_arg);
546
547 insn->immx0 = immxcnt;
548 add_immx (insn, 0, pf->pseudo_relocs.reloc_up27,
549 reloc_arg, 1, 1);
550 immx_ready = 1;
551 }
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");
556
557 if (pf->pseudo_relocs.reloc_type == S64_LO10_UP27_EX27)
558 {
559 insn->immx1 = immxcnt;
560 add_immx (insn, 0, pf->pseudo_relocs.reloc_ex, reloc_arg,
561 1, 1);
562 }
563 else if (pf->pseudo_relocs.reloc_type == S43_LO10_UP27_EX6)
564 add_fixup (insn, pf->pseudo_relocs.reloc_ex, reloc_arg);
565 }
566 }
567 else
568 {
569 if (exp.X_op == O_constant)
570 {
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;
576 }
577 else if (exp.X_op == O_subtract)
578 as_fatal ("O_subtract not supported.");
579 else
580 {
581
582 /* This is a symbol which needs a relocation. */
583 if (insn->nfixups == 0)
584 {
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))
596 {
597 add_fixup (insn, BFD_RELOC_KVX_S32_LO5, exp);
598
599 insn->immx0 = immxcnt;
600 add_immx (insn, 0, BFD_RELOC_KVX_S32_UP27, exp, 1, 1);
601
602 immx_ready = 1;
603 }
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))
611 {
612 add_fixup (insn, BFD_RELOC_KVX_S37_LO10, exp);
613
614 insn->immx0 = immxcnt;
615 add_immx (insn, 0, BFD_RELOC_KVX_S37_UP27, exp, 1, 1);
616
617 immx_ready = 1;
618 }
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))
622 {
623 add_fixup (insn, BFD_RELOC_KVX_S43_LO10, exp);
624 add_fixup (insn, BFD_RELOC_KVX_S43_EX6, exp);
625
626 insn->immx0 = immxcnt;
627 add_immx (insn, insn->words[1],
628 BFD_RELOC_KVX_S43_UP27, exp, 1, 1);
629
630 immx_ready = 1;
631 }
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))
635 {
636 add_fixup (insn, BFD_RELOC_KVX_S64_LO10, exp);
637
638 insn->immx0 = immxcnt;
639 add_immx (insn, insn->words[1],
640 BFD_RELOC_KVX_S64_UP27, exp, 1, 1);
641
642 insn->immx1 = immxcnt;
643 add_immx (insn, insn->words[2],
644 BFD_RELOC_KVX_S64_EX27, exp, 1, 1);
645
646 immx_ready = 1;
647 }
648 else
649 as_fatal ("don't know how to generate a fixup record");
650 return immx_ready;
651 }
652 else
653 as_fatal ("No room for fixup ");
654 }
655 }
656 }
657 break;
658 default:
659 break;
660 }
661
662 for (int bf_idx = 0; bf_idx < bf_nb; bf_idx++)
663 {
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;
672 }
673
674 return immx_ready;
675
676 #undef chk_imm
677 #undef add_immx
678 #undef add_fixup
679 }
680
681 /*
682 * Given a set of operands and a matching instruction,
683 * assemble it
684 *
685 */
686 static void
687 assemble_insn (const struct kvxopc * opcode, struct token_list *tok, struct kvxinsn *insn)
688 {
689 unsigned immx_ready = 0;
690
691 memset (insn, 0, sizeof (*insn));
692 insn->opdef = opcode;
693 for (int i = 0; i < opcode->wordcount; i++)
694 {
695 insn->words[i] = opcode->codewords[i].opcode;
696 insn->len += 1;
697 }
698
699 insn->immx0 = NOIMMX;
700 insn->immx1 = NOIMMX;
701
702 struct token_list *tok_ = tok;
703 struct kvx_operand *const *format = opcode->format;
704
705 while (tok_)
706 {
707 int ret = insert_operand (insn, *format, tok_);
708 immx_ready |= ret;
709 while ((tok_ = tok_->next) && tok_->category == CAT_SEPARATOR);
710 format++;
711 }
712
713 // Handle immx if insert_operand did not already take care of that
714 if (!immx_ready)
715 {
716 for (int i = 0; i < opcode->wordcount; i++)
717 {
718 if (opcode->codewords[i].flags & kvxOPCODE_FLAG_IMMX0)
719 {
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 ();
726 }
727 if (opcode->codewords[i].flags & kvxOPCODE_FLAG_IMMX1)
728 {
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 ();
735 }
736 }
737 }
738 }
739
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.
743 *
744 * Only handles main syllables of bundle. Immediate extensions are
745 * handled by insert_operand.
746 */
747 static void
748 emit_insn (struct kvxinsn * insn, int insn_pos, int stopflag)
749 {
750 char *f;
751 unsigned int image;
752
753 /* if we are listing, attach frag to previous line. */
754 if (listing)
755 listing_prev_line ();
756
757 /* Update text size for lane parity checking. */
758 set_byte_counter (now_seg, (get_byte_counter (now_seg) + (insn->len * 4)));
759
760 /* allocate space in the fragment. */
761 f = frag_more (insn->len * 4);
762
763 /* spit out bits. */
764 for (int i = 0; i < insn->len; i++)
765 {
766 image = insn->words[i];
767
768 /* Handle bundle parallel bit. */ ;
769 if ((i == insn->len - 1) && stopflag)
770 image &= ~PARALLEL_BIT;
771 else
772 image |= PARALLEL_BIT;
773
774 /* Emit the instruction image. */
775 md_number_to_chars (f + (i * 4), image, 4);
776 }
777
778 /* generate fixup records */
779
780 for (int i = 0; i < insn->nfixups; i++)
781 {
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;
788
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.
792 */
793 assert (!(insn_pos == -1 && pcrel));
794 if (pcrel && insn_pos > 0)
795 insn->fixup[i].exp.X_add_number += insn_pos * 4;
796
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);
804 /*
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
811 */
812 fixup->fx_no_overflow = 1;
813 }
814 }
815
816
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)
823 {
824 /* enum pseudo_type pseudo_type; */
825 /* char *name = NULL; */
826 size_t len;
827 int ch, i;
828
829 switch (*input_line_pointer)
830 {
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)
837 {
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]))
842 {
843 input_line_pointer += len;
844 break;
845 }
846 }
847 SKIP_WHITESPACE ();
848 if (*input_line_pointer != '(')
849 {
850 as_bad ("Expected '('");
851 goto err;
852 }
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++ != ')')
858 {
859 as_bad ("Missing ')'");
860 goto err;
861 }
862 if (!kvx_core_info->pseudo_funcs[i].pseudo_relocs.has_no_arg)
863 {
864 if (e->X_op != O_symbol)
865 as_fatal ("Illegal combination of relocation functions");
866 }
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;
872
873 default:
874 break;
875 }
876 return;
877
878 err:
879 ignore_rest_of_line ();
880 }
881
882 /*
883 * Return the Bundling type for an insn.
884 */
885 static int
886 find_bundling (const struct kvxinsn * insn)
887 {
888 return insn->opdef->bundling;
889 }
890
891 static int
892 find_reservation (const struct kvxinsn * insn)
893 {
894 return insn->opdef->reservation;
895 }
896
897 static struct kvxopc *
898 assemble_tokens (struct token_list *tok_list)
899 {
900 assert (tok_list != NULL);
901 struct token_list *toks = tok_list;
902
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.");
907
908 /* TODO: Merge */
909 struct kvxinsn *insn;
910 insn = insbuf + insncnt;
911
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;
915
916 opcode = toks->tok;
917 toks = toks->next;
918
919 while (toks && toks->category == CAT_SEPARATOR)
920 toks = toks->next;
921
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;
925
926 struct token_list *toks_ = toks;
927
928 while (!format && format_tbl && STREQ (opcode, format_tbl->as_op))
929 {
930 for (int i = 0 ; toks_ && format_tbl->format[i]
931 && toks_->class_id == format_tbl->format[i]->type ;)
932 {
933 toks_ = toks_->next;
934 while (toks_ && toks_->category == CAT_SEPARATOR)
935 toks_ = toks_->next;
936 i += 1;
937 }
938
939 if (!toks_)
940 format = format_tbl;
941 else
942 {
943 toks_ = toks;
944 format_tbl++;
945 }
946 }
947
948 assert (format != NULL);
949
950 assemble_insn (format, toks, insn);
951 insncnt++;
952
953 return NULL;
954 }
955
956 /*
957 * Write in buf at most buf_size.
958 * Returns the number of writen characters.
959 */
960 static int ATTRIBUTE_UNUSED
961 insn_syntax (struct kvxopc * op, char *buf, int buf_size)
962 {
963 int chars = snprintf (buf, buf_size, "%s ", op->as_op);
964 const char *fmtp = op->fmtstring;
965 char ch = 0;
966
967 for (int i = 0; op->format[i]; i++)
968 {
969 int type = op->format[i]->type;
970 const char *type_name = TOKEN_NAME (type);
971 int offset = 0;
972
973 for (int j = 0 ; type_name[j] ; ++j)
974 if (type_name[j] == '_')
975 offset = j + 1;
976
977 /* Print characters in the format string up to the following * % or nul. */
978 while ((chars < buf_size) && (ch = *fmtp) && ch != '%')
979 {
980 buf[chars++] = ch;
981 fmtp++;
982 }
983
984 /* Skip past %s */
985 if (ch == '%')
986 {
987 ch = *fmtp++;
988 fmtp++;
989 }
990
991 chars += snprintf (&buf[chars], buf_size - chars, "%s", type_name + offset);
992 }
993
994 /* Print trailing characters in the format string, if any */
995 while ((chars < buf_size) && (ch = *fmtp))
996 {
997 buf[chars++] = ch;
998 fmtp++;
999 }
1000
1001 if (chars < buf_size)
1002 buf[chars++] = '\0';
1003 else
1004 buf[buf_size - 1] = '\0';
1005
1006 return chars;
1007 }
1008
1009 #define ASM_CHARS_MAX (71)
1010
1011 static void
1012 kvx_print_insn (struct kvxopc * op ATTRIBUTE_UNUSED)
1013 {
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 = "";
1018
1019 for (int i = chars - 1; i < ASM_CHARS_MAX - 1; i++)
1020 asm_str[i] = '-';
1021
1022 /* This is a hack which works because the Bundling is the same for all cores
1023 for now. */
1024 switch (op->bundling)
1025 {
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);
1065 }
1066
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.");
1076
1077 printf ("%s | syllables: %d | type: %s | mode: %s bits\n", asm_str,
1078 op->wordcount, insn_type, insn_mode);
1079 }
1080
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)
1085 {
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);
1095 }
1096
1097 static void
1098 kvx_reorder_bundle (struct kvxinsn *bundle_insn[], int bundle_insncnt)
1099 {
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;
1104
1105 memset (issued, 0, sizeof (issued));
1106 for (int i = 0; i < bundle_insncnt; i++)
1107 {
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 (find_bundling (kvxinsn))
1113 {
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])
1135 {
1136 issued[EXU_ALU0] = kvxinsn;
1137 tag = Modifier_kv3_v1_exunum_ALU0;
1138 exu = EXU_ALU0;
1139 }
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])
1147 {
1148 issued[EXU_ALU0] = kvxinsn;
1149 tag = Modifier_kv3_v1_exunum_ALU0;
1150 exu = EXU_ALU0;
1151 }
1152 else if (!issued[EXU_ALU1])
1153 {
1154 issued[EXU_ALU1] = kvxinsn;
1155 tag = Modifier_kv3_v1_exunum_ALU1;
1156 exu = EXU_ALU1;
1157 }
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])
1165 {
1166 issued[EXU_MAU] = kvxinsn;
1167 tag = Modifier_kv3_v1_exunum_MAU;
1168 exu = EXU_MAU;
1169 }
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])
1177 {
1178 issued[EXU_LSU] = kvxinsn;
1179 tag = Modifier_kv3_v1_exunum_LSU;
1180 exu = EXU_LSU;
1181 }
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])
1190 {
1191 issued[EXU_ALU0] = kvxinsn;
1192 tag = Modifier_kv3_v1_exunum_ALU0;
1193 exu = EXU_ALU0;
1194 }
1195 else if (!issued[EXU_ALU1])
1196 {
1197 issued[EXU_ALU1] = kvxinsn;
1198 tag = Modifier_kv3_v1_exunum_ALU1;
1199 exu = EXU_ALU1;
1200 }
1201 else if (!issued[EXU_MAU])
1202 {
1203 issued[EXU_MAU] = kvxinsn;
1204 tag = Modifier_kv3_v1_exunum_MAU;
1205 exu = EXU_MAU;
1206 }
1207 else if (!issued[EXU_LSU])
1208 {
1209 issued[EXU_LSU] = kvxinsn;
1210 tag = Modifier_kv3_v1_exunum_LSU;
1211 exu = EXU_LSU;
1212 }
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));
1218 }
1219 if (tag >= 0)
1220 {
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);
1225 }
1226 }
1227
1228 int i;
1229 for (i = 0, exu = 0; exu < EXU__; exu++)
1230 {
1231 if (issued[exu])
1232 bundle_insn[i++] = issued[exu];
1233 }
1234 if (i != bundle_insncnt)
1235 as_fatal ("Mismatch between bundle and issued instructions");
1236 }
1237
1238 static void
1239 kvx_check_resource_usage (struct kvxinsn **bundle_insn, int bundle_insncnt)
1240 {
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));
1247
1248 for (int i = 0; i < bundle_insncnt; i++)
1249 {
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];
1255 }
1256
1257 for (int i = 0; i < kvx_core_info->reservation_table_lines; i++)
1258 {
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])
1261 {
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]);
1266 }
1267 }
1268 free (resources_used);
1269 }
1270
1271 /*
1272 * Called by core to assemble a single line
1273 */
1274 void
1275 md_assemble (char *line)
1276 {
1277 char *line_cursor = line;
1278
1279 if (get_byte_counter (now_seg) & 3)
1280 as_fatal ("code segment not word aligned in md_assemble");
1281
1282 while (is_whitespace (line_cursor[0]))
1283 line_cursor++;
1284
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)
1291 {
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;
1299
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++)
1305 {
1306 insbuf[j].order = j;
1307 bundle_insn[bundle_insncnt++] = &insbuf[j];
1308 syllables += insbuf[j].len;
1309 }
1310
1311 if (syllables + immxcnt > KVXMAXBUNDLEWORDS)
1312 as_fatal ("Bundle has too many syllables : %d instead of %d",
1313 syllables + immxcnt, KVXMAXBUNDLEWORDS);
1314
1315 if (env.opts.check_resource_usage)
1316 kvx_check_resource_usage (bundle_insn, bundle_insncnt);
1317
1318 /* Reorder and check the bundle. */
1319 if (!env.opts.generate_illegal_code)
1320 {
1321 /* Sort the bundle_insn in order of bundling. */
1322 qsort (bundle_insn, bundle_insncnt, sizeof (struct kvxinsn *), kvxinsn_compare);
1323
1324 kvx_reorder_bundle (bundle_insn, bundle_insncnt);
1325 }
1326
1327 /* The ordering of the insns has been set correctly in bundle_insn. */
1328 for (int i = 0; i < bundle_insncnt; i++)
1329 {
1330 emit_insn (bundle_insn[i], i, (i == bundle_insncnt + immxcnt - 1));
1331 bundle_insn[i]->written = 1;
1332 }
1333
1334 // Emit immx, ordering them by EXU tags, 0 to 3
1335 entry = 0;
1336 for (int tag = 0; tag < 4; tag++)
1337 {
1338 for (int j = 0; j < immxcnt; j++)
1339 {
1340 #define kv3_exunum2_fld(x) (int)(((unsigned int)(x) >> 27) & 0x3)
1341 if (kv3_exunum2_fld (immxbuf[j].words[0]) == tag)
1342 {
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++;
1348 }
1349 #undef kv3_exunum2_fld
1350 }
1351 }
1352 if (entry != immxcnt)
1353 as_fatal ("%d IMMX produced, only %d emitted.", immxcnt, entry);
1354
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)
1363 {
1364 struct label_fix *fix = label_fixes;
1365
1366 label_fixes = fix->next;
1367 symbol_set_value_now (fix->sym);
1368 free (fix);
1369 }
1370
1371 insncnt = 0;
1372 immxcnt = 0;
1373 memset (immxbuf, 0, sizeof (immxbuf));
1374
1375 return;
1376 }
1377
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);
1383
1384 if (!tok_lst)
1385 return;
1386
1387 /* Skip opcode */
1388 line_cursor += strlen (tok_lst->tok);
1389
1390 assembling_insn = true;
1391
1392 inside_bundle = 1;
1393 assemble_tokens (tok_lst);
1394 free_token_list (tok_lst);
1395 assembling_insn = false;
1396 }
1397
1398 static void
1399 kvx_set_cpu (void)
1400 {
1401 if (!kvx_core_info)
1402 kvx_core_info = &kvx_kv3_v1_core_info;
1403
1404 if (!kvx_registers)
1405 kvx_registers = kvx_kv3_v1_registers;
1406
1407 if (!kvx_regfiles)
1408 kvx_regfiles = kvx_kv3_v1_regfiles;
1409
1410 if (!kvx_modifiers)
1411 kvx_modifiers = kvx_kv3_v1_modifiers;
1412
1413 if (env.params.core == -1)
1414 env.params.core = kvx_core_info->elf_core;
1415
1416 int kvx_bfd_mach;
1417 print_insn = kvx_print_insn;
1418
1419 switch (kvx_core_info->elf_core)
1420 {
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);
1435 }
1436
1437 if (!bfd_set_arch_mach (stdoutput, TARGET_ARCH, kvx_bfd_mach))
1438 as_warn (_("could not set architecture and machine"));
1439 }
1440
1441 static int
1442 kvxop_compar (const void *a, const void *b)
1443 {
1444 const struct kvxopc *opa = a;
1445 const struct kvxopc *opb = b;
1446 int res = strcmp (opa->as_op, opb->as_op);
1447
1448 if (res)
1449 return res;
1450 else
1451 {
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;
1456 }
1457 }
1458
1459 /***************************************************/
1460 /* INITIALIZE ASSEMBLER */
1461 /***************************************************/
1462
1463 static int
1464 print_hash (void **slot, void *arg ATTRIBUTE_UNUSED)
1465 {
1466 string_tuple_t *tuple = *((string_tuple_t **) slot);
1467 printf ("%s\n", tuple->key);
1468 return 1;
1469 }
1470
1471 static void
1472 declare_register (const char *name, int number)
1473 {
1474 symbolS *regS = symbol_create (name, reg_section,
1475 &zero_address_frag, number);
1476
1477 if (str_hash_insert (env.reg_hash, S_GET_NAME (regS), regS, 0) != NULL)
1478 as_fatal (_("duplicate %s"), name);
1479 }
1480
1481 void
1482 md_begin ()
1483 {
1484 kvx_set_cpu ();
1485
1486 /*
1487 * Declare register names with symbols
1488 */
1489
1490 env.reg_hash = str_htab_create ();
1491
1492 for (int i = 0; i < kvx_regfiles[KVX_REGFILE_REGISTERS]; i++)
1493 declare_register (kvx_registers[i].name, kvx_registers[i].id);
1494
1495 /* Sort optab, so that identical mnemonics appear consecutively */
1496 {
1497 int nel;
1498 for (nel = 0; !STREQ ("", kvx_core_info->optab[nel].as_op); nel++)
1499 ;
1500 qsort (kvx_core_info->optab, nel, sizeof (kvx_core_info->optab[0]),
1501 kvxop_compar);
1502 }
1503
1504 /* The '?' is an operand separator */
1505 lex_type['?'] = 0;
1506
1507 /* Create the opcode hash table */
1508 /* Each name should appear only once */
1509
1510 env.opcode_hash = str_htab_create ();
1511 env.reloc_hash = str_htab_create ();
1512
1513 {
1514 struct kvxopc *op;
1515 const char *name = 0;
1516 for (op = kvx_core_info->optab; !(STREQ ("", op->as_op)); op++)
1517 {
1518 /* enter in hash table if this is a new name */
1519 if (!(STREQ (name, op->as_op)))
1520 {
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);
1524 }
1525
1526
1527 for (int i = 0 ; op->format[i] ; ++i)
1528 {
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);
1535 }
1536 }
1537 }
1538
1539 if (env.opts.dump_table)
1540 {
1541 htab_traverse (env.opcode_hash, print_hash, NULL);
1542 exit (0);
1543 }
1544
1545 if (env.opts.dump_insn)
1546 {
1547 for (struct kvxopc *op = kvx_core_info->optab; !(STREQ ("", op->as_op)); op++)
1548 print_insn (op);
1549 exit (0);
1550 }
1551
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
1556 */
1557
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);
1562
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);
1576
1577 for (int i = 0; i < kvx_core_info->nb_pseudo_funcs; ++i)
1578 {
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);
1609
1610 kvx_core_info->pseudo_funcs[i].sym = sym;
1611 }
1612 }
1613
1614 /***************************************************/
1615 /* ASSEMBLER CLEANUP STUFF */
1616 /***************************************************/
1617
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.
1621
1622 This is from tc-aarch64.c
1623 */
1624
1625 static bfd_boolean
1626 signed_overflow (offsetT value, unsigned bits)
1627 {
1628 offsetT lim;
1629 if (bits >= sizeof (offsetT) * 8)
1630 return FALSE;
1631 lim = (offsetT) 1 << (bits - 1);
1632 return (value < -lim || value >= lim);
1633 }
1634
1635 /***************************************************/
1636 /* ASSEMBLER FIXUP STUFF */
1637 /***************************************************/
1638
1639 void
1640 md_apply_fix (fixS * fixP, valueT * valueP, segT segmentP ATTRIBUTE_UNUSED)
1641 {
1642 char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
1643 valueT value = *valueP;
1644 valueT image;
1645 arelent *rel;
1646
1647 rel = xmalloc (sizeof (arelent));
1648
1649 rel->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
1650 if (rel->howto == NULL)
1651 {
1652 as_fatal
1653 ("[md_apply_fix] unsupported relocation type (can't find howto)");
1654 }
1655
1656 /* Note whether this will delete the relocation. */
1657 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
1658 fixP->fx_done = 1;
1659
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)
1665 {
1666 switch (fixP->fx_r_type)
1667 {
1668 case BFD_RELOC_KVX_S37_TLS_LE_UP27:
1669 case BFD_RELOC_KVX_S37_TLS_LE_LO10:
1670
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:
1674
1675 case BFD_RELOC_KVX_S37_TLS_GD_LO10:
1676 case BFD_RELOC_KVX_S37_TLS_GD_UP27:
1677
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:
1681
1682 case BFD_RELOC_KVX_S37_TLS_IE_LO10:
1683 case BFD_RELOC_KVX_S37_TLS_IE_UP27:
1684
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:
1688
1689 case BFD_RELOC_KVX_S37_TLS_LD_LO10:
1690 case BFD_RELOC_KVX_S37_TLS_LD_UP27:
1691
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:
1695
1696 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1697 break;
1698 default:
1699 break;
1700 }
1701 }
1702
1703 /* If relocation has been marked for deletion, apply remaining changes */
1704 if (fixP->fx_done)
1705 {
1706 switch (fixP->fx_r_type)
1707 {
1708 case BFD_RELOC_8:
1709 case BFD_RELOC_16:
1710 case BFD_RELOC_32:
1711 case BFD_RELOC_64:
1712
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;
1721
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;
1727
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;
1733
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;
1739
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;
1747
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;
1754
1755 case BFD_RELOC_KVX_S64_PCREL_LO10:
1756 case BFD_RELOC_KVX_S64_PCREL_UP27:
1757 case BFD_RELOC_KVX_S64_PCREL_EX27:
1758
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;
1768
1769 case BFD_RELOC_KVX_S64_GOTADDR_LO10:
1770 case BFD_RELOC_KVX_S64_GOTADDR_UP27:
1771 case BFD_RELOC_KVX_S64_GOTADDR_EX27:
1772
1773 case BFD_RELOC_KVX_S43_GOTADDR_LO10:
1774 case BFD_RELOC_KVX_S43_GOTADDR_UP27:
1775 case BFD_RELOC_KVX_S43_GOTADDR_EX6:
1776
1777 case BFD_RELOC_KVX_S37_GOTADDR_LO10:
1778 case BFD_RELOC_KVX_S37_GOTADDR_UP27:
1779 value = 0;
1780 /* Fallthrough */
1781
1782 case BFD_RELOC_KVX_S32_UP27:
1783
1784 case BFD_RELOC_KVX_S37_UP27:
1785
1786 case BFD_RELOC_KVX_S43_UP27:
1787
1788 case BFD_RELOC_KVX_S64_UP27:
1789 case BFD_RELOC_KVX_S64_EX27:
1790 case BFD_RELOC_KVX_S64_LO10:
1791
1792 case BFD_RELOC_KVX_S43_TLS_LE_UP27:
1793 case BFD_RELOC_KVX_S43_TLS_LE_EX6:
1794
1795 case BFD_RELOC_KVX_S37_TLS_LE_UP27:
1796
1797 case BFD_RELOC_KVX_S37_GOTOFF_UP27:
1798
1799 case BFD_RELOC_KVX_S43_GOTOFF_UP27:
1800 case BFD_RELOC_KVX_S43_GOTOFF_EX6:
1801
1802 case BFD_RELOC_KVX_S43_GOT_UP27:
1803 case BFD_RELOC_KVX_S43_GOT_EX6:
1804
1805 case BFD_RELOC_KVX_S37_GOT_UP27:
1806
1807 case BFD_RELOC_KVX_S32_LO5:
1808 case BFD_RELOC_KVX_S37_LO10:
1809
1810 case BFD_RELOC_KVX_S43_LO10:
1811 case BFD_RELOC_KVX_S43_EX6:
1812
1813 case BFD_RELOC_KVX_S43_TLS_LE_LO10:
1814 case BFD_RELOC_KVX_S37_TLS_LE_LO10:
1815
1816 case BFD_RELOC_KVX_S37_GOTOFF_LO10:
1817 case BFD_RELOC_KVX_S43_GOTOFF_LO10:
1818
1819 case BFD_RELOC_KVX_S43_GOT_LO10:
1820 case BFD_RELOC_KVX_S37_GOT_LO10:
1821
1822 default:
1823 as_fatal ("[md_apply_fix]:"
1824 "unsupported relocation type (type not handled : %d)",
1825 fixP->fx_r_type);
1826 }
1827 }
1828 xfree (rel);
1829 }
1830
1831 /*
1832 * Warning: Can be called only in fixup_segment() after fx_addsy field
1833 * has been updated by calling symbol_get_value_expression(...->X_add_symbol)
1834 */
1835 int
1836 kvx_validate_sub_fix (fixS * fixP)
1837 {
1838 segT add_symbol_segment, sub_symbol_segment;
1839
1840 switch (fixP->fx_r_type)
1841 {
1842 case BFD_RELOC_8:
1843 case BFD_RELOC_16:
1844 case BFD_RELOC_32:
1845 if (fixP->fx_addsy != NULL)
1846 add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy);
1847 else
1848 return 0;
1849 if (fixP->fx_subsy != NULL)
1850 sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy);
1851 else
1852 return 0;
1853
1854 if ((strcmp (S_GET_NAME (fixP->fx_addsy),
1855 S_GET_NAME (fixP->fx_subsy)) == 0) &&
1856 (add_symbol_segment == sub_symbol_segment))
1857 return 1;
1858 break;
1859 default:
1860 break;
1861 }
1862
1863 return 0;
1864 }
1865
1866 /* This is called whenever some data item (not an instruction) needs a
1867 * fixup. */
1868 void
1869 kvx_cons_fix_new (fragS * f, int where, int nbytes, expressionS * exp,
1870 bfd_reloc_code_real_type code)
1871 {
1872 if (exp->X_op == O_pseudo_fixup)
1873 {
1874 exp->X_op = O_symbol;
1875 struct pseudo_func *pf =
1876 kvx_get_pseudo_func_data_scn (exp->X_op_symbol);
1877 assert (pf != NULL);
1878 code = pf->pseudo_relocs.single;
1879
1880 if (code == BFD_RELOC_UNUSED)
1881 as_fatal ("Unsupported relocation");
1882 }
1883 else
1884 {
1885 switch (nbytes)
1886 {
1887 case 1:
1888 code = BFD_RELOC_8;
1889 break;
1890 case 2:
1891 code = BFD_RELOC_16;
1892 break;
1893 case 4:
1894 code = BFD_RELOC_32;
1895 break;
1896 case 8:
1897 code = BFD_RELOC_64;
1898 break;
1899 default:
1900 as_fatal ("unsupported BFD relocation size %u", nbytes);
1901 break;
1902 }
1903 }
1904 fix_new_exp (f, where, nbytes, exp, 0, code);
1905 }
1906
1907 /*
1908 * generate a relocation record
1909 */
1910
1911 arelent *
1912 tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
1913 {
1914 arelent *reloc;
1915 bfd_reloc_code_real_type code;
1916
1917 reloc = notes_alloc (sizeof (arelent));
1918 reloc->sym_ptr_ptr = notes_alloc (sizeof (asymbol *));
1919 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1920 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1921
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);
1926
1927 if (reloc->howto == NULL)
1928 {
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;
1933 }
1934
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);
1941
1942 reloc->addend = fixp->fx_offset;
1943
1944 /*
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.
1949 */
1950
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 */
1956
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.
1996 */
1997
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;
2001
2002 return reloc;
2003 }
2004
2005 /* Round up segment to appropriate boundary */
2006
2007 valueT
2008 md_section_align (asection * seg ATTRIBUTE_UNUSED, valueT size)
2009 {
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
2019 }
2020
2021 int
2022 md_estimate_size_before_relax (register fragS * fragP ATTRIBUTE_UNUSED,
2023 segT segtype ATTRIBUTE_UNUSED)
2024 {
2025 as_fatal ("estimate_size_before_relax called");
2026 }
2027
2028 void
2029 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
2030 asection * sec ATTRIBUTE_UNUSED,
2031 fragS * fragp ATTRIBUTE_UNUSED)
2032 {
2033 as_fatal ("kvx convert_frag");
2034 }
2035
2036 symbolS *
2037 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
2038 {
2039 return 0;
2040 }
2041
2042 const char *
2043 md_atof (int type ATTRIBUTE_UNUSED,
2044 char *litp ATTRIBUTE_UNUSED, int *sizep ATTRIBUTE_UNUSED)
2045 {
2046 return ieee_md_atof (type, litp, sizep, TARGET_BYTES_BIG_ENDIAN);
2047 }
2048
2049 /*
2050 * calculate the base for a pcrel fixup
2051 * -- for relocation, we might need to add addend ?
2052 */
2053
2054 long
2055 md_pcrel_from (fixS * fixP)
2056 {
2057 return (fixP->fx_where + fixP->fx_frag->fr_address);
2058 }
2059
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 /************************************************************/
2066
2067 static symbolS *last_proc_sym = NULL;
2068 static int update_last_proc_sym = 0;
2069
2070 void
2071 kvx_frob_label (symbolS *sym)
2072 {
2073 if (update_last_proc_sym)
2074 {
2075 last_proc_sym = sym;
2076 update_last_proc_sym = 0;
2077 }
2078
2079 if (inside_bundle)
2080 {
2081 struct label_fix *fix;
2082 fix = malloc (sizeof (*fix));
2083 fix->next = label_fixes;
2084 fix->sym = sym;
2085 label_fixes = fix;
2086 }
2087
2088 dwarf2_emit_label (sym);
2089 }
2090
2091 void
2092 kvx_check_label (symbolS *sym)
2093 {
2094 /* Labels followed by a second semi-colon are considered external symbols. */
2095 if (*input_line_pointer == ':')
2096 {
2097 S_SET_EXTERNAL (sym);
2098 input_line_pointer++;
2099 }
2100 }
2101
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
2105 */
2106 void
2107 kvx_emit_single_noop (void)
2108 {
2109 char nop[] = "nop";
2110 char end_of_bundle[] = "be";
2111
2112 char *saved_ilp = input_line_pointer;
2113 md_assemble (nop);
2114 md_assemble (end_of_bundle);
2115 input_line_pointer = saved_ilp;
2116 }
2117
2118 /* edit out some syntactic sugar that confuses GAS */
2119 /* input_line_pointer is guaranteed to point to the */
2120 /* the current line but may include text from following */
2121 /* lines. Thus, '\n' must be scanned for as well as '\0' */
2122
2123 void
2124 kvx_md_start_line_hook (void)
2125 {
2126 char *t;
2127
2128 for (t = input_line_pointer; is_whitespace (t[0]); t++);
2129
2130 /* Detect illegal syntax patterns:
2131 * - two bundle ends on the same line: ;; ;;
2132 * - illegal token: ;;;
2133 */
2134 if (t && (t[0] == ';') && (t[1] == ';'))
2135 {
2136 char *tmp_t;
2137 bool newline_seen = false;
2138
2139 if (t[2] == ';')
2140 as_fatal ("Syntax error: Illegal ;;; token");
2141
2142 tmp_t = t + 2;
2143
2144 while (tmp_t && tmp_t[0])
2145 {
2146 while (tmp_t && tmp_t[0] &&
2147 (is_whitespace (tmp_t[0]) || is_end_of_stmt (tmp_t[0])))
2148 {
2149 if (is_end_of_stmt (tmp_t[0]))
2150 newline_seen = true;
2151 tmp_t++;
2152 }
2153 if (tmp_t[0] == ';' && tmp_t[1] == ';')
2154 {
2155 /* if there's no newline between the two bundle stops
2156 * then raise a syntax error now, otherwise a strange error
2157 * message from read.c will be raised: "junk at end of line..."
2158 */
2159 if (tmp_t[2] == ';')
2160 as_fatal ("Syntax error: Illegal ;;; token");
2161
2162 if (!newline_seen)
2163 as_fatal ("Syntax error: More than one bundle stop on a line");
2164 newline_seen = false; /* reset */
2165
2166 /* this is an empty bundle, transform it into an
2167 * empty statement */
2168 tmp_t[0] = ';';
2169 tmp_t[1] = ' ';
2170
2171 tmp_t += 2;
2172 }
2173 else
2174 break;
2175 }
2176 }
2177
2178 /* check for bundle end */
2179 /* we transform these into a special opcode BE */
2180 /* because gas has ';' hardwired as a statement end */
2181 if (t && (t[0] == ';') && (t[1] == ';'))
2182 {
2183 t[0] = 'B';
2184 t[1] = 'E';
2185 return;
2186 }
2187 }
2188
2189 static void
2190 kvx_check_resources (int f)
2191 {
2192 env.opts.check_resource_usage = f;
2193 }
2194
2195 /** called before write_object_file */
2196 void
2197 kvx_end (void)
2198 {
2199 int newflags;
2200
2201 if (!env.params.core_set)
2202 env.params.core = kvx_core_info->elf_core;
2203
2204 /* (pp) the flags must be set at once */
2205 newflags = env.params.core | env.params.abi | env.params.pic_flags;
2206
2207 if (env.params.arch_size == 64)
2208 newflags |= ELF_KVX_ABI_64B_ADDR_BIT;
2209
2210 bfd_set_private_flags (stdoutput, newflags);
2211
2212 cleanup ();
2213
2214 if (inside_bundle && insncnt != 0)
2215 as_bad ("unexpected end-of-file while processing a bundle."
2216 " Please check that ;; is on its own line.");
2217 }
2218
2219 static void
2220 kvx_type (int start ATTRIBUTE_UNUSED)
2221 {
2222 char *name;
2223 char c;
2224 int type;
2225 char *typename = NULL;
2226 symbolS *sym;
2227 elf_symbol_type *elfsym;
2228
2229 c = get_symbol_name (&name);
2230 sym = symbol_find_or_make (name);
2231 elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
2232 *input_line_pointer = c;
2233
2234 if (!*S_GET_NAME (sym))
2235 as_bad (_("Missing symbol name in directive"));
2236
2237 SKIP_WHITESPACE ();
2238 if (*input_line_pointer == ',')
2239 ++input_line_pointer;
2240
2241
2242 SKIP_WHITESPACE ();
2243 if (*input_line_pointer == '#'
2244 || *input_line_pointer == '@'
2245 || *input_line_pointer == '"' || *input_line_pointer == '%')
2246 ++input_line_pointer;
2247
2248 /* typename = input_line_pointer; */
2249 /* c = get_symbol_end(); */
2250 c = get_symbol_name (&typename);
2251
2252 type = 0;
2253 if (strcmp (typename, "function") == 0
2254 || strcmp (typename, "STT_FUNC") == 0)
2255 type = BSF_FUNCTION;
2256 else if (strcmp (typename, "object") == 0
2257 || strcmp (typename, "STT_OBJECT") == 0)
2258 type = BSF_OBJECT;
2259 else if (strcmp (typename, "tls_object") == 0
2260 || strcmp (typename, "STT_TLS") == 0)
2261 type = BSF_OBJECT | BSF_THREAD_LOCAL;
2262 else if (strcmp (typename, "common") == 0
2263 || strcmp (typename, "STT_COMMON") == 0)
2264 type = BSF_ELF_COMMON;
2265 else if (strcmp (typename, "gnu_unique_object") == 0
2266 || strcmp (typename, "STB_GNU_UNIQUE") == 0)
2267 {
2268 elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_unique;
2269 type = BSF_OBJECT | BSF_GNU_UNIQUE;
2270 }
2271 else if (strcmp (typename, "notype") == 0
2272 || strcmp (typename, "STT_NOTYPE") == 0)
2273 ;
2274 #ifdef md_elf_symbol_type
2275 else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
2276 ;
2277 #endif
2278 else
2279 as_bad (_("unrecognized symbol type \"%s\""), typename);
2280
2281 *input_line_pointer = c;
2282
2283 if (*input_line_pointer == '"')
2284 ++input_line_pointer;
2285
2286 elfsym->symbol.flags |= type;
2287 symbol_get_bfdsym (sym)->flags |= type;
2288
2289 demand_empty_rest_of_line ();
2290 }
2291
2292 #define ENDPROCEXTENSION "$endproc"
2293 #define MINUSEXPR ".-"
2294
2295 static int proc_endp_status = 0;
2296
2297 static void
2298 kvx_endp (int start ATTRIBUTE_UNUSED)
2299 {
2300 char c;
2301 char *name;
2302
2303 if (inside_bundle)
2304 as_warn (".endp directive inside a bundle.");
2305 /* function name is optionnal and is ignored */
2306 /* there may be several names separated by commas... */
2307 while (1)
2308 {
2309 SKIP_WHITESPACE ();
2310 c = get_symbol_name (&name);
2311 (void) restore_line_pointer (c);
2312 SKIP_WHITESPACE ();
2313 if (*input_line_pointer != ',')
2314 break;
2315 ++input_line_pointer;
2316 }
2317 demand_empty_rest_of_line ();
2318
2319 if (!proc_endp_status)
2320 {
2321 as_warn (".endp directive doesn't follow .proc -- ignoring ");
2322 return;
2323 }
2324
2325 proc_endp_status = 0;
2326
2327 /* TB begin : add BSF_FUNCTION attribute to last_proc_sym symbol */
2328 if (size_type_function)
2329 {
2330 if (!last_proc_sym)
2331 {
2332 as_bad ("Cannot set function attributes (bad symbol)");
2333 return;
2334 }
2335
2336 /* last_proc_sym->symbol.flags |= BSF_FUNCTION; */
2337 symbol_get_bfdsym (last_proc_sym)->flags |= BSF_FUNCTION;
2338 /* Add .size funcname,.-funcname in order to add size
2339 * attribute to the current function */
2340 {
2341 const int newdirective_sz =
2342 strlen (S_GET_NAME (last_proc_sym)) + strlen (MINUSEXPR) + 1;
2343 char *newdirective = malloc (newdirective_sz);
2344 char *savep = input_line_pointer;
2345 expressionS exp;
2346
2347 memset (newdirective, 0, newdirective_sz);
2348
2349 /* BUILD :".-funcname" expression */
2350 strcat (newdirective, MINUSEXPR);
2351 strcat (newdirective, S_GET_NAME (last_proc_sym));
2352 input_line_pointer = newdirective;
2353 expression (&exp);
2354
2355 if (exp.X_op == O_constant)
2356 {
2357 S_SET_SIZE (last_proc_sym, exp.X_add_number);
2358 symbol_get_obj (last_proc_sym)->size = NULL;
2359 }
2360 else
2361 {
2362 symbol_get_obj (last_proc_sym)->size = notes_alloc (sizeof (exp));
2363 *symbol_get_obj (last_proc_sym)->size = exp;
2364 }
2365
2366 /* just restore the real input pointer */
2367 input_line_pointer = savep;
2368 free (newdirective);
2369 }
2370 }
2371 /* TB end */
2372
2373 last_proc_sym = NULL;
2374 }
2375
2376 static void
2377 kvx_proc (int start ATTRIBUTE_UNUSED)
2378 {
2379 char c;
2380 char *name;
2381 /* there may be several names separated by commas... */
2382 while (1)
2383 {
2384 SKIP_WHITESPACE ();
2385 c = get_symbol_name (&name);
2386 (void) restore_line_pointer (c);
2387
2388 SKIP_WHITESPACE ();
2389 if (*input_line_pointer != ',')
2390 break;
2391 ++input_line_pointer;
2392 }
2393 demand_empty_rest_of_line ();
2394
2395 if (proc_endp_status)
2396 {
2397 as_warn (".proc follows .proc -- ignoring");
2398 return;
2399 }
2400
2401 proc_endp_status = 1;
2402
2403 /* this code emit a global symbol to mark the end of each function */
2404 /* the symbol emitted has a name formed by the original function name */
2405 /* concatenated with $endproc so if _foo is a function name the symbol */
2406 /* marking the end of it is _foo$endproc */
2407 /* It is also required for generation of .size directive in kvx_endp() */
2408
2409 if (size_type_function)
2410 update_last_proc_sym = 1;
2411 }
2412
2413 int
2414 kvx_force_reloc (fixS * fixP)
2415 {
2416 symbolS *sym;
2417 asection *symsec;
2418
2419 if (generic_force_reloc (fixP))
2420 return 1;
2421
2422 switch (fixP->fx_r_type)
2423 {
2424 case BFD_RELOC_KVX_32_GOTOFF:
2425 case BFD_RELOC_KVX_S37_GOTOFF_UP27:
2426 case BFD_RELOC_KVX_S37_GOTOFF_LO10:
2427
2428 case BFD_RELOC_KVX_64_GOTOFF:
2429 case BFD_RELOC_KVX_S43_GOTOFF_UP27:
2430 case BFD_RELOC_KVX_S43_GOTOFF_LO10:
2431 case BFD_RELOC_KVX_S43_GOTOFF_EX6:
2432
2433 case BFD_RELOC_KVX_32_GOT:
2434 case BFD_RELOC_KVX_64_GOT:
2435 case BFD_RELOC_KVX_S37_GOT_UP27:
2436 case BFD_RELOC_KVX_S37_GOT_LO10:
2437
2438 case BFD_RELOC_KVX_GLOB_DAT:
2439 return 1;
2440 default:
2441 return 0;
2442 }
2443
2444 sym = fixP->fx_addsy;
2445 if (sym)
2446 {
2447 symsec = S_GET_SEGMENT (sym);
2448 /* if (bfd_is_abs_section (symsec)) return 0; */
2449 if (!SEG_NORMAL (symsec))
2450 return 0;
2451 }
2452 return 1;
2453 }
2454
2455 int
2456 kvx_force_reloc_sub_same (fixS * fixP, segT sec)
2457 {
2458 symbolS *sym;
2459 asection *symsec;
2460 const char *sec_name = NULL;
2461
2462 if (generic_force_reloc (fixP))
2463 return 1;
2464
2465 switch (fixP->fx_r_type)
2466 {
2467 case BFD_RELOC_KVX_32_GOTOFF:
2468 case BFD_RELOC_KVX_S37_GOTOFF_UP27:
2469 case BFD_RELOC_KVX_S37_GOTOFF_LO10:
2470
2471 case BFD_RELOC_KVX_64_GOTOFF:
2472 case BFD_RELOC_KVX_S43_GOTOFF_UP27:
2473 case BFD_RELOC_KVX_S43_GOTOFF_LO10:
2474 case BFD_RELOC_KVX_S43_GOTOFF_EX6:
2475
2476 case BFD_RELOC_KVX_32_GOT:
2477 case BFD_RELOC_KVX_64_GOT:
2478 case BFD_RELOC_KVX_S37_GOT_UP27:
2479 case BFD_RELOC_KVX_S37_GOT_LO10:
2480
2481 case BFD_RELOC_KVX_S37_LO10:
2482 case BFD_RELOC_KVX_S37_UP27:
2483
2484 case BFD_RELOC_KVX_GLOB_DAT:
2485 return 1;
2486
2487 default:
2488 return 0;
2489 }
2490
2491 sym = fixP->fx_addsy;
2492 if (sym)
2493 {
2494 symsec = S_GET_SEGMENT (sym);
2495 /* if (bfd_is_abs_section (symsec)) return 0; */
2496 if (!SEG_NORMAL (symsec))
2497 return 0;
2498
2499 /*
2500 * for .debug_arrange, .debug_frame, .eh_frame sections, containing
2501 * expressions of the form "sym2 - sym1 + addend", solve them even when
2502 * --emit-all-relocs is set. Otherwise, a relocation on two symbols
2503 * is necessary and fails at elf level. Binopt should not be impacted by
2504 * the resolution of this relocatable expression on symbols inside a
2505 * function.
2506 */
2507 sec_name = segment_name (sec);
2508 if ((strcmp (sec_name, ".eh_frame") == 0) ||
2509 (strcmp (sec_name, ".except_table") == 0) ||
2510 (strncmp (sec_name, ".debug_", sizeof (".debug_")) == 0))
2511 return 0;
2512 }
2513 return 1;
2514 }
2515
2516 /* Pads code section with bundle of nops when possible, 0 if not. */
2517
2518 void
2519 kvx_handle_align (fragS *fragP)
2520 {
2521 if (fragP->fr_type != rs_align_code)
2522 return;
2523
2524 static unsigned int nop_single = 0;
2525 if (!nop_single)
2526 {
2527 const struct kvxopc *opcode = str_hash_find (env.opcode_hash, "nop");
2528
2529 if (opcode == NULL)
2530 as_fatal
2531 ("internal error: could not find opcode for 'nop' during padding");
2532
2533 nop_single = opcode->codewords[0].opcode;
2534 }
2535
2536 bfd_signed_vma bytes = (fragP->fr_next->fr_address
2537 - fragP->fr_address - fragP->fr_fix);
2538 if (bytes <= 0)
2539 return;
2540
2541 char *p = fragP->fr_literal + fragP->fr_fix;
2542
2543 /* KVX instructions are always 4-bytes aligned. If we are at a
2544 position that is not 4 bytes aligned, it means this is not part
2545 of an instruction, so it is safe to use a zero byte for padding. */
2546 int fix = bytes & 3;
2547 if (fix != 0)
2548 {
2549 memset (p, 0, fix);
2550 p += fix;
2551 bytes -= fix;
2552 }
2553
2554 /* Output any nops that don't make a full bundle. */
2555 while (bytes & 15)
2556 {
2557 unsigned int nop = nop_single;
2558 bytes -= 4;
2559 if (bytes & 15)
2560 nop |= PARALLEL_BIT;
2561 memcpy (p, &nop, 4);
2562 p += 4;
2563 fix += 4;
2564 }
2565 fragP->fr_fix += fix;
2566
2567 /* Any more are repeated copies of this full bundle of nops. */
2568 if (bytes)
2569 {
2570 unsigned int nop = nop_single | PARALLEL_BIT;
2571 memcpy (p, &nop, 4);
2572 p += 4;
2573 memcpy (p, &nop, 4);
2574 p += 4;
2575 memcpy (p, &nop, 4);
2576 p += 4;
2577 memcpy (p, &nop_single, 4);
2578 fragP->fr_var = 16;
2579 }
2580 }
2581 /*
2582 * This is just used for debugging
2583 */
2584
2585 ATTRIBUTE_UNUSED
2586 static void
2587 print_operand (expressionS * e, FILE * out)
2588 {
2589 if (e)
2590 {
2591 switch (e->X_op)
2592 {
2593 case O_register:
2594 fprintf (out, "%s", kvx_registers[e->X_add_number].name);
2595 break;
2596
2597 case O_constant:
2598 if (e->X_add_symbol)
2599 {
2600 if (e->X_add_number)
2601 fprintf (out, "(%s + %d)", S_GET_NAME (e->X_add_symbol),
2602 (int) e->X_add_number);
2603 else
2604 fprintf (out, "%s", S_GET_NAME (e->X_add_symbol));
2605 }
2606 else
2607 fprintf (out, "%d", (int) e->X_add_number);
2608 break;
2609
2610 case O_symbol:
2611 if (e->X_add_symbol)
2612 {
2613 if (e->X_add_number)
2614 fprintf (out, "(%s + %d)", S_GET_NAME (e->X_add_symbol),
2615 (int) e->X_add_number);
2616 else
2617 fprintf (out, "%s", S_GET_NAME (e->X_add_symbol));
2618 }
2619 else
2620 fprintf (out, "%d", (int) e->X_add_number);
2621 break;
2622
2623 default:
2624 fprintf (out, "o,ptype-%d", e->X_op);
2625 }
2626 }
2627 }
2628
2629 void
2630 kvx_cfi_frame_initial_instructions (void)
2631 {
2632 cfi_add_CFA_def_cfa (KVX_SP_REGNO, 0);
2633 }
2634
2635 int
2636 kvx_regname_to_dw2regnum (const char *regname)
2637 {
2638 unsigned int regnum = -1;
2639 const char *p;
2640 char *q;
2641
2642 if (regname[0] == 'r')
2643 {
2644 p = regname + 1;
2645 regnum = strtoul (p, &q, 10);
2646 if (p == q || *q || regnum >= 64)
2647 return -1;
2648 }
2649 return regnum;
2650 }
2651