]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-score7.c
x86: Enable TLS relocation check only for ELF
[thirdparty/binutils-gdb.git] / gas / config / tc-score7.c
CommitLineData
c3b7224a 1/* tc-score7.c -- Assembler for Score7
fd67aa11 2 Copyright (C) 2009-2024 Free Software Foundation, Inc.
c3b7224a
NC
3 Contributed by:
4 Brain.lin (brain.lin@sunplusct.com)
5 Mei Ligang (ligang@sunnorth.com.cn)
6 Pei-Lin Tsai (pltsai@sunplus.com)
7
8 This file is part of GAS, the GNU Assembler.
9
10 GAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
14
15 GAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GAS; see the file COPYING. If not, write to the Free
22 Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
23 MA 02110-1301, USA. */
24
25#include "as.h"
26#include "config.h"
27#include "subsegs.h"
28#include "safe-ctype.h"
29#include "opcode/score-inst.h"
c3b7224a
NC
30#include "libiberty.h"
31
32#ifdef OBJ_ELF
33#include "elf/score.h"
34#include "dwarf2dbg.h"
35#endif
36
37static void s7_do_ldst_insn (char *);
38static void s7_do_crdcrscrsimm5 (char *);
39static void s7_do_ldst_unalign (char *);
40static void s7_do_ldst_atomic (char *);
41static void s7_do_ldst_cop (char *);
42static void s7_do_macro_li_rdi32 (char *);
43static void s7_do_macro_la_rdi32 (char *);
44static void s7_do_macro_rdi32hi (char *);
45static void s7_do_macro_rdi32lo (char *);
46static void s7_do_macro_mul_rdrsrs (char *);
47static void s7_do_macro_ldst_label (char *);
48static void s7_do_branch (char *);
49static void s7_do_jump (char *);
50static void s7_do_empty (char *);
51static void s7_do_rdrsrs (char *);
52static void s7_do_rdsi16 (char *);
53static void s7_do_rdrssi14 (char *);
54static void s7_do_sub_rdsi16 (char *);
55static void s7_do_sub_rdrssi14 (char *);
56static void s7_do_rdrsi5 (char *);
57static void s7_do_rdrsi14 (char *);
58static void s7_do_rdi16 (char *);
59static void s7_do_xrsi5 (char *);
60static void s7_do_rdrs (char *);
61static void s7_do_rdxrs (char *);
62static void s7_do_rsrs (char *);
63static void s7_do_rdcrs (char *);
64static void s7_do_rdsrs (char *);
65static void s7_do_rd (char *);
66static void s7_do_rs (char *);
67static void s7_do_i15 (char *);
68static void s7_do_xi5x (char *);
69static void s7_do_ceinst (char *);
70static void s7_do_cache (char *);
71static void s7_do16_rdrs (char *);
72static void s7_do16_rs (char *);
73static void s7_do16_xrs (char *);
74static void s7_do16_mv_rdrs (char *);
75static void s7_do16_hrdrs (char *);
76static void s7_do16_rdhrs (char *);
77static void s7_do16_rdi4 (char *);
78static void s7_do16_rdi5 (char *);
79static void s7_do16_xi5 (char *);
80static void s7_do16_ldst_insn (char *);
81static void s7_do16_ldst_imm_insn (char *);
82static void s7_do16_push_pop (char *);
83static void s7_do16_branch (char *);
84static void s7_do16_jump (char *);
85static void s7_do_rdi16_pic (char *);
86static void s7_do_addi_s_pic (char *);
87static void s7_do_addi_u_pic (char *);
88static void s7_do_lw_pic (char *);
89
90#define s7_GP 28
91#define s7_PIC_CALL_REG 29
92#define s7_MAX_LITERAL_POOL_SIZE 1024
93#define s7_FAIL 0x80000000
94#define s7_SUCCESS 0
95#define s7_INSN_SIZE 4
96#define s7_INSN16_SIZE 2
97#define s7_RELAX_INST_NUM 3
98
99/* For score5u : div/mul will pop warning message, mmu/alw/asw will pop error message. */
100#define s7_BAD_ARGS _("bad arguments to instruction")
101#define s7_ERR_FOR_SCORE5U_MUL_DIV _("div / mul are reserved instructions")
102#define s7_ERR_FOR_SCORE5U_MMU _("This architecture doesn't support mmu")
103#define s7_ERR_FOR_SCORE5U_ATOMIC _("This architecture doesn't support atomic instruction")
104#define s7_BAD_SKIP_COMMA s7_BAD_ARGS
105#define s7_BAD_GARBAGE _("garbage following instruction");
106
107#define s7_skip_whitespace(str) while (*(str) == ' ') ++(str)
108
109/* The name of the readonly data section. */
110#define s7_RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_aout_flavour \
111 ? ".data" \
112 : OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
113 ? ".rdata" \
114 : OUTPUT_FLAVOR == bfd_target_coff_flavour \
115 ? ".rdata" \
116 : OUTPUT_FLAVOR == bfd_target_elf_flavour \
117 ? ".rodata" \
118 : (abort (), ""))
119
120#define s7_RELAX_ENCODE(old, new, type, reloc1, reloc2, opt) \
121 ((relax_substateT) \
122 (((old) << 23) \
123 | ((new) << 16) \
124 | ((type) << 9) \
125 | ((reloc1) << 5) \
126 | ((reloc2) << 1) \
127 | ((opt) ? 1 : 0)))
128
129#define s7_RELAX_OLD(i) (((i) >> 23) & 0x7f)
130#define s7_RELAX_NEW(i) (((i) >> 16) & 0x7f)
131#define s7_RELAX_TYPE(i) (((i) >> 9) & 0x7f)
132#define s7_RELAX_RELOC1(i) ((valueT) ((i) >> 5) & 0xf)
133#define s7_RELAX_RELOC2(i) ((valueT) ((i) >> 1) & 0xf)
134#define s7_RELAX_OPT(i) ((i) & 1)
135#define s7_RELAX_OPT_CLEAR(i) ((i) & ~1)
136
137#define s7_SET_INSN_ERROR(s) (s7_inst.error = (s))
138#define s7_INSN_IS_PCE_P(s) (strstr (str, "||") != NULL)
139
140#define s7_GET_INSN_CLASS(type) (s7_get_insn_class_from_type (type))
141
142#define s7_GET_INSN_SIZE(type) ((s7_GET_INSN_CLASS (type) == INSN_CLASS_16) \
143 ? s7_INSN16_SIZE : s7_INSN_SIZE)
144
c3b7224a
NC
145#define s7_INSN_NAME_LEN 16
146
147/* Relax will need some padding for alignment. */
148#define s7_RELAX_PAD_BYTE 3
149
150#define s7_USE_GLOBAL_POINTER_OPT 1
151
152\f
153
154/* Enumeration matching entries in table above. */
155enum s7_score_reg_type
156{
157 s7_REG_TYPE_SCORE = 0,
158#define REG_TYPE_FIRST s7_REG_TYPE_SCORE
159 s7_REG_TYPE_SCORE_SR = 1,
160 s7_REG_TYPE_SCORE_CR = 2,
161 s7_REG_TYPE_MAX = 3
162};
163
164enum s7_score_pic_level
165{
166 s7_NO_PIC,
167 s7_PIC
168};
169static enum s7_score_pic_level s7_score_pic = s7_NO_PIC;
170
171enum s7_insn_type_for_dependency
172{
173 s7_D_pce,
174 s7_D_cond_br,
175 s7_D_cond_mv,
176 s7_D_cached,
177 s7_D_cachei,
178 s7_D_ldst,
179 s7_D_ldcombine,
180 s7_D_mtcr,
181 s7_D_mfcr,
182 s7_D_mfsr,
183 s7_D_mftlb,
184 s7_D_mtptlb,
185 s7_D_mtrtlb,
186 s7_D_stlb,
187 s7_D_all_insn
188};
189
190struct s7_insn_to_dependency
191{
b9bb4a93 192 const char *insn_name;
c3b7224a
NC
193 enum s7_insn_type_for_dependency type;
194};
195
196struct s7_data_dependency
197{
198 enum s7_insn_type_for_dependency pre_insn_type;
199 char pre_reg[6];
200 enum s7_insn_type_for_dependency cur_insn_type;
201 char cur_reg[6];
202 int bubblenum_7;
203 int bubblenum_5;
204 int warn_or_error; /* warning - 0; error - 1 */
205};
206
207static const struct s7_insn_to_dependency s7_insn_to_dependency_table[] =
208{
209 /* pce instruction. */
210 {"pce", s7_D_pce},
211 /* conditional branch instruction. */
212 {"bcs", s7_D_cond_br},
213 {"bcc", s7_D_cond_br},
214 {"bgtu", s7_D_cond_br},
215 {"bleu", s7_D_cond_br},
216 {"beq", s7_D_cond_br},
217 {"bne", s7_D_cond_br},
218 {"bgt", s7_D_cond_br},
219 {"ble", s7_D_cond_br},
220 {"bge", s7_D_cond_br},
221 {"blt", s7_D_cond_br},
222 {"bmi", s7_D_cond_br},
223 {"bpl", s7_D_cond_br},
224 {"bvs", s7_D_cond_br},
225 {"bvc", s7_D_cond_br},
226 {"bcsl", s7_D_cond_br},
227 {"bccl", s7_D_cond_br},
228 {"bgtul", s7_D_cond_br},
229 {"bleul", s7_D_cond_br},
230 {"beql", s7_D_cond_br},
231 {"bnel", s7_D_cond_br},
232 {"bgtl", s7_D_cond_br},
233 {"blel", s7_D_cond_br},
234 {"bgel", s7_D_cond_br},
235 {"bltl", s7_D_cond_br},
236 {"bmil", s7_D_cond_br},
237 {"bpll", s7_D_cond_br},
238 {"bvsl", s7_D_cond_br},
239 {"bvcl", s7_D_cond_br},
240 {"bcs!", s7_D_cond_br},
241 {"bcc!", s7_D_cond_br},
242 {"bgtu!", s7_D_cond_br},
243 {"bleu!", s7_D_cond_br},
244 {"beq!", s7_D_cond_br},
245 {"bne!", s7_D_cond_br},
246 {"bgt!", s7_D_cond_br},
247 {"ble!", s7_D_cond_br},
248 {"bge!", s7_D_cond_br},
249 {"blt!", s7_D_cond_br},
250 {"bmi!", s7_D_cond_br},
251 {"bpl!", s7_D_cond_br},
252 {"bvs!", s7_D_cond_br},
253 {"bvc!", s7_D_cond_br},
254 {"brcs", s7_D_cond_br},
255 {"brcc", s7_D_cond_br},
256 {"brgtu", s7_D_cond_br},
257 {"brleu", s7_D_cond_br},
258 {"breq", s7_D_cond_br},
259 {"brne", s7_D_cond_br},
260 {"brgt", s7_D_cond_br},
261 {"brle", s7_D_cond_br},
262 {"brge", s7_D_cond_br},
263 {"brlt", s7_D_cond_br},
264 {"brmi", s7_D_cond_br},
265 {"brpl", s7_D_cond_br},
266 {"brvs", s7_D_cond_br},
267 {"brvc", s7_D_cond_br},
268 {"brcsl", s7_D_cond_br},
269 {"brccl", s7_D_cond_br},
270 {"brgtul", s7_D_cond_br},
271 {"brleul", s7_D_cond_br},
272 {"breql", s7_D_cond_br},
273 {"brnel", s7_D_cond_br},
274 {"brgtl", s7_D_cond_br},
275 {"brlel", s7_D_cond_br},
276 {"brgel", s7_D_cond_br},
277 {"brltl", s7_D_cond_br},
278 {"brmil", s7_D_cond_br},
279 {"brpll", s7_D_cond_br},
280 {"brvsl", s7_D_cond_br},
281 {"brvcl", s7_D_cond_br},
282 {"brcs!", s7_D_cond_br},
283 {"brcc!", s7_D_cond_br},
284 {"brgtu!", s7_D_cond_br},
285 {"brleu!", s7_D_cond_br},
286 {"breq!", s7_D_cond_br},
287 {"brne!", s7_D_cond_br},
288 {"brgt!", s7_D_cond_br},
289 {"brle!", s7_D_cond_br},
290 {"brge!", s7_D_cond_br},
291 {"brlt!", s7_D_cond_br},
292 {"brmi!", s7_D_cond_br},
293 {"brpl!", s7_D_cond_br},
294 {"brvs!", s7_D_cond_br},
295 {"brvc!", s7_D_cond_br},
296 {"brcsl!", s7_D_cond_br},
297 {"brccl!", s7_D_cond_br},
298 {"brgtul!", s7_D_cond_br},
299 {"brleul!", s7_D_cond_br},
300 {"breql!", s7_D_cond_br},
301 {"brnel!", s7_D_cond_br},
302 {"brgtl!", s7_D_cond_br},
303 {"brlel!", s7_D_cond_br},
304 {"brgel!", s7_D_cond_br},
305 {"brltl!", s7_D_cond_br},
306 {"brmil!", s7_D_cond_br},
307 {"brpll!", s7_D_cond_br},
308 {"brvsl!", s7_D_cond_br},
309 {"brvcl!", s7_D_cond_br},
310 /* conditional move instruction. */
311 {"mvcs", s7_D_cond_mv},
312 {"mvcc", s7_D_cond_mv},
313 {"mvgtu", s7_D_cond_mv},
314 {"mvleu", s7_D_cond_mv},
315 {"mveq", s7_D_cond_mv},
316 {"mvne", s7_D_cond_mv},
317 {"mvgt", s7_D_cond_mv},
318 {"mvle", s7_D_cond_mv},
319 {"mvge", s7_D_cond_mv},
320 {"mvlt", s7_D_cond_mv},
321 {"mvmi", s7_D_cond_mv},
322 {"mvpl", s7_D_cond_mv},
323 {"mvvs", s7_D_cond_mv},
324 {"mvvc", s7_D_cond_mv},
33eaf5de 325 /* move special instruction. */
c3b7224a
NC
326 {"mtcr", s7_D_mtcr},
327 {"mftlb", s7_D_mftlb},
328 {"mtptlb", s7_D_mtptlb},
329 {"mtrtlb", s7_D_mtrtlb},
330 {"stlb", s7_D_stlb},
331 {"mfcr", s7_D_mfcr},
332 {"mfsr", s7_D_mfsr},
333 /* cache instruction. */
334 {"cache 8", s7_D_cached},
335 {"cache 9", s7_D_cached},
336 {"cache 10", s7_D_cached},
337 {"cache 11", s7_D_cached},
338 {"cache 12", s7_D_cached},
339 {"cache 13", s7_D_cached},
340 {"cache 14", s7_D_cached},
341 {"cache 24", s7_D_cached},
342 {"cache 26", s7_D_cached},
343 {"cache 27", s7_D_cached},
344 {"cache 29", s7_D_cached},
345 {"cache 30", s7_D_cached},
346 {"cache 31", s7_D_cached},
347 {"cache 0", s7_D_cachei},
348 {"cache 1", s7_D_cachei},
349 {"cache 2", s7_D_cachei},
350 {"cache 3", s7_D_cachei},
351 {"cache 4", s7_D_cachei},
352 {"cache 16", s7_D_cachei},
353 {"cache 17", s7_D_cachei},
354 /* load/store instruction. */
355 {"lb", s7_D_ldst},
356 {"lbu", s7_D_ldst},
357 {"lbu!", s7_D_ldst},
358 {"lbup!", s7_D_ldst},
359 {"lh", s7_D_ldst},
360 {"lhu", s7_D_ldst},
361 {"lh!", s7_D_ldst},
362 {"lhp!", s7_D_ldst},
363 {"lw", s7_D_ldst},
364 {"lw!", s7_D_ldst},
365 {"lwp!", s7_D_ldst},
366 {"sb", s7_D_ldst},
367 {"sb!", s7_D_ldst},
368 {"sbp!", s7_D_ldst},
369 {"sh", s7_D_ldst},
370 {"sh!", s7_D_ldst},
371 {"shp!", s7_D_ldst},
372 {"sw", s7_D_ldst},
373 {"sw!", s7_D_ldst},
374 {"swp!", s7_D_ldst},
375 {"alw", s7_D_ldst},
376 {"asw", s7_D_ldst},
377 {"push!", s7_D_ldst},
378 {"pushhi!", s7_D_ldst},
379 {"pop!", s7_D_ldst},
380 {"pophi!", s7_D_ldst},
381 {"ldc1", s7_D_ldst},
382 {"ldc2", s7_D_ldst},
383 {"ldc3", s7_D_ldst},
384 {"stc1", s7_D_ldst},
385 {"stc2", s7_D_ldst},
386 {"stc3", s7_D_ldst},
387 {"scb", s7_D_ldst},
388 {"scw", s7_D_ldst},
389 {"sce", s7_D_ldst},
390 /* load combine instruction. */
391 {"lcb", s7_D_ldcombine},
392 {"lcw", s7_D_ldcombine},
393 {"lce", s7_D_ldcombine},
394};
395
396static const struct s7_data_dependency s7_data_dependency_table[] =
397{
398 /* Condition register. */
399 {s7_D_mtcr, "cr1", s7_D_pce, "", 2, 1, 0},
400 {s7_D_mtcr, "cr1", s7_D_cond_br, "", 1, 0, 1},
401 {s7_D_mtcr, "cr1", s7_D_cond_mv, "", 1, 0, 1},
33eaf5de 402 /* Status register. */
c3b7224a 403 {s7_D_mtcr, "cr0", s7_D_all_insn, "", 5, 4, 0},
33eaf5de 404 /* CCR register. */
c3b7224a
NC
405 {s7_D_mtcr, "cr4", s7_D_all_insn, "", 6, 5, 0},
406 /* EntryHi/EntryLo register. */
407 {s7_D_mftlb, "", s7_D_mtptlb, "", 1, 1, 1},
408 {s7_D_mftlb, "", s7_D_mtrtlb, "", 1, 1, 1},
409 {s7_D_mftlb, "", s7_D_stlb, "", 1, 1,1},
410 {s7_D_mftlb, "", s7_D_mfcr, "cr11", 1, 1, 1},
411 {s7_D_mftlb, "", s7_D_mfcr, "cr12", 1, 1, 1},
412 /* Index register. */
413 {s7_D_stlb, "", s7_D_mtptlb, "", 1, 1, 1},
414 {s7_D_stlb, "", s7_D_mftlb, "", 1, 1, 1},
415 {s7_D_stlb, "", s7_D_mfcr, "cr8", 2, 2, 1},
416 /* Cache. */
417 {s7_D_cached, "", s7_D_ldst, "", 1, 1, 0},
418 {s7_D_cached, "", s7_D_ldcombine, "", 1, 1, 0},
419 {s7_D_cachei, "", s7_D_all_insn, "", 5, 4, 0},
420 /* Load combine. */
421 {s7_D_ldcombine, "", s7_D_mfsr, "sr1", 3, 3, 1},
422};
423
424\f
425
426/* Used to contain constructed error messages. */
427static char s7_err_msg[255];
428static int s7_fix_data_dependency = 0;
429static int s7_warn_fix_data_dependency = 1;
430
431static int s7_in_my_get_expression = 0;
432
433/* Default, pop warning message when using r1. */
434static int s7_nor1 = 1;
435
436/* Default will do instruction relax, -O0 will set s7_g_opt = 0. */
437static unsigned int s7_g_opt = 1;
438
439/* The size of the small data section. */
440static unsigned int s7_g_switch_value = 8;
441
442static segT s7_pdr_seg;
443
444struct s7_score_it
445{
446 char name[s7_INSN_NAME_LEN];
447 unsigned long instruction;
448 unsigned long relax_inst;
449 int size;
450 int relax_size;
451 enum score_insn_type type;
452 char str[s7_MAX_LITERAL_POOL_SIZE];
453 const char *error;
454 int bwarn;
455 char reg[s7_INSN_NAME_LEN];
456 struct
457 {
458 bfd_reloc_code_real_type type;
459 expressionS exp;
460 int pc_rel;
461 }reloc;
462};
463static struct s7_score_it s7_inst;
464
465typedef struct proc
466{
467 symbolS *isym;
468 unsigned long reg_mask;
469 unsigned long reg_offset;
470 unsigned long fpreg_mask;
471 unsigned long leaf;
472 unsigned long frame_offset;
473 unsigned long frame_reg;
474 unsigned long pc_reg;
475} s7_procS;
476static s7_procS s7_cur_proc;
477static s7_procS *s7_cur_proc_ptr;
478static int s7_numprocs;
479
480/* Structure for a hash table entry for a register. */
481struct s7_reg_entry
482{
483 const char *name;
484 int number;
485};
486
487static const struct s7_reg_entry s7_score_rn_table[] =
488{
489 {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
490 {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
491 {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
492 {"r12", 12}, {"r13", 13}, {"r14", 14}, {"r15", 15},
493 {"r16", 16}, {"r17", 17}, {"r18", 18}, {"r19", 19},
494 {"r20", 20}, {"r21", 21}, {"r22", 22}, {"r23", 23},
495 {"r24", 24}, {"r25", 25}, {"r26", 26}, {"r27", 27},
496 {"r28", 28}, {"r29", 29}, {"r30", 30}, {"r31", 31},
497 {NULL, 0}
498};
499
500static const struct s7_reg_entry s7_score_srn_table[] =
501{
502 {"sr0", 0}, {"sr1", 1}, {"sr2", 2},
503 {NULL, 0}
504};
505
506static const struct s7_reg_entry s7_score_crn_table[] =
507{
508 {"cr0", 0}, {"cr1", 1}, {"cr2", 2}, {"cr3", 3},
509 {"cr4", 4}, {"cr5", 5}, {"cr6", 6}, {"cr7", 7},
510 {"cr8", 8}, {"cr9", 9}, {"cr10", 10}, {"cr11", 11},
511 {"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15},
512 {"cr16", 16}, {"cr17", 17}, {"cr18", 18}, {"cr19", 19},
513 {"cr20", 20}, {"cr21", 21}, {"cr22", 22}, {"cr23", 23},
514 {"cr24", 24}, {"cr25", 25}, {"cr26", 26}, {"cr27", 27},
515 {"cr28", 28}, {"cr29", 29}, {"cr30", 30}, {"cr31", 31},
516 {NULL, 0}
517};
518
519struct s7_reg_map
520{
521 const struct s7_reg_entry *names;
522 int max_regno;
629310ab 523 htab_t htab;
c3b7224a
NC
524 const char *expected;
525};
526
527static struct s7_reg_map s7_all_reg_maps[] =
528{
529 {s7_score_rn_table, 31, NULL, N_("S+core register expected")},
530 {s7_score_srn_table, 2, NULL, N_("S+core special-register expected")},
531 {s7_score_crn_table, 31, NULL, N_("S+core co-processor register expected")},
532};
533
629310ab
ML
534static htab_t s7_score_ops_hsh = NULL;
535static htab_t s7_dependency_insn_hsh = NULL;
c3b7224a
NC
536
537\f
538struct s7_datafield_range
539{
540 int data_type;
541 int bits;
542 int range[2];
543};
544
545static struct s7_datafield_range s7_score_df_range[] =
546{
547 {_IMM4, 4, {0, (1 << 4) - 1}}, /* ( 0 ~ 15 ) */
548 {_IMM5, 5, {0, (1 << 5) - 1}}, /* ( 0 ~ 31 ) */
549 {_IMM8, 8, {0, (1 << 8) - 1}}, /* ( 0 ~ 255 ) */
550 {_IMM14, 14, {0, (1 << 14) - 1}}, /* ( 0 ~ 16383) */
551 {_IMM15, 15, {0, (1 << 15) - 1}}, /* ( 0 ~ 32767) */
552 {_IMM16, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */
553 {_SIMM10, 10, {-(1 << 9), (1 << 9) - 1}}, /* ( -512 ~ 511 ) */
554 {_SIMM12, 12, {-(1 << 11), (1 << 11) - 1}}, /* ( -2048 ~ 2047 ) */
555 {_SIMM14, 14, {-(1 << 13), (1 << 13) - 1}}, /* ( -8192 ~ 8191 ) */
556 {_SIMM15, 15, {-(1 << 14), (1 << 14) - 1}}, /* (-16384 ~ 16383) */
557 {_SIMM16, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
558 {_SIMM14_NEG, 14, {-(1 << 13), (1 << 13) - 1}}, /* ( -8191 ~ 8192 ) */
559 {_IMM16_NEG, 16, {0, (1 << 16) - 1}}, /* (-65535 ~ 0 ) */
560 {_SIMM16_NEG, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
561 {_IMM20, 20, {0, (1 << 20) - 1}},
562 {_IMM25, 25, {0, (1 << 25) - 1}},
563 {_DISP8div2, 8, {-(1 << 8), (1 << 8) - 1}}, /* ( -256 ~ 255 ) */
564 {_DISP11div2, 11, {0, 0}},
565 {_DISP19div2, 19, {-(1 << 19), (1 << 19) - 1}}, /* (-524288 ~ 524287) */
566 {_DISP24div2, 24, {0, 0}},
567 {_VALUE, 32, {0, ((unsigned int)1 << 31) - 1}},
568 {_VALUE_HI16, 16, {0, (1 << 16) - 1}},
569 {_VALUE_LO16, 16, {0, (1 << 16) - 1}},
570 {_VALUE_LDST_LO16, 16, {0, (1 << 16) - 1}},
571 {_SIMM16_LA, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
572 {_IMM5_RSHIFT_1, 5, {0, (1 << 6) - 1}}, /* ( 0 ~ 63 ) */
573 {_IMM5_RSHIFT_2, 5, {0, (1 << 7) - 1}}, /* ( 0 ~ 127 ) */
574 {_SIMM16_LA_POS, 16, {0, (1 << 15) - 1}}, /* ( 0 ~ 32767) */
575 {_IMM5_RANGE_8_31, 5, {8, 31}}, /* But for cop0 the valid data : (8 ~ 31). */
576 {_IMM10_RSHIFT_2, 10, {-(1 << 11), (1 << 11) - 1}}, /* For ldc#, stc#. */
577 {_SIMM10, 10, {0, (1 << 10) - 1}}, /* ( -1024 ~ 1023 ) */
578 {_SIMM12, 12, {0, (1 << 12) - 1}}, /* ( -2048 ~ 2047 ) */
579 {_SIMM14, 14, {0, (1 << 14) - 1}}, /* ( -8192 ~ 8191 ) */
580 {_SIMM15, 15, {0, (1 << 15) - 1}}, /* (-16384 ~ 16383) */
581 {_SIMM16, 16, {0, (1 << 16) - 1}}, /* (-65536 ~ 65536) */
582 {_SIMM14_NEG, 14, {0, (1 << 16) - 1}}, /* ( -8191 ~ 8192 ) */
583 {_IMM16_NEG, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
584 {_SIMM16_NEG, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
585 {_IMM20, 20, {0, (1 << 20) - 1}}, /* (-32768 ~ 32767) */
586 {_IMM25, 25, {0, (1 << 25) - 1}}, /* (-32768 ~ 32767) */
587 {_GP_IMM15, 15, {0, (1 << 15) - 1}}, /* ( 0 ~ 65535) */
588 {_GP_IMM14, 14, {0, (1 << 14) - 1}}, /* ( 0 ~ 65535) */
589 {_SIMM16_pic, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
590 {_IMM16_LO16_pic, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
591 {_IMM16_pic, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */
592};
593
594\f
595struct s7_asm_opcode
596{
597 /* Instruction name. */
d3ce72d0 598 const char *template_name;
c3b7224a
NC
599
600 /* Instruction Opcode. */
601 bfd_vma value;
602
603 /* Instruction bit mask. */
604 bfd_vma bitmask;
605
606 /* Relax instruction opcode. 0x8000 imply no relaxation. */
607 bfd_vma relax_value;
608
609 /* Instruction type. */
610 enum score_insn_type type;
611
612 /* Function to call to parse args. */
613 void (*parms) (char *);
614};
615
616static const struct s7_asm_opcode s7_score_ldst_insns[] =
617{
618 {"lw", 0x20000000, 0x3e000000, 0x2008, Rd_rvalueRs_SI15, s7_do_ldst_insn},
619 {"lw", 0x06000000, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s7_do_ldst_insn},
620 {"lw", 0x0e000000, 0x3e000007, 0x200a, Rd_rvalueRs_postSI12, s7_do_ldst_insn},
621 {"lh", 0x22000000, 0x3e000000, 0x2009, Rd_rvalueRs_SI15, s7_do_ldst_insn},
622 {"lh", 0x06000001, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s7_do_ldst_insn},
623 {"lh", 0x0e000001, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s7_do_ldst_insn},
624 {"lhu", 0x24000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, s7_do_ldst_insn},
625 {"lhu", 0x06000002, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s7_do_ldst_insn},
626 {"lhu", 0x0e000002, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s7_do_ldst_insn},
627 {"lb", 0x26000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, s7_do_ldst_insn},
628 {"lb", 0x06000003, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s7_do_ldst_insn},
629 {"lb", 0x0e000003, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s7_do_ldst_insn},
630 {"sw", 0x28000000, 0x3e000000, 0x200c, Rd_lvalueRs_SI15, s7_do_ldst_insn},
631 {"sw", 0x06000004, 0x3e000007, 0x200e, Rd_lvalueRs_preSI12, s7_do_ldst_insn},
632 {"sw", 0x0e000004, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s7_do_ldst_insn},
633 {"sh", 0x2a000000, 0x3e000000, 0x200d, Rd_lvalueRs_SI15, s7_do_ldst_insn},
634 {"sh", 0x06000005, 0x3e000007, 0x8000, Rd_lvalueRs_preSI12, s7_do_ldst_insn},
635 {"sh", 0x0e000005, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s7_do_ldst_insn},
636 {"lbu", 0x2c000000, 0x3e000000, 0x200b, Rd_rvalueRs_SI15, s7_do_ldst_insn},
637 {"lbu", 0x06000006, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s7_do_ldst_insn},
638 {"lbu", 0x0e000006, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s7_do_ldst_insn},
639 {"sb", 0x2e000000, 0x3e000000, 0x200f, Rd_lvalueRs_SI15, s7_do_ldst_insn},
640 {"sb", 0x06000007, 0x3e000007, 0x8000, Rd_lvalueRs_preSI12, s7_do_ldst_insn},
641 {"sb", 0x0e000007, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s7_do_ldst_insn},
642};
643
644static const struct s7_asm_opcode s7_score_insns[] =
645{
646 {"abs", 0x3800000a, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
647 {"abs.s", 0x3800004b, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
648 {"add", 0x00000010, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
649 {"add.c", 0x00000011, 0x3e0003ff, 0x2000, Rd_Rs_Rs, s7_do_rdrsrs},
650 {"add.s", 0x38000048, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
651 {"addc", 0x00000012, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
652 {"addc.c", 0x00000013, 0x3e0003ff, 0x0009, Rd_Rs_Rs, s7_do_rdrsrs},
653 {"addi", 0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_rdsi16},
654 {"addi.c", 0x02000001, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_rdsi16},
655 {"addis", 0x0a000000, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_rdi16},
656 {"addis.c", 0x0a000001, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_rdi16},
657 {"addri", 0x10000000, 0x3e000001, 0x8000, Rd_Rs_SI14, s7_do_rdrssi14},
658 {"addri.c", 0x10000001, 0x3e000001, 0x8000, Rd_Rs_SI14, s7_do_rdrssi14},
659 {"addc!", 0x0009, 0x700f, 0x00000013, Rd_Rs, s7_do16_rdrs},
660 {"add!", 0x2000, 0x700f, 0x00000011, Rd_Rs, s7_do16_rdrs},
661 {"addei!", 0x6000 , 0x7087, 0x02000001, Rd_I4, s7_do16_rdi4},
662 {"subi", 0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_sub_rdsi16},
663 {"subi.c", 0x02000001, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_sub_rdsi16},
664 {"subri", 0x10000000, 0x3e000001, 0x8000, Rd_Rs_SI14, s7_do_sub_rdrssi14},
665 {"subri.c", 0x10000001, 0x3e000001, 0x8000, Rd_Rs_SI14, s7_do_sub_rdrssi14},
666 {"and", 0x00000020, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
667 {"and.c", 0x00000021, 0x3e0003ff, 0x2004, Rd_Rs_Rs, s7_do_rdrsrs},
668 {"andi", 0x02080000, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
669 {"andi.c", 0x02080001, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
670 {"andis", 0x0a080000, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
671 {"andis.c", 0x0a080001, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
672 {"andri", 0x18000000, 0x3e000001, 0x8000, Rd_Rs_I14, s7_do_rdrsi14},
673 {"andri.c", 0x18000001, 0x3e000001, 0x8000, Rd_Rs_I14, s7_do_rdrsi14},
674 {"and!", 0x2004, 0x700f, 0x00000021, Rd_Rs, s7_do16_rdrs},
675 {"bcs", 0x08000000, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
676 {"bcc", 0x08000400, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
677 {"bcnz", 0x08003800, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
678 {"bcsl", 0x08000001, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
679 {"bccl", 0x08000401, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
680 {"bcnzl", 0x08003801, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
681 {"bcs!", 0x4000, 0x7f00, 0x08000000, PC_DISP8div2, s7_do16_branch},
682 {"bcc!", 0x4100, 0x7f00, 0x08000400, PC_DISP8div2, s7_do16_branch},
683 {"bcnz!", 0x4e00, 0x7f00, 0x08003800, PC_DISP8div2, s7_do16_branch},
684 {"beq", 0x08001000, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
685 {"beql", 0x08001001, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
686 {"beq!", 0x4400, 0x7f00, 0x08001000, PC_DISP8div2, s7_do16_branch},
687 {"bgtu", 0x08000800, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
688 {"bgt", 0x08001800, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
689 {"bge", 0x08002000, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
690 {"bgtul", 0x08000801, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
691 {"bgtl", 0x08001801, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
692 {"bgel", 0x08002001, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
693 {"bgtu!", 0x4200, 0x7f00, 0x08000800, PC_DISP8div2, s7_do16_branch},
694 {"bgt!", 0x4600, 0x7f00, 0x08001800, PC_DISP8div2, s7_do16_branch},
695 {"bge!", 0x4800, 0x7f00, 0x08002000, PC_DISP8div2, s7_do16_branch},
696 {"bitclr.c", 0x00000029, 0x3e0003ff, 0x6004, Rd_Rs_I5, s7_do_rdrsi5},
697 {"bitrev", 0x3800000c, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
698 {"bitset.c", 0x0000002b, 0x3e0003ff, 0x6005, Rd_Rs_I5, s7_do_rdrsi5},
699 {"bittst.c", 0x0000002d, 0x3e0003ff, 0x6006, x_Rs_I5, s7_do_xrsi5},
700 {"bittgl.c", 0x0000002f, 0x3e0003ff, 0x6007, Rd_Rs_I5, s7_do_rdrsi5},
701 {"bitclr!", 0x6004, 0x7007, 0x00000029, Rd_I5, s7_do16_rdi5},
702 {"bitset!", 0x6005, 0x7007, 0x0000002b, Rd_I5, s7_do16_rdi5},
703 {"bittst!", 0x6006, 0x7007, 0x0000002d, Rd_I5, s7_do16_rdi5},
704 {"bittgl!", 0x6007, 0x7007, 0x0000002f, Rd_I5, s7_do16_rdi5},
705 {"bleu", 0x08000c00, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
706 {"ble", 0x08001c00, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
707 {"blt", 0x08002400, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
708 {"bleul", 0x08000c01, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
709 {"blel", 0x08001c01, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
710 {"bltl", 0x08002401, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
711 {"bl", 0x08003c01, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
712 {"bleu!", 0x4300, 0x7f00, 0x08000c00, PC_DISP8div2, s7_do16_branch},
713 {"ble!", 0x4700, 0x7f00, 0x08001c00, PC_DISP8div2, s7_do16_branch},
714 {"blt!", 0x4900, 0x7f00, 0x08002400, PC_DISP8div2, s7_do16_branch},
715 {"bmi", 0x08002800, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
716 {"bmil", 0x08002801, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
717 {"bmi!", 0x00004a00, 0x00007f00, 0x08002800, PC_DISP8div2, s7_do16_branch},
718 {"bne", 0x08001400, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
719 {"bnel", 0x08001401, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
720 {"bne!", 0x4500, 0x7f00, 0x08001400, PC_DISP8div2, s7_do16_branch},
721 {"bpl", 0x08002c00, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
722 {"bpll", 0x08002c01, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
723 {"bpl!", 0x4b00, 0x7f00, 0x08002c00, PC_DISP8div2, s7_do16_branch},
724 {"brcs", 0x00000008, 0x3e007fff, 0x0004, x_Rs_x, s7_do_rs},
725 {"brcc", 0x00000408, 0x3e007fff, 0x0104, x_Rs_x, s7_do_rs},
726 {"brgtu", 0x00000808, 0x3e007fff, 0x0204, x_Rs_x, s7_do_rs},
727 {"brleu", 0x00000c08, 0x3e007fff, 0x0304, x_Rs_x, s7_do_rs},
728 {"breq", 0x00001008, 0x3e007fff, 0x0404, x_Rs_x, s7_do_rs},
729 {"brne", 0x00001408, 0x3e007fff, 0x0504, x_Rs_x, s7_do_rs},
730 {"brgt", 0x00001808, 0x3e007fff, 0x0604, x_Rs_x, s7_do_rs},
731 {"brle", 0x00001c08, 0x3e007fff, 0x0704, x_Rs_x, s7_do_rs},
732 {"brge", 0x00002008, 0x3e007fff, 0x0804, x_Rs_x, s7_do_rs},
733 {"brlt", 0x00002408, 0x3e007fff, 0x0904, x_Rs_x, s7_do_rs},
734 {"brmi", 0x00002808, 0x3e007fff, 0x0a04, x_Rs_x, s7_do_rs},
735 {"brpl", 0x00002c08, 0x3e007fff, 0x0b04, x_Rs_x, s7_do_rs},
736 {"brvs", 0x00003008, 0x3e007fff, 0x0c04, x_Rs_x, s7_do_rs},
737 {"brvc", 0x00003408, 0x3e007fff, 0x0d04, x_Rs_x, s7_do_rs},
738 {"brcnz", 0x00003808, 0x3e007fff, 0x0e04, x_Rs_x, s7_do_rs},
739 {"br", 0x00003c08, 0x3e007fff, 0x0f04, x_Rs_x, s7_do_rs},
740 {"brcsl", 0x00000009, 0x3e007fff, 0x000c, x_Rs_x, s7_do_rs},
741 {"brccl", 0x00000409, 0x3e007fff, 0x010c, x_Rs_x, s7_do_rs},
742 {"brgtul", 0x00000809, 0x3e007fff, 0x020c, x_Rs_x, s7_do_rs},
743 {"brleul", 0x00000c09, 0x3e007fff, 0x030c, x_Rs_x, s7_do_rs},
744 {"breql", 0x00001009, 0x3e007fff, 0x040c, x_Rs_x, s7_do_rs},
745 {"brnel", 0x00001409, 0x3e007fff, 0x050c, x_Rs_x, s7_do_rs},
746 {"brgtl", 0x00001809, 0x3e007fff, 0x060c, x_Rs_x, s7_do_rs},
747 {"brlel", 0x00001c09, 0x3e007fff, 0x070c, x_Rs_x, s7_do_rs},
748 {"brgel", 0x00002009, 0x3e007fff, 0x080c, x_Rs_x, s7_do_rs},
749 {"brltl", 0x00002409, 0x3e007fff, 0x090c, x_Rs_x, s7_do_rs},
750 {"brmil", 0x00002809, 0x3e007fff, 0x0a0c, x_Rs_x, s7_do_rs},
751 {"brpll", 0x00002c09, 0x3e007fff, 0x0b0c, x_Rs_x, s7_do_rs},
752 {"brvsl", 0x00003009, 0x3e007fff, 0x0c0c, x_Rs_x, s7_do_rs},
753 {"brvcl", 0x00003409, 0x3e007fff, 0x0d0c, x_Rs_x, s7_do_rs},
754 {"brcnzl", 0x00003809, 0x3e007fff, 0x0e0c, x_Rs_x, s7_do_rs},
755 {"brl", 0x00003c09, 0x3e007fff, 0x0f0c, x_Rs_x, s7_do_rs},
756 {"brcs!", 0x0004, 0x7f0f, 0x00000008, x_Rs, s7_do16_xrs},
757 {"brcc!", 0x0104, 0x7f0f, 0x00000408, x_Rs, s7_do16_xrs},
758 {"brgtu!", 0x0204, 0x7f0f, 0x00000808, x_Rs, s7_do16_xrs},
759 {"brleu!", 0x0304, 0x7f0f, 0x00000c08, x_Rs, s7_do16_xrs},
760 {"breq!", 0x0404, 0x7f0f, 0x00001008, x_Rs, s7_do16_xrs},
761 {"brne!", 0x0504, 0x7f0f, 0x00001408, x_Rs, s7_do16_xrs},
762 {"brgt!", 0x0604, 0x7f0f, 0x00001808, x_Rs, s7_do16_xrs},
763 {"brle!", 0x0704, 0x7f0f, 0x00001c08, x_Rs, s7_do16_xrs},
764 {"brge!", 0x0804, 0x7f0f, 0x00002008, x_Rs, s7_do16_xrs},
765 {"brlt!", 0x0904, 0x7f0f, 0x00002408, x_Rs, s7_do16_xrs},
766 {"brmi!", 0x0a04, 0x7f0f, 0x00002808, x_Rs, s7_do16_xrs},
767 {"brpl!", 0x0b04, 0x7f0f, 0x00002c08, x_Rs, s7_do16_xrs},
768 {"brvs!", 0x0c04, 0x7f0f, 0x00003008, x_Rs, s7_do16_xrs},
769 {"brvc!", 0x0d04, 0x7f0f, 0x00003408, x_Rs, s7_do16_xrs},
770 {"brcnz!", 0x0e04, 0x7f0f, 0x00003808, x_Rs, s7_do16_xrs},
771 {"br!", 0x0f04, 0x7f0f, 0x00003c08, x_Rs, s7_do16_xrs},
772 {"brcsl!", 0x000c, 0x7f0f, 0x00000009, x_Rs, s7_do16_xrs},
773 {"brccl!", 0x010c, 0x7f0f, 0x00000409, x_Rs, s7_do16_xrs},
774 {"brgtul!", 0x020c, 0x7f0f, 0x00000809, x_Rs, s7_do16_xrs},
775 {"brleul!", 0x030c, 0x7f0f, 0x00000c09, x_Rs, s7_do16_xrs},
776 {"breql!", 0x040c, 0x7f0f, 0x00001009, x_Rs, s7_do16_xrs},
777 {"brnel!", 0x050c, 0x7f0f, 0x00001409, x_Rs, s7_do16_xrs},
778 {"brgtl!", 0x060c, 0x7f0f, 0x00001809, x_Rs, s7_do16_xrs},
779 {"brlel!", 0x070c, 0x7f0f, 0x00001c09, x_Rs, s7_do16_xrs},
780 {"brgel!", 0x080c, 0x7f0f, 0x00002009, x_Rs, s7_do16_xrs},
781 {"brltl!", 0x090c, 0x7f0f, 0x00002409, x_Rs, s7_do16_xrs},
782 {"brmil!", 0x0a0c, 0x7f0f, 0x00002809, x_Rs, s7_do16_xrs},
783 {"brpll!", 0x0b0c, 0x7f0f, 0x00002c09, x_Rs, s7_do16_xrs},
784 {"brvsl!", 0x0c0c, 0x7f0f, 0x00003009, x_Rs, s7_do16_xrs},
785 {"brvcl!", 0x0d0c, 0x7f0f, 0x00003409, x_Rs, s7_do16_xrs},
786 {"brcnzl!", 0x0e0c, 0x7f0f, 0x00003809, x_Rs, s7_do16_xrs},
787 {"brl!", 0x0f0c, 0x7f0f, 0x00003c09, x_Rs, s7_do16_xrs},
788 {"bvs", 0x08003000, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
789 {"bvc", 0x08003400, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
790 {"bvsl", 0x08003001, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
791 {"bvcl", 0x08003401, 0x3e007c01, 0x8000, PC_DISP19div2, s7_do_branch},
792 {"bvs!", 0x4c00, 0x7f00, 0x08003000, PC_DISP8div2, s7_do16_branch},
793 {"bvc!", 0x4d00, 0x7f00, 0x08003400, PC_DISP8div2, s7_do16_branch},
794 {"b!", 0x4f00, 0x7f00, 0x08003c00, PC_DISP8div2, s7_do16_branch},
795 {"b", 0x08003c00, 0x3e007c01, 0x4000, PC_DISP19div2, s7_do_branch},
796 {"cache", 0x30000000, 0x3ff00000, 0x8000, OP5_rvalueRs_SI15, s7_do_cache},
797 {"ceinst", 0x38000000, 0x3e000000, 0x8000, I5_Rs_Rs_I5_OP5, s7_do_ceinst},
798 {"clz", 0x3800000d, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
799 {"cmpteq.c", 0x00000019, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
800 {"cmptmi.c", 0x00100019, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
801 {"cmp.c", 0x00300019, 0x3ff003ff, 0x2003, x_Rs_Rs, s7_do_rsrs},
802 {"cmpzteq.c", 0x0000001b, 0x3ff07fff, 0x8000, x_Rs_x, s7_do_rs},
803 {"cmpztmi.c", 0x0010001b, 0x3ff07fff, 0x8000, x_Rs_x, s7_do_rs},
804 {"cmpz.c", 0x0030001b, 0x3ff07fff, 0x8000, x_Rs_x, s7_do_rs},
805 {"cmpi.c", 0x02040001, 0x3e0e0001, 0x8000, Rd_SI16, s7_do_rdsi16},
806 {"cmp!", 0x2003, 0x700f, 0x00300019, Rd_Rs, s7_do16_rdrs},
807 {"cop1", 0x0c00000c, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, s7_do_crdcrscrsimm5},
808 {"cop2", 0x0c000014, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, s7_do_crdcrscrsimm5},
809 {"cop3", 0x0c00001c, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, s7_do_crdcrscrsimm5},
810 {"drte", 0x0c0000a4, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
811 {"extsb", 0x00000058, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
812 {"extsb.c", 0x00000059, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
813 {"extsh", 0x0000005a, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
814 {"extsh.c", 0x0000005b, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
815 {"extzb", 0x0000005c, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
816 {"extzb.c", 0x0000005d, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
817 {"extzh", 0x0000005e, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
818 {"extzh.c", 0x0000005f, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
819 {"jl", 0x04000001, 0x3e000001, 0x8000, PC_DISP24div2, s7_do_jump},
820 {"jl!", 0x3001, 0x7001, 0x04000001, PC_DISP11div2, s7_do16_jump},
821 {"j!", 0x3000, 0x7001, 0x04000000, PC_DISP11div2, s7_do16_jump},
822 {"j", 0x04000000, 0x3e000001, 0x8000, PC_DISP24div2, s7_do_jump},
823 {"lbu!", 0x200b, 0x0000700f, 0x2c000000, Rd_rvalueRs, s7_do16_ldst_insn},
824 {"lbup!", 0x7003, 0x7007, 0x2c000000, Rd_rvalueBP_I5, s7_do16_ldst_imm_insn},
825 {"alw", 0x0000000c, 0x3e0003ff, 0x8000, Rd_rvalue32Rs, s7_do_ldst_atomic},
826 {"lcb", 0x00000060, 0x3e0003ff, 0x8000, x_rvalueRs_post4, s7_do_ldst_unalign},
827 {"lcw", 0x00000062, 0x3e0003ff, 0x8000, Rd_rvalueRs_post4, s7_do_ldst_unalign},
828 {"lce", 0x00000066, 0x3e0003ff, 0x8000, Rd_rvalueRs_post4, s7_do_ldst_unalign},
829 {"ldc1", 0x0c00000a, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, s7_do_ldst_cop},
830 {"ldc2", 0x0c000012, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, s7_do_ldst_cop},
831 {"ldc3", 0x0c00001a, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, s7_do_ldst_cop},
832 {"lh!", 0x2009, 0x700f, 0x22000000, Rd_rvalueRs, s7_do16_ldst_insn},
833 {"lhp!", 0x7001, 0x7007, 0x22000000, Rd_rvalueBP_I5, s7_do16_ldst_imm_insn},
834 {"ldi", 0x020c0000, 0x3e0e0000, 0x5000, Rd_SI16, s7_do_rdsi16},
835 {"ldis", 0x0a0c0000, 0x3e0e0000, 0x8000, Rd_I16, s7_do_rdi16},
836 {"ldiu!", 0x5000, 0x7000, 0x020c0000, Rd_I8, s7_do16_ldst_imm_insn},
837 {"lw!", 0x2008, 0x700f, 0x20000000, Rd_rvalueRs, s7_do16_ldst_insn},
838 {"lwp!", 0x7000, 0x7007, 0x20000000, Rd_rvalueBP_I5, s7_do16_ldst_imm_insn},
839 {"mfcel", 0x00000448, 0x3e007fff, 0x8000, Rd_x_x, s7_do_rd},
840 {"mfcel!", 0x1001, 0x7f0f, 0x00000448, x_Rs, s7_do16_rs},
841 {"mad", 0x38000000, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
842 {"mad.f!", 0x1004, 0x700f, 0x38000080, Rd_Rs, s7_do16_rdrs},
843 {"madh", 0x38000203, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
844 {"madh.fs", 0x380002c3, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
845 {"madh.fs!", 0x100b, 0x700f, 0x380002c3, Rd_Rs, s7_do16_rdrs},
846 {"madl", 0x38000002, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
847 {"madl.fs", 0x380000c2, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
848 {"madl.fs!", 0x100a, 0x700f, 0x380000c2, Rd_Rs, s7_do16_rdrs},
849 {"madu", 0x38000020, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
850 {"madu!", 0x1005, 0x700f, 0x38000020, Rd_Rs, s7_do16_rdrs},
851 {"mad.f", 0x38000080, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
852 {"max", 0x38000007, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
853 {"mazh", 0x38000303, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
854 {"mazh.f", 0x38000383, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
855 {"mazh.f!", 0x1009, 0x700f, 0x38000383, Rd_Rs, s7_do16_rdrs},
856 {"mazl", 0x38000102, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
857 {"mazl.f", 0x38000182, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
858 {"mazl.f!", 0x1008, 0x700f, 0x38000182, Rd_Rs, s7_do16_rdrs},
859 {"mfceh", 0x00000848, 0x3e007fff, 0x8000, Rd_x_x, s7_do_rd},
860 {"mfceh!", 0x1101, 0x7f0f, 0x00000848, x_Rs, s7_do16_rs},
861 {"mfcehl", 0x00000c48, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
862 {"mfsr", 0x00000050, 0x3e0003ff, 0x8000, Rd_x_I5, s7_do_rdsrs},
863 {"mfcr", 0x0c000001, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
864 {"mfc1", 0x0c000009, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
865 {"mfc2", 0x0c000011, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
866 {"mfc3", 0x0c000019, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
867 {"mfcc1", 0x0c00000f, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
868 {"mfcc2", 0x0c000017, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
869 {"mfcc3", 0x0c00001f, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
870 {"mhfl!", 0x0002, 0x700f, 0x00003c56, Rd_LowRs, s7_do16_hrdrs},
871 {"min", 0x38000006, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
872 {"mlfh!", 0x0001, 0x700f, 0x00003c56, Rd_HighRs, s7_do16_rdhrs},
873 {"msb", 0x38000001, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
874 {"msb.f!", 0x1006, 0x700f, 0x38000081, Rd_Rs, s7_do16_rdrs},
875 {"msbh", 0x38000205, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
876 {"msbh.fs", 0x380002c5, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
877 {"msbh.fs!", 0x100f, 0x700f, 0x380002c5, Rd_Rs, s7_do16_rdrs},
878 {"msbl", 0x38000004, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
879 {"msbl.fs", 0x380000c4, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
880 {"msbl.fs!", 0x100e, 0x700f, 0x380000c4, Rd_Rs, s7_do16_rdrs},
881 {"msbu", 0x38000021, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
882 {"msbu!", 0x1007, 0x700f, 0x38000021, Rd_Rs, s7_do16_rdrs},
883 {"msb.f", 0x38000081, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
884 {"mszh", 0x38000305, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
885 {"mszh.f", 0x38000385, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
886 {"mszh.f!", 0x100d, 0x700f, 0x38000385, Rd_Rs, s7_do16_rdrs},
887 {"mszl", 0x38000104, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
888 {"mszl.f", 0x38000184, 0x3ff003ff, 0x8000, x_Rs_Rs, s7_do_rsrs},
889 {"mszl.f!", 0x100c, 0x700f, 0x38000184, Rd_Rs, s7_do16_rdrs},
890 {"mtcel!", 0x1000, 0x7f0f, 0x0000044a, x_Rs, s7_do16_rs},
891 {"mtcel", 0x0000044a, 0x3e007fff, 0x8000, Rd_x_x, s7_do_rd},
892 {"mtceh", 0x0000084a, 0x3e007fff, 0x8000, Rd_x_x, s7_do_rd},
893 {"mtceh!", 0x1100, 0x7f0f, 0x0000084a, x_Rs, s7_do16_rs},
894 {"mtcehl", 0x00000c4a, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
895 {"mtsr", 0x00000052, 0x3e0003ff, 0x8000, x_Rs_I5, s7_do_rdsrs},
896 {"mtcr", 0x0c000000, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
897 {"mtc1", 0x0c000008, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
898 {"mtc2", 0x0c000010, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
899 {"mtc3", 0x0c000018, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
900 {"mtcc1", 0x0c00000e, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
901 {"mtcc2", 0x0c000016, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
902 {"mtcc3", 0x0c00001e, 0x3e00001f, 0x8000, Rd_Rs_x, s7_do_rdcrs},
903 {"mul.f!", 0x1002, 0x700f, 0x00000041, Rd_Rs, s7_do16_rdrs},
904 {"mulu!", 0x1003, 0x700f, 0x00000042, Rd_Rs, s7_do16_rdrs},
905 {"mvcs", 0x00000056, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
906 {"mvcc", 0x00000456, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
907 {"mvgtu", 0x00000856, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
908 {"mvleu", 0x00000c56, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
909 {"mveq", 0x00001056, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
910 {"mvne", 0x00001456, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
911 {"mvgt", 0x00001856, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
912 {"mvle", 0x00001c56, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
913 {"mvge", 0x00002056, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
914 {"mvlt", 0x00002456, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
915 {"mvmi", 0x00002856, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
916 {"mvpl", 0x00002c56, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
917 {"mvvs", 0x00003056, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
918 {"mvvc", 0x00003456, 0x3e007fff, 0x8000, Rd_Rs_x, s7_do_rdrs},
919 {"mv", 0x00003c56, 0x3e007fff, 0x0003, Rd_Rs_x, s7_do_rdrs},
920 {"mv!", 0x0003, 0x700f, 0x00003c56, Rd_Rs, s7_do16_mv_rdrs},
921 {"neg", 0x0000001e, 0x3e0003ff, 0x8000, Rd_x_Rs, s7_do_rdxrs},
922 {"neg.c", 0x0000001f, 0x3e0003ff, 0x2002, Rd_x_Rs, s7_do_rdxrs},
923 {"neg!", 0x2002, 0x700f, 0x0000001f, Rd_Rs, s7_do16_rdrs},
924 {"nop", 0x00000000, 0x3e0003ff, 0x0000, NO_OPD, s7_do_empty},
925 {"not", 0x00000024, 0x3e0003ff, 0x8000, Rd_Rs_x, s7_do_rdrs},
926 {"not.c", 0x00000025, 0x3e0003ff, 0x2006, Rd_Rs_x, s7_do_rdrs},
927 {"nop!", 0x0000, 0x700f, 0x00000000, NO16_OPD, s7_do_empty},
928 {"not!", 0x2006, 0x700f, 0x00000025, Rd_Rs, s7_do16_rdrs},
929 {"or", 0x00000022, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
930 {"or.c", 0x00000023, 0x3e0003ff, 0x2005, Rd_Rs_Rs, s7_do_rdrsrs},
931 {"ori", 0x020a0000, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
932 {"ori.c", 0x020a0001, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
933 {"oris", 0x0a0a0000, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
934 {"oris.c", 0x0a0a0001, 0x3e0e0001, 0x8000, Rd_I16, s7_do_rdi16},
935 {"orri", 0x1a000000, 0x3e000001, 0x8000, Rd_Rs_I14, s7_do_rdrsi14},
936 {"orri.c", 0x1a000001, 0x3e000001, 0x8000, Rd_Rs_I14, s7_do_rdrsi14},
937 {"or!", 0x2005, 0x700f, 0x00000023, Rd_Rs, s7_do16_rdrs},
938 {"pflush", 0x0000000a, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
939 {"pop!", 0x200a, 0x700f, 0x0e000000, Rd_rvalueRs, s7_do16_push_pop},
940 {"push!", 0x200e, 0x700f, 0x06000004, Rd_lvalueRs, s7_do16_push_pop},
941 {"ror", 0x00000038, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
942 {"ror.c", 0x00000039, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
943 {"rorc.c", 0x0000003b, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
944 {"rol", 0x0000003c, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
945 {"rol.c", 0x0000003d, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
946 {"rolc.c", 0x0000003f, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
947 {"rori", 0x00000078, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
948 {"rori.c", 0x00000079, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
949 {"roric.c", 0x0000007b, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
950 {"roli", 0x0000007c, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
951 {"roli.c", 0x0000007d, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
952 {"rolic.c", 0x0000007f, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
953 {"rte", 0x0c000084, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
954 {"sb!", 0x200f, 0x700f, 0x2e000000, Rd_lvalueRs, s7_do16_ldst_insn},
955 {"sbp!", 0x7007, 0x7007, 0x2e000000, Rd_lvalueBP_I5, s7_do16_ldst_imm_insn},
956 {"asw", 0x0000000e, 0x3e0003ff, 0x8000, Rd_lvalue32Rs, s7_do_ldst_atomic},
957 {"scb", 0x00000068, 0x3e0003ff, 0x8000, Rd_lvalueRs_post4, s7_do_ldst_unalign},
958 {"scw", 0x0000006a, 0x3e0003ff, 0x8000, Rd_lvalueRs_post4, s7_do_ldst_unalign},
959 {"sce", 0x0000006e, 0x3e0003ff, 0x8000, x_lvalueRs_post4, s7_do_ldst_unalign},
960 {"sdbbp", 0x00000006, 0x3e0003ff, 0x6002, x_I5_x, s7_do_xi5x},
961 {"sdbbp!", 0x6002, 0x7007, 0x00000006, Rd_I5, s7_do16_xi5},
962 {"sh!", 0x200d, 0x700f, 0x2a000000, Rd_lvalueRs, s7_do16_ldst_insn},
963 {"shp!", 0x7005, 0x7007, 0x2a000000, Rd_lvalueBP_I5, s7_do16_ldst_imm_insn},
964 {"sleep", 0x0c0000c4, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
965 {"sll", 0x00000030, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
966 {"sll.c", 0x00000031, 0x3e0003ff, 0x0008, Rd_Rs_Rs, s7_do_rdrsrs},
967 {"sll.s", 0x3800004e, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
968 {"slli", 0x00000070, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
969 {"slli.c", 0x00000071, 0x3e0003ff, 0x6001, Rd_Rs_I5, s7_do_rdrsi5},
970 {"sll!", 0x0008, 0x700f, 0x00000031, Rd_Rs, s7_do16_rdrs},
971 {"slli!", 0x6001, 0x7007, 0x00000071, Rd_I5, s7_do16_rdi5},
972 {"srl", 0x00000034, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
973 {"srl.c", 0x00000035, 0x3e0003ff, 0x000a, Rd_Rs_Rs, s7_do_rdrsrs},
974 {"sra", 0x00000036, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
975 {"sra.c", 0x00000037, 0x3e0003ff, 0x000b, Rd_Rs_Rs, s7_do_rdrsrs},
976 {"srli", 0x00000074, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
977 {"srli.c", 0x00000075, 0x3e0003ff, 0x6003, Rd_Rs_I5, s7_do_rdrsi5},
978 {"srai", 0x00000076, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
979 {"srai.c", 0x00000077, 0x3e0003ff, 0x8000, Rd_Rs_I5, s7_do_rdrsi5},
980 {"srl!", 0x000a, 0x700f, 0x00000035, Rd_Rs, s7_do16_rdrs},
981 {"sra!", 0x000b, 0x700f, 0x00000037, Rd_Rs, s7_do16_rdrs},
982 {"srli!", 0x6003, 0x7007, 0x00000075, Rd_Rs, s7_do16_rdi5},
983 {"stc1", 0x0c00000b, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, s7_do_ldst_cop},
984 {"stc2", 0x0c000013, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, s7_do_ldst_cop},
985 {"stc3", 0x0c00001b, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, s7_do_ldst_cop},
986 {"sub", 0x00000014, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
987 {"sub.c", 0x00000015, 0x3e0003ff, 0x2001, Rd_Rs_Rs, s7_do_rdrsrs},
988 {"sub.s", 0x38000049, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
989 {"subc", 0x00000016, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
990 {"subc.c", 0x00000017, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
991 {"sub!", 0x2001, 0x700f, 0x00000015, Rd_Rs, s7_do16_rdrs},
992 {"subei!", 0x6080, 0x7087, 0x02000001, Rd_I4, s7_do16_rdi4},
993 {"sw!", 0x200c, 0x700f, 0x28000000, Rd_lvalueRs, s7_do16_ldst_insn},
994 {"swp!", 0x7004, 0x7007, 0x28000000, Rd_lvalueBP_I5, s7_do16_ldst_imm_insn},
995 {"syscall", 0x00000002, 0x3e0003ff, 0x8000, I15, s7_do_i15},
996 {"tcs", 0x00000054, 0x3e007fff, 0x0005, NO_OPD, s7_do_empty},
997 {"tcc", 0x00000454, 0x3e007fff, 0x0105, NO_OPD, s7_do_empty},
998 {"tcnz", 0x00003854, 0x3e007fff, 0x0e05, NO_OPD, s7_do_empty},
999 {"tcs!", 0x0005, 0x7f0f, 0x00000054, NO16_OPD, s7_do_empty},
1000 {"tcc!", 0x0105, 0x7f0f, 0x00000454, NO16_OPD, s7_do_empty},
1001 {"tcnz!", 0x0e05, 0x7f0f, 0x00003854, NO16_OPD, s7_do_empty},
1002 {"teq", 0x00001054, 0x3e007fff, 0x0405, NO_OPD, s7_do_empty},
1003 {"teq!", 0x0405, 0x7f0f, 0x00001054, NO16_OPD, s7_do_empty},
1004 {"tgtu", 0x00000854, 0x3e007fff, 0x0205, NO_OPD, s7_do_empty},
1005 {"tgt", 0x00001854, 0x3e007fff, 0x0605, NO_OPD, s7_do_empty},
1006 {"tge", 0x00002054, 0x3e007fff, 0x0805, NO_OPD, s7_do_empty},
1007 {"tgtu!", 0x0205, 0x7f0f, 0x00000854, NO16_OPD, s7_do_empty},
1008 {"tgt!", 0x0605, 0x7f0f, 0x00001854, NO16_OPD, s7_do_empty},
1009 {"tge!", 0x0805, 0x7f0f, 0x00002054, NO16_OPD, s7_do_empty},
1010 {"tleu", 0x00000c54, 0x3e007fff, 0x0305, NO_OPD, s7_do_empty},
1011 {"tle", 0x00001c54, 0x3e007fff, 0x0705, NO_OPD, s7_do_empty},
1012 {"tlt", 0x00002454, 0x3e007fff, 0x0905, NO_OPD, s7_do_empty},
1013 {"stlb", 0x0c000004, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
1014 {"mftlb", 0x0c000024, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
1015 {"mtptlb", 0x0c000044, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
1016 {"mtrtlb", 0x0c000064, 0x3e0003ff, 0x8000, NO_OPD, s7_do_empty},
1017 {"tleu!", 0x0305, 0x7f0f, 0x00000c54, NO16_OPD, s7_do_empty},
1018 {"tle!", 0x0705, 0x7f0f, 0x00001c54, NO16_OPD, s7_do_empty},
1019 {"tlt!", 0x0905, 0x7f0f, 0x00002454, NO16_OPD, s7_do_empty},
1020 {"tmi", 0x00002854, 0x3e007fff, 0x0a05, NO_OPD, s7_do_empty},
1021 {"tmi!", 0x0a05, 0x7f0f, 0x00002854, NO16_OPD, s7_do_empty},
1022 {"tne", 0x00001454, 0x3e007fff, 0x0505, NO_OPD, s7_do_empty},
1023 {"tne!", 0x0505, 0x7f0f, 0x00001454, NO16_OPD, s7_do_empty},
1024 {"tpl", 0x00002c54, 0x3e007fff, 0x0b05, NO_OPD, s7_do_empty},
1025 {"tpl!", 0x0b05, 0x7f0f, 0x00002c54, NO16_OPD, s7_do_empty},
1026 {"trapcs", 0x00000004, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1027 {"trapcc", 0x00000404, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1028 {"trapgtu", 0x00000804, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1029 {"trapleu", 0x00000c04, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1030 {"trapeq", 0x00001004, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1031 {"trapne", 0x00001404, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1032 {"trapgt", 0x00001804, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1033 {"traple", 0x00001c04, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1034 {"trapge", 0x00002004, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1035 {"traplt", 0x00002404, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1036 {"trapmi", 0x00002804, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1037 {"trappl", 0x00002c04, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1038 {"trapvs", 0x00003004, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1039 {"trapvc", 0x00003404, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1040 {"trap", 0x00003c04, 0x3e007fff, 0x8000, x_I5_x, s7_do_xi5x},
1041 {"tset", 0x00003c54, 0x3e007fff, 0x0f05, NO_OPD, s7_do_empty},
1042 {"tset!", 0x0f05, 0x00007f0f, 0x00003c54, NO16_OPD, s7_do_empty},
1043 {"tvs", 0x00003054, 0x3e007fff, 0x0c05, NO_OPD, s7_do_empty},
1044 {"tvc", 0x00003454, 0x3e007fff, 0x0d05, NO_OPD, s7_do_empty},
1045 {"tvs!", 0x0c05, 0x7f0f, 0x00003054, NO16_OPD, s7_do_empty},
1046 {"tvc!", 0x0d05, 0x7f0f, 0x00003454, NO16_OPD, s7_do_empty},
1047 {"xor", 0x00000026, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s7_do_rdrsrs},
1048 {"xor.c", 0x00000027, 0x3e0003ff, 0x2007, Rd_Rs_Rs, s7_do_rdrsrs},
1049 {"xor!", 0x2007, 0x700f, 0x00000027, Rd_Rs, s7_do16_rdrs},
1050 /* Macro instruction. */
1051 {"li", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, s7_do_macro_li_rdi32},
1052 /* la reg, imm32 -->(1) ldi reg, simm16
1053 (2) ldis reg, %HI(imm32)
1054 ori reg, %LO(imm32)
1055
1056 la reg, symbol -->(1) lis reg, %HI(imm32)
1057 ori reg, %LO(imm32) */
1058 {"la", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, s7_do_macro_la_rdi32},
1059 {"div", 0x00000044, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1060 {"divu", 0x00000046, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1061 {"rem", 0x00000044, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1062 {"remu", 0x00000046, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1063 {"mul", 0x00000040, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1064 {"mulu", 0x00000042, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1065 {"maz", 0x00000040, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1066 {"mazu", 0x00000042, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1067 {"mul.f", 0x00000041, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1068 {"maz.f", 0x00000041, 0x3e0003ff, 0x8000, Insn_Type_SYN, s7_do_macro_mul_rdrsrs},
1069 {"lb", INSN_LB, 0x00000000, 0x8000, Insn_Type_SYN, s7_do_macro_ldst_label},
1070 {"lbu", INSN_LBU, 0x00000000, 0x200b, Insn_Type_SYN, s7_do_macro_ldst_label},
1071 {"lh", INSN_LH, 0x00000000, 0x2009, Insn_Type_SYN, s7_do_macro_ldst_label},
1072 {"lhu", INSN_LHU, 0x00000000, 0x8000, Insn_Type_SYN, s7_do_macro_ldst_label},
1073 {"lw", INSN_LW, 0x00000000, 0x2008, Insn_Type_SYN, s7_do_macro_ldst_label},
1074 {"sb", INSN_SB, 0x00000000, 0x200f, Insn_Type_SYN, s7_do_macro_ldst_label},
1075 {"sh", INSN_SH, 0x00000000, 0x200d, Insn_Type_SYN, s7_do_macro_ldst_label},
1076 {"sw", INSN_SW, 0x00000000, 0x200c, Insn_Type_SYN, s7_do_macro_ldst_label},
1077 /* Assembler use internal. */
1078 {"ld_i32hi", 0x0a0c0000, 0x3e0e0000, 0x8000, Insn_internal, s7_do_macro_rdi32hi},
1079 {"ld_i32lo", 0x020a0000, 0x3e0e0001, 0x8000, Insn_internal, s7_do_macro_rdi32lo},
1080 {"ldis_pic", 0x0a0c0000, 0x3e0e0000, 0x5000, Insn_internal, s7_do_rdi16_pic},
1081 {"addi_s_pic",0x02000000, 0x3e0e0001, 0x8000, Insn_internal, s7_do_addi_s_pic},
1082 {"addi_u_pic",0x02000000, 0x3e0e0001, 0x8000, Insn_internal, s7_do_addi_u_pic},
1083 {"lw_pic", 0x20000000, 0x3e000000, 0x8000, Insn_internal, s7_do_lw_pic},
1084};
1085
1086#define s7_SCORE5_PIPELINE 5
1087#define s7_SCORE7_PIPELINE 7
1088
1089static int s7_university_version = 0;
1090static int s7_vector_size = s7_SCORE7_PIPELINE;
1091static struct s7_score_it s7_dependency_vector[s7_SCORE7_PIPELINE];
1092
1093static int s7_score7d = 1;
1094
1095\f
1096
1097static int
1098s7_end_of_line (char *str)
1099{
1100 int retval = s7_SUCCESS;
1101
1102 s7_skip_whitespace (str);
1103 if (*str != '\0')
1104 {
1105 retval = (int) s7_FAIL;
1106
1107 if (!s7_inst.error)
1108 s7_inst.error = s7_BAD_GARBAGE;
1109 }
1110
1111 return retval;
1112}
1113
1114static int
629310ab 1115s7_score_reg_parse (char **ccp, htab_t htab)
c3b7224a
NC
1116{
1117 char *start = *ccp;
1118 char c;
1119 char *p;
1120 struct s7_reg_entry *reg;
1121
1122 p = start;
1123 if (!ISALPHA (*p) || !is_name_beginner (*p))
1124 return (int) s7_FAIL;
1125
1126 c = *p++;
1127
1128 while (ISALPHA (c) || ISDIGIT (c) || c == '_')
1129 c = *p++;
1130
1131 *--p = 0;
629310ab 1132 reg = (struct s7_reg_entry *) str_hash_find (htab, start);
c3b7224a
NC
1133 *p = c;
1134
1135 if (reg)
1136 {
1137 *ccp = p;
1138 return reg->number;
1139 }
1140 return (int) s7_FAIL;
1141}
1142
1143/* If shift <= 0, only return reg. */
1144static int
1145s7_reg_required_here (char **str, int shift, enum s7_score_reg_type reg_type)
1146{
1147 static char buff[s7_MAX_LITERAL_POOL_SIZE];
1148 int reg = (int) s7_FAIL;
1149 char *start = *str;
1150
1151 if ((reg = s7_score_reg_parse (str, s7_all_reg_maps[reg_type].htab)) != (int) s7_FAIL)
1152 {
1153 if (reg_type == s7_REG_TYPE_SCORE)
1154 {
1155 if ((reg == 1) && (s7_nor1 == 1) && (s7_inst.bwarn == 0))
1156 {
1157 as_warn (_("Using temp register(r1)"));
1158 s7_inst.bwarn = 1;
1159 }
1160 }
1161 if (shift >= 0)
1162 {
1163 if (reg_type == s7_REG_TYPE_SCORE_CR)
1164 strcpy (s7_inst.reg, s7_score_crn_table[reg].name);
1165 else if (reg_type == s7_REG_TYPE_SCORE_SR)
1166 strcpy (s7_inst.reg, s7_score_srn_table[reg].name);
1167 else
1168 strcpy (s7_inst.reg, "");
1169
1170 s7_inst.instruction |= reg << shift;
1171 }
1172 }
1173 else
1174 {
1175 *str = start;
1176 sprintf (buff, _("register expected, not '%.100s'"), start);
1177 s7_inst.error = buff;
1178 }
1179
1180 return reg;
1181}
1182
1183static int
1184s7_skip_past_comma (char **str)
1185{
1186 char *p = *str;
1187 char c;
1188 int comma = 0;
1189
1190 while ((c = *p) == ' ' || c == ',')
1191 {
1192 p++;
1193 if (c == ',' && comma++)
1194 {
1195 s7_inst.error = s7_BAD_SKIP_COMMA;
1196 return (int) s7_FAIL;
1197 }
1198 }
1199
1200 if ((c == '\0') || (comma == 0))
1201 {
1202 s7_inst.error = s7_BAD_SKIP_COMMA;
1203 return (int) s7_FAIL;
1204 }
1205
1206 *str = p;
1207 return comma ? s7_SUCCESS : (int) s7_FAIL;
1208}
1209
1210static void
1211s7_do_rdrsrs (char *str)
1212{
1213 s7_skip_whitespace (str);
1214
1215 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1216 || s7_skip_past_comma (&str) == (int) s7_FAIL
1217 || s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1218 || s7_skip_past_comma (&str) == (int) s7_FAIL
1219 || s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1220 || s7_end_of_line (str) == (int) s7_FAIL)
1221 {
1222 return;
1223 }
1224 else
1225 {
1226 if ((((s7_inst.instruction >> 15) & 0x10) == 0)
1227 && (((s7_inst.instruction >> 10) & 0x10) == 0)
1228 && (((s7_inst.instruction >> 20) & 0x10) == 0)
1229 && (s7_inst.relax_inst != 0x8000)
1230 && (((s7_inst.instruction >> 20) & 0xf) == ((s7_inst.instruction >> 15) & 0xf)))
1231 {
1232 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0xf) << 4)
1233 | (((s7_inst.instruction >> 15) & 0xf) << 8);
1234 s7_inst.relax_size = 2;
1235 }
1236 else
1237 {
1238 s7_inst.relax_inst = 0x8000;
1239 }
1240 }
1241}
1242
1243static int
1244s7_walk_no_bignums (symbolS * sp)
1245{
1246 if (symbol_get_value_expression (sp)->X_op == O_big)
1247 return 1;
1248
1249 if (symbol_get_value_expression (sp)->X_add_symbol)
1250 return (s7_walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
1251 || (symbol_get_value_expression (sp)->X_op_symbol
1252 && s7_walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
1253
1254 return 0;
1255}
1256
1257static int
1258s7_my_get_expression (expressionS * ep, char **str)
1259{
1260 char *save_in;
c3b7224a
NC
1261
1262 save_in = input_line_pointer;
1263 input_line_pointer = *str;
1264 s7_in_my_get_expression = 1;
f9e53abc
NC
1265
1266 (void) expression (ep);
c3b7224a
NC
1267 s7_in_my_get_expression = 0;
1268
1269 if (ep->X_op == O_illegal)
1270 {
1271 *str = input_line_pointer;
1272 input_line_pointer = save_in;
1273 s7_inst.error = _("illegal expression");
1274 return (int) s7_FAIL;
1275 }
1276 /* Get rid of any bignums now, so that we don't generate an error for which
1277 we can't establish a line number later on. Big numbers are never valid
1278 in instructions, which is where this routine is always called. */
1279 if (ep->X_op == O_big
1280 || (ep->X_add_symbol
1281 && (s7_walk_no_bignums (ep->X_add_symbol)
1282 || (ep->X_op_symbol && s7_walk_no_bignums (ep->X_op_symbol)))))
1283 {
1284 s7_inst.error = _("invalid constant");
1285 *str = input_line_pointer;
1286 input_line_pointer = save_in;
1287 return (int) s7_FAIL;
1288 }
1289
1290 if ((ep->X_add_symbol != NULL)
1291 && (s7_inst.type != PC_DISP19div2)
1292 && (s7_inst.type != PC_DISP8div2)
1293 && (s7_inst.type != PC_DISP24div2)
1294 && (s7_inst.type != PC_DISP11div2)
1295 && (s7_inst.type != Insn_Type_SYN)
1296 && (s7_inst.type != Rd_rvalueRs_SI15)
1297 && (s7_inst.type != Rd_lvalueRs_SI15)
1298 && (s7_inst.type != Insn_internal))
1299 {
1300 s7_inst.error = s7_BAD_ARGS;
1301 *str = input_line_pointer;
1302 input_line_pointer = save_in;
1303 return (int) s7_FAIL;
1304 }
1305
1306 *str = input_line_pointer;
1307 input_line_pointer = save_in;
1308 return s7_SUCCESS;
1309}
1310
1311/* Check if an immediate is valid. If so, convert it to the right format. */
1312
1313static bfd_signed_vma
1314s7_validate_immediate (bfd_signed_vma val, unsigned int data_type, int hex_p)
1315{
1316 switch (data_type)
1317 {
1318 case _VALUE_HI16:
1319 {
1320 int val_hi = ((val & 0xffff0000) >> 16);
1321
1322 if (s7_score_df_range[data_type].range[0] <= val_hi
1323 && val_hi <= s7_score_df_range[data_type].range[1])
1324 return val_hi;
1325 }
1326 break;
1327
1328 case _VALUE_LO16:
1329 {
1330 int val_lo = (val & 0xffff);
1331
1332 if (s7_score_df_range[data_type].range[0] <= val_lo
1333 && val_lo <= s7_score_df_range[data_type].range[1])
1334 return val_lo;
1335 }
1336 break;
1337
1338 case _SIMM12:
1339 if (hex_p == 1)
1340 {
1341 if (!(val >= -0x800 && val <= 0xfff))
1342 {
1343 return (int) s7_FAIL;
1344 }
1345 }
1346 else
1347 {
1348 if (!(val >= -2048 && val <= 2047))
1349 {
1350 return (int) s7_FAIL;
1351 }
1352 }
1353
1354 return val;
1355 break;
1356
1357 case _SIMM14:
1358 if (hex_p == 1)
1359 {
1360 if (!(val >= -0x2000 && val <= 0x3fff))
1361 {
1362 return (int) s7_FAIL;
1363 }
1364 }
1365 else
1366 {
1367 if (!(val >= -8192 && val <= 8191))
1368 {
1369 return (int) s7_FAIL;
1370 }
1371 }
1372
1373 return val;
1374 break;
1375
1376 case _SIMM15:
1377 if (hex_p == 1)
1378 {
1379 if (!(val >= -0x4000 && val <= 0x7fff))
1380 {
1381 return (int) s7_FAIL;
1382 }
1383 }
1384 else
1385 {
1386 if (!(val >= -16384 && val <= 16383))
1387 {
1388 return (int) s7_FAIL;
1389 }
1390 }
1391
1392 return val;
1393 break;
1394
1395 case _SIMM16:
1396 if (hex_p == 1)
1397 {
1398 if (!(val >= -0x8000 && val <= 0xffff))
1399 {
1400 return (int) s7_FAIL;
1401 }
1402 }
1403 else
1404 {
1405 if (!(val >= -32768 && val <= 32767))
1406 {
1407 return (int) s7_FAIL;
1408 }
1409 }
1410
1411 return val;
1412 break;
1413
1414 case _SIMM16_NEG:
1415 if (hex_p == 1)
1416 {
1417 if (!(val >= -0x7fff && val <= 0xffff && val != 0x8000))
1418 {
1419 return (int) s7_FAIL;
1420 }
1421 }
1422 else
1423 {
1424 if (!(val >= -32767 && val <= 32768))
1425 {
1426 return (int) s7_FAIL;
1427 }
1428 }
1429
1430 val = -val;
1431 return val;
1432 break;
1433
1434 case _IMM32:
1435 if (val >= 0 && val <= 0xffffffff)
1436 {
1437 return val;
1438 }
1439 else
1440 {
1441 return (int) s7_FAIL;
1442 }
1443
1444 default:
1445 if (data_type == _SIMM14_NEG || data_type == _IMM16_NEG)
1446 val = -val;
1447
1448 if (s7_score_df_range[data_type].range[0] <= val
1449 && val <= s7_score_df_range[data_type].range[1])
1450 return val;
1451
1452 break;
1453 }
1454
1455 return (int) s7_FAIL;
1456}
1457
1458static int
1459s7_data_op2 (char **str, int shift, enum score_data_type data_type)
1460{
1461 int value;
1462 char data_exp[s7_MAX_LITERAL_POOL_SIZE];
1463 char *dataptr;
1464 int cnt = 0;
1465 char *pp = NULL;
1466
1467 s7_skip_whitespace (*str);
1468 s7_inst.error = NULL;
1469 dataptr = * str;
1470
1471 /* Set hex_p to zero. */
1472 int hex_p = 0;
1473
1474 while ((*dataptr != '\0') && (*dataptr != '|') && (cnt <= s7_MAX_LITERAL_POOL_SIZE)) /* 0x7c = ='|' */
1475 {
1476 data_exp[cnt] = *dataptr;
1477 dataptr++;
1478 cnt++;
1479 }
1480
1481 data_exp[cnt] = '\0';
1482 pp = (char *)&data_exp;
1483
1484 if (*dataptr == '|') /* process PCE */
1485 {
1486 if (s7_my_get_expression (&s7_inst.reloc.exp, &pp) == (int) s7_FAIL)
1487 return (int) s7_FAIL;
1488 s7_end_of_line (pp);
1489 if (s7_inst.error != 0)
1490 return (int) s7_FAIL; /* to ouptut_inst to printf out the error */
1491 *str = dataptr;
1492 }
1493 else /* process 16 bit */
1494 {
1495 if (s7_my_get_expression (&s7_inst.reloc.exp, str) == (int) s7_FAIL)
1496 {
1497 return (int) s7_FAIL;
1498 }
1499
1500 dataptr = (char *) data_exp;
1501 for (; *dataptr != '\0'; dataptr++)
1502 {
1503 *dataptr = TOLOWER (*dataptr);
1504 if (*dataptr == '!' || *dataptr == ' ')
1505 break;
1506 }
1507 dataptr = (char *) data_exp;
1508
1509 if ((dataptr != NULL)
1510 && (((strstr (dataptr, "0x")) != NULL)
1511 || ((strstr (dataptr, "0X")) != NULL)))
1512 {
1513 hex_p = 1;
1514 if ((data_type != _SIMM16_LA)
1515 && (data_type != _VALUE_HI16)
1516 && (data_type != _VALUE_LO16)
1517 && (data_type != _IMM16)
1518 && (data_type != _IMM15)
1519 && (data_type != _IMM14)
1520 && (data_type != _IMM4)
1521 && (data_type != _IMM5)
1522 && (data_type != _IMM8)
1523 && (data_type != _IMM5_RSHIFT_1)
1524 && (data_type != _IMM5_RSHIFT_2)
1525 && (data_type != _SIMM14)
1526 && (data_type != _SIMM16)
1527 && (data_type != _SIMM14_NEG)
1528 && (data_type != _SIMM16_NEG)
1529 && (data_type != _IMM10_RSHIFT_2)
1530 && (data_type != _GP_IMM15))
1531 {
1532 data_type += 24;
1533 }
1534 }
1535
1536 if ((s7_inst.reloc.exp.X_add_number == 0)
1537 /* for "addi r0,-((((((32*4)+4)+4)+4)+4)&0xf)". */
1538 && (s7_inst.type != Rd_SI16)
1539 && (s7_inst.type != Insn_Type_SYN)
1540 && (s7_inst.type != Rd_rvalueRs_SI15)
1541 && (s7_inst.type != Rd_lvalueRs_SI15)
1542 && (s7_inst.type != Insn_internal)
1543 && (((*dataptr >= 'a') && (*dataptr <= 'z'))
1544 || ((*dataptr == '0') && (*(dataptr + 1) == 'x') && (*(dataptr + 2) != '0'))
1545 || ((*dataptr == '+') && (*(dataptr + 1) != '0'))
1546 || ((*dataptr == '-') && (*(dataptr + 1) != '0'))))
1547 {
1548 s7_inst.error = s7_BAD_ARGS;
1549 return (int) s7_FAIL;
1550 }
1551 }
1552
1553 if ((s7_inst.reloc.exp.X_add_symbol)
1554 && ((data_type == _SIMM16)
1555 || (data_type == _SIMM16_NEG)
1556 || (data_type == _IMM16_NEG)
1557 || (data_type == _SIMM14)
1558 || (data_type == _SIMM14_NEG)
1559 || (data_type == _IMM5)
1560 || (data_type == _IMM14)
1561 || (data_type == _IMM20)
1562 || (data_type == _IMM16)
1563 || (data_type == _IMM15)
1564 || (data_type == _IMM4)))
1565 {
1566 s7_inst.error = s7_BAD_ARGS;
1567 return (int) s7_FAIL;
1568 }
1569
1570 if (s7_inst.reloc.exp.X_add_symbol)
1571 {
1572 switch (data_type)
1573 {
1574 case _SIMM16_LA:
1575 return (int) s7_FAIL;
1576 case _VALUE_HI16:
1577 s7_inst.reloc.type = BFD_RELOC_HI16_S;
1578 s7_inst.reloc.pc_rel = 0;
1579 break;
1580 case _VALUE_LO16:
1581 s7_inst.reloc.type = BFD_RELOC_LO16;
1582 s7_inst.reloc.pc_rel = 0;
1583 break;
1584 case _GP_IMM15:
1585 s7_inst.reloc.type = BFD_RELOC_SCORE_GPREL15;
1586 s7_inst.reloc.pc_rel = 0;
1587 break;
1588 case _SIMM16_pic:
1589 case _IMM16_LO16_pic:
1590 s7_inst.reloc.type = BFD_RELOC_SCORE_GOT_LO16;
1591 s7_inst.reloc.pc_rel = 0;
1592 break;
1593 default:
1594 s7_inst.reloc.type = BFD_RELOC_32;
1595 s7_inst.reloc.pc_rel = 0;
1596 break;
1597 }
1598 }
1599 else
1600 {
1601 if (data_type == _IMM16_pic)
1602 {
1603 s7_inst.reloc.type = BFD_RELOC_SCORE_DUMMY_HI16;
1604 s7_inst.reloc.pc_rel = 0;
1605 }
1606
1607 if (data_type == _SIMM16_LA && s7_inst.reloc.exp.X_unsigned == 1)
1608 {
1609 value = s7_validate_immediate (s7_inst.reloc.exp.X_add_number, _SIMM16_LA_POS, hex_p);
1610 if (value == (int) s7_FAIL) /* for advance to check if this is ldis */
1611 if ((s7_inst.reloc.exp.X_add_number & 0xffff) == 0)
1612 {
1613 s7_inst.instruction |= 0x8000000;
1614 s7_inst.instruction |= ((s7_inst.reloc.exp.X_add_number >> 16) << 1) & 0x1fffe;
1615 return s7_SUCCESS;
1616 }
1617 }
1618 else
1619 {
1620 value = s7_validate_immediate (s7_inst.reloc.exp.X_add_number, data_type, hex_p);
1621 }
1622
1623 if (value == (int) s7_FAIL)
1624 {
1625 if ((data_type != _SIMM14_NEG) && (data_type != _SIMM16_NEG) && (data_type != _IMM16_NEG))
1626 {
1627 sprintf (s7_err_msg,
1628 _("invalid constant: %d bit expression not in range %d..%d"),
1629 s7_score_df_range[data_type].bits,
1630 s7_score_df_range[data_type].range[0], s7_score_df_range[data_type].range[1]);
1631 }
1632 else
1633 {
1634 sprintf (s7_err_msg,
1635 _("invalid constant: %d bit expression not in range %d..%d"),
1636 s7_score_df_range[data_type].bits,
1637 -s7_score_df_range[data_type].range[1], -s7_score_df_range[data_type].range[0]);
1638 }
1639
1640 s7_inst.error = s7_err_msg;
1641 return (int) s7_FAIL;
1642 }
1643
1644 if ((s7_score_df_range[data_type].range[0] != 0) || (data_type == _IMM5_RANGE_8_31))
1645 {
1646 value &= (1 << s7_score_df_range[data_type].bits) - 1;
1647 }
1648
1649 s7_inst.instruction |= value << shift;
1650 }
1651
1652 if ((s7_inst.instruction & 0x3e000000) == 0x30000000)
1653 {
1654 if ((((s7_inst.instruction >> 20) & 0x1F) != 0)
1655 && (((s7_inst.instruction >> 20) & 0x1F) != 1)
1656 && (((s7_inst.instruction >> 20) & 0x1F) != 2)
1657 && (((s7_inst.instruction >> 20) & 0x1F) != 3)
1658 && (((s7_inst.instruction >> 20) & 0x1F) != 4)
1659 && (((s7_inst.instruction >> 20) & 0x1F) != 8)
1660 && (((s7_inst.instruction >> 20) & 0x1F) != 9)
1661 && (((s7_inst.instruction >> 20) & 0x1F) != 0xa)
1662 && (((s7_inst.instruction >> 20) & 0x1F) != 0xb)
1663 && (((s7_inst.instruction >> 20) & 0x1F) != 0xc)
1664 && (((s7_inst.instruction >> 20) & 0x1F) != 0xd)
1665 && (((s7_inst.instruction >> 20) & 0x1F) != 0xe)
1666 && (((s7_inst.instruction >> 20) & 0x1F) != 0x10)
1667 && (((s7_inst.instruction >> 20) & 0x1F) != 0x11)
1668 && (((s7_inst.instruction >> 20) & 0x1F) != 0x18)
1669 && (((s7_inst.instruction >> 20) & 0x1F) != 0x1A)
1670 && (((s7_inst.instruction >> 20) & 0x1F) != 0x1B)
1671 && (((s7_inst.instruction >> 20) & 0x1F) != 0x1d)
1672 && (((s7_inst.instruction >> 20) & 0x1F) != 0x1e)
1673 && (((s7_inst.instruction >> 20) & 0x1F) != 0x1f))
1674 {
1675 s7_inst.error = _("invalid constant: bit expression not defined");
1676 return (int) s7_FAIL;
1677 }
1678 }
1679
1680 return s7_SUCCESS;
1681}
1682
1683/* Handle addi/addi.c/addis.c/cmpi.c/addis.c/ldi. */
1684
1685static void
1686s7_do_rdsi16 (char *str)
1687{
1688 s7_skip_whitespace (str);
1689
1690 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1691 || s7_skip_past_comma (&str) == (int) s7_FAIL
1692 || s7_data_op2 (&str, 1, _SIMM16) == (int) s7_FAIL
1693 || s7_end_of_line (str) == (int) s7_FAIL)
1694 return;
1695
1696 /* ldi. */
1697 if ((s7_inst.instruction & 0x20c0000) == 0x20c0000)
1698 {
1699 if ((((s7_inst.instruction >> 20) & 0x10) == 0x10) || ((s7_inst.instruction & 0x1fe00) != 0))
1700 {
1701 s7_inst.relax_inst = 0x8000;
1702 }
1703 else
1704 {
1705 s7_inst.relax_inst |= (s7_inst.instruction >> 1) & 0xff;
1706 s7_inst.relax_inst |= (((s7_inst.instruction >> 20) & 0xf) << 8);
1707 s7_inst.relax_size = 2;
1708 }
1709 }
1710 else if (((s7_inst.instruction >> 20) & 0x10) == 0x10)
1711 {
1712 s7_inst.relax_inst = 0x8000;
1713 }
1714}
1715
1716/* Handle subi/subi.c. */
1717
1718static void
1719s7_do_sub_rdsi16 (char *str)
1720{
1721 s7_skip_whitespace (str);
1722
1723 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1724 && s7_skip_past_comma (&str) != (int) s7_FAIL
1725 && s7_data_op2 (&str, 1, _SIMM16_NEG) != (int) s7_FAIL)
1726 s7_end_of_line (str);
1727}
1728
1729
1730/* Handle addri/addri.c. */
1731
1732static void
1733s7_do_rdrssi14 (char *str) /* -(2^13)~((2^13)-1) */
1734{
1735 s7_skip_whitespace (str);
1736
1737 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1738 && s7_skip_past_comma (&str) != (int) s7_FAIL
1739 && s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1740 && s7_skip_past_comma (&str) != (int) s7_FAIL)
1741 s7_data_op2 (&str, 1, _SIMM14);
1742}
1743
1744/* Handle subri.c/subri. */
1745
1746static void
1747s7_do_sub_rdrssi14 (char *str) /* -(2^13)~((2^13)-1) */
1748{
1749 s7_skip_whitespace (str);
1750
1751 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1752 && s7_skip_past_comma (&str) != (int) s7_FAIL
1753 && s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1754 && s7_skip_past_comma (&str) != (int) s7_FAIL
1755 && s7_data_op2 (&str, 1, _SIMM14_NEG) != (int) s7_FAIL)
1756 s7_end_of_line (str);
1757}
1758
1759/* Handle bitclr.c/bitset.c/bittgl.c/slli.c/srai.c/srli.c/roli.c/rori.c/rolic.c. */
1760
1761static void
1762s7_do_rdrsi5 (char *str) /* 0~((2^14)-1) */
1763{
1764 s7_skip_whitespace (str);
1765
1766 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1767 || s7_skip_past_comma (&str) == (int) s7_FAIL
1768 || s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1769 || s7_skip_past_comma (&str) == (int) s7_FAIL
1770 || s7_data_op2 (&str, 10, _IMM5) == (int) s7_FAIL
1771 || s7_end_of_line (str) == (int) s7_FAIL)
1772 return;
1773
1774 if ((((s7_inst.instruction >> 20) & 0x1f) == ((s7_inst.instruction >> 15) & 0x1f))
1775 && (s7_inst.relax_inst != 0x8000) && (((s7_inst.instruction >> 15) & 0x10) == 0))
1776 {
1777 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0x1f) << 3) | (((s7_inst.instruction >> 15) & 0xf) << 8);
1778 s7_inst.relax_size = 2;
1779 }
1780 else
1781 s7_inst.relax_inst = 0x8000;
1782}
1783
1784/* Handle andri/orri/andri.c/orri.c. */
1785
1786static void
1787s7_do_rdrsi14 (char *str) /* 0 ~ ((2^14)-1) */
1788{
1789 s7_skip_whitespace (str);
1790
1791 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1792 && s7_skip_past_comma (&str) != (int) s7_FAIL
1793 && s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1794 && s7_skip_past_comma (&str) != (int) s7_FAIL
1795 && s7_data_op2 (&str, 1, _IMM14) != (int) s7_FAIL)
1796 s7_end_of_line (str);
1797}
1798
1799/* Handle bittst.c. */
1800
1801static void
1802s7_do_xrsi5 (char *str)
1803{
1804 s7_skip_whitespace (str);
1805
1806 if (s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1807 || s7_skip_past_comma (&str) == (int) s7_FAIL
1808 || s7_data_op2 (&str, 10, _IMM5) == (int) s7_FAIL
1809 || s7_end_of_line (str) == (int) s7_FAIL)
1810 return;
1811
1812 if ((s7_inst.relax_inst != 0x8000) && (((s7_inst.instruction >> 15) & 0x10) == 0))
1813 {
1814 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0x1f) << 3) | (((s7_inst.instruction >> 15) & 0xf) << 8);
1815 s7_inst.relax_size = 2;
1816 }
1817 else
1818 s7_inst.relax_inst = 0x8000;
1819}
1820
1821/* Handle addis/andi/ori/andis/oris/ldis. */
1822
1823static void
1824s7_do_rdi16 (char *str)
1825{
1826 s7_skip_whitespace (str);
1827
1828 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1829 || s7_skip_past_comma (&str) == (int) s7_FAIL
1830 || s7_data_op2 (&str, 1, _IMM16) == (int) s7_FAIL
1831 || s7_end_of_line (str) == (int) s7_FAIL)
1832 return;
1833}
1834
1835static void
1836s7_do_macro_rdi32hi (char *str)
1837{
1838 s7_skip_whitespace (str);
1839
1840 /* Do not handle s7_end_of_line(). */
1841 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1842 && s7_skip_past_comma (&str) != (int) s7_FAIL)
1843 s7_data_op2 (&str, 1, _VALUE_HI16);
1844}
1845
1846static void
1847s7_do_macro_rdi32lo (char *str)
1848{
1849 s7_skip_whitespace (str);
1850
1851 /* Do not handle s7_end_of_line(). */
1852 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1853 && s7_skip_past_comma (&str) != (int) s7_FAIL)
1854 s7_data_op2 (&str, 1, _VALUE_LO16);
1855}
1856
1857/* Handle ldis_pic. */
1858
1859static void
1860s7_do_rdi16_pic (char *str)
1861{
1862 s7_skip_whitespace (str);
1863
1864 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1865 && s7_skip_past_comma (&str) != (int) s7_FAIL
1866 && s7_data_op2 (&str, 1, _IMM16_pic) != (int) s7_FAIL)
1867 s7_end_of_line (str);
1868}
1869
1870/* Handle addi_s_pic to generate R_SCORE_GOT_LO16 . */
1871
1872static void
1873s7_do_addi_s_pic (char *str)
1874{
1875 s7_skip_whitespace (str);
1876
1877 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1878 && s7_skip_past_comma (&str) != (int) s7_FAIL
1879 && s7_data_op2 (&str, 1, _SIMM16_pic) != (int) s7_FAIL)
1880 s7_end_of_line (str);
1881}
1882
1883/* Handle addi_u_pic to generate R_SCORE_GOT_LO16 . */
1884
1885static void
1886s7_do_addi_u_pic (char *str)
1887{
1888 s7_skip_whitespace (str);
1889
1890 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
1891 && s7_skip_past_comma (&str) != (int) s7_FAIL
1892 && s7_data_op2 (&str, 1, _IMM16_LO16_pic) != (int) s7_FAIL)
1893 s7_end_of_line (str);
1894}
1895
1896/* Handle mfceh/mfcel/mtceh/mtchl. */
1897
1898static void
1899s7_do_rd (char *str)
1900{
1901 s7_skip_whitespace (str);
1902
1903 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL)
1904 s7_end_of_line (str);
1905}
1906
1907static void
1908s7_do_rs (char *str)
1909{
1910 s7_skip_whitespace (str);
1911
1912 if (s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1913 || s7_end_of_line (str) == (int) s7_FAIL)
1914 return;
1915
1916 if ((s7_inst.relax_inst != 0x8000) && (((s7_inst.instruction >> 15) & 0x10) == 0))
1917 {
1918 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0xf) << 8) | (((s7_inst.instruction >> 15) & 0xf) << 4);
1919 s7_inst.relax_size = 2;
1920 }
1921 else
1922 s7_inst.relax_inst = 0x8000;
1923}
1924
1925static void
1926s7_do_i15 (char *str)
1927{
1928 s7_skip_whitespace (str);
1929
1930 if (s7_data_op2 (&str, 10, _IMM15) != (int) s7_FAIL)
1931 s7_end_of_line (str);
1932}
1933
1934static void
1935s7_do_xi5x (char *str)
1936{
1937 s7_skip_whitespace (str);
1938
1939 if (s7_data_op2 (&str, 15, _IMM5) == (int) s7_FAIL || s7_end_of_line (str) == (int) s7_FAIL)
1940 return;
1941
1942 if (s7_inst.relax_inst != 0x8000)
1943 {
1944 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0x1f) << 3);
1945 s7_inst.relax_size = 2;
1946 }
1947}
1948
1949static void
1950s7_do_rdrs (char *str)
1951{
1952 s7_skip_whitespace (str);
1953
1954 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1955 || s7_skip_past_comma (&str) == (int) s7_FAIL
1956 || s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
1957 || s7_end_of_line (str) == (int) s7_FAIL)
1958 return;
1959
1960 if (s7_inst.relax_inst != 0x8000)
1961 {
1962 if (((s7_inst.instruction & 0x7f) == 0x56)) /* adjust mv -> mv! / mlfh! / mhfl! */
1963 {
1964 /* mlfh */
1965 if ((((s7_inst.instruction >> 15) & 0x10) != 0x0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
1966 {
1967 s7_inst.relax_inst = 0x00000001 | (((s7_inst.instruction >> 15) & 0xf) << 4)
1968 | (((s7_inst.instruction >> 20) & 0xf) << 8);
1969 s7_inst.relax_size = 2;
1970 }
1971 /* mhfl */
1972 else if ((((s7_inst.instruction >> 15) & 0x10) == 0x0) && ((s7_inst.instruction >> 20) & 0x10) != 0)
1973 {
1974 s7_inst.relax_inst = 0x00000002 | (((s7_inst.instruction >> 15) & 0xf) << 4)
1975 | (((s7_inst.instruction >> 20) & 0xf) << 8);
1976 s7_inst.relax_size = 2;
1977 }
1978 else if ((((s7_inst.instruction >> 15) & 0x10) == 0x0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
1979 {
1980 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
1981 | (((s7_inst.instruction >> 20) & 0xf) << 8);
1982 s7_inst.relax_size = 2;
1983 }
1984 else
1985 {
1986 s7_inst.relax_inst = 0x8000;
1987 }
1988 }
1989 else if ((((s7_inst.instruction >> 15) & 0x10) == 0x0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
1990 {
1991 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
1992 | (((s7_inst.instruction >> 20) & 0xf) << 8);
1993 s7_inst.relax_size = 2;
1994 }
1995 else
1996 {
1997 s7_inst.relax_inst = 0x8000;
1998 }
1999 }
2000}
2001
2002/* Handle mfcr/mtcr. */
2003static void
2004s7_do_rdcrs (char *str)
2005{
2006 s7_skip_whitespace (str);
2007
2008 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
2009 && s7_skip_past_comma (&str) != (int) s7_FAIL
2010 && s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE_CR) != (int) s7_FAIL)
2011 s7_end_of_line (str);
2012}
2013
2014/* Handle mfsr/mtsr. */
2015
2016static void
2017s7_do_rdsrs (char *str)
2018{
2019 s7_skip_whitespace (str);
2020
2021 /* mfsr */
2022 if ((s7_inst.instruction & 0xff) == 0x50)
2023 {
2024 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) != (int) s7_FAIL
2025 && s7_skip_past_comma (&str) != (int) s7_FAIL
2026 && s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE_SR) != (int) s7_FAIL)
2027 s7_end_of_line (str);
2028 }
2029 else
2030 {
2031 if (s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) != (int) s7_FAIL
2032 && s7_skip_past_comma (&str) != (int) s7_FAIL)
2033 s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE_SR);
2034 }
2035}
2036
2037/* Handle neg. */
2038
2039static void
2040s7_do_rdxrs (char *str)
2041{
2042 s7_skip_whitespace (str);
2043
2044 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL
2045 || s7_skip_past_comma (&str) == (int) s7_FAIL
2046 || s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE) == (int) s7_FAIL
2047 || s7_end_of_line (str) == (int) s7_FAIL)
2048 return;
2049
2050 if ((s7_inst.relax_inst != 0x8000) && (((s7_inst.instruction >> 10) & 0x10) == 0)
2051 && (((s7_inst.instruction >> 20) & 0x10) == 0))
2052 {
2053 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0xf) << 4) | (((s7_inst.instruction >> 20) & 0xf) << 8);
2054 s7_inst.relax_size = 2;
2055 }
2056 else
2057 s7_inst.relax_inst = 0x8000;
2058}
2059
2060/* Handle cmp.c/cmp<cond>. */
2061static void
2062s7_do_rsrs (char *str)
2063{
2064 s7_skip_whitespace (str);
2065
2066 if (s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
2067 || s7_skip_past_comma (&str) == (int) s7_FAIL
2068 || s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE) == (int) s7_FAIL
2069 || s7_end_of_line (str) == (int) s7_FAIL)
2070 return;
2071
2072 if ((s7_inst.relax_inst != 0x8000) && (((s7_inst.instruction >> 20) & 0x1f) == 3)
2073 && (((s7_inst.instruction >> 10) & 0x10) == 0) && (((s7_inst.instruction >> 15) & 0x10) == 0))
2074 {
2075 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0xf) << 4) | (((s7_inst.instruction >> 15) & 0xf) << 8);
2076 s7_inst.relax_size = 2;
2077 }
2078 else
2079 s7_inst.relax_inst = 0x8000;
2080}
2081
2082static void
2083s7_do_ceinst (char *str)
2084{
2085 char *strbak;
2086
2087 strbak = str;
2088 s7_skip_whitespace (str);
2089
2090 if (s7_data_op2 (&str, 20, _IMM5) == (int) s7_FAIL
2091 || s7_skip_past_comma (&str) == (int) s7_FAIL
2092 || s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL
2093 || s7_skip_past_comma (&str) == (int) s7_FAIL
2094 || s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE) == (int) s7_FAIL
2095 || s7_skip_past_comma (&str) == (int) s7_FAIL
2096 || s7_data_op2 (&str, 5, _IMM5) == (int) s7_FAIL
2097 || s7_skip_past_comma (&str) == (int) s7_FAIL
2098 || s7_data_op2 (&str, 0, _IMM5) == (int) s7_FAIL
2099 || s7_end_of_line (str) == (int) s7_FAIL)
2100 {
2101 return;
2102 }
2103 else
2104 {
2105 str = strbak;
2106 if (s7_data_op2 (&str, 0, _IMM25) == (int) s7_FAIL)
2107 return;
2108 }
2109}
2110
2111static int
2112s7_reglow_required_here (char **str, int shift)
2113{
2114 static char buff[s7_MAX_LITERAL_POOL_SIZE];
2115 int reg;
2116 char *start = *str;
2117
2118 if ((reg = s7_score_reg_parse (str, s7_all_reg_maps[s7_REG_TYPE_SCORE].htab)) != (int) s7_FAIL)
2119 {
2120 if ((reg == 1) && (s7_nor1 == 1) && (s7_inst.bwarn == 0))
2121 {
2122 as_warn (_("Using temp register(r1)"));
2123 s7_inst.bwarn = 1;
2124 }
2125 if (reg < 16)
2126 {
2127 if (shift >= 0)
2128 s7_inst.instruction |= reg << shift;
2129
2130 return reg;
2131 }
2132 }
2133
2134 /* Restore the start point, we may have got a reg of the wrong class. */
2135 *str = start;
2136 sprintf (buff, _("low register(r0-r15)expected, not '%.100s'"), start);
2137 s7_inst.error = buff;
2138 return (int) s7_FAIL;
2139}
2140
2141/* Handle addc!/add!/and!/cmp!/neg!/not!/or!/sll!/srl!/sra!/xor!/sub!. */
2142
2143static void
2144s7_do16_rdrs (char *str)
2145{
2146 s7_skip_whitespace (str);
2147
2148 if (s7_reglow_required_here (&str, 8) == (int) s7_FAIL
2149 || s7_skip_past_comma (&str) == (int) s7_FAIL
2150 || s7_reglow_required_here (&str, 4) == (int) s7_FAIL
2151 || s7_end_of_line (str) == (int) s7_FAIL)
2152 {
2153 return;
2154 }
2155 else
2156 {
2157 if ((s7_inst.instruction & 0x700f) == 0x2003) /* cmp! */
2158 {
2159 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 15)
2160 | (((s7_inst.instruction >> 4) & 0xf) << 10);
2161 }
2162 else if ((s7_inst.instruction & 0x700f) == 0x2006) /* not! */
2163 {
2164 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2165 | (((s7_inst.instruction >> 4) & 0xf) << 15);
2166 }
2167 else if ((s7_inst.instruction & 0x700f) == 0x1009) /* mazh.f! */
2168 {
2169 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 15)
2170 | (((s7_inst.instruction >> 4) & 0xf) << 10);
2171 }
2172 else
2173 {
2174 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2175 | (((s7_inst.instruction >> 8) & 0xf) << 15) | (((s7_inst.instruction >> 4) & 0xf) << 10);
2176 }
2177 s7_inst.relax_size = 4;
2178 }
2179}
2180
2181static void
2182s7_do16_rs (char *str)
2183{
2184 int rd = 0;
2185
2186 s7_skip_whitespace (str);
2187
2188 if ((rd = s7_reglow_required_here (&str, 4)) == (int) s7_FAIL
2189 || s7_end_of_line (str) == (int) s7_FAIL)
2190 {
2191 return;
2192 }
2193 else
2194 {
2195 s7_inst.relax_inst |= rd << 20;
2196 s7_inst.relax_size = 4;
2197 }
2198}
2199
2200/* Handle br!/brl!. */
2201
2202static void
2203s7_do16_xrs (char *str)
2204{
2205 s7_skip_whitespace (str);
2206
2207 if (s7_reglow_required_here (&str, 4) == (int) s7_FAIL || s7_end_of_line (str) == (int) s7_FAIL)
2208 {
2209 return;
2210 }
2211 else
2212 {
2213 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 10)
2214 | (((s7_inst.instruction >> 4) & 0xf) << 15);
2215 s7_inst.relax_size = 4;
2216 }
2217}
2218
2219static int
2220s7_reghigh_required_here (char **str, int shift)
2221{
2222 static char buff[s7_MAX_LITERAL_POOL_SIZE];
2223 int reg;
2224 char *start = *str;
2225
2226 if ((reg = s7_score_reg_parse (str, s7_all_reg_maps[s7_REG_TYPE_SCORE].htab)) != (int) s7_FAIL)
2227 {
2228 if (15 < reg && reg < 32)
2229 {
2230 if (shift >= 0)
2231 s7_inst.instruction |= (reg & 0xf) << shift;
2232
2233 return reg;
2234 }
2235 }
2236
2237 *str = start;
2238 sprintf (buff, _("high register(r16-r31)expected, not '%.100s'"), start);
2239 s7_inst.error = buff;
2240 return (int) s7_FAIL;
2241}
2242
2243/* Handle mhfl!. */
2244
2245static void
2246s7_do16_hrdrs (char *str)
2247{
2248 s7_skip_whitespace (str);
2249
2250 if (s7_reghigh_required_here (&str, 8) != (int) s7_FAIL
2251 && s7_skip_past_comma (&str) != (int) s7_FAIL
2252 && s7_reglow_required_here (&str, 4) != (int) s7_FAIL
2253 && s7_end_of_line (str) != (int) s7_FAIL)
2254 {
2255 s7_inst.relax_inst |= ((((s7_inst.instruction >> 8) & 0xf) | 0x10) << 20)
2256 | (((s7_inst.instruction >> 4) & 0xf) << 15) | (0xf << 10);
2257 s7_inst.relax_size = 4;
2258 }
2259}
2260
2261/* Handle mlfh!. */
2262
2263static void
2264s7_do16_rdhrs (char *str)
2265{
2266 s7_skip_whitespace (str);
2267
2268 if (s7_reglow_required_here (&str, 8) != (int) s7_FAIL
2269 && s7_skip_past_comma (&str) != (int) s7_FAIL
2270 && s7_reghigh_required_here (&str, 4) != (int) s7_FAIL
2271 && s7_end_of_line (str) != (int) s7_FAIL)
2272 {
2273 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2274 | ((((s7_inst.instruction >> 4) & 0xf) | 0x10) << 15) | (0xf << 10);
2275 s7_inst.relax_size = 4;
2276 }
2277}
2278
2279/* We need to be able to fix up arbitrary expressions in some statements.
2280 This is so that we can handle symbols that are an arbitrary distance from
2281 the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
2282 which returns part of an address in a form which will be valid for
2283 a data instruction. We do this by pushing the expression into a symbol
2284 in the expr_section, and creating a fix for that. */
2285
2286static fixS *
2287s7_fix_new_score (fragS * frag, int where, short int size, expressionS * exp, int pc_rel, int reloc)
2288{
2289 fixS *new_fix;
2290
2291 switch (exp->X_op)
2292 {
2293 case O_constant:
2294 case O_symbol:
2295 case O_add:
2296 case O_subtract:
2297 new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
2298 break;
2299 default:
2300 new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0, pc_rel, reloc);
2301 break;
2302 }
2303 return new_fix;
2304}
2305
2306static void
2307s7_init_dependency_vector (void)
2308{
2309 int i;
2310
2311 for (i = 0; i < s7_vector_size; i++)
2312 memset (&s7_dependency_vector[i], '\0', sizeof (s7_dependency_vector[i]));
2313
2314 return;
2315}
2316
2317static enum s7_insn_type_for_dependency
2318s7_dependency_type_from_insn (char *insn_name)
2319{
2320 char name[s7_INSN_NAME_LEN];
2321 const struct s7_insn_to_dependency *tmp;
2322
2323 strcpy (name, insn_name);
fe0e921f
AM
2324 tmp = (const struct s7_insn_to_dependency *)
2325 str_hash_find (s7_dependency_insn_hsh, name);
c3b7224a
NC
2326
2327 if (tmp)
2328 return tmp->type;
2329
2330 return s7_D_all_insn;
2331}
2332
2333static int
2334s7_check_dependency (char *pre_insn, char *pre_reg,
2335 char *cur_insn, char *cur_reg, int *warn_or_error)
2336{
2337 int bubbles = 0;
2338 unsigned int i;
2339 enum s7_insn_type_for_dependency pre_insn_type;
2340 enum s7_insn_type_for_dependency cur_insn_type;
2341
2342 pre_insn_type = s7_dependency_type_from_insn (pre_insn);
2343 cur_insn_type = s7_dependency_type_from_insn (cur_insn);
2344
2345 for (i = 0; i < sizeof (s7_data_dependency_table) / sizeof (s7_data_dependency_table[0]); i++)
2346 {
2347 if ((pre_insn_type == s7_data_dependency_table[i].pre_insn_type)
2348 && (s7_D_all_insn == s7_data_dependency_table[i].cur_insn_type
2349 || cur_insn_type == s7_data_dependency_table[i].cur_insn_type)
2350 && (strcmp (s7_data_dependency_table[i].pre_reg, "") == 0
2351 || strcmp (s7_data_dependency_table[i].pre_reg, pre_reg) == 0)
2352 && (strcmp (s7_data_dependency_table[i].cur_reg, "") == 0
2353 || strcmp (s7_data_dependency_table[i].cur_reg, cur_reg) == 0))
2354 {
2355 if (s7_vector_size == s7_SCORE5_PIPELINE)
2356 bubbles = s7_data_dependency_table[i].bubblenum_5;
2357 else
2358 bubbles = s7_data_dependency_table[i].bubblenum_7;
2359 *warn_or_error = s7_data_dependency_table[i].warn_or_error;
2360 break;
2361 }
2362 }
2363
2364 return bubbles;
2365}
2366
2367/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
2368 for use in the a.out file, and stores them in the array pointed to by buf.
2369 This knows about the endian-ness of the target machine and does
2370 THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
2371 2 (short) and 4 (long) Floating numbers are put out as a series of
2372 LITTLENUMS (shorts, here at least). */
2373
2374static void
2375s7_number_to_chars (char *buf, valueT val, int n)
2376{
2377 if (target_big_endian)
2378 number_to_chars_bigendian (buf, val, n);
2379 else
2380 number_to_chars_littleendian (buf, val, n);
2381}
2382
2383static void
2384s7_build_one_frag (struct s7_score_it one_inst)
2385{
2386 char *p;
2387 int relaxable_p = s7_g_opt;
2388 int relax_size = 0;
2389
2390 /* Start a new frag if frag_now is not empty. */
2391 if (frag_now_fix () != 0)
2392 {
2393 if (!frag_now->tc_frag_data.is_insn)
2394 frag_wane (frag_now);
2395
2396 frag_new (0);
2397 }
2398 frag_grow (20);
2399
2400 p = frag_more (one_inst.size);
2401 s7_number_to_chars (p, one_inst.instruction, one_inst.size);
2402
2403#ifdef OBJ_ELF
2404 dwarf2_emit_insn (one_inst.size);
2405#endif
2406
2407 relaxable_p &= (one_inst.relax_size != 0);
2408 relax_size = relaxable_p ? one_inst.relax_size : 0;
2409
2410 p = frag_var (rs_machine_dependent, relax_size + s7_RELAX_PAD_BYTE, 0,
2411 s7_RELAX_ENCODE (one_inst.size, one_inst.relax_size,
2412 one_inst.type, 0, 0, relaxable_p),
2413 NULL, 0, NULL);
2414
2415 if (relaxable_p)
2416 s7_number_to_chars (p, one_inst.relax_inst, relax_size);
2417}
2418
2419static void
2420s7_handle_dependency (struct s7_score_it *theinst)
2421{
2422 int i;
2423 int warn_or_error = 0; /* warn - 0; error - 1 */
2424 int bubbles = 0;
2425 int remainder_bubbles = 0;
2426 char cur_insn[s7_INSN_NAME_LEN];
2427 char pre_insn[s7_INSN_NAME_LEN];
2428 struct s7_score_it nop_inst;
2429 struct s7_score_it pflush_inst;
2430
2431 nop_inst.instruction = 0x0000;
2432 nop_inst.size = 2;
2433 nop_inst.relax_inst = 0x80008000;
2434 nop_inst.relax_size = 4;
2435 nop_inst.type = NO16_OPD;
2436
2437 pflush_inst.instruction = 0x8000800a;
2438 pflush_inst.size = 4;
2439 pflush_inst.relax_inst = 0x8000;
2440 pflush_inst.relax_size = 0;
2441 pflush_inst.type = NO_OPD;
2442
2443 /* pflush will clear all data dependency. */
2444 if (strcmp (theinst->name, "pflush") == 0)
2445 {
2446 s7_init_dependency_vector ();
2447 return;
2448 }
2449
2450 /* Push current instruction to s7_dependency_vector[0]. */
2451 for (i = s7_vector_size - 1; i > 0; i--)
2452 memcpy (&s7_dependency_vector[i], &s7_dependency_vector[i - 1], sizeof (s7_dependency_vector[i]));
2453
2454 memcpy (&s7_dependency_vector[0], theinst, sizeof (s7_dependency_vector[i]));
2455
2456 /* There is no dependency between nop and any instruction. */
2457 if (strcmp (s7_dependency_vector[0].name, "nop") == 0
2458 || strcmp (s7_dependency_vector[0].name, "nop!") == 0)
2459 return;
2460
2461 /* "pce" is defined in s7_insn_to_dependency_table. */
2462#define PCE_NAME "pce"
2463
2464 if (s7_dependency_vector[0].type == Insn_Type_PCE)
2465 strcpy (cur_insn, PCE_NAME);
2466 else
2467 strcpy (cur_insn, s7_dependency_vector[0].name);
2468
2469 for (i = 1; i < s7_vector_size; i++)
2470 {
2471 /* The element of s7_dependency_vector is NULL. */
2472 if (s7_dependency_vector[i].name[0] == '\0')
2473 continue;
2474
2475 if (s7_dependency_vector[i].type == Insn_Type_PCE)
2476 strcpy (pre_insn, PCE_NAME);
2477 else
2478 strcpy (pre_insn, s7_dependency_vector[i].name);
2479
2480 bubbles = s7_check_dependency (pre_insn, s7_dependency_vector[i].reg,
2481 cur_insn, s7_dependency_vector[0].reg, &warn_or_error);
2482 remainder_bubbles = bubbles - i + 1;
2483
2484 if (remainder_bubbles > 0)
2485 {
2486 int j;
2487
2488 if (s7_fix_data_dependency == 1)
2489 {
2490 if (remainder_bubbles <= 2)
2491 {
2492 if (s7_warn_fix_data_dependency)
33eaf5de 2493 as_warn (_("Fix data dependency: %s %s -- %s %s (insert %d nop!/%d)"),
c3b7224a
NC
2494 s7_dependency_vector[i].name, s7_dependency_vector[i].reg,
2495 s7_dependency_vector[0].name, s7_dependency_vector[0].reg,
2496 remainder_bubbles, bubbles);
2497
2498 for (j = (s7_vector_size - 1); (j - remainder_bubbles) > 0; j--)
2499 memcpy (&s7_dependency_vector[j], &s7_dependency_vector[j - remainder_bubbles],
2500 sizeof (s7_dependency_vector[j]));
2501
2502 for (j = 1; j <= remainder_bubbles; j++)
2503 {
2504 memset (&s7_dependency_vector[j], '\0', sizeof (s7_dependency_vector[j]));
2505 /* Insert nop!. */
2506 s7_build_one_frag (nop_inst);
2507 }
2508 }
2509 else
2510 {
2511 if (s7_warn_fix_data_dependency)
33eaf5de 2512 as_warn (_("Fix data dependency: %s %s -- %s %s (insert 1 pflush/%d)"),
c3b7224a
NC
2513 s7_dependency_vector[i].name, s7_dependency_vector[i].reg,
2514 s7_dependency_vector[0].name, s7_dependency_vector[0].reg,
2515 bubbles);
2516
2517 for (j = 1; j < s7_vector_size; j++)
2518 memset (&s7_dependency_vector[j], '\0', sizeof (s7_dependency_vector[j]));
2519
2520 /* Insert pflush. */
2521 s7_build_one_frag (pflush_inst);
2522 }
2523 }
2524 else
2525 {
2526 if (warn_or_error)
2527 {
33eaf5de 2528 as_bad (_("data dependency: %s %s -- %s %s (%d/%d bubble)"),
c3b7224a
NC
2529 s7_dependency_vector[i].name, s7_dependency_vector[i].reg,
2530 s7_dependency_vector[0].name, s7_dependency_vector[0].reg,
2531 remainder_bubbles, bubbles);
2532 }
2533 else
2534 {
33eaf5de 2535 as_warn (_("data dependency: %s %s -- %s %s (%d/%d bubble)"),
c3b7224a
NC
2536 s7_dependency_vector[i].name, s7_dependency_vector[i].reg,
2537 s7_dependency_vector[0].name, s7_dependency_vector[0].reg,
2538 remainder_bubbles, bubbles);
2539 }
2540 }
2541 }
2542 }
2543}
2544
2545static enum insn_class
2546s7_get_insn_class_from_type (enum score_insn_type type)
2547{
2548 enum insn_class retval = (int) s7_FAIL;
2549
2550 switch (type)
2551 {
2552 case Rd_I4:
2553 case Rd_I5:
2554 case Rd_rvalueBP_I5:
2555 case Rd_lvalueBP_I5:
2556 case Rd_I8:
2557 case PC_DISP8div2:
2558 case PC_DISP11div2:
2559 case Rd_Rs:
2560 case Rd_HighRs:
2561 case Rd_lvalueRs:
2562 case Rd_rvalueRs:
2563 case x_Rs:
2564 case Rd_LowRs:
2565 case NO16_OPD:
2566 retval = INSN_CLASS_16;
2567 break;
2568 case Rd_Rs_I5:
2569 case x_Rs_I5:
2570 case x_I5_x:
2571 case Rd_Rs_I14:
2572 case I15:
2573 case Rd_I16:
2574 case Rd_SI16:
2575 case Rd_rvalueRs_SI10:
2576 case Rd_lvalueRs_SI10:
2577 case Rd_rvalueRs_preSI12:
2578 case Rd_rvalueRs_postSI12:
2579 case Rd_lvalueRs_preSI12:
2580 case Rd_lvalueRs_postSI12:
2581 case Rd_Rs_SI14:
2582 case Rd_rvalueRs_SI15:
2583 case Rd_lvalueRs_SI15:
2584 case PC_DISP19div2:
2585 case PC_DISP24div2:
2586 case Rd_Rs_Rs:
2587 case x_Rs_x:
2588 case x_Rs_Rs:
2589 case Rd_Rs_x:
2590 case Rd_x_Rs:
2591 case Rd_x_x:
2592 case OP5_rvalueRs_SI15:
2593 case I5_Rs_Rs_I5_OP5:
2594 case x_rvalueRs_post4:
2595 case Rd_rvalueRs_post4:
2596 case Rd_x_I5:
2597 case Rd_lvalueRs_post4:
2598 case x_lvalueRs_post4:
2599 case Rd_Rs_Rs_imm:
2600 case NO_OPD:
2601 case Rd_lvalue32Rs:
2602 case Rd_rvalue32Rs:
2603 case Insn_GP:
2604 case Insn_PIC:
2605 case Insn_internal:
2606 retval = INSN_CLASS_32;
2607 break;
2608 case Insn_Type_PCE:
2609 retval = INSN_CLASS_PCE;
2610 break;
2611 case Insn_Type_SYN:
2612 retval = INSN_CLASS_SYN;
2613 break;
2614 default:
2615 abort ();
2616 break;
2617 }
2618 return retval;
2619}
2620
2621static unsigned long
96d56e9f 2622s7_adjust_paritybit (unsigned long m_code, enum insn_class i_class)
c3b7224a
NC
2623{
2624 unsigned long result = 0;
2625 unsigned long m_code_high = 0;
2626 unsigned long m_code_low = 0;
2627 unsigned long pb_high = 0;
2628 unsigned long pb_low = 0;
2629
96d56e9f 2630 if (i_class == INSN_CLASS_32)
c3b7224a
NC
2631 {
2632 pb_high = 0x80000000;
2633 pb_low = 0x00008000;
2634 }
96d56e9f 2635 else if (i_class == INSN_CLASS_16)
c3b7224a
NC
2636 {
2637 pb_high = 0;
2638 pb_low = 0;
2639 }
96d56e9f 2640 else if (i_class == INSN_CLASS_PCE)
c3b7224a
NC
2641 {
2642 pb_high = 0;
2643 pb_low = 0x00008000;
2644 }
96d56e9f 2645 else if (i_class == INSN_CLASS_SYN)
c3b7224a
NC
2646 {
2647 /* FIXME. at this time, INSN_CLASS_SYN must be 32 bit, but, instruction type should
2648 be changed if macro instruction has been expanded. */
2649 pb_high = 0x80000000;
2650 pb_low = 0x00008000;
2651 }
2652 else
2653 {
2654 abort ();
2655 }
2656
2657 m_code_high = m_code & 0x3fff8000;
2658 m_code_low = m_code & 0x00007fff;
2659 result = pb_high | (m_code_high << 1) | pb_low | m_code_low;
2660 return result;
2661
2662}
2663
2664static void
2665s7_gen_insn_frag (struct s7_score_it *part_1, struct s7_score_it *part_2)
2666{
2667 char *p;
5b7c81bd 2668 bool pce_p = false;
c3b7224a
NC
2669 int relaxable_p = s7_g_opt;
2670 int relax_size = 0;
2671 struct s7_score_it *inst1 = part_1;
2672 struct s7_score_it *inst2 = part_2;
2673 struct s7_score_it backup_inst1;
2674
63b4cc53 2675 pce_p = inst2 != NULL;
c3b7224a
NC
2676 memcpy (&backup_inst1, inst1, sizeof (struct s7_score_it));
2677
2678 /* Adjust instruction opcode and to be relaxed instruction opcode. */
2679 if (pce_p)
2680 {
2681 backup_inst1.instruction = ((backup_inst1.instruction & 0x7FFF) << 15)
2682 | (inst2->instruction & 0x7FFF);
2683 backup_inst1.instruction = s7_adjust_paritybit (backup_inst1.instruction, INSN_CLASS_PCE);
2684 if (!target_big_endian)
2685 {
2686 unsigned long tmp = backup_inst1.instruction;
2687 backup_inst1.instruction = ((tmp & 0xffff) << 16)
2688 | (tmp >> 16);
2689 }
2690 backup_inst1.relax_inst = 0x8000;
2691 backup_inst1.size = s7_INSN_SIZE;
2692 backup_inst1.relax_size = 0;
2693 backup_inst1.type = Insn_Type_PCE;
2694 }
2695 else
2696 {
2697 backup_inst1.instruction = s7_adjust_paritybit (backup_inst1.instruction,
2698 s7_GET_INSN_CLASS (backup_inst1.type));
2699 }
2700
2701 if (backup_inst1.relax_size != 0)
2702 {
2703 enum insn_class tmp;
2704
2705 tmp = (backup_inst1.size == s7_INSN_SIZE) ? INSN_CLASS_16 : INSN_CLASS_32;
2706 backup_inst1.relax_inst = s7_adjust_paritybit (backup_inst1.relax_inst, tmp);
2707 }
2708
2709 /* Check data dependency. */
2710 s7_handle_dependency (&backup_inst1);
2711
2712 /* Start a new frag if frag_now is not empty and is not instruction frag, maybe it contains
2713 data produced by .ascii etc. Doing this is to make one instruction per frag. */
2714 if (frag_now_fix () != 0)
2715 {
2716 if (!frag_now->tc_frag_data.is_insn)
2717 frag_wane (frag_now);
2718
2719 frag_new (0);
2720 }
2721
2722 /* Here, we must call frag_grow in order to keep the instruction frag type is
2723 rs_machine_dependent.
2724 For, frag_var may change frag_now->fr_type to rs_fill by calling frag_grow which
33eaf5de 2725 actually will call frag_wane.
c3b7224a
NC
2726 Calling frag_grow first will create a new frag_now which free size is 20 that is enough
2727 for frag_var. */
2728 frag_grow (20);
2729
2730 p = frag_more (backup_inst1.size);
2731 s7_number_to_chars (p, backup_inst1.instruction, backup_inst1.size);
2732
2733#ifdef OBJ_ELF
2734 dwarf2_emit_insn (backup_inst1.size);
2735#endif
2736
2737 /* Generate fixup structure. */
2738 if (pce_p)
2739 {
2740 if (inst1->reloc.type != BFD_RELOC_NONE)
2741 s7_fix_new_score (frag_now, p - frag_now->fr_literal,
2742 inst1->size, &inst1->reloc.exp,
2743 inst1->reloc.pc_rel, inst1->reloc.type);
2744
2745 if (inst2->reloc.type != BFD_RELOC_NONE)
2746 s7_fix_new_score (frag_now, p - frag_now->fr_literal + 2,
2747 inst2->size, &inst2->reloc.exp, inst2->reloc.pc_rel, inst2->reloc.type);
2748 }
2749 else
2750 {
2751 if (backup_inst1.reloc.type != BFD_RELOC_NONE)
2752 s7_fix_new_score (frag_now, p - frag_now->fr_literal,
2753 backup_inst1.size, &backup_inst1.reloc.exp,
2754 backup_inst1.reloc.pc_rel, backup_inst1.reloc.type);
2755 }
2756
2757 /* relax_size may be 2, 4, 12 or 0, 0 indicates no relaxation. */
2758 relaxable_p &= (backup_inst1.relax_size != 0);
2759 relax_size = relaxable_p ? backup_inst1.relax_size : 0;
2760
2761 p = frag_var (rs_machine_dependent, relax_size + s7_RELAX_PAD_BYTE, 0,
2762 s7_RELAX_ENCODE (backup_inst1.size, backup_inst1.relax_size,
2763 backup_inst1.type, 0, 0, relaxable_p),
2764 backup_inst1.reloc.exp.X_add_symbol, 0, NULL);
2765
2766 if (relaxable_p)
2767 s7_number_to_chars (p, backup_inst1.relax_inst, relax_size);
2768
2769 memcpy (inst1, &backup_inst1, sizeof (struct s7_score_it));
2770}
2771
2772static void
5b7c81bd 2773s7_parse_16_32_inst (char *insnstr, bool gen_frag_p)
c3b7224a
NC
2774{
2775 char c;
2776 char *p;
2777 char *operator = insnstr;
2778 const struct s7_asm_opcode *opcode;
2779
2780 /* Parse operator and operands. */
2781 s7_skip_whitespace (operator);
2782
2783 for (p = operator; *p != '\0'; p++)
2784 if ((*p == ' ') || (*p == '!'))
2785 break;
2786
2787 if (*p == '!')
2788 p++;
2789
2790 c = *p;
2791 *p = '\0';
2792
fe0e921f
AM
2793 opcode = (const struct s7_asm_opcode *) str_hash_find (s7_score_ops_hsh,
2794 operator);
c3b7224a
NC
2795 *p = c;
2796
2797 memset (&s7_inst, '\0', sizeof (s7_inst));
2132b407 2798 strcpy (s7_inst.str, insnstr);
c3b7224a
NC
2799 if (opcode)
2800 {
2801 s7_inst.instruction = opcode->value;
2802 s7_inst.relax_inst = opcode->relax_value;
2803 s7_inst.type = opcode->type;
2804 s7_inst.size = s7_GET_INSN_SIZE (s7_inst.type);
2805 s7_inst.relax_size = 0;
2806 s7_inst.bwarn = 0;
2132b407 2807 strcpy (s7_inst.name, opcode->template_name);
c3b7224a
NC
2808 strcpy (s7_inst.reg, "");
2809 s7_inst.error = NULL;
2810 s7_inst.reloc.type = BFD_RELOC_NONE;
2811
2812 (*opcode->parms) (p);
2813
2814 /* It indicates current instruction is a macro instruction if s7_inst.bwarn equals -1. */
2815 if ((s7_inst.bwarn != -1) && (!s7_inst.error) && (gen_frag_p))
2816 s7_gen_insn_frag (&s7_inst, NULL);
2817 }
2818 else
2819 s7_inst.error = _("unrecognized opcode");
2820}
2821
2822static int
5b7c81bd 2823s7_append_insn (char *str, bool gen_frag_p)
c3b7224a
NC
2824{
2825 int retval = s7_SUCCESS;
2826
2827 s7_parse_16_32_inst (str, gen_frag_p);
2828
2829 if (s7_inst.error)
2830 {
2831 retval = (int) s7_FAIL;
2832 as_bad (_("%s -- `%s'"), s7_inst.error, s7_inst.str);
2833 s7_inst.error = NULL;
2834 }
2835
2836 return retval;
2837}
2838
2839/* Handle mv! reg_high, reg_low;
2840 mv! reg_low, reg_high;
2841 mv! reg_low, reg_low; */
2842static void
2843s7_do16_mv_rdrs (char *str)
2844{
2845 int reg_rd;
2846 int reg_rs;
2847 char *backupstr = NULL;
2848
2849 backupstr = str;
2850 s7_skip_whitespace (str);
2851
2852 if ((reg_rd = s7_reg_required_here (&str, 8, s7_REG_TYPE_SCORE)) == (int) s7_FAIL
2853 || s7_skip_past_comma (&str) == (int) s7_FAIL
2854 || (reg_rs = s7_reg_required_here (&str, 4, s7_REG_TYPE_SCORE)) == (int) s7_FAIL
2855 || s7_end_of_line (str) == (int) s7_FAIL)
2856 {
2857 return;
2858 }
2859 else
2860 {
2861 /* Case 1 : mv! or mlfh!. */
2862 if (reg_rd < 16)
2863 {
2864 if (reg_rs < 16)
2865 {
2866 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2867 | (((s7_inst.instruction >> 4) & 0xf) << 15) | (0xf << 10);
2868 s7_inst.relax_size = 4;
2869 }
2870 else
2871 {
2872 char append_str[s7_MAX_LITERAL_POOL_SIZE];
2873
2874 sprintf (append_str, "mlfh! %s", backupstr);
5b7c81bd 2875 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
2876 return;
2877 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
2878 s7_inst.bwarn = -1;
2879 }
2880 }
2881 /* Case 2 : mhfl!. */
2882 else
2883 {
2884 if (reg_rs > 16)
2885 {
2886 s7_SET_INSN_ERROR (s7_BAD_ARGS);
2887 return;
2888 }
2889 else
2890 {
2891 char append_str[s7_MAX_LITERAL_POOL_SIZE];
2892
2893 sprintf (append_str, "mhfl! %s", backupstr);
5b7c81bd 2894 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
2895 return;
2896
2897 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
2898 s7_inst.bwarn = -1;
2899 }
2900 }
2901 }
2902}
2903
2904static void
2905s7_do16_rdi4 (char *str)
2906{
2907 s7_skip_whitespace (str);
2908
2909 if (s7_reglow_required_here (&str, 8) == (int) s7_FAIL
2910 || s7_skip_past_comma (&str) == (int) s7_FAIL
2911 || s7_data_op2 (&str, 3, _IMM4) == (int) s7_FAIL
2912 || s7_end_of_line (str) == (int) s7_FAIL)
2913 {
2914 return;
2915 }
2916 else
2917 {
2918 if (((s7_inst.instruction >> 3) & 0x10) == 0) /* for judge is addei or subei : bit 5 =0 : addei */
2919 {
2920 if (((s7_inst.instruction >> 3) & 0xf) != 0xf)
2921 {
2922 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2923 | ((1 << ((s7_inst.instruction >> 3) & 0xf)) << 1);
2924 s7_inst.relax_size = 4;
2925 }
2926 else
2927 {
2928 s7_inst.relax_inst = 0x8000;
2929 }
2930 }
2931 else
2932 {
2933 if (((s7_inst.instruction >> 3) & 0xf) != 0xf)
2934 {
2935 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2936 | (((-(1 << ((s7_inst.instruction >> 3) & 0xf))) & 0xffff) << 1);
2937 s7_inst.relax_size = 4;
2938 }
2939 else
2940 {
2941 s7_inst.relax_inst = 0x8000;
2942 }
2943 }
2944 }
2945}
2946
2947static void
2948s7_do16_rdi5 (char *str)
2949{
2950 s7_skip_whitespace (str);
2951
2952 if (s7_reglow_required_here (&str, 8) == (int) s7_FAIL
2953 || s7_skip_past_comma (&str) == (int) s7_FAIL
2954 || s7_data_op2 (&str, 3, _IMM5) == (int) s7_FAIL
2955 || s7_end_of_line (str) == (int) s7_FAIL)
2956 return;
2957 else
2958 {
2959 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
2960 | (((s7_inst.instruction >> 8) & 0xf) << 15) | (((s7_inst.instruction >> 3) & 0x1f) << 10);
2961 s7_inst.relax_size = 4;
2962 }
2963}
2964
2965/* Handle sdbbp. */
2966
2967static void
2968s7_do16_xi5 (char *str)
2969{
2970 s7_skip_whitespace (str);
2971
2972 if (s7_data_op2 (&str, 3, _IMM5) == (int) s7_FAIL || s7_end_of_line (str) == (int) s7_FAIL)
2973 return;
2974 else
2975 {
2976 s7_inst.relax_inst |= (((s7_inst.instruction >> 3) & 0x1f) << 15);
2977 s7_inst.relax_size = 4;
2978 }
2979}
2980
2981/* Check that an immediate is word alignment or half word alignment.
2982 If so, convert it to the right format. */
2983
2984static int
2985s7_validate_immediate_align (int val, unsigned int data_type)
2986{
2987 if (data_type == _IMM5_RSHIFT_1)
2988 {
2989 if (val % 2)
2990 {
2991 s7_inst.error = _("address offset must be half word alignment");
2992 return (int) s7_FAIL;
2993 }
2994 }
2995 else if ((data_type == _IMM5_RSHIFT_2) || (data_type == _IMM10_RSHIFT_2))
2996 {
2997 if (val % 4)
2998 {
2999 s7_inst.error = _("address offset must be word alignment");
3000 return (int) s7_FAIL;
3001 }
3002 }
3003
3004 return s7_SUCCESS;
3005}
3006
3007static int
3008s7_exp_ldst_offset (char **str, int shift, unsigned int data_type)
3009{
3010 char *dataptr;
3011 int hex_p = 0;
3012
3013 dataptr = * str;
3014
3015 if ((dataptr != NULL)
3016 && (((strstr (dataptr, "0x")) != NULL)
3017 || ((strstr (dataptr, "0X")) != NULL)))
3018 {
3019 hex_p = 1;
3020 if ((data_type != _SIMM16_LA)
3021 && (data_type != _VALUE_HI16)
3022 && (data_type != _VALUE_LO16)
3023 && (data_type != _IMM16)
3024 && (data_type != _IMM15)
3025 && (data_type != _IMM14)
3026 && (data_type != _IMM4)
3027 && (data_type != _IMM5)
3028 && (data_type != _IMM8)
3029 && (data_type != _IMM5_RSHIFT_1)
3030 && (data_type != _IMM5_RSHIFT_2)
3031 && (data_type != _SIMM12)
3032 && (data_type != _SIMM15)
3033 && (data_type != _SIMM14_NEG)
3034 && (data_type != _IMM10_RSHIFT_2))
3035 {
3036 data_type += 24;
3037 }
3038 }
3039
3040 if (s7_my_get_expression (&s7_inst.reloc.exp, str) == (int) s7_FAIL)
3041 return (int) s7_FAIL;
3042
3043 if (s7_inst.reloc.exp.X_op == O_constant)
3044 {
3045 /* Need to check the immediate align. */
3046 int value = s7_validate_immediate_align (s7_inst.reloc.exp.X_add_number, data_type);
3047
3048 if (value == (int) s7_FAIL)
3049 return (int) s7_FAIL;
3050
3051 value = s7_validate_immediate (s7_inst.reloc.exp.X_add_number, data_type, hex_p);
3052 if (value == (int) s7_FAIL)
3053 {
3054 if (data_type < 30)
3055 sprintf (s7_err_msg,
3056 _("invalid constant: %d bit expression not in range %d..%d"),
3057 s7_score_df_range[data_type].bits,
3058 s7_score_df_range[data_type].range[0], s7_score_df_range[data_type].range[1]);
3059 else
3060 sprintf (s7_err_msg,
3061 _("invalid constant: %d bit expression not in range %d..%d"),
3062 s7_score_df_range[data_type - 24].bits,
3063 s7_score_df_range[data_type - 24].range[0], s7_score_df_range[data_type - 24].range[1]);
3064 s7_inst.error = s7_err_msg;
3065 return (int) s7_FAIL;
3066 }
3067
3068 if (data_type == _IMM5_RSHIFT_1)
3069 {
3070 value >>= 1;
3071 }
3072 else if ((data_type == _IMM5_RSHIFT_2) || (data_type == _IMM10_RSHIFT_2))
3073 {
3074 value >>= 2;
3075 }
3076
3077 if (s7_score_df_range[data_type].range[0] != 0)
3078 {
3079 value &= (1 << s7_score_df_range[data_type].bits) - 1;
3080 }
3081
3082 s7_inst.instruction |= value << shift;
3083 }
3084 else
3085 {
3086 s7_inst.reloc.pc_rel = 0;
3087 }
3088
3089 return s7_SUCCESS;
3090}
3091
3092static void
3093s7_do_ldst_insn (char *str)
3094{
3095 int pre_inc = 0;
3096 int conflict_reg;
3097 int value;
3098 char * temp;
c3b7224a
NC
3099 char *dataptr;
3100 int reg;
3101 int ldst_idx = 0;
3102
3103 int hex_p = 0;
3104
c3b7224a
NC
3105 s7_skip_whitespace (str);
3106
3107 if (((conflict_reg = s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
3108 || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3109 return;
3110
3111 /* ld/sw rD, [rA, simm15] ld/sw rD, [rA]+, simm12 ld/sw rD, [rA, simm12]+. */
3112 if (*str == '[')
3113 {
3114 str++;
3115 s7_skip_whitespace (str);
3116
3117 if ((reg = s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
3118 return;
3119
3120 /* Conflicts can occur on stores as well as loads. */
3121 conflict_reg = (conflict_reg == reg);
3122 s7_skip_whitespace (str);
3123 temp = str + 1; /* The latter will process decimal/hex expression. */
3124
3125 /* ld/sw rD, [rA]+, simm12 ld/sw rD, [rA]+. */
3126 if (*str == ']')
3127 {
3128 str++;
3129 if (*str == '+')
3130 {
3131 str++;
3132 /* ld/sw rD, [rA]+, simm12. */
3133 if (s7_skip_past_comma (&str) == s7_SUCCESS)
3134 {
3135 if ((s7_exp_ldst_offset (&str, 3, _SIMM12) == (int) s7_FAIL)
3136 || (s7_end_of_line (str) == (int) s7_FAIL))
3137 return;
3138
3139 if (conflict_reg)
3140 {
3141 unsigned int ldst_func = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
3142
3143 if ((ldst_func == INSN_LH)
3144 || (ldst_func == INSN_LHU)
3145 || (ldst_func == INSN_LW)
3146 || (ldst_func == INSN_LB)
3147 || (ldst_func == INSN_LBU))
3148 {
3149 s7_inst.error = _("register same as write-back base");
3150 return;
3151 }
3152 }
3153
3154 ldst_idx = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
3155 s7_inst.instruction &= ~OPC_PSEUDOLDST_MASK;
3156 s7_inst.instruction |= s7_score_ldst_insns[ldst_idx * 3 + LDST_POST].value;
3157
3158 /* lw rD, [rA]+, 4 convert to pop rD, [rA]. */
3159 if ((s7_inst.instruction & 0x3e000007) == 0x0e000000)
3160 {
3161 /* rs = r0-r7, offset = 4 */
3162 if ((((s7_inst.instruction >> 15) & 0x18) == 0)
3163 && (((s7_inst.instruction >> 3) & 0xfff) == 4))
3164 {
3165 /* Relax to pophi. */
3166 if ((((s7_inst.instruction >> 20) & 0x10) == 0x10))
3167 {
3168 s7_inst.relax_inst = 0x0000200a | (((s7_inst.instruction >> 20) & 0xf)
3169 << 8) | 1 << 7 |
3170 (((s7_inst.instruction >> 15) & 0x7) << 4);
3171 }
3172 /* Relax to pop. */
3173 else
3174 {
3175 s7_inst.relax_inst = 0x0000200a | (((s7_inst.instruction >> 20) & 0xf)
3176 << 8) | 0 << 7 |
3177 (((s7_inst.instruction >> 15) & 0x7) << 4);
3178 }
3179 s7_inst.relax_size = 2;
3180 }
3181 }
3182 return;
3183 }
3184 /* ld/sw rD, [rA]+ convert to ld/sw rD, [rA, 0]+. */
3185 else
3186 {
3187 s7_SET_INSN_ERROR (NULL);
3188 if (s7_end_of_line (str) == (int) s7_FAIL)
3189 {
3190 return;
3191 }
3192
3193 pre_inc = 1;
3194 value = s7_validate_immediate (s7_inst.reloc.exp.X_add_number, _SIMM12, 0);
3195 value &= (1 << s7_score_df_range[_SIMM12].bits) - 1;
3196 ldst_idx = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
3197 s7_inst.instruction &= ~OPC_PSEUDOLDST_MASK;
3198 s7_inst.instruction |= s7_score_ldst_insns[ldst_idx * 3 + pre_inc].value;
3199 s7_inst.instruction |= value << 3;
3200 s7_inst.relax_inst = 0x8000;
3201 return;
3202 }
3203 }
3204 /* ld/sw rD, [rA] convert to ld/sw rD, [rA, simm15]. */
3205 else
3206 {
3207 if (s7_end_of_line (str) == (int) s7_FAIL)
3208 return;
3209
3210 ldst_idx = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
3211 s7_inst.instruction &= ~OPC_PSEUDOLDST_MASK;
3212 s7_inst.instruction |= s7_score_ldst_insns[ldst_idx * 3 + LDST_NOUPDATE].value;
3213
3214 /* lbu rd, [rs] -> lbu! rd, [rs] */
3215 if (ldst_idx == INSN_LBU)
3216 {
3217 s7_inst.relax_inst = INSN16_LBU;
3218 }
3219 else if (ldst_idx == INSN_LH)
3220 {
3221 s7_inst.relax_inst = INSN16_LH;
3222 }
3223 else if (ldst_idx == INSN_LW)
3224 {
3225 s7_inst.relax_inst = INSN16_LW;
3226 }
3227 else if (ldst_idx == INSN_SB)
3228 {
3229 s7_inst.relax_inst = INSN16_SB;
3230 }
3231 else if (ldst_idx == INSN_SH)
3232 {
3233 s7_inst.relax_inst = INSN16_SH;
3234 }
3235 else if (ldst_idx == INSN_SW)
3236 {
3237 s7_inst.relax_inst = INSN16_SW;
3238 }
3239 else
3240 {
3241 s7_inst.relax_inst = 0x8000;
3242 }
3243
3244 /* lw/lh/lbu/sw/sh/sb, offset = 0, relax to 16 bit instruction. */
3245 if ((ldst_idx == INSN_LBU)
3246 || (ldst_idx == INSN_LH)
3247 || (ldst_idx == INSN_LW)
3248 || (ldst_idx == INSN_SB) || (ldst_idx == INSN_SH) || (ldst_idx == INSN_SW))
3249 {
3250 if ((((s7_inst.instruction >> 15) & 0x10) == 0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
3251 {
3252 s7_inst.relax_inst |= (2 << 12) | (((s7_inst.instruction >> 20) & 0xf) << 8) |
3253 (((s7_inst.instruction >> 15) & 0xf) << 4);
3254 s7_inst.relax_size = 2;
3255 }
3256 }
3257
3258 return;
3259 }
3260 }
3261 /* ld/sw rD, [rA, simm15] ld/sw rD, [rA, simm12]+. */
3262 else
3263 {
3264 if (s7_skip_past_comma (&str) == (int) s7_FAIL)
3265 {
3266 s7_inst.error = _("pre-indexed expression expected");
3267 return;
3268 }
3269
3270 if (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL)
3271 return;
3272
3273 s7_skip_whitespace (str);
3274 if (*str++ != ']')
3275 {
3276 s7_inst.error = _("missing ]");
3277 return;
3278 }
3279
3280 s7_skip_whitespace (str);
3281 /* ld/sw rD, [rA, simm12]+. */
3282 if (*str == '+')
3283 {
3284 str++;
3285 pre_inc = 1;
3286 if (conflict_reg)
3287 {
3288 unsigned int ldst_func = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
3289
3290 if ((ldst_func == INSN_LH)
3291 || (ldst_func == INSN_LHU)
3292 || (ldst_func == INSN_LW)
3293 || (ldst_func == INSN_LB)
3294 || (ldst_func == INSN_LBU))
3295 {
3296 s7_inst.error = _("register same as write-back base");
3297 return;
3298 }
3299 }
3300 }
3301
3302 if (s7_end_of_line (str) == (int) s7_FAIL)
3303 return;
3304
3305 if (s7_inst.reloc.exp.X_op == O_constant)
3306 {
c3b7224a
NC
3307 unsigned int data_type;
3308
3309 if (pre_inc == 1)
3310 data_type = _SIMM12;
3311 else
3312 data_type = _SIMM15;
3313 dataptr = temp;
3314
3315 if ((dataptr != NULL)
3316 && (((strstr (dataptr, "0x")) != NULL)
3317 || ((strstr (dataptr, "0X")) != NULL)))
3318 {
3319 hex_p = 1;
3320 if ((data_type != _SIMM16_LA)
3321 && (data_type != _VALUE_HI16)
3322 && (data_type != _VALUE_LO16)
3323 && (data_type != _IMM16)
3324 && (data_type != _IMM15)
3325 && (data_type != _IMM14)
3326 && (data_type != _IMM4)
3327 && (data_type != _IMM5)
3328 && (data_type != _IMM8)
3329 && (data_type != _SIMM12)
3330 && (data_type != _SIMM15)
3331 && (data_type != _IMM5_RSHIFT_1)
3332 && (data_type != _IMM5_RSHIFT_2)
3333 && (data_type != _SIMM14_NEG)
3334 && (data_type != _IMM10_RSHIFT_2))
3335 {
3336 data_type += 24;
3337 }
3338 }
3339
3340 value = s7_validate_immediate (s7_inst.reloc.exp.X_add_number, data_type, hex_p);
3341 if (value == (int) s7_FAIL)
3342 {
3343 if (data_type < 30)
3344 sprintf (s7_err_msg,
3345 _("invalid constant: %d bit expression not in range %d..%d"),
3346 s7_score_df_range[data_type].bits,
3347 s7_score_df_range[data_type].range[0], s7_score_df_range[data_type].range[1]);
3348 else
3349 sprintf (s7_err_msg,
3350 _("invalid constant: %d bit expression not in range %d..%d"),
3351 s7_score_df_range[data_type - 24].bits,
3352 s7_score_df_range[data_type - 24].range[0],
3353 s7_score_df_range[data_type - 24].range[1]);
3354 s7_inst.error = s7_err_msg;
3355 return;
3356 }
3357
3358 value &= (1 << s7_score_df_range[data_type].bits) - 1;
3359 ldst_idx = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
3360 s7_inst.instruction &= ~OPC_PSEUDOLDST_MASK;
3361 s7_inst.instruction |= s7_score_ldst_insns[ldst_idx * 3 + pre_inc].value;
3362 if (pre_inc == 1)
3363 s7_inst.instruction |= value << 3;
3364 else
3365 s7_inst.instruction |= value;
3366
3367 /* lw rD, [rA, simm15] */
3368 if ((s7_inst.instruction & 0x3e000000) == 0x20000000)
3369 {
3370 /* Both rD and rA are in [r0 - r15]. */
3371 if ((((s7_inst.instruction >> 15) & 0x10) == 0)
3372 && (((s7_inst.instruction >> 20) & 0x10) == 0))
3373 {
3374 /* simm15 = 0, lw -> lw!. */
3375 if ((s7_inst.instruction & 0x7fff) == 0)
3376 {
3377 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
3378 | (((s7_inst.instruction >> 20) & 0xf) << 8);
3379 s7_inst.relax_size = 2;
3380 }
3381 /* rA = r2, lw -> lwp!. */
3382 else if ((((s7_inst.instruction >> 15) & 0xf) == 2)
3383 && ((s7_inst.instruction & 0x3) == 0)
3384 && ((s7_inst.instruction & 0x7fff) < 128))
3385 {
3386 s7_inst.relax_inst = 0x7000 | (((s7_inst.instruction >> 20) & 0xf) << 8)
3387 | (((s7_inst.instruction & 0x7fff) >> 2) << 3);
3388 s7_inst.relax_size = 2;
3389 }
3390 else
3391 {
3392 s7_inst.relax_inst = 0x8000;
3393 }
3394 }
3395 else
3396 {
3397 s7_inst.relax_inst = 0x8000;
3398 }
3399 }
3400 /* sw rD, [rA, simm15] */
3401 else if ((s7_inst.instruction & 0x3e000000) == 0x28000000)
3402 {
3403 /* Both rD and rA are in [r0 - r15]. */
3404 if ((((s7_inst.instruction >> 15) & 0x10) == 0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
3405 {
3406 /* simm15 = 0, sw -> sw!. */
3407 if ((s7_inst.instruction & 0x7fff) == 0)
3408 {
3409 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
3410 | (((s7_inst.instruction >> 20) & 0xf) << 8);
3411 s7_inst.relax_size = 2;
3412 }
3413 /* rA = r2, sw -> swp!. */
3414 else if ((((s7_inst.instruction >> 15) & 0xf) == 2)
3415 && ((s7_inst.instruction & 0x3) == 0)
3416 && ((s7_inst.instruction & 0x7fff) < 128))
3417 {
3418 s7_inst.relax_inst = 0x7004 | (((s7_inst.instruction >> 20) & 0xf) << 8)
3419 | (((s7_inst.instruction & 0x7fff) >> 2) << 3);
3420 s7_inst.relax_size = 2;
3421 }
3422 else
3423 {
3424 s7_inst.relax_inst = 0x8000;
3425 }
3426 }
3427 else
3428 {
3429 s7_inst.relax_inst = 0x8000;
3430 }
3431 }
3432 /* sw rD, [rA, simm15]+ sw pre. */
3433 else if ((s7_inst.instruction & 0x3e000007) == 0x06000004)
3434 {
3435 /* rA is in [r0 - r7], and simm15 = -4. */
3436 if ((((s7_inst.instruction >> 15) & 0x18) == 0)
3437 && (((s7_inst.instruction >> 3) & 0xfff) == 0xffc))
3438 {
3439 /* sw -> pushhi!. */
3440 if ((((s7_inst.instruction >> 20) & 0x10) == 0x10))
3441 {
3442 s7_inst.relax_inst = 0x0000200e | (((s7_inst.instruction >> 20) & 0xf) << 8)
3443 | 1 << 7 | (((s7_inst.instruction >> 15) & 0x7) << 4);
3444 s7_inst.relax_size = 2;
3445 }
3446 /* sw -> push!. */
3447 else
3448 {
3449 s7_inst.relax_inst = 0x0000200e | (((s7_inst.instruction >> 20) & 0xf) << 8)
3450 | 0 << 7 | (((s7_inst.instruction >> 15) & 0x7) << 4);
3451 s7_inst.relax_size = 2;
3452 }
3453 }
3454 else
3455 {
3456 s7_inst.relax_inst = 0x8000;
3457 }
3458 }
3459 /* lh rD, [rA, simm15] */
3460 else if ((s7_inst.instruction & 0x3e000000) == 0x22000000)
3461 {
3462 /* Both rD and rA are in [r0 - r15]. */
3463 if ((((s7_inst.instruction >> 15) & 0x10) == 0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
3464 {
3465 /* simm15 = 0, lh -> lh!. */
3466 if ((s7_inst.instruction & 0x7fff) == 0)
3467 {
3468 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
3469 | (((s7_inst.instruction >> 20) & 0xf) << 8);
3470 s7_inst.relax_size = 2;
3471 }
3472 /* rA = r2, lh -> lhp!. */
3473 else if ((((s7_inst.instruction >> 15) & 0xf) == 2)
3474 && ((s7_inst.instruction & 0x1) == 0)
3475 && ((s7_inst.instruction & 0x7fff) < 64))
3476 {
3477 s7_inst.relax_inst = 0x7001 | (((s7_inst.instruction >> 20) & 0xf) << 8)
3478 | (((s7_inst.instruction & 0x7fff) >> 1) << 3);
3479 s7_inst.relax_size = 2;
3480 }
3481 else
3482 {
3483 s7_inst.relax_inst = 0x8000;
3484 }
3485 }
3486 else
3487 {
3488 s7_inst.relax_inst = 0x8000;
3489 }
3490 }
3491 /* sh rD, [rA, simm15] */
3492 else if ((s7_inst.instruction & 0x3e000000) == 0x2a000000)
3493 {
3494 /* Both rD and rA are in [r0 - r15]. */
3495 if ((((s7_inst.instruction >> 15) & 0x10) == 0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
3496 {
3497 /* simm15 = 0, sh -> sh!. */
3498 if ((s7_inst.instruction & 0x7fff) == 0)
3499 {
3500 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
3501 | (((s7_inst.instruction >> 20) & 0xf) << 8);
3502 s7_inst.relax_size = 2;
3503 }
3504 /* rA = r2, sh -> shp!. */
3505 else if ((((s7_inst.instruction >> 15) & 0xf) == 2)
3506 && ((s7_inst.instruction & 0x1) == 0)
3507 && ((s7_inst.instruction & 0x7fff) < 64))
3508 {
3509 s7_inst.relax_inst = 0x7005 | (((s7_inst.instruction >> 20) & 0xf) << 8)
3510 | (((s7_inst.instruction & 0x7fff) >> 1) << 3);
3511 s7_inst.relax_size = 2;
3512 }
3513 else
3514 {
3515 s7_inst.relax_inst = 0x8000;
3516 }
3517 }
3518 else
3519 {
3520 s7_inst.relax_inst = 0x8000;
3521 }
3522 }
3523 /* lbu rD, [rA, simm15] */
3524 else if ((s7_inst.instruction & 0x3e000000) == 0x2c000000)
3525 {
3526 /* Both rD and rA are in [r0 - r15]. */
3527 if ((((s7_inst.instruction >> 15) & 0x10) == 0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
3528 {
3529 /* simm15 = 0, lbu -> lbu!. */
3530 if ((s7_inst.instruction & 0x7fff) == 0)
3531 {
3532 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
3533 | (((s7_inst.instruction >> 20) & 0xf) << 8);
3534 s7_inst.relax_size = 2;
3535 }
3536 /* rA = r2, lbu -> lbup!. */
3537 else if ((((s7_inst.instruction >> 15) & 0xf) == 2)
3538 && ((s7_inst.instruction & 0x7fff) < 32))
3539 {
3540 s7_inst.relax_inst = 0x7003 | (((s7_inst.instruction >> 20) & 0xf) << 8)
3541 | ((s7_inst.instruction & 0x7fff) << 3);
3542 s7_inst.relax_size = 2;
3543 }
3544 else
3545 {
3546 s7_inst.relax_inst = 0x8000;
3547 }
3548 }
3549 else
3550 {
3551 s7_inst.relax_inst = 0x8000;
3552 }
3553 }
3554 /* sb rD, [rA, simm15] */
3555 else if ((s7_inst.instruction & 0x3e000000) == 0x2e000000)
3556 {
3557 /* Both rD and rA are in [r0 - r15]. */
3558 if ((((s7_inst.instruction >> 15) & 0x10) == 0) && (((s7_inst.instruction >> 20) & 0x10) == 0))
3559 {
3560 /* simm15 = 0, sb -> sb!. */
3561 if ((s7_inst.instruction & 0x7fff) == 0)
3562 {
3563 s7_inst.relax_inst |= (((s7_inst.instruction >> 15) & 0xf) << 4)
3564 | (((s7_inst.instruction >> 20) & 0xf) << 8);
3565 s7_inst.relax_size = 2;
3566 }
3567 /* rA = r2, sb -> sb!. */
3568 else if ((((s7_inst.instruction >> 15) & 0xf) == 2)
3569 && ((s7_inst.instruction & 0x7fff) < 32))
3570 {
3571 s7_inst.relax_inst = 0x7007 | (((s7_inst.instruction >> 20) & 0xf) << 8)
3572 | ((s7_inst.instruction & 0x7fff) << 3);
3573 s7_inst.relax_size = 2;
3574 }
3575 else
3576 {
3577 s7_inst.relax_inst = 0x8000;
3578 }
3579 }
3580 else
3581 {
3582 s7_inst.relax_inst = 0x8000;
3583 }
3584 }
3585 else
3586 {
3587 s7_inst.relax_inst = 0x8000;
3588 }
3589
3590 return;
3591 }
3592 else
3593 {
3594 /* FIXME: may set error, for there is no ld/sw rD, [rA, label] */
3595 s7_inst.reloc.pc_rel = 0;
3596 }
3597 }
3598 }
3599 else
3600 {
3601 s7_inst.error = s7_BAD_ARGS;
3602 }
3603}
3604
3605/* Handle cache. */
3606static void
3607s7_do_cache (char *str)
3608{
3609 s7_skip_whitespace (str);
3610
3611 if ((s7_data_op2 (&str, 20, _IMM5) == (int) s7_FAIL) || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3612 {
3613 return;
3614 }
3615 else
3616 {
3617 int cache_op;
3618
3619 cache_op = (s7_inst.instruction >> 20) & 0x1F;
3620 sprintf (s7_inst.name, "cache %d", cache_op);
3621 }
3622
3623 if (*str == '[')
3624 {
3625 str++;
3626 s7_skip_whitespace (str);
3627
3628 if (s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL)
3629 return;
3630
3631 s7_skip_whitespace (str);
3632
3633 /* cache op, [rA] */
3634 if (s7_skip_past_comma (&str) == (int) s7_FAIL)
3635 {
3636 s7_SET_INSN_ERROR (NULL);
3637 if (*str != ']')
3638 {
3639 s7_inst.error = _("missing ]");
3640 return;
3641 }
3642 str++;
3643 }
3644 /* cache op, [rA, simm15] */
3645 else
3646 {
3647 if (s7_exp_ldst_offset (&str, 0, _SIMM15) == (int) s7_FAIL)
3648 {
3649 return;
3650 }
3651
3652 s7_skip_whitespace (str);
3653 if (*str++ != ']')
3654 {
3655 s7_inst.error = _("missing ]");
3656 return;
3657 }
3658 }
3659
3660 if (s7_end_of_line (str) == (int) s7_FAIL)
3661 return;
3662 }
3663 else
3664 {
3665 s7_inst.error = s7_BAD_ARGS;
3666 }
3667}
3668
3669static void
3670s7_do_crdcrscrsimm5 (char *str)
3671{
3672 char *strbak;
3673
3674 strbak = str;
3675 s7_skip_whitespace (str);
3676
3677 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE_CR) == (int) s7_FAIL
3678 || s7_skip_past_comma (&str) == (int) s7_FAIL
3679 || s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE_CR) == (int) s7_FAIL
3680 || s7_skip_past_comma (&str) == (int) s7_FAIL
3681 || s7_reg_required_here (&str, 10, s7_REG_TYPE_SCORE_CR) == (int) s7_FAIL
3682 || s7_skip_past_comma (&str) == (int) s7_FAIL)
3683 {
3684 str = strbak;
3685 /* cop1 cop_code20. */
3686 if (s7_data_op2 (&str, 5, _IMM20) == (int) s7_FAIL)
3687 return;
3688 }
3689 else
3690 {
3691 if (s7_data_op2 (&str, 5, _IMM5) == (int) s7_FAIL)
3692 return;
3693 }
3694
3695 s7_end_of_line (str);
3696}
3697
3698/* Handle ldc/stc. */
3699static void
3700s7_do_ldst_cop (char *str)
3701{
3702 s7_skip_whitespace (str);
3703
3704 if ((s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE_CR) == (int) s7_FAIL)
3705 || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3706 return;
3707
3708 if (*str == '[')
3709 {
3710 str++;
3711 s7_skip_whitespace (str);
3712
3713 if (s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL)
3714 return;
3715
3716 s7_skip_whitespace (str);
3717
3718 if (*str++ != ']')
3719 {
3720 if (s7_exp_ldst_offset (&str, 5, _IMM10_RSHIFT_2) == (int) s7_FAIL)
3721 return;
3722
3723 s7_skip_whitespace (str);
3724 if (*str++ != ']')
3725 {
3726 s7_inst.error = _("missing ]");
3727 return;
3728 }
3729 }
3730
3731 s7_end_of_line (str);
3732 }
3733 else
3734 s7_inst.error = s7_BAD_ARGS;
3735}
3736
3737static void
3738s7_do16_ldst_insn (char *str)
3739{
3740 s7_skip_whitespace (str);
3741
3742 if ((s7_reglow_required_here (&str, 8) == (int) s7_FAIL) || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3743 return;
3744
3745 if (*str == '[')
3746 {
3747 int reg;
3748
3749 str++;
3750 s7_skip_whitespace (str);
3751
3752 if ((reg = s7_reglow_required_here (&str, 4)) == (int) s7_FAIL)
3753 return;
3754
3755 s7_skip_whitespace (str);
3756 if (*str++ == ']')
3757 {
3758 if (s7_end_of_line (str) == (int) s7_FAIL)
3759 return;
3760 else
3761 {
3762 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
3763 | (((s7_inst.instruction >> 4) & 0xf) << 15);
3764 s7_inst.relax_size = 4;
3765 }
3766 }
3767 else
3768 {
3769 s7_inst.error = _("missing ]");
3770 }
3771 }
3772 else
3773 {
3774 s7_inst.error = s7_BAD_ARGS;
3775 }
3776}
3777
3778/* Handle lbup!/lhp!/ldiu!/lwp!/sbp!/shp!/swp!. */
3779
3780static void
3781s7_do16_ldst_imm_insn (char *str)
3782{
3783 char data_exp[s7_MAX_LITERAL_POOL_SIZE];
3784 int reg_rd;
3785 char *dataptr = NULL, *pp = NULL;
3786 int cnt = 0;
3787 int assign_data = (int) s7_FAIL;
3788 unsigned int ldst_func;
3789
3790 s7_skip_whitespace (str);
3791
3792 if (((reg_rd = s7_reglow_required_here (&str, 8)) == (int) s7_FAIL)
3793 || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3794 return;
3795
3796 s7_skip_whitespace (str);
3797 dataptr = str;
3798
3799 while ((*dataptr != '\0') && (*dataptr != '|') && (cnt <= s7_MAX_LITERAL_POOL_SIZE))
3800 {
3801 data_exp[cnt] = *dataptr;
3802 dataptr++;
3803 cnt++;
3804 }
3805
3806 data_exp[cnt] = '\0';
3807 pp = &data_exp[0];
3808
3809 str = dataptr;
3810
3811 ldst_func = s7_inst.instruction & LDST16_RI_MASK;
3812 if (ldst_func == N16_LIU)
3813 assign_data = s7_exp_ldst_offset (&pp, 0, _IMM8);
3814 else if (ldst_func == N16_LHP || ldst_func == N16_SHP)
3815 assign_data = s7_exp_ldst_offset (&pp, 3, _IMM5_RSHIFT_1);
3816 else if (ldst_func == N16_LWP || ldst_func == N16_SWP)
3817 assign_data = s7_exp_ldst_offset (&pp, 3, _IMM5_RSHIFT_2);
3818 else
3819 assign_data = s7_exp_ldst_offset (&pp, 3, _IMM5);
3820
3821 if ((assign_data == (int) s7_FAIL) || (s7_end_of_line (pp) == (int) s7_FAIL))
3822 return;
3823 else
3824 {
3825 if ((s7_inst.instruction & 0x7000) == N16_LIU)
3826 {
3827 s7_inst.relax_inst |= ((s7_inst.instruction >> 8) & 0xf) << 20
3828 | ((s7_inst.instruction & 0xff) << 1);
3829 }
3830 else if (((s7_inst.instruction & 0x7007) == N16_LHP)
3831 || ((s7_inst.instruction & 0x7007) == N16_SHP))
3832 {
3833 s7_inst.relax_inst |= ((s7_inst.instruction >> 8) & 0xf) << 20 | 2 << 15
3834 | (((s7_inst.instruction >> 3) & 0x1f) << 1);
3835 }
3836 else if (((s7_inst.instruction & 0x7007) == N16_LWP)
3837 || ((s7_inst.instruction & 0x7007) == N16_SWP))
3838 {
3839 s7_inst.relax_inst |= ((s7_inst.instruction >> 8) & 0xf) << 20 | 2 << 15
3840 | (((s7_inst.instruction >> 3) & 0x1f) << 2);
3841 }
3842 else if (((s7_inst.instruction & 0x7007) == N16_LBUP)
3843 || ((s7_inst.instruction & 0x7007) == N16_SBP))
3844 {
3845 s7_inst.relax_inst |= ((s7_inst.instruction >> 8) & 0xf) << 20 | 2 << 15
3846 | (((s7_inst.instruction >> 3) & 0x1f));
3847 }
3848
3849 s7_inst.relax_size = 4;
3850 }
3851}
3852
3853static void
3854s7_do16_push_pop (char *str)
3855{
3856 int reg_rd;
3857 int H_bit_mask = 0;
3858
3859 s7_skip_whitespace (str);
3860 if (((reg_rd = s7_reg_required_here (&str, 8, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
3861 || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3862 return;
3863
3864 if (reg_rd >= 16)
3865 H_bit_mask = 1;
3866
3867 /* s7_reg_required_here will change bit 12 of opcode, so we must restore bit 12. */
3868 s7_inst.instruction &= ~(1 << 12);
3869
3870 s7_inst.instruction |= H_bit_mask << 7;
3871
3872 if (*str == '[')
3873 {
3874 int reg;
3875
3876 str++;
3877 s7_skip_whitespace (str);
3878 if ((reg = s7_reg_required_here (&str, 4, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
3879 return;
3880 else if (reg > 7)
3881 {
3882 if (!s7_inst.error)
3883 s7_inst.error = _("base register nums are over 3 bit");
3884
3885 return;
3886 }
3887
3888 s7_skip_whitespace (str);
3889 if ((*str++ != ']') || (s7_end_of_line (str) == (int) s7_FAIL))
3890 {
3891 if (!s7_inst.error)
3892 s7_inst.error = _("missing ]");
3893
3894 return;
3895 }
3896
3897 /* pop! */
3898 if ((s7_inst.instruction & 0xf) == 0xa)
3899 {
3900 if (H_bit_mask)
3901 {
3902 s7_inst.relax_inst |= ((((s7_inst.instruction >> 8) & 0xf) | 0x10) << 20)
3903 | (((s7_inst.instruction >> 4) & 0x7) << 15) | (4 << 3);
3904 }
3905 else
3906 {
3907 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
3908 | (((s7_inst.instruction >> 4) & 0x7) << 15) | (4 << 3);
3909 }
3910 }
3911 /* push! */
3912 else
3913 {
3914 if (H_bit_mask)
3915 {
3916 s7_inst.relax_inst |= ((((s7_inst.instruction >> 8) & 0xf) | 0x10) << 20)
3917 | (((s7_inst.instruction >> 4) & 0x7) << 15) | (((-4) & 0xfff) << 3);
3918 }
3919 else
3920 {
3921 s7_inst.relax_inst |= (((s7_inst.instruction >> 8) & 0xf) << 20)
3922 | (((s7_inst.instruction >> 4) & 0x7) << 15) | (((-4) & 0xfff) << 3);
3923 }
3924 }
3925 s7_inst.relax_size = 4;
3926 }
3927 else
3928 {
3929 s7_inst.error = s7_BAD_ARGS;
3930 }
3931}
3932
3933/* Handle lcb/lcw/lce/scb/scw/sce. */
3934static void
3935s7_do_ldst_unalign (char *str)
3936{
3937 int conflict_reg;
3938
3939 if (s7_university_version == 1)
3940 {
3941 s7_inst.error = s7_ERR_FOR_SCORE5U_ATOMIC;
3942 return;
3943 }
3944
3945 s7_skip_whitespace (str);
3946
3947 /* lcb/scb [rA]+. */
3948 if (*str == '[')
3949 {
3950 str++;
3951 s7_skip_whitespace (str);
3952
3953 if (s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE) == (int) s7_FAIL)
3954 return;
3955
3956 if (*str++ == ']')
3957 {
3958 if (*str++ != '+')
3959 {
3960 s7_inst.error = _("missing +");
3961 return;
3962 }
3963 }
3964 else
3965 {
3966 s7_inst.error = _("missing ]");
3967 return;
3968 }
3969
3970 if (s7_end_of_line (str) == (int) s7_FAIL)
3971 return;
3972 }
3973 /* lcw/lce/scb/sce rD, [rA]+. */
3974 else
3975 {
3976 if (((conflict_reg = s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
3977 || (s7_skip_past_comma (&str) == (int) s7_FAIL))
3978 {
3979 return;
3980 }
3981
3982 s7_skip_whitespace (str);
3983 if (*str++ == '[')
3984 {
3985 int reg;
3986
3987 s7_skip_whitespace (str);
3988 if ((reg = s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
3989 {
3990 return;
3991 }
3992
3993 /* Conflicts can occur on stores as well as loads. */
3994 conflict_reg = (conflict_reg == reg);
3995 s7_skip_whitespace (str);
3996 if (*str++ == ']')
3997 {
3998 unsigned int ldst_func = s7_inst.instruction & LDST_UNALIGN_MASK;
3999
4000 if (*str++ == '+')
4001 {
4002 if (conflict_reg)
4003 {
4004 as_warn (_("%s register same as write-back base"),
4005 ((ldst_func & UA_LCE) || (ldst_func & UA_LCW)
4006 ? _("destination") : _("source")));
4007 }
4008 }
4009 else
4010 {
4011 s7_inst.error = _("missing +");
4012 return;
4013 }
4014
4015 if (s7_end_of_line (str) == (int) s7_FAIL)
4016 return;
4017 }
4018 else
4019 {
4020 s7_inst.error = _("missing ]");
4021 return;
4022 }
4023 }
4024 else
4025 {
4026 s7_inst.error = s7_BAD_ARGS;
4027 return;
4028 }
4029 }
4030}
4031
4032/* Handle alw/asw. */
4033
4034static void
4035s7_do_ldst_atomic (char *str)
4036{
4037 if (s7_university_version == 1)
4038 {
4039 s7_inst.error = s7_ERR_FOR_SCORE5U_ATOMIC;
4040 return;
4041 }
4042
4043 s7_skip_whitespace (str);
4044
4045 if ((s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE) == (int) s7_FAIL)
4046 || (s7_skip_past_comma (&str) == (int) s7_FAIL))
4047 {
4048 return;
4049 }
4050 else
4051 {
4052
4053 s7_skip_whitespace (str);
4054 if (*str++ == '[')
4055 {
4056 int reg;
4057
4058 s7_skip_whitespace (str);
4059 if ((reg = s7_reg_required_here (&str, 15, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
4060 {
4061 return;
4062 }
4063
4064 s7_skip_whitespace (str);
4065 if (*str++ != ']')
4066 {
4067 s7_inst.error = _("missing ]");
4068 return;
4069 }
4070
4071 s7_end_of_line (str);
4072 }
4073 else
4074 s7_inst.error = s7_BAD_ARGS;
4075 }
4076}
4077
4078static void
4079s7_build_relax_frag (struct s7_score_it fix_insts[s7_RELAX_INST_NUM],
4080 int fix_num ATTRIBUTE_UNUSED,
4081 struct s7_score_it var_insts[s7_RELAX_INST_NUM], int var_num,
4082 symbolS *add_symbol)
4083{
4084 int i;
4085 char *p;
4086 fixS *fixp = NULL;
4087 fixS *cur_fixp = NULL;
4088 long where;
4089 struct s7_score_it inst_main;
4090
4091 memcpy (&inst_main, &fix_insts[0], sizeof (struct s7_score_it));
4092
4093 /* Adjust instruction opcode and to be relaxed instruction opcode. */
4094 inst_main.instruction = s7_adjust_paritybit (inst_main.instruction, s7_GET_INSN_CLASS (inst_main.type));
4095 inst_main.type = Insn_PIC;
4096
4097 for (i = 0; i < var_num; i++)
4098 {
4099 inst_main.relax_size += var_insts[i].size;
4100 var_insts[i].instruction = s7_adjust_paritybit (var_insts[i].instruction,
4101 s7_GET_INSN_CLASS (var_insts[i].type));
4102 }
4103
4104 /* Check data dependency. */
4105 s7_handle_dependency (&inst_main);
4106
4107 /* Start a new frag if frag_now is not empty. */
4108 if (frag_now_fix () != 0)
4109 {
4110 if (!frag_now->tc_frag_data.is_insn)
4111 {
4112 frag_wane (frag_now);
4113 }
4114 frag_new (0);
4115 }
4116 frag_grow (20);
4117
4118 /* Write fr_fix part. */
4119 p = frag_more (inst_main.size);
4120 s7_number_to_chars (p, inst_main.instruction, inst_main.size);
4121
4122 if (inst_main.reloc.type != BFD_RELOC_NONE)
4123 fixp = s7_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size,
4124 &inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type);
4125
4126 frag_now->tc_frag_data.fixp = fixp;
4127 cur_fixp = frag_now->tc_frag_data.fixp;
4128
4129#ifdef OBJ_ELF
4130 dwarf2_emit_insn (inst_main.size);
4131#endif
4132
4133 where = p - frag_now->fr_literal + inst_main.size;
4134 for (i = 0; i < var_num; i++)
4135 {
4136 if (i > 0)
4137 where += var_insts[i - 1].size;
4138
4139 if (var_insts[i].reloc.type != BFD_RELOC_NONE)
4140 {
4141 fixp = s7_fix_new_score (frag_now, where, var_insts[i].size,
4142 &var_insts[i].reloc.exp, var_insts[i].reloc.pc_rel,
4143 var_insts[i].reloc.type);
4144 if (fixp)
4145 {
4146 if (cur_fixp)
4147 {
4148 cur_fixp->fx_next = fixp;
4149 cur_fixp = cur_fixp->fx_next;
4150 }
4151 else
4152 {
4153 frag_now->tc_frag_data.fixp = fixp;
4154 cur_fixp = frag_now->tc_frag_data.fixp;
4155 }
4156 }
4157 }
4158 }
4159
4160 p = frag_var (rs_machine_dependent, inst_main.relax_size + s7_RELAX_PAD_BYTE, 0,
4161 s7_RELAX_ENCODE (inst_main.size, inst_main.relax_size, inst_main.type,
4162 0, inst_main.size, 0), add_symbol, 0, NULL);
4163
4164 /* Write fr_var part.
4165 no calling s7_gen_insn_frag, no fixS will be generated. */
4166 for (i = 0; i < var_num; i++)
4167 {
4168 s7_number_to_chars (p, var_insts[i].instruction, var_insts[i].size);
4169 p += var_insts[i].size;
4170 }
4171 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4172 s7_inst.bwarn = -1;
4173}
4174
4175/* Build a relax frag for la instruction when generating s7_PIC,
4176 external symbol first and local symbol second. */
4177
4178static void
4179s7_build_la_pic (int reg_rd, expressionS exp)
4180{
4181 symbolS *add_symbol = exp.X_add_symbol;
4182 offsetT add_number = exp.X_add_number;
4183 struct s7_score_it fix_insts[s7_RELAX_INST_NUM];
4184 struct s7_score_it var_insts[s7_RELAX_INST_NUM];
4185 int fix_num = 0;
4186 int var_num = 0;
4187 char tmp[s7_MAX_LITERAL_POOL_SIZE];
4188 int r1_bak;
4189
4190 r1_bak = s7_nor1;
4191 s7_nor1 = 0;
4192
4193 if (add_number == 0)
4194 {
4195 fix_num = 1;
4196 var_num = 2;
4197
4198 /* For an external symbol, only one insn is generated;
4199 For a local symbol, two insns are generated. */
4200 /* Fix part
4201 For an external symbol: lw rD, <sym>($gp)
4202 (BFD_RELOC_SCORE_GOT15 or BFD_RELOC_SCORE_CALL15) */
8d1015a8 4203 sprintf (tmp, "lw_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
5b7c81bd 4204 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4205 return;
4206
4207 if (reg_rd == s7_PIC_CALL_REG)
4208 s7_inst.reloc.type = BFD_RELOC_SCORE_CALL15;
4209 memcpy (&fix_insts[0], &s7_inst, sizeof (struct s7_score_it));
4210
4211 /* Var part
4212 For a local symbol :
4213 lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15)
4214 addi rD, <sym> (BFD_RELOC_GOT_LO16) */
4215 s7_inst.reloc.type = BFD_RELOC_SCORE_GOT15;
4216 memcpy (&var_insts[0], &s7_inst, sizeof (struct s7_score_it));
8d1015a8 4217 sprintf (tmp, "addi_s_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
5b7c81bd 4218 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4219 return;
4220
4221 memcpy (&var_insts[1], &s7_inst, sizeof (struct s7_score_it));
4222 s7_build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
4223 }
4224 else if (add_number >= -0x8000 && add_number <= 0x7fff)
4225 {
4226 /* Insn 1: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */
8d1015a8 4227 sprintf (tmp, "lw_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
5b7c81bd 4228 if (s7_append_insn (tmp, true) == (int) s7_FAIL)
c3b7224a
NC
4229 return;
4230
4231 /* Insn 2 */
4232 fix_num = 1;
4233 var_num = 1;
4234 /* Fix part
4235 For an external symbol: addi rD, <constant> */
4236 sprintf (tmp, "addi r%d, %d", reg_rd, (int) add_number);
5b7c81bd 4237 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4238 return;
4239
4240 memcpy (&fix_insts[0], &s7_inst, sizeof (struct s7_score_it));
4241
4242 /* Var part
4243 For a local symbol: addi rD, <sym>+<constant> (BFD_RELOC_GOT_LO16) */
8d1015a8
AM
4244 sprintf (tmp, "addi_s_pic r%d, %s + %d", reg_rd,
4245 S_GET_NAME (add_symbol), (int) add_number);
5b7c81bd 4246 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4247 return;
4248
4249 memcpy (&var_insts[0], &s7_inst, sizeof (struct s7_score_it));
4250 s7_build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
4251 }
4252 else
4253 {
4254 int hi = (add_number >> 16) & 0x0000FFFF;
4255 int lo = add_number & 0x0000FFFF;
4256
4257 /* Insn 1: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */
8d1015a8 4258 sprintf (tmp, "lw_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
5b7c81bd 4259 if (s7_append_insn (tmp, true) == (int) s7_FAIL)
c3b7224a
NC
4260 return;
4261
4262 /* Insn 2 */
4263 fix_num = 1;
4264 var_num = 1;
4265 /* Fix part
4266 For an external symbol: ldis r1, HI%<constant> */
4267 sprintf (tmp, "ldis r1, %d", hi);
5b7c81bd 4268 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4269 return;
4270
4271 memcpy (&fix_insts[0], &s7_inst, sizeof (struct s7_score_it));
4272
4273 /* Var part
4274 For a local symbol: ldis r1, HI%<constant>
33eaf5de 4275 but, if lo is out of 16 bit, make hi plus 1 */
c3b7224a
NC
4276 if ((lo < -0x8000) || (lo > 0x7fff))
4277 {
4278 hi += 1;
4279 }
4280 sprintf (tmp, "ldis_pic r1, %d", hi);
5b7c81bd 4281 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4282 return;
4283
4284 memcpy (&var_insts[0], &s7_inst, sizeof (struct s7_score_it));
4285 s7_build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
4286
4287 /* Insn 3 */
4288 fix_num = 1;
4289 var_num = 1;
4290 /* Fix part
4291 For an external symbol: ori r1, LO%<constant> */
4292 sprintf (tmp, "ori r1, %d", lo);
5b7c81bd 4293 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4294 return;
4295
4296 memcpy (&fix_insts[0], &s7_inst, sizeof (struct s7_score_it));
4297
4298 /* Var part
4299 For a local symbol: addi r1, <sym>+LO%<constant> (BFD_RELOC_GOT_LO16) */
8d1015a8 4300 sprintf (tmp, "addi_u_pic r1, %s + %d", S_GET_NAME (add_symbol), lo);
5b7c81bd 4301 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4302 return;
4303
4304 memcpy (&var_insts[0], &s7_inst, sizeof (struct s7_score_it));
4305 s7_build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
4306
4307 /* Insn 4: add rD, rD, r1 */
4308 sprintf (tmp, "add r%d, r%d, r1", reg_rd, reg_rd);
5b7c81bd 4309 if (s7_append_insn (tmp, true) == (int) s7_FAIL)
c3b7224a
NC
4310 return;
4311
4312 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4313 s7_inst.bwarn = -1;
4314 }
4315
4316 s7_nor1 = r1_bak;
4317}
4318
4319/* Handle la. */
4320
4321static void
4322s7_do_macro_la_rdi32 (char *str)
4323{
4324 int reg_rd;
4325
4326 s7_skip_whitespace (str);
4327 if ((reg_rd = s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE)) == (int) s7_FAIL
4328 || s7_skip_past_comma (&str) == (int) s7_FAIL)
4329 {
4330 return;
4331 }
4332 else
4333 {
4334 char append_str[s7_MAX_LITERAL_POOL_SIZE];
4335 char *keep_data = str;
4336
4337 /* Check immediate value. */
4338 if (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL)
4339 {
4340 s7_inst.error = _("expression error");
4341 return;
4342 }
4343 else if ((s7_inst.reloc.exp.X_add_symbol == NULL)
4344 && (s7_validate_immediate (s7_inst.reloc.exp.X_add_number, _IMM32, 0) == (int) s7_FAIL))
4345 {
4346 s7_inst.error = _("value not in range [0, 0xffffffff]");
4347 return;
4348 }
4349
4350 /* Reset str. */
4351 str = keep_data;
4352
4353 /* la rd, simm16. */
4354 if (s7_data_op2 (&str, 1, _SIMM16_LA) != (int) s7_FAIL)
4355 {
4356 s7_end_of_line (str);
4357 return;
4358 }
4359 /* la rd, imm32 or la rd, label. */
4360 else
4361 {
4362 s7_SET_INSN_ERROR (NULL);
4363 str = keep_data;
4364 if ((s7_data_op2 (&str, 1, _VALUE_HI16) == (int) s7_FAIL)
4365 || (s7_end_of_line (str) == (int) s7_FAIL))
4366 {
4367 return;
4368 }
4369 else
4370 {
4371 if ((s7_score_pic == s7_NO_PIC) || (!s7_inst.reloc.exp.X_add_symbol))
4372 {
4373 sprintf (append_str, "ld_i32hi r%d, %s", reg_rd, keep_data);
5b7c81bd 4374 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
4375 return;
4376
4377 sprintf (append_str, "ld_i32lo r%d, %s", reg_rd, keep_data);
5b7c81bd 4378 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
4379 return;
4380 }
4381 else
4382 {
9c2799c2 4383 gas_assert (s7_inst.reloc.exp.X_add_symbol);
c3b7224a
NC
4384 s7_build_la_pic (reg_rd, s7_inst.reloc.exp);
4385 }
4386
4387 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4388 s7_inst.bwarn = -1;
4389 }
4390 }
4391 }
4392}
4393
4394/* Handle li. */
4395
4396static void
4397s7_do_macro_li_rdi32 (char *str)
4398{
4399 int reg_rd;
4400
4401 s7_skip_whitespace (str);
4402 if ((reg_rd = s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE)) == (int) s7_FAIL
4403 || s7_skip_past_comma (&str) == (int) s7_FAIL)
4404 {
4405 return;
4406 }
4407 else
4408 {
4409 char *keep_data = str;
4410
4411 /* Check immediate value. */
4412 if (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL)
4413 {
4414 s7_inst.error = _("expression error");
4415 return;
4416 }
4417 else if (!(s7_inst.reloc.exp.X_add_number >= -0xffffffffLL
4418 && s7_inst.reloc.exp.X_add_number <= 0xffffffffLL))
4419 {
4420 s7_inst.error = _("value not in range [-0xffffffff, 0xffffffff]");
4421 return;
4422 }
4423
4424 /* Reset str. */
4425 str = keep_data;
4426
4427 /* li rd, simm16. */
4428 if (s7_data_op2 (&str, 1, _SIMM16_LA) != (int) s7_FAIL)
4429 {
4430 s7_end_of_line (str);
4431 return;
4432 }
4433 /* li rd, imm32. */
4434 else
4435 {
4436 char append_str[s7_MAX_LITERAL_POOL_SIZE];
4437
4438 str = keep_data;
4439
4440 if ((s7_data_op2 (&str, 1, _VALUE_HI16) == (int) s7_FAIL)
4441 || (s7_end_of_line (str) == (int) s7_FAIL))
4442 {
4443 return;
4444 }
4445 else if (s7_inst.reloc.exp.X_add_symbol)
4446 {
4447 s7_inst.error = _("li rd label isn't correct instruction form");
4448 return;
4449 }
4450 else
4451 {
4452 sprintf (append_str, "ld_i32hi r%d, %s", reg_rd, keep_data);
4453
5b7c81bd 4454 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
4455 return;
4456 else
4457 {
4458 sprintf (append_str, "ld_i32lo r%d, %s", reg_rd, keep_data);
5b7c81bd 4459 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
4460 return;
4461
4462 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4463 s7_inst.bwarn = -1;
4464 }
4465 }
4466 }
4467 }
4468}
4469
4470/* Handle mul/mulu/div/divu/rem/remu. */
4471
4472static void
4473s7_do_macro_mul_rdrsrs (char *str)
4474{
4475 int reg_rd;
4476 int reg_rs1;
4477 int reg_rs2;
4478 char *backupstr;
4479 char append_str[s7_MAX_LITERAL_POOL_SIZE];
4480
4481 if (s7_university_version == 1)
4482 as_warn ("%s", s7_ERR_FOR_SCORE5U_MUL_DIV);
4483
4484 strcpy (append_str, str);
4485 backupstr = append_str;
4486 s7_skip_whitespace (backupstr);
4487 if (((reg_rd = s7_reg_required_here (&backupstr, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
4488 || (s7_skip_past_comma (&backupstr) == (int) s7_FAIL)
4489 || ((reg_rs1 = s7_reg_required_here (&backupstr, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL))
4490 {
4491 s7_inst.error = s7_BAD_ARGS;
4492 return;
4493 }
4494
4495 if (s7_skip_past_comma (&backupstr) == (int) s7_FAIL)
4496 {
4497 /* rem/remu rA, rB is error format. */
4498 if (strcmp (s7_inst.name, "rem") == 0 || strcmp (s7_inst.name, "remu") == 0)
4499 {
4500 s7_SET_INSN_ERROR (s7_BAD_ARGS);
4501 }
4502 else
4503 {
4504 s7_SET_INSN_ERROR (NULL);
4505 s7_do_rsrs (str);
4506 }
4507 return;
4508 }
4509 else
4510 {
4511 s7_SET_INSN_ERROR (NULL);
4512 if (((reg_rs2 = s7_reg_required_here (&backupstr, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
4513 || (s7_end_of_line (backupstr) == (int) s7_FAIL))
4514 {
4515 return;
4516 }
4517 else
4518 {
4519 char append_str1[s7_MAX_LITERAL_POOL_SIZE];
4520
4521 if (strcmp (s7_inst.name, "rem") == 0)
4522 {
4523 sprintf (append_str, "mul r%d, r%d", reg_rs1, reg_rs2);
4524 sprintf (append_str1, "mfceh r%d", reg_rd);
4525 }
4526 else if (strcmp (s7_inst.name, "remu") == 0)
4527 {
4528 sprintf (append_str, "mulu r%d, r%d", reg_rs1, reg_rs2);
4529 sprintf (append_str1, "mfceh r%d", reg_rd);
4530 }
4531 else
4532 {
4533 sprintf (append_str, "%s r%d, r%d", s7_inst.name, reg_rs1, reg_rs2);
4534 sprintf (append_str1, "mfcel r%d", reg_rd);
4535 }
4536
4537 /* Output mul/mulu or div/divu or rem/remu. */
5b7c81bd 4538 if (s7_append_insn (append_str, true) == (int) s7_FAIL)
c3b7224a
NC
4539 return;
4540
4541 /* Output mfcel or mfceh. */
5b7c81bd 4542 if (s7_append_insn (append_str1, true) == (int) s7_FAIL)
c3b7224a
NC
4543 return;
4544
4545 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4546 s7_inst.bwarn = -1;
4547 }
4548 }
4549}
4550
4551static void
4552s7_exp_macro_ldst_abs (char *str)
4553{
4554 int reg_rd;
4555 char *backupstr, *tmp;
4556 char append_str[s7_MAX_LITERAL_POOL_SIZE];
4557 char verifystr[s7_MAX_LITERAL_POOL_SIZE];
4558 struct s7_score_it inst_backup;
4559 int r1_bak = 0;
4560
4561 r1_bak = s7_nor1;
4562 s7_nor1 = 0;
4563 memcpy (&inst_backup, &s7_inst, sizeof (struct s7_score_it));
4564
4565 strcpy (verifystr, str);
4566 backupstr = verifystr;
4567 s7_skip_whitespace (backupstr);
4568 if ((reg_rd = s7_reg_required_here (&backupstr, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
4569 return;
4570
4571 tmp = backupstr;
4572 if (s7_skip_past_comma (&backupstr) == (int) s7_FAIL)
4573 return;
4574
4575 backupstr = tmp;
4576 sprintf (append_str, "li r1 %s", backupstr);
5b7c81bd 4577 s7_append_insn (append_str, true);
c3b7224a
NC
4578
4579 memcpy (&s7_inst, &inst_backup, sizeof (struct s7_score_it));
4580 sprintf (append_str, " r%d, [r1,0]", reg_rd);
4581 s7_do_ldst_insn (append_str);
4582
4583 s7_nor1 = r1_bak;
4584}
4585
4586static int
4587s7_nopic_need_relax (symbolS * sym, int before_relaxing)
4588{
4589 if (sym == NULL)
4590 return 0;
4591 else if (s7_USE_GLOBAL_POINTER_OPT && s7_g_switch_value > 0)
4592 {
4593 const char *symname;
4594 const char *segname;
4595
4596 /* Find out whether this symbol can be referenced off the $gp
4597 register. It can be if it is smaller than the -G size or if
4598 it is in the .sdata or .sbss section. Certain symbols can
4599 not be referenced off the $gp, although it appears as though
4600 they can. */
4601 symname = S_GET_NAME (sym);
4602 if (symname != NULL
4603 && (strcmp (symname, "eprol") == 0
4604 || strcmp (symname, "etext") == 0
4605 || strcmp (symname, "_gp") == 0
4606 || strcmp (symname, "edata") == 0
4607 || strcmp (symname, "_fbss") == 0
4608 || strcmp (symname, "_fdata") == 0
4609 || strcmp (symname, "_ftext") == 0
4610 || strcmp (symname, "end") == 0
4611 || strcmp (symname, GP_DISP_LABEL) == 0))
4612 {
4613 return 1;
4614 }
4615 else if ((!S_IS_DEFINED (sym) || S_IS_COMMON (sym)) && (0
4616 /* We must defer this decision until after the whole file has been read,
4617 since there might be a .extern after the first use of this symbol. */
4618 || (before_relaxing
4619 && S_GET_VALUE (sym) == 0)
4620 || (S_GET_VALUE (sym) != 0
4621 && S_GET_VALUE (sym) <= s7_g_switch_value)))
4622 {
4623 return 0;
4624 }
4625
4626 segname = segment_name (S_GET_SEGMENT (sym));
4627 return (strcmp (segname, ".sdata") != 0
4628 && strcmp (segname, ".sbss") != 0
d34049e8
ML
4629 && !startswith (segname, ".sdata.")
4630 && !startswith (segname, ".gnu.linkonce.s."));
c3b7224a
NC
4631 }
4632 /* We are not optimizing for the $gp register. */
4633 else
4634 return 1;
4635}
4636
4637/* Build a relax frag for lw/st instruction when generating s7_PIC,
4638 external symbol first and local symbol second. */
4639
4640static void
4641s7_build_lwst_pic (int reg_rd, expressionS exp, const char *insn_name)
4642{
4643 symbolS *add_symbol = exp.X_add_symbol;
4644 int add_number = exp.X_add_number;
4645 struct s7_score_it fix_insts[s7_RELAX_INST_NUM];
4646 struct s7_score_it var_insts[s7_RELAX_INST_NUM];
4647 int fix_num = 0;
4648 int var_num = 0;
4649 char tmp[s7_MAX_LITERAL_POOL_SIZE];
4650 int r1_bak;
4651
4652 r1_bak = s7_nor1;
4653 s7_nor1 = 0;
4654
4655 if ((add_number == 0) || (add_number >= -0x8000 && add_number <= 0x7fff))
4656 {
4657 fix_num = 1;
4658 var_num = 2;
4659
4660 /* For an external symbol, two insns are generated;
4661 For a local symbol, three insns are generated. */
4662 /* Fix part
4663 For an external symbol: lw rD, <sym>($gp)
4664 (BFD_RELOC_SCORE_GOT15) */
8d1015a8 4665 sprintf (tmp, "lw_pic r1, %s", S_GET_NAME (add_symbol));
5b7c81bd 4666 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4667 return;
4668
4669 memcpy (&fix_insts[0], &s7_inst, sizeof (struct s7_score_it));
4670
4671 /* Var part
4672 For a local symbol :
4673 lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15)
4674 addi rD, <sym> (BFD_RELOC_GOT_LO16) */
4675 s7_inst.reloc.type = BFD_RELOC_SCORE_GOT15;
4676 memcpy (&var_insts[0], &s7_inst, sizeof (struct s7_score_it));
8d1015a8 4677 sprintf (tmp, "addi_s_pic r1, %s", S_GET_NAME (add_symbol));
5b7c81bd 4678 if (s7_append_insn (tmp, false) == (int) s7_FAIL)
c3b7224a
NC
4679 return;
4680
4681 memcpy (&var_insts[1], &s7_inst, sizeof (struct s7_score_it));
4682 s7_build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
4683
4684 /* Insn 2 or Insn 3: lw/st rD, [r1, constant] */
4685 sprintf (tmp, "%s r%d, [r1, %d]", insn_name, reg_rd, add_number);
5b7c81bd 4686 if (s7_append_insn (tmp, true) == (int) s7_FAIL)
c3b7224a
NC
4687 return;
4688
4689 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4690 s7_inst.bwarn = -1;
4691 }
4692 else
4693 {
4694 s7_inst.error = _("PIC code offset overflow (max 16 signed bits)");
4695 return;
4696 }
4697
4698 s7_nor1 = r1_bak;
4699}
4700
4701static void
4702s7_do_macro_ldst_label (char *str)
4703{
4704 int i;
4705 int ldst_gp_p = 0;
4706 int reg_rd;
4707 int r1_bak;
4708 char *backup_str;
4709 char *label_str;
4710 char *absolute_value;
4711 char append_str[3][s7_MAX_LITERAL_POOL_SIZE];
4712 char verifystr[s7_MAX_LITERAL_POOL_SIZE];
4713 struct s7_score_it inst_backup;
4714 struct s7_score_it inst_expand[3];
4715 struct s7_score_it inst_main;
4716
4717 memcpy (&inst_backup, &s7_inst, sizeof (struct s7_score_it));
4718 strcpy (verifystr, str);
4719 backup_str = verifystr;
4720
4721 s7_skip_whitespace (backup_str);
4722 if ((reg_rd = s7_reg_required_here (&backup_str, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
4723 return;
4724
4725 if (s7_skip_past_comma (&backup_str) == (int) s7_FAIL)
4726 return;
4727
4728 label_str = backup_str;
4729
4730 /* Ld/st rD, [rA, imm] ld/st rD, [rA]+, imm ld/st rD, [rA, imm]+. */
4731 if (*backup_str == '[')
4732 {
4733 s7_inst.type = Rd_rvalueRs_preSI12;
4734 s7_do_ldst_insn (str);
4735 return;
4736 }
4737
4738 /* Ld/st rD, imm. */
4739 absolute_value = backup_str;
4740 s7_inst.type = Rd_rvalueRs_SI15;
4741
4742 if (s7_my_get_expression (&s7_inst.reloc.exp, &backup_str) == (int) s7_FAIL)
4743 {
4744 s7_inst.error = _("expression error");
4745 return;
4746 }
4747 else if ((s7_inst.reloc.exp.X_add_symbol == NULL)
4748 && (s7_validate_immediate (s7_inst.reloc.exp.X_add_number, _VALUE, 0) == (int) s7_FAIL))
4749 {
4750 s7_inst.error = _("value not in range [0, 0x7fffffff]");
4751 return;
4752 }
4753 else if (s7_end_of_line (backup_str) == (int) s7_FAIL)
4754 {
4755 s7_inst.error = _("end on line error");
4756 return;
4757 }
4758 else
4759 {
4760 if (s7_inst.reloc.exp.X_add_symbol == 0)
4761 {
4762 memcpy (&s7_inst, &inst_backup, sizeof (struct s7_score_it));
4763 s7_exp_macro_ldst_abs (str);
4764 return;
4765 }
4766 }
4767
4768 /* Ld/st rD, label. */
4769 s7_inst.type = Rd_rvalueRs_SI15;
4770 backup_str = absolute_value;
4771 if ((s7_data_op2 (&backup_str, 1, _GP_IMM15) == (int) s7_FAIL)
4772 || (s7_end_of_line (backup_str) == (int) s7_FAIL))
4773 {
4774 return;
4775 }
4776 else
4777 {
4778 if (s7_inst.reloc.exp.X_add_symbol == 0)
4779 {
4780 if (!s7_inst.error)
4781 s7_inst.error = s7_BAD_ARGS;
4782
4783 return;
4784 }
4785
4786 if (s7_score_pic == s7_PIC)
4787 {
4788 int ldst_idx = 0;
4789 ldst_idx = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
d3ce72d0
NC
4790 s7_build_lwst_pic (reg_rd, s7_inst.reloc.exp,
4791 s7_score_ldst_insns[ldst_idx * 3 + 0].template_name);
c3b7224a
NC
4792 return;
4793 }
4794 else
4795 {
4796 if ((s7_inst.reloc.exp.X_add_number <= 0x3fff)
4797 && (s7_inst.reloc.exp.X_add_number >= -0x4000)
4798 && (!s7_nopic_need_relax (s7_inst.reloc.exp.X_add_symbol, 1)))
4799 {
4800 int ldst_idx = 0;
4801
4802 /* Assign the real opcode. */
4803 ldst_idx = s7_inst.instruction & OPC_PSEUDOLDST_MASK;
4804 s7_inst.instruction &= ~OPC_PSEUDOLDST_MASK;
4805 s7_inst.instruction |= s7_score_ldst_insns[ldst_idx * 3 + 0].value;
4806 s7_inst.instruction |= reg_rd << 20;
4807 s7_inst.instruction |= s7_GP << 15;
4808 s7_inst.relax_inst = 0x8000;
4809 s7_inst.relax_size = 0;
4810 ldst_gp_p = 1;
4811 }
4812 }
4813 }
4814
4815 /* Backup s7_inst. */
4816 memcpy (&inst_main, &s7_inst, sizeof (struct s7_score_it));
4817 r1_bak = s7_nor1;
4818 s7_nor1 = 0;
4819
4820 /* Determine which instructions should be output. */
4821 sprintf (append_str[0], "ld_i32hi r1, %s", label_str);
4822 sprintf (append_str[1], "ld_i32lo r1, %s", label_str);
4823 sprintf (append_str[2], "%s r%d, [r1, 0]", inst_backup.name, reg_rd);
4824
4825 /* Generate three instructions.
4826 la r1, label
4827 ld/st rd, [r1, 0] */
4828 for (i = 0; i < 3; i++)
4829 {
5b7c81bd 4830 if (s7_append_insn (append_str[i], false) == (int) s7_FAIL)
c3b7224a
NC
4831 return;
4832
4833 memcpy (&inst_expand[i], &s7_inst, sizeof (struct s7_score_it));
4834 }
4835
4836 if (ldst_gp_p)
4837 {
4838 char *p;
4839
4840 /* Adjust instruction opcode and to be relaxed instruction opcode. */
4841 inst_main.instruction = s7_adjust_paritybit (inst_main.instruction, s7_GET_INSN_CLASS (inst_main.type));
4842 inst_main.relax_size = inst_expand[0].size + inst_expand[1].size + inst_expand[2].size;
4843 inst_main.type = Insn_GP;
4844
4845 for (i = 0; i < 3; i++)
4846 inst_expand[i].instruction = s7_adjust_paritybit (inst_expand[i].instruction
4847 , s7_GET_INSN_CLASS (inst_expand[i].type));
4848
4849 /* Check data dependency. */
4850 s7_handle_dependency (&inst_main);
4851
4852 /* Start a new frag if frag_now is not empty. */
4853 if (frag_now_fix () != 0)
4854 {
4855 if (!frag_now->tc_frag_data.is_insn)
4856 frag_wane (frag_now);
4857
4858 frag_new (0);
4859 }
4860 frag_grow (20);
4861
4862 /* Write fr_fix part. */
4863 p = frag_more (inst_main.size);
4864 s7_number_to_chars (p, inst_main.instruction, inst_main.size);
4865
4866 if (inst_main.reloc.type != BFD_RELOC_NONE)
4867 {
4868 s7_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size,
4869 &inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type);
4870 }
4871
4872#ifdef OBJ_ELF
4873 dwarf2_emit_insn (inst_main.size);
4874#endif
4875
4876 /* s7_GP instruction can not do optimization, only can do relax between
4877 1 instruction and 3 instructions. */
4878 p = frag_var (rs_machine_dependent, inst_main.relax_size + s7_RELAX_PAD_BYTE, 0,
4879 s7_RELAX_ENCODE (inst_main.size, inst_main.relax_size, inst_main.type, 0, 4, 0),
4880 inst_main.reloc.exp.X_add_symbol, 0, NULL);
4881
4882 /* Write fr_var part.
4883 no calling s7_gen_insn_frag, no fixS will be generated. */
4884 s7_number_to_chars (p, inst_expand[0].instruction, inst_expand[0].size);
4885 p += inst_expand[0].size;
4886 s7_number_to_chars (p, inst_expand[1].instruction, inst_expand[1].size);
4887 p += inst_expand[1].size;
4888 s7_number_to_chars (p, inst_expand[2].instruction, inst_expand[2].size);
4889 }
4890 else
4891 {
4892 s7_gen_insn_frag (&inst_expand[0], NULL);
4893 s7_gen_insn_frag (&inst_expand[1], NULL);
4894 s7_gen_insn_frag (&inst_expand[2], NULL);
4895 }
4896 s7_nor1 = r1_bak;
4897
4898 /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
4899 s7_inst.bwarn = -1;
4900}
4901
4902static void
4903s7_do_lw_pic (char *str)
4904{
4905 int reg_rd;
4906
4907 s7_skip_whitespace (str);
4908 if (((reg_rd = s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
4909 || (s7_skip_past_comma (&str) == (int) s7_FAIL)
4910 || (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL)
4911 || (s7_end_of_line (str) == (int) s7_FAIL))
4912 {
4913 return;
4914 }
4915 else
4916 {
4917 if (s7_inst.reloc.exp.X_add_symbol == 0)
4918 {
4919 if (!s7_inst.error)
4920 s7_inst.error = s7_BAD_ARGS;
4921
4922 return;
4923 }
4924
4925 s7_inst.instruction |= s7_GP << 15;
4926 s7_inst.reloc.type = BFD_RELOC_SCORE_GOT15;
4927 }
4928}
4929
4930static void
4931s7_do_empty (char *str)
4932{
4933 str = str;
4934 if (s7_university_version == 1)
4935 {
4936 if (((s7_inst.instruction & 0x3e0003ff) == 0x0c000004)
4937 || ((s7_inst.instruction & 0x3e0003ff) == 0x0c000024)
4938 || ((s7_inst.instruction & 0x3e0003ff) == 0x0c000044)
4939 || ((s7_inst.instruction & 0x3e0003ff) == 0x0c000064))
4940 {
4941 s7_inst.error = s7_ERR_FOR_SCORE5U_MMU;
4942 return;
4943 }
4944 }
4945 if (s7_end_of_line (str) == (int) s7_FAIL)
4946 return;
4947
4948 if (s7_inst.relax_inst != 0x8000)
4949 {
4950 if (s7_inst.type == NO_OPD)
4951 {
4952 s7_inst.relax_size = 2;
4953 }
4954 else
4955 {
4956 s7_inst.relax_size = 4;
4957 }
4958 }
4959}
4960
4961static void
4962s7_do_jump (char *str)
4963{
4964 char *save_in;
4965
4966 s7_skip_whitespace (str);
4967 if (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL
4968 || s7_end_of_line (str) == (int) s7_FAIL)
4969 return;
4970
4971 if (s7_inst.reloc.exp.X_add_symbol == 0)
4972 {
4973 s7_inst.error = _("lacking label ");
4974 return;
4975 }
4976
4977 if (!(s7_inst.reloc.exp.X_add_number >= -16777216
4978 && s7_inst.reloc.exp.X_add_number <= 16777215))
4979 {
4980 s7_inst.error = _("invalid constant: 25 bit expression not in range [-16777216, 16777215]");
4981 return;
4982 }
4983
4984 save_in = input_line_pointer;
4985 input_line_pointer = str;
4986 s7_inst.reloc.type = BFD_RELOC_SCORE_JMP;
4987 s7_inst.reloc.pc_rel = 1;
4988 input_line_pointer = save_in;
4989}
4990
4991static void
4992s7_do16_jump (char *str)
4993{
4994 s7_skip_whitespace (str);
4995 if (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL
4996 || s7_end_of_line (str) == (int) s7_FAIL)
4997 {
4998 return;
4999 }
5000 else if (s7_inst.reloc.exp.X_add_symbol == 0)
5001 {
5002 s7_inst.error = _("lacking label ");
5003 return;
5004 }
5005 else if (!(s7_inst.reloc.exp.X_add_number >= 0
5006 && s7_inst.reloc.exp.X_add_number <= 4095))
5007 {
5008 s7_inst.error = _("invalid constant: 12 bit expression not in range [0, 4095]");
5009 return;
5010 }
5011
5012 s7_inst.reloc.type = BFD_RELOC_SCORE16_JMP;
5013 s7_inst.reloc.pc_rel = 1;
5014}
5015
5016static void
5017s7_do_branch (char *str)
5018{
5019 unsigned long abs_value = 0;
5020
5021 if (s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL
5022 || s7_end_of_line (str) == (int) s7_FAIL)
5023 {
5024 return;
5025 }
5026 else if (s7_inst.reloc.exp.X_add_symbol == 0)
5027 {
5028 s7_inst.error = _("lacking label ");
5029 return;
5030 }
5031 else if (!(s7_inst.reloc.exp.X_add_number >= -524288
5032 && s7_inst.reloc.exp.X_add_number <= 524287))
5033 {
5034 s7_inst.error = _("invalid constant: 20 bit expression not in range -2^19..2^19");
5035 return;
5036 }
5037
5038 s7_inst.reloc.type = BFD_RELOC_SCORE_BRANCH;
5039 s7_inst.reloc.pc_rel = 1;
5040
5041 /* Branch 32 offset field : 20 bit, 16 bit branch offset field : 8 bit. */
5042 s7_inst.instruction |= (s7_inst.reloc.exp.X_add_number & 0x3fe) | ((s7_inst.reloc.exp.X_add_number & 0xffc00) << 5);
5043
5044 /* Compute 16 bit branch instruction. */
5045 if ((s7_inst.relax_inst != 0x8000) && (abs_value & 0xfffffe00) == 0)
5046 {
5047 s7_inst.relax_inst |= (((s7_inst.instruction >> 10) & 0xf) << 8);
5048 s7_inst.relax_inst |= ((s7_inst.reloc.exp.X_add_number >> 1) & 0xff);
5049 s7_inst.relax_size = 2;
5050 }
5051 else
5052 {
5053 s7_inst.relax_inst = 0x8000;
5054 }
5055}
5056
5057static void
5058s7_do16_branch (char *str)
5059{
5060 if ((s7_my_get_expression (&s7_inst.reloc.exp, &str) == (int) s7_FAIL
5061 || s7_end_of_line (str) == (int) s7_FAIL))
5062 {
5063 ;
5064 }
5065 else if (s7_inst.reloc.exp.X_add_symbol == 0)
5066 {
5067 s7_inst.error = _("lacking label");
5068 }
5069 else if (!(s7_inst.reloc.exp.X_add_number >= -512
5070 && s7_inst.reloc.exp.X_add_number <= 511))
5071 {
5072 s7_inst.error = _("invalid constant: 10 bit expression not in range [-2^9, 2^9-1]");
5073 }
5074 else
5075 {
5076 s7_inst.reloc.type = BFD_RELOC_SCORE16_BRANCH;
5077 s7_inst.reloc.pc_rel = 1;
5078 s7_inst.instruction |= ((s7_inst.reloc.exp.X_add_number >> 1) & 0xff);
5079 }
5080}
5081
5082/* Iterate over the base tables to create the instruction patterns. */
5083
5084static void
5085s7_build_score_ops_hsh (void)
5086{
5087 unsigned int i;
c3b7224a 5088
c3b7224a
NC
5089 for (i = 0; i < sizeof (s7_score_insns) / sizeof (struct s7_asm_opcode); i++)
5090 {
5091 const struct s7_asm_opcode *insn = s7_score_insns + i;
7bfc4db2 5092 size_t len = strlen (insn->template_name) + 1;
d3ce72d0
NC
5093 struct s7_asm_opcode *new_opcode;
5094 char *template_name;
d3ce72d0 5095
7bfc4db2
AM
5096 new_opcode = notes_alloc (sizeof (*new_opcode));
5097 template_name = notes_memdup (insn->template_name, len, len);
5098
d3ce72d0
NC
5099 new_opcode->template_name = template_name;
5100 new_opcode->parms = insn->parms;
5101 new_opcode->value = insn->value;
5102 new_opcode->relax_value = insn->relax_value;
5103 new_opcode->type = insn->type;
5104 new_opcode->bitmask = insn->bitmask;
629310ab 5105 str_hash_insert (s7_score_ops_hsh, new_opcode->template_name,
fe0e921f 5106 new_opcode, 0);
c3b7224a
NC
5107 }
5108}
5109
5110static void
5111s7_build_dependency_insn_hsh (void)
5112{
5113 unsigned int i;
c3b7224a 5114
c3b7224a
NC
5115 for (i = 0; i < ARRAY_SIZE (s7_insn_to_dependency_table); i++)
5116 {
5117 const struct s7_insn_to_dependency *tmp = s7_insn_to_dependency_table + i;
7bfc4db2 5118 size_t len = strlen (tmp->insn_name) + 1;
d3ce72d0 5119 struct s7_insn_to_dependency *new_i2d;
b9bb4a93 5120 char *insn_name;
c3b7224a 5121
7bfc4db2
AM
5122 new_i2d = notes_alloc (sizeof (*new_i2d));
5123 insn_name = notes_memdup (tmp->insn_name, len, len);
c3b7224a 5124
b9bb4a93 5125 new_i2d->insn_name = insn_name;
d3ce72d0 5126 new_i2d->type = tmp->type;
fe0e921f 5127 str_hash_insert (s7_dependency_insn_hsh, new_i2d->insn_name, new_i2d, 0);
c3b7224a
NC
5128 }
5129}
5130
5131static valueT
5132s7_md_chars_to_number (char *buf, int n)
5133{
5134 valueT result = 0;
5135 unsigned char *where = (unsigned char *) buf;
5136
5137 if (target_big_endian)
5138 {
5139 while (n--)
5140 {
5141 result <<= 8;
5142 result |= (*where++ & 255);
5143 }
5144 }
5145 else
5146 {
5147 while (n--)
5148 {
5149 result <<= 8;
5150 result |= (where[n] & 255);
5151 }
5152 }
5153
5154 return result;
5155}
5156
5157/* Return true if the given symbol should be considered local for s7_PIC. */
5158
5b7c81bd 5159static bool
c3b7224a
NC
5160s7_pic_need_relax (symbolS *sym, asection *segtype)
5161{
5162 asection *symsec;
5b7c81bd 5163 bool linkonce;
c3b7224a
NC
5164
5165 /* Handle the case of a symbol equated to another symbol. */
5166 while (symbol_equated_reloc_p (sym))
5167 {
5168 symbolS *n;
5169
5170 /* It's possible to get a loop here in a badly written
5171 program. */
5172 n = symbol_get_value_expression (sym)->X_add_symbol;
5173 if (n == sym)
5174 break;
5175 sym = n;
5176 }
5177
5178 symsec = S_GET_SEGMENT (sym);
5179
5180 /* Duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
5b7c81bd 5181 linkonce = false;
c3b7224a
NC
5182 if (symsec != segtype && ! S_IS_LOCAL (sym))
5183 {
fd361982 5184 if ((bfd_section_flags (symsec) & SEC_LINK_ONCE) != 0)
5b7c81bd 5185 linkonce = true;
c3b7224a
NC
5186
5187 /* The GNU toolchain uses an extension for ELF: a section
5188 beginning with the magic string .gnu.linkonce is a linkonce
5189 section. */
d34049e8 5190 if (startswith (segment_name (symsec), ".gnu.linkonce"))
5b7c81bd 5191 linkonce = true;
c3b7224a
NC
5192 }
5193
5194 /* This must duplicate the test in adjust_reloc_syms. */
45dfa85a
AM
5195 return (!bfd_is_und_section (symsec)
5196 && !bfd_is_abs_section (symsec)
5197 && !bfd_is_com_section (symsec)
5198 && !linkonce
c3b7224a
NC
5199#ifdef OBJ_ELF
5200 /* A global or weak symbol is treated as external. */
5201 && (OUTPUT_FLAVOR != bfd_target_elf_flavour
5202 || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
5203#endif
5204 );
5205}
5206
5207static int
5208s7_judge_size_before_relax (fragS * fragp, asection *sec)
5209{
5210 int change = 0;
5211
5212 if (s7_score_pic == s7_NO_PIC)
5213 change = s7_nopic_need_relax (fragp->fr_symbol, 0);
5214 else
5215 change = s7_pic_need_relax (fragp->fr_symbol, sec);
5216
5217 if (change == 1)
5218 {
5219 /* Only at the first time determining whether s7_GP instruction relax should be done,
33eaf5de 5220 return the difference between instruction size and instruction relax size. */
c3b7224a
NC
5221 if (fragp->fr_opcode == NULL)
5222 {
5223 fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype);
5224 fragp->fr_opcode = fragp->fr_literal + s7_RELAX_RELOC1 (fragp->fr_subtype);
5225 return s7_RELAX_NEW (fragp->fr_subtype) - s7_RELAX_OLD (fragp->fr_subtype);
5226 }
5227 }
5228
5229 return 0;
5230}
5231
5232static int
5233s7_b32_relax_to_b16 (fragS * fragp)
5234{
5235 int grows = 0;
5236 int relaxable_p = 0;
c3b7224a
NC
5237 int frag_addr = fragp->fr_address + fragp->insn_addr;
5238
5239 addressT symbol_address = 0;
5240 symbolS *s;
5241 offsetT offset;
5242 unsigned long value;
5243 unsigned long abs_value;
5244
5245 /* FIXME : here may be able to modify better .
5246 I don't know how to get the fragp's section ,
5247 so in relax stage , it may be wrong to calculate the symbol's offset when the frag's section
5248 is different from the symbol's. */
5249
c3b7224a
NC
5250 relaxable_p = s7_RELAX_OPT (fragp->fr_subtype);
5251
5252 s = fragp->fr_symbol;
5253 /* b/bl immediate */
5254 if (s == NULL)
5255 frag_addr = 0;
5256 else
8d1015a8 5257 symbol_address = (addressT) symbol_get_frag (s)->fr_address;
c3b7224a
NC
5258
5259 value = s7_md_chars_to_number (fragp->fr_literal, s7_INSN_SIZE);
5260
5261 /* b 32's offset : 20 bit, b 16's tolerate field : 0xff. */
5262 offset = ((value & 0x3ff0000) >> 6) | (value & 0x3fe);
5263 if ((offset & 0x80000) == 0x80000)
5264 offset |= 0xfff00000;
5265
5266 abs_value = offset + symbol_address - frag_addr;
5267 if ((abs_value & 0x80000000) == 0x80000000)
5268 abs_value = 0xffffffff - abs_value + 1;
5269
5270 /* Relax branch 32 to branch 16. */
8d1015a8 5271 if (relaxable_p && ((abs_value & 0xffffff00) == 0)
c3b7224a
NC
5272 && (S_IS_DEFINED (s) && !S_IS_COMMON (s) && !S_IS_EXTERNAL (s)))
5273 {
5274 /* do nothing. */
5275 }
5276 else
5277 {
5278 /* Branch 32 can not be relaxed to b 16, so clear OPT bit. */
5279 fragp->fr_opcode = NULL;
5280 fragp->fr_subtype = s7_RELAX_OPT_CLEAR (fragp->fr_subtype);
5281 }
5282
5283 return grows;
5284}
5285
5286static void
5287s7_parse_pce_inst (char *insnstr)
5288{
5289 char c;
5290 char *p;
5291 char *q;
5292 char first[s7_MAX_LITERAL_POOL_SIZE];
5293 char second[s7_MAX_LITERAL_POOL_SIZE];
5294 struct s7_score_it pec_part_1;
5295
5296 /* Get first part string of PCE. */
5297 p = strstr (insnstr, "||");
5298 c = *p;
5299 *p = '\0';
2132b407 5300 strcpy (first, insnstr);
c3b7224a
NC
5301
5302 /* Get second part string of PCE. */
5303 *p = c;
5304 p += 2;
2132b407 5305 strcpy (second, p);
c3b7224a 5306
5b7c81bd 5307 s7_parse_16_32_inst (first, false);
c3b7224a
NC
5308 if (s7_inst.error)
5309 return;
5310
5311 memcpy (&pec_part_1, &s7_inst, sizeof (s7_inst));
5312
5313 q = second;
5314 while (q && *q)
5315 {
5316 *q = TOLOWER (*q);
5317 q++;
5318 }
5319
5b7c81bd 5320 s7_parse_16_32_inst (second, false);
c3b7224a
NC
5321 if (s7_inst.error)
5322 return;
5323
5324 if ( ((pec_part_1.size == s7_INSN_SIZE) && (s7_inst.size == s7_INSN_SIZE))
5325 || ((pec_part_1.size == s7_INSN_SIZE) && (s7_inst.size == s7_INSN16_SIZE))
5326 || ((pec_part_1.size == s7_INSN16_SIZE) && (s7_inst.size == s7_INSN_SIZE)))
5327 {
5328 s7_inst.error = _("pce instruction error (16 bit || 16 bit)'");
2132b407 5329 strcpy (s7_inst.str, insnstr);
c3b7224a
NC
5330 return;
5331 }
5332
5333 if (!s7_inst.error)
5334 s7_gen_insn_frag (&pec_part_1, &s7_inst);
5335}
5336
5337\f
5338
5339static void
629310ab 5340s7_insert_reg (const struct s7_reg_entry *r, htab_t htab)
c3b7224a
NC
5341{
5342 int i = 0;
5343 int len = strlen (r->name) + 2;
325801bd
TS
5344 char *buf = XNEWVEC (char, len);
5345 char *buf2 = XNEWVEC (char, len);
c3b7224a
NC
5346
5347 strcpy (buf + i, r->name);
5348 for (i = 0; buf[i]; i++)
5349 {
5350 buf2[i] = TOUPPER (buf[i]);
5351 }
5352 buf2[i] = '\0';
5353
fe0e921f
AM
5354 str_hash_insert (htab, buf, r, 0);
5355 str_hash_insert (htab, buf2, r, 0);
c3b7224a
NC
5356}
5357
5358static void
5359s7_build_reg_hsh (struct s7_reg_map *map)
5360{
5361 const struct s7_reg_entry *r;
5362
f16c3d4f 5363 map->htab = str_htab_create ();
c3b7224a 5364 for (r = map->names; r->name != NULL; r++)
f16c3d4f 5365 s7_insert_reg (r, map->htab);
c3b7224a
NC
5366}
5367
5368\f
5369
c3b7224a
NC
5370static void
5371s7_s_section (int ignore)
5372{
5373 obj_elf_section (ignore);
fd361982 5374 if ((bfd_section_flags (now_seg) & SEC_CODE) != 0)
c3b7224a
NC
5375 record_alignment (now_seg, 2);
5376
5377}
5378
5379static void
5380s7_s_change_sec (int sec)
5381{
5382 segT seg;
5383
5384#ifdef OBJ_ELF
5385 /* The ELF backend needs to know that we are changing sections, so
5386 that .previous works correctly. We could do something like check
5387 for an obj_section_change_hook macro, but that might be confusing
5388 as it would not be appropriate to use it in the section changing
5389 functions in read.c, since obj-elf.c intercepts those. FIXME:
5390 This should be cleaner, somehow. */
5391 obj_elf_section_change_hook ();
5392#endif
5393 switch (sec)
5394 {
5395 case 'r':
5396 seg = subseg_new (s7_RDATA_SECTION_NAME, (subsegT) get_absolute_expression ());
a4dd6c97
AM
5397 bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_READONLY
5398 | SEC_RELOC | SEC_DATA));
c3b7224a
NC
5399 if (strcmp (TARGET_OS, "elf") != 0)
5400 record_alignment (seg, 4);
5401 demand_empty_rest_of_line ();
5402 break;
5403 case 's':
5404 seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
a4dd6c97
AM
5405 bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_RELOC
5406 | SEC_DATA | SEC_SMALL_DATA));
c3b7224a
NC
5407 if (strcmp (TARGET_OS, "elf") != 0)
5408 record_alignment (seg, 4);
5409 demand_empty_rest_of_line ();
5410 break;
5411 }
5412}
5413
5414static void
5415s7_s_score_mask (int reg_type ATTRIBUTE_UNUSED)
5416{
5417 long mask, off;
5418
5419 if (s7_cur_proc_ptr == NULL)
5420 {
5421 as_warn (_(".mask outside of .ent"));
5422 demand_empty_rest_of_line ();
5423 return;
5424 }
5425 if (get_absolute_expression_and_terminator (&mask) != ',')
5426 {
5427 as_warn (_("Bad .mask directive"));
5428 --input_line_pointer;
5429 demand_empty_rest_of_line ();
5430 return;
5431 }
5432 off = get_absolute_expression ();
5433 s7_cur_proc_ptr->reg_mask = mask;
5434 s7_cur_proc_ptr->reg_offset = off;
5435 demand_empty_rest_of_line ();
5436}
5437
5438static symbolS *
5439s7_get_symbol (void)
5440{
5441 int c;
5442 char *name;
5443 symbolS *p;
5444
d02603dc 5445 c = get_symbol_name (&name);
c3b7224a 5446 p = (symbolS *) symbol_find_or_make (name);
d02603dc 5447 (void) restore_line_pointer (c);
c3b7224a
NC
5448 return p;
5449}
5450
5451static long
5452s7_get_number (void)
5453{
5454 int negative = 0;
5455 long val = 0;
5456
5457 if (*input_line_pointer == '-')
5458 {
5459 ++input_line_pointer;
5460 negative = 1;
5461 }
5462 if (!ISDIGIT (*input_line_pointer))
5463 as_bad (_("expected simple number"));
5464 if (input_line_pointer[0] == '0')
5465 {
5466 if (input_line_pointer[1] == 'x')
5467 {
5468 input_line_pointer += 2;
5469 while (ISXDIGIT (*input_line_pointer))
5470 {
5471 val <<= 4;
5472 val |= hex_value (*input_line_pointer++);
5473 }
5474 return negative ? -val : val;
5475 }
5476 else
5477 {
5478 ++input_line_pointer;
5479 while (ISDIGIT (*input_line_pointer))
5480 {
5481 val <<= 3;
5482 val |= *input_line_pointer++ - '0';
5483 }
5484 return negative ? -val : val;
5485 }
5486 }
5487 if (!ISDIGIT (*input_line_pointer))
5488 {
5489 printf (_(" *input_line_pointer == '%c' 0x%02x\n"), *input_line_pointer, *input_line_pointer);
5490 as_warn (_("invalid number"));
5491 return -1;
5492 }
5493 while (ISDIGIT (*input_line_pointer))
5494 {
5495 val *= 10;
5496 val += *input_line_pointer++ - '0';
5497 }
5498 return negative ? -val : val;
5499}
5500
5501/* The .aent and .ent directives. */
5502
5503static void
5504s7_s_score_ent (int aent)
5505{
5506 symbolS *symbolP;
5507 int maybe_text;
5508
5509 symbolP = s7_get_symbol ();
5510 if (*input_line_pointer == ',')
5511 ++input_line_pointer;
5512 SKIP_WHITESPACE ();
5513 if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
5514 s7_get_number ();
5515
fd361982 5516 if ((bfd_section_flags (now_seg) & SEC_CODE) != 0)
c3b7224a
NC
5517 maybe_text = 1;
5518 else
5519 maybe_text = 0;
c3b7224a
NC
5520 if (!maybe_text)
5521 as_warn (_(".ent or .aent not in text section."));
5522 if (!aent && s7_cur_proc_ptr)
5523 as_warn (_("missing .end"));
5524 if (!aent)
5525 {
5526 s7_cur_proc_ptr = &s7_cur_proc;
5527 s7_cur_proc_ptr->reg_mask = 0xdeadbeaf;
5528 s7_cur_proc_ptr->reg_offset = 0xdeadbeaf;
5529 s7_cur_proc_ptr->fpreg_mask = 0xdeafbeaf;
5530 s7_cur_proc_ptr->leaf = 0xdeafbeaf;
5531 s7_cur_proc_ptr->frame_offset = 0xdeafbeaf;
5532 s7_cur_proc_ptr->frame_reg = 0xdeafbeaf;
5533 s7_cur_proc_ptr->pc_reg = 0xdeafbeaf;
5534 s7_cur_proc_ptr->isym = symbolP;
5535 symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
5536 ++s7_numprocs;
5537 if (debug_type == DEBUG_STABS)
5538 stabs_generate_asm_func (S_GET_NAME (symbolP), S_GET_NAME (symbolP));
5539 }
5540 demand_empty_rest_of_line ();
5541}
5542
5543static void
5544s7_s_score_frame (int ignore ATTRIBUTE_UNUSED)
5545{
5546 char *backupstr;
5547 char str[30];
5548 long val;
5549 int i = 0;
5550
5551 backupstr = input_line_pointer;
5552
5553#ifdef OBJ_ELF
5554 if (s7_cur_proc_ptr == NULL)
5555 {
5556 as_warn (_(".frame outside of .ent"));
5557 demand_empty_rest_of_line ();
5558 return;
5559 }
5560 s7_cur_proc_ptr->frame_reg = s7_reg_required_here ((&backupstr), 0, s7_REG_TYPE_SCORE);
5561 SKIP_WHITESPACE ();
5562 s7_skip_past_comma (&backupstr);
5563 while (*backupstr != ',')
5564 {
5565 str[i] = *backupstr;
5566 i++;
5567 backupstr++;
5568 }
5569 str[i] = '\0';
5570 val = atoi (str);
5571
5572 SKIP_WHITESPACE ();
5573 s7_skip_past_comma (&backupstr);
5574 s7_cur_proc_ptr->frame_offset = val;
5575 s7_cur_proc_ptr->pc_reg = s7_reg_required_here ((&backupstr), 0, s7_REG_TYPE_SCORE);
5576
5577 SKIP_WHITESPACE ();
5578 s7_skip_past_comma (&backupstr);
5579 i = 0;
5580 while (*backupstr != '\n')
5581 {
5582 str[i] = *backupstr;
5583 i++;
5584 backupstr++;
5585 }
5586 str[i] = '\0';
5587 val = atoi (str);
5588 s7_cur_proc_ptr->leaf = val;
5589 SKIP_WHITESPACE ();
5590 s7_skip_past_comma (&backupstr);
5591
5592#endif /* OBJ_ELF */
5593 while (input_line_pointer != backupstr)
5594 input_line_pointer++;
5595}
5596
5597/* The .end directive. */
5598
5599static void
5600s7_s_score_end (int x ATTRIBUTE_UNUSED)
5601{
5602 symbolS *p;
5603 int maybe_text;
5604
5605 /* Generate a .pdr section. */
5606 segT saved_seg = now_seg;
5607 subsegT saved_subseg = now_subseg;
c3b7224a
NC
5608 expressionS exp;
5609 char *fragp;
5610
5611 if (!is_end_of_line[(unsigned char)*input_line_pointer])
5612 {
5613 p = s7_get_symbol ();
5614 demand_empty_rest_of_line ();
5615 }
5616 else
5617 p = NULL;
5618
fd361982 5619 if ((bfd_section_flags (now_seg) & SEC_CODE) != 0)
c3b7224a
NC
5620 maybe_text = 1;
5621 else
5622 maybe_text = 0;
c3b7224a
NC
5623
5624 if (!maybe_text)
5625 as_warn (_(".end not in text section"));
5626 if (!s7_cur_proc_ptr)
5627 {
5628 as_warn (_(".end directive without a preceding .ent directive."));
5629 demand_empty_rest_of_line ();
5630 return;
5631 }
5632 if (p != NULL)
5633 {
9c2799c2 5634 gas_assert (S_GET_NAME (p));
c3b7224a
NC
5635 if (strcmp (S_GET_NAME (p), S_GET_NAME (s7_cur_proc_ptr->isym)))
5636 as_warn (_(".end symbol does not match .ent symbol."));
5637 if (debug_type == DEBUG_STABS)
5638 stabs_generate_asm_endfunc (S_GET_NAME (p), S_GET_NAME (p));
5639 }
5640 else
5641 as_warn (_(".end directive missing or unknown symbol"));
5642
5643 if ((s7_cur_proc_ptr->reg_mask == 0xdeadbeaf) ||
5644 (s7_cur_proc_ptr->reg_offset == 0xdeadbeaf) ||
5645 (s7_cur_proc_ptr->leaf == 0xdeafbeaf) ||
5646 (s7_cur_proc_ptr->frame_offset == 0xdeafbeaf) ||
5647 (s7_cur_proc_ptr->frame_reg == 0xdeafbeaf) || (s7_cur_proc_ptr->pc_reg == 0xdeafbeaf));
5648
5649 else
5650 {
f9e53abc 5651 (void) frag_now_fix ();
9c2799c2 5652 gas_assert (s7_pdr_seg);
c3b7224a
NC
5653 subseg_set (s7_pdr_seg, 0);
5654 /* Write the symbol. */
5655 exp.X_op = O_symbol;
5656 exp.X_add_symbol = p;
5657 exp.X_add_number = 0;
5658 emit_expr (&exp, 4);
5659 fragp = frag_more (7 * 4);
5660 s7_number_to_chars (fragp, (valueT) s7_cur_proc_ptr->reg_mask, 4);
5661 s7_number_to_chars (fragp + 4, (valueT) s7_cur_proc_ptr->reg_offset, 4);
5662 s7_number_to_chars (fragp + 8, (valueT) s7_cur_proc_ptr->fpreg_mask, 4);
5663 s7_number_to_chars (fragp + 12, (valueT) s7_cur_proc_ptr->leaf, 4);
5664 s7_number_to_chars (fragp + 16, (valueT) s7_cur_proc_ptr->frame_offset, 4);
5665 s7_number_to_chars (fragp + 20, (valueT) s7_cur_proc_ptr->frame_reg, 4);
5666 s7_number_to_chars (fragp + 24, (valueT) s7_cur_proc_ptr->pc_reg, 4);
5667 subseg_set (saved_seg, saved_subseg);
5668
5669 }
5670 s7_cur_proc_ptr = NULL;
5671}
5672
5673/* Handle the .set pseudo-op. */
5674
5675static void
5676s7_s_score_set (int x ATTRIBUTE_UNUSED)
5677{
5678 int i = 0;
5679 char name[s7_MAX_LITERAL_POOL_SIZE];
5680 char * orig_ilp = input_line_pointer;
5681
5682 while (!is_end_of_line[(unsigned char)*input_line_pointer])
5683 {
5684 name[i] = (char) * input_line_pointer;
5685 i++;
5686 ++input_line_pointer;
5687 }
5688
5689 name[i] = '\0';
5690
5691 if (strcmp (name, "nwarn") == 0)
5692 {
5693 s7_warn_fix_data_dependency = 0;
5694 }
5695 else if (strcmp (name, "fixdd") == 0)
5696 {
5697 s7_fix_data_dependency = 1;
5698 }
5699 else if (strcmp (name, "nofixdd") == 0)
5700 {
5701 s7_fix_data_dependency = 0;
5702 }
5703 else if (strcmp (name, "r1") == 0)
5704 {
5705 s7_nor1 = 0;
5706 }
5707 else if (strcmp (name, "nor1") == 0)
5708 {
5709 s7_nor1 = 1;
5710 }
5711 else if (strcmp (name, "optimize") == 0)
5712 {
5713 s7_g_opt = 1;
5714 }
5715 else if (strcmp (name, "volatile") == 0)
5716 {
5717 s7_g_opt = 0;
5718 }
5719 else if (strcmp (name, "pic") == 0)
5720 {
5721 s7_score_pic = s7_PIC;
5722 }
5723 else
5724 {
5725 input_line_pointer = orig_ilp;
5726 s_set (0);
5727 }
5728}
5729
5730/* Handle the .cpload pseudo-op. This is used when generating s7_PIC code. It sets the
5731 $gp register for the function based on the function address, which is in the register
5732 named in the argument. This uses a relocation against GP_DISP_LABEL, which is handled
5733 specially by the linker. The result is:
5734 ldis gp, %hi(GP_DISP_LABEL)
5735 ori gp, %low(GP_DISP_LABEL)
5736 add gp, gp, .cpload argument
5737 The .cpload argument is normally r29. */
5738
5739static void
5740s7_s_score_cpload (int ignore ATTRIBUTE_UNUSED)
5741{
5742 int reg;
5743 char insn_str[s7_MAX_LITERAL_POOL_SIZE];
5744
5745 /* If we are not generating s7_PIC code, .cpload is ignored. */
5746 if (s7_score_pic == s7_NO_PIC)
5747 {
5748 s_ignore (0);
5749 return;
5750 }
5751
5752 if ((reg = s7_reg_required_here (&input_line_pointer, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
5753 return;
5754
5755 demand_empty_rest_of_line ();
5756
5757 sprintf (insn_str, "ld_i32hi r%d, %s", s7_GP, GP_DISP_LABEL);
5b7c81bd 5758 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5759 return;
5760
5761 sprintf (insn_str, "ld_i32lo r%d, %s", s7_GP, GP_DISP_LABEL);
5b7c81bd 5762 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5763 return;
5764
5765 sprintf (insn_str, "add r%d, r%d, r%d", s7_GP, s7_GP, reg);
5b7c81bd 5766 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5767 return;
5768}
5769
5770/* Handle the .cprestore pseudo-op. This stores $gp into a given
5771 offset from $sp. The offset is remembered, and after making a s7_PIC
5772 call $gp is restored from that location. */
5773
5774static void
5775s7_s_score_cprestore (int ignore ATTRIBUTE_UNUSED)
5776{
5777 int reg;
5778 int cprestore_offset;
5779 char insn_str[s7_MAX_LITERAL_POOL_SIZE];
5780
5781 /* If we are not generating s7_PIC code, .cprestore is ignored. */
5782 if (s7_score_pic == s7_NO_PIC)
5783 {
5784 s_ignore (0);
5785 return;
5786 }
5787
5788 if ((reg = s7_reg_required_here (&input_line_pointer, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL
5789 || s7_skip_past_comma (&input_line_pointer) == (int) s7_FAIL)
5790 {
5791 return;
5792 }
5793
5794 cprestore_offset = get_absolute_expression ();
5795
5796 if (cprestore_offset <= 0x3fff)
5797 {
5798 sprintf (insn_str, "sw r%d, [r%d, %d]", s7_GP, reg, cprestore_offset);
5b7c81bd 5799 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5800 return;
5801 }
5802 else
5803 {
5804 int r1_bak;
5805
5806 r1_bak = s7_nor1;
5807 s7_nor1 = 0;
5808
5809 sprintf (insn_str, "li r1, %d", cprestore_offset);
5b7c81bd 5810 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5811 return;
5812
5813 sprintf (insn_str, "add r1, r1, r%d", reg);
5b7c81bd 5814 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5815 return;
5816
5817 sprintf (insn_str, "sw r%d, [r1]", s7_GP);
5b7c81bd 5818 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5819 return;
5820
5821 s7_nor1 = r1_bak;
5822 }
5823
5824 demand_empty_rest_of_line ();
5825}
5826
5827/* Handle the .gpword pseudo-op. This is used when generating s7_PIC
5828 code. It generates a 32 bit s7_GP relative reloc. */
5829
5830static void
5831s7_s_score_gpword (int ignore ATTRIBUTE_UNUSED)
5832{
5833 expressionS ex;
5834 char *p;
5835
5836 /* When not generating s7_PIC code, this is treated as .word. */
5837 if (s7_score_pic == s7_NO_PIC)
5838 {
5839 cons (4);
5840 return;
5841 }
5842 expression (&ex);
5843 if (ex.X_op != O_symbol || ex.X_add_number != 0)
5844 {
5845 as_bad (_("Unsupported use of .gpword"));
5846 ignore_rest_of_line ();
5847 }
5848 p = frag_more (4);
5849 s7_number_to_chars (p, (valueT) 0, 4);
5b7c81bd 5850 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, false, BFD_RELOC_GPREL32);
c3b7224a
NC
5851 demand_empty_rest_of_line ();
5852}
5853
5854/* Handle the .cpadd pseudo-op. This is used when dealing with switch
5855 tables in s7_PIC code. */
5856
5857static void
5858s7_s_score_cpadd (int ignore ATTRIBUTE_UNUSED)
5859{
5860 int reg;
5861 char insn_str[s7_MAX_LITERAL_POOL_SIZE];
5862
5863 /* If we are not generating s7_PIC code, .cpload is ignored. */
5864 if (s7_score_pic == s7_NO_PIC)
5865 {
5866 s_ignore (0);
5867 return;
5868 }
5869
5870 if ((reg = s7_reg_required_here (&input_line_pointer, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
5871 {
5872 return;
5873 }
5874 demand_empty_rest_of_line ();
5875
5876 /* Add $gp to the register named as an argument. */
5877 sprintf (insn_str, "add r%d, r%d, r%d", reg, reg, s7_GP);
5b7c81bd 5878 if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
c3b7224a
NC
5879 return;
5880}
5881
5882#ifndef TC_IMPLICIT_LCOMM_ALIGNMENT
5883#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \
5884 do \
5885 { \
5886 if ((SIZE) >= 8) \
5887 (P2VAR) = 3; \
5888 else if ((SIZE) >= 4) \
5889 (P2VAR) = 2; \
5890 else if ((SIZE) >= 2) \
5891 (P2VAR) = 1; \
5892 else \
5893 (P2VAR) = 0; \
5894 } \
5895 while (0)
5896#endif
5897
5898static void
5899s7_s_score_lcomm (int bytes_p)
5900{
5901 char *name;
5902 char c;
5903 char *p;
5904 int temp;
5905 symbolS *symbolP;
5906 segT current_seg = now_seg;
5907 subsegT current_subseg = now_subseg;
5908 const int max_alignment = 15;
5909 int align = 0;
5910 segT bss_seg = bss_section;
5911 int needs_align = 0;
5912
d02603dc 5913 c = get_symbol_name (&name);
c3b7224a
NC
5914 p = input_line_pointer;
5915 *p = c;
5916
5917 if (name == p)
5918 {
5919 as_bad (_("expected symbol name"));
5920 discard_rest_of_line ();
5921 return;
5922 }
5923
d02603dc 5924 SKIP_WHITESPACE_AFTER_NAME ();
c3b7224a
NC
5925
5926 /* Accept an optional comma after the name. The comma used to be
5927 required, but Irix 5 cc does not generate it. */
5928 if (*input_line_pointer == ',')
5929 {
5930 ++input_line_pointer;
5931 SKIP_WHITESPACE ();
5932 }
5933
5934 if (is_end_of_line[(unsigned char)*input_line_pointer])
5935 {
5936 as_bad (_("missing size expression"));
5937 return;
5938 }
5939
5940 if ((temp = get_absolute_expression ()) < 0)
5941 {
5942 as_warn (_("BSS length (%d) < 0 ignored"), temp);
5943 ignore_rest_of_line ();
5944 return;
5945 }
5946
5947#if defined (TC_SCORE)
5948 if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour || OUTPUT_FLAVOR == bfd_target_elf_flavour)
5949 {
5950 /* For Score and Alpha ECOFF or ELF, small objects are put in .sbss. */
5951 if ((unsigned) temp <= bfd_get_gp_size (stdoutput))
a4dd6c97
AM
5952 {
5953 bss_seg = subseg_new (".sbss", 1);
5954 seg_info (bss_seg)->bss = 1;
5955 if (!bfd_set_section_flags (bss_seg, SEC_ALLOC | SEC_SMALL_DATA))
5956 as_warn (_("error setting flags for \".sbss\": %s"),
5957 bfd_errmsg (bfd_get_error ()));
5958 }
c3b7224a
NC
5959 }
5960#endif
5961
5962 SKIP_WHITESPACE ();
5963 if (*input_line_pointer == ',')
5964 {
5965 ++input_line_pointer;
5966 SKIP_WHITESPACE ();
5967
5968 if (is_end_of_line[(unsigned char)*input_line_pointer])
5969 {
5970 as_bad (_("missing alignment"));
5971 return;
5972 }
5973 else
5974 {
5975 align = get_absolute_expression ();
5976 needs_align = 1;
5977 }
5978 }
5979
5980 if (!needs_align)
5981 {
5982 TC_IMPLICIT_LCOMM_ALIGNMENT (temp, align);
5983
5984 /* Still zero unless TC_IMPLICIT_LCOMM_ALIGNMENT set it. */
5985 if (align)
5986 record_alignment (bss_seg, align);
5987 }
5988
5989 if (needs_align)
5990 {
5991 if (bytes_p)
5992 {
5993 /* Convert to a power of 2. */
5994 if (align != 0)
5995 {
5996 unsigned int i;
5997
5998 for (i = 0; align != 0; align >>= 1, ++i)
5999 ;
6000 align = i - 1;
6001 }
6002 }
6003
6004 if (align > max_alignment)
6005 {
6006 align = max_alignment;
6007 as_warn (_("alignment too large; %d assumed"), align);
6008 }
6009 else if (align < 0)
6010 {
6011 align = 0;
6012 as_warn (_("alignment negative; 0 assumed"));
6013 }
6014
6015 record_alignment (bss_seg, align);
6016 }
c3b7224a
NC
6017
6018 *p = 0;
6019 symbolP = symbol_find_or_make (name);
6020 *p = c;
6021
6022 if (
a8eb42a8 6023#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
c3b7224a
NC
6024 (OUTPUT_FLAVOR != bfd_target_aout_flavour
6025 || (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) &&
c3b7224a
NC
6026#endif
6027 (S_GET_SEGMENT (symbolP) == bss_seg || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0)))
6028 {
6029 char *pfrag;
6030
6031 subseg_set (bss_seg, 1);
6032
6033 if (align)
6034 frag_align (align, 0, 0);
6035
6036 /* Detach from old frag. */
6037 if (S_GET_SEGMENT (symbolP) == bss_seg)
6038 symbol_get_frag (symbolP)->fr_symbol = NULL;
6039
6040 symbol_set_frag (symbolP, frag_now);
6041 pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, (offsetT) temp, NULL);
6042 *pfrag = 0;
6043
6044
6045 S_SET_SEGMENT (symbolP, bss_seg);
6046
6047#ifdef OBJ_COFF
6048 /* The symbol may already have been created with a preceding
6049 ".globl" directive -- be careful not to step on storage class
6050 in that case. Otherwise, set it to static. */
6051 if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
6052 {
6053 S_SET_STORAGE_CLASS (symbolP, C_STAT);
6054 }
6055#endif /* OBJ_COFF */
6056
6057#ifdef S_SET_SIZE
6058 S_SET_SIZE (symbolP, temp);
6059#endif
6060 }
6061 else
6062 as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP));
6063
6064 subseg_set (current_seg, current_subseg);
6065
6066 demand_empty_rest_of_line ();
6067}
6068
6069\f
6070
6071static void
6072s7_begin (void)
6073{
6074 unsigned int i;
6075 segT seg;
6076 subsegT subseg;
6077
f16c3d4f 6078 s7_score_ops_hsh = str_htab_create ();
c3b7224a
NC
6079
6080 s7_build_score_ops_hsh ();
6081
f16c3d4f 6082 s7_dependency_insn_hsh = str_htab_create ();
c3b7224a
NC
6083
6084 s7_build_dependency_insn_hsh ();
6085
6086 for (i = (int) REG_TYPE_FIRST; i < (int) s7_REG_TYPE_MAX; i++)
6087 s7_build_reg_hsh (s7_all_reg_maps + i);
6088
6089 /* Initialize dependency vector. */
6090 s7_init_dependency_vector ();
6091
6092 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
6093 seg = now_seg;
6094 subseg = now_subseg;
6095 s7_pdr_seg = subseg_new (".pdr", (subsegT) 0);
fd361982
AM
6096 bfd_set_section_flags (s7_pdr_seg, SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
6097 bfd_set_section_alignment (s7_pdr_seg, 2);
c3b7224a
NC
6098 subseg_set (seg, subseg);
6099
6100 if (s7_USE_GLOBAL_POINTER_OPT)
6101 bfd_set_gp_size (stdoutput, s7_g_switch_value);
6102}
6103
6104static void
6105s7_assemble (char *str)
6106{
6107 know (str);
6108 know (strlen (str) < s7_MAX_LITERAL_POOL_SIZE);
6109
6110 memset (&s7_inst, '\0', sizeof (s7_inst));
6111 if (s7_INSN_IS_PCE_P (str))
6112 s7_parse_pce_inst (str);
6113 else
5b7c81bd 6114 s7_parse_16_32_inst (str, true);
c3b7224a
NC
6115
6116 if (s7_inst.error)
6117 as_bad (_("%s -- `%s'"), s7_inst.error, s7_inst.str);
6118}
6119
6120/* We handle all bad expressions here, so that we can report the faulty
6121 instruction in the error message. */
6122
6123static void
91d6fa6a 6124s7_operand (expressionS * exp)
c3b7224a
NC
6125{
6126 if (s7_in_my_get_expression)
6127 {
91d6fa6a 6128 exp->X_op = O_illegal;
c3b7224a
NC
6129 if (s7_inst.error == NULL)
6130 {
6131 s7_inst.error = _("bad expression");
6132 }
6133 }
6134}
6135
6136/* Turn a string in input_line_pointer into a floating point constant
6137 of type TYPE, and store the appropriate bytes in *LITP. The number
6138 of LITTLENUMS emitted is stored in *SIZEP. An error message is
6139 returned, or NULL on OK.
6140
6141 Note that fp constants aren't represent in the normal way on the ARM.
6142 In big endian mode, things are as expected. However, in little endian
6143 mode fp constants are big-endian word-wise, and little-endian byte-wise
6144 within the words. For example, (double) 1.1 in big endian mode is
6145 the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
6146 the byte sequence 99 99 f1 3f 9a 99 99 99. */
6147
585ba040 6148static const char *
c3b7224a
NC
6149s7_atof (int type, char *litP, int *sizeP)
6150{
6151 int prec;
3076e594 6152 LITTLENUM_TYPE words[MAX_LITTLENUMS];
c3b7224a
NC
6153 char *t;
6154 int i;
6155
6156 switch (type)
6157 {
6158 case 'f':
6159 case 'F':
6160 case 's':
6161 case 'S':
6162 prec = 2;
6163 break;
6164 case 'd':
6165 case 'D':
6166 case 'r':
6167 case 'R':
6168 prec = 4;
6169 break;
6170 case 'x':
6171 case 'X':
6172 case 'p':
6173 case 'P':
6174 prec = 6;
6175 break;
6176 default:
6177 *sizeP = 0;
6178 return _("bad call to MD_ATOF()");
6179 }
6180
6181 t = atof_ieee (input_line_pointer, type, words);
6182 if (t)
6183 input_line_pointer = t;
6184 *sizeP = prec * 2;
6185
6186 if (target_big_endian)
6187 {
6188 for (i = 0; i < prec; i++)
6189 {
6190 s7_number_to_chars (litP, (valueT) words[i], 2);
6191 litP += 2;
6192 }
6193 }
6194 else
6195 {
6196 for (i = 0; i < prec; i += 2)
6197 {
6198 s7_number_to_chars (litP, (valueT) words[i + 1], 2);
6199 s7_number_to_chars (litP + 2, (valueT) words[i], 2);
6200 litP += 4;
6201 }
6202 }
6203
6204 return 0;
6205}
6206
6207/* Implementation of md_frag_check.
6208 Called after md_convert_frag(). */
6209
6210static void
bd56defd 6211s7_frag_check (fragS * fragp ATTRIBUTE_UNUSED)
c3b7224a
NC
6212{
6213 know (fragp->insn_addr <= s7_RELAX_PAD_BYTE);
6214}
6215
6216/* Implementation of TC_VALIDATE_FIX.
6217 Called before md_apply_fix() and after md_convert_frag(). */
6218
6219static void
6220s7_validate_fix (fixS *fixP)
6221{
6222 fixP->fx_where += fixP->fx_frag->insn_addr;
6223}
6224
6225static int
6226s7_force_relocation (struct fix *fixp)
6227{
6228 int retval = 0;
6229
6230 if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
6231 || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
6232 || fixp->fx_r_type == BFD_RELOC_SCORE_JMP
6233 || fixp->fx_r_type == BFD_RELOC_SCORE_BRANCH
6234 || fixp->fx_r_type == BFD_RELOC_SCORE16_JMP
6235 || fixp->fx_r_type == BFD_RELOC_SCORE16_BRANCH)
6236 {
6237 retval = 1;
6238 }
6239
6240 return retval;
6241}
6242
5b7c81bd 6243static bool
c3b7224a
NC
6244s7_fix_adjustable (fixS * fixP)
6245{
6246 if (fixP->fx_addsy == NULL)
6247 {
6248 return 1;
6249 }
6250 else if (OUTPUT_FLAVOR == bfd_target_elf_flavour
6251 && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)))
6252 {
6253 return 0;
6254 }
6255 else if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
6256 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
6257 || fixP->fx_r_type == BFD_RELOC_SCORE_JMP
6258 || fixP->fx_r_type == BFD_RELOC_SCORE16_JMP)
6259 {
6260 return 0;
6261 }
6262
6263 return 1;
6264}
6265
6266static void
6267s7_elf_final_processing (void)
6268{
6269 unsigned long val = E_SCORE_MACH_SCORE7;
6270
6271 elf_elfheader (stdoutput)->e_machine = EM_SCORE;
6272 elf_elfheader (stdoutput)->e_flags &= ~EF_SCORE_MACH;
6273 elf_elfheader (stdoutput)->e_flags |= val;
6274
6275 if (s7_fix_data_dependency == 1)
6276 {
6277 elf_elfheader (stdoutput)->e_flags |= EF_SCORE_FIXDEP;
6278 }
6279 if (s7_score_pic == s7_PIC)
6280 {
6281 elf_elfheader (stdoutput)->e_flags |= EF_SCORE_PIC;
6282 }
6283}
6284
6285/* In this function, we determine whether s7_GP instruction should do relaxation,
6286 for the label being against was known now.
6287 Doing this here but not in md_relax_frag() can induce iteration times
6288 in stage of doing relax. */
6289
6290static int
6291s7_estimate_size_before_relax (fragS * fragp, asection * sec)
6292{
6293 if ((s7_RELAX_TYPE (fragp->fr_subtype) == Insn_GP)
6294 || (s7_RELAX_TYPE (fragp->fr_subtype) == Insn_PIC))
6295 return s7_judge_size_before_relax (fragp, sec);
6296
6297 return 0;
6298}
6299
6300static int
6301s7_relax_frag (asection * sec ATTRIBUTE_UNUSED,
6302 fragS * fragp,
6303 long stretch ATTRIBUTE_UNUSED)
6304{
6305 int grows = 0;
6306 int insn_size;
c3b7224a
NC
6307 int do_relax_p = 0; /* Indicate doing relaxation for this frag. */
6308 int relaxable_p = 0;
5b7c81bd 6309 bool word_align_p = false;
c3b7224a
NC
6310 fragS *next_fragp;
6311
6312 /* If the instruction address is odd, make it half word align first. */
6313 if ((fragp->fr_address) % 2 != 0)
6314 {
6315 if ((fragp->fr_address + fragp->insn_addr) % 2 != 0)
6316 {
6317 fragp->insn_addr = 1;
6318 grows += 1;
6319 }
6320 }
6321
63b4cc53 6322 word_align_p = (fragp->fr_address + fragp->insn_addr) % 4 == 0;
c3b7224a
NC
6323
6324 /* Get instruction size and relax size after the last relaxation. */
6325 if (fragp->fr_opcode)
f9e53abc 6326 insn_size = s7_RELAX_NEW (fragp->fr_subtype);
c3b7224a 6327 else
f9e53abc 6328 insn_size = s7_RELAX_OLD (fragp->fr_subtype);
c3b7224a
NC
6329
6330 /* Handle specially for s7_GP instruction. for, s7_judge_size_before_relax() has already determine
6331 whether the s7_GP instruction should do relax. */
6332 if ((s7_RELAX_TYPE (fragp->fr_subtype) == Insn_GP)
6333 || (s7_RELAX_TYPE (fragp->fr_subtype) == Insn_PIC))
6334 {
6335 if (!word_align_p)
6336 {
6337 if (fragp->insn_addr < 2)
6338 {
6339 fragp->insn_addr += 2;
6340 grows += 2;
6341 }
6342 else
6343 {
6344 fragp->insn_addr -= 2;
6345 grows -= 2;
6346 }
6347 }
6348
6349 if (fragp->fr_opcode)
6350 fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype) + fragp->insn_addr;
6351 else
6352 fragp->fr_fix = s7_RELAX_OLD (fragp->fr_subtype) + fragp->insn_addr;
6353 }
6354 else
6355 {
6356 if (s7_RELAX_TYPE (fragp->fr_subtype) == PC_DISP19div2)
6357 s7_b32_relax_to_b16 (fragp);
6358
6359 relaxable_p = s7_RELAX_OPT (fragp->fr_subtype);
6360 next_fragp = fragp->fr_next;
6361 while ((next_fragp) && (next_fragp->fr_type != rs_machine_dependent))
6362 {
6363 next_fragp = next_fragp->fr_next;
6364 }
6365
6366 if (next_fragp)
6367 {
6368 int n_insn_size;
6369 int n_relaxable_p = 0;
6370
6371 if (next_fragp->fr_opcode)
6372 {
6373 n_insn_size = s7_RELAX_NEW (next_fragp->fr_subtype);
6374 }
6375 else
6376 {
6377 n_insn_size = s7_RELAX_OLD (next_fragp->fr_subtype);
6378 }
6379
6380 if (s7_RELAX_TYPE (next_fragp->fr_subtype) == PC_DISP19div2)
6381 s7_b32_relax_to_b16 (next_fragp);
6382 n_relaxable_p = s7_RELAX_OPT (next_fragp->fr_subtype);
6383
6384 if (word_align_p)
6385 {
6386 if (insn_size == 4)
6387 {
6388 /* 32 -> 16. */
6389 if (relaxable_p && ((n_insn_size == 2) || n_relaxable_p))
6390 {
6391 grows -= 2;
6392 do_relax_p = 1;
6393 }
6394 }
6395 else if (insn_size == 2)
6396 {
6397 /* 16 -> 32. */
6398 if (relaxable_p && (((n_insn_size == 4) && !n_relaxable_p) || (n_insn_size > 4)))
6399 {
6400 grows += 2;
6401 do_relax_p = 1;
6402 }
6403 }
6404 else
6405 {
6406 abort ();
6407 }
6408 }
6409 else
6410 {
6411 if (insn_size == 4)
6412 {
6413 /* 32 -> 16. */
6414 if (relaxable_p)
6415 {
6416 grows -= 2;
6417 do_relax_p = 1;
6418 }
33eaf5de 6419 /* Make the 32 bit instruction word align. */
c3b7224a
NC
6420 else
6421 {
6422 fragp->insn_addr += 2;
6423 grows += 2;
6424 }
6425 }
6426 else if (insn_size == 2)
6427 {
6428 /* Do nothing. */
6429 }
6430 else
6431 {
6432 abort ();
6433 }
6434 }
6435 }
6436 else
6437 {
6438 /* Here, try best to do relax regardless fragp->fr_next->fr_type. */
535b785f 6439 if (!word_align_p)
c3b7224a
NC
6440 {
6441 if (insn_size % 4 == 0)
6442 {
6443 /* 32 -> 16. */
6444 if (relaxable_p)
6445 {
6446 grows -= 2;
6447 do_relax_p = 1;
6448 }
6449 else
6450 {
6451 fragp->insn_addr += 2;
6452 grows += 2;
6453 }
6454 }
6455 }
6456 else
6457 {
6458 /* Do nothing. */
6459 }
6460 }
6461
6462 /* fragp->fr_opcode indicates whether this frag should be relaxed. */
6463 if (do_relax_p)
6464 {
6465 if (fragp->fr_opcode)
6466 {
6467 fragp->fr_opcode = NULL;
6468 /* Guarantee estimate stage is correct. */
6469 fragp->fr_fix = s7_RELAX_OLD (fragp->fr_subtype);
6470 fragp->fr_fix += fragp->insn_addr;
6471 }
6472 else
6473 {
6474 fragp->fr_opcode = fragp->fr_literal + s7_RELAX_RELOC1 (fragp->fr_subtype);
6475 /* Guarantee estimate stage is correct. */
6476 fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype);
6477 fragp->fr_fix += fragp->insn_addr;
6478 }
6479 }
6480 else
6481 {
6482 if (fragp->fr_opcode)
6483 {
6484 /* Guarantee estimate stage is correct. */
6485 fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype);
6486 fragp->fr_fix += fragp->insn_addr;
6487 }
6488 else
6489 {
6490 /* Guarantee estimate stage is correct. */
6491 fragp->fr_fix = s7_RELAX_OLD (fragp->fr_subtype);
6492 fragp->fr_fix += fragp->insn_addr;
6493 }
6494 }
6495 }
6496
6497 return grows;
6498}
6499
6500static void
6501s7_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
6502 segT sec ATTRIBUTE_UNUSED,
6503 fragS * fragp)
6504{
90bd3c90
AM
6505 unsigned int r_old;
6506 unsigned int r_new;
c3b7224a
NC
6507 char backup[20];
6508 fixS *fixp;
6509
d3ce72d0
NC
6510 r_old = s7_RELAX_OLD (fragp->fr_subtype);
6511 r_new = s7_RELAX_NEW (fragp->fr_subtype);
c3b7224a
NC
6512
6513 /* fragp->fr_opcode indicates whether this frag should be relaxed. */
6514 if (fragp->fr_opcode == NULL)
6515 {
d3ce72d0
NC
6516 memcpy (backup, fragp->fr_literal, r_old);
6517 fragp->fr_fix = r_old;
c3b7224a
NC
6518 }
6519 else
6520 {
d3ce72d0
NC
6521 memcpy (backup, fragp->fr_literal + r_old, r_new);
6522 fragp->fr_fix = r_new;
c3b7224a
NC
6523 }
6524
6525 fixp = fragp->tc_frag_data.fixp;
d3ce72d0 6526 while (fixp && fixp->fx_frag == fragp && fixp->fx_where < r_old)
c3b7224a
NC
6527 {
6528 if (fragp->fr_opcode)
6529 fixp->fx_done = 1;
6530 fixp = fixp->fx_next;
6531 }
6532 while (fixp && fixp->fx_frag == fragp)
6533 {
6534 if (fragp->fr_opcode)
d3ce72d0 6535 fixp->fx_where -= r_old + fragp->insn_addr;
c3b7224a
NC
6536 else
6537 fixp->fx_done = 1;
6538 fixp = fixp->fx_next;
6539 }
6540
6541 if (fragp->insn_addr)
6542 {
6543 s7_number_to_chars (fragp->fr_literal, 0x0, fragp->insn_addr);
6544 }
6545 memcpy (fragp->fr_literal + fragp->insn_addr, backup, fragp->fr_fix);
6546 fragp->fr_fix += fragp->insn_addr;
6547}
6548
6549static long
6550s7_pcrel_from (fixS * fixP)
6551{
6552 long retval = 0;
6553
6554 if (fixP->fx_addsy
6555 && (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
6556 && (fixP->fx_subsy == NULL))
6557 {
6558 retval = 0;
6559 }
6560 else
6561 {
6562 retval = fixP->fx_where + fixP->fx_frag->fr_address;
6563 }
6564
6565 return retval;
6566}
6567
6568/* Round up a section size to the appropriate boundary. */
6569static valueT
6570s7_section_align (segT segment, valueT size)
6571{
fd361982 6572 int align = bfd_section_alignment (segment);
c3b7224a 6573
8d3842cd 6574 return ((size + (1 << align) - 1) & -(1 << align));
c3b7224a
NC
6575}
6576
6577static void
6578s7_apply_fix (fixS *fixP, valueT *valP, segT seg)
6579{
548c8b2b
AM
6580 valueT value = *valP;
6581 valueT abs_value = 0;
6582 valueT newval;
6583 valueT content;
6584 valueT HI, LO;
c3b7224a
NC
6585
6586 char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
6587
9c2799c2 6588 gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
c3b7224a
NC
6589 if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
6590 {
6591 if (fixP->fx_r_type != BFD_RELOC_SCORE_DUMMY_HI16)
6592 fixP->fx_done = 1;
6593 }
6594
6595 /* If this symbol is in a different section then we need to leave it for
6596 the linker to deal with. Unfortunately, md_pcrel_from can't tell,
6597 so we have to undo it's effects here. */
6598 if (fixP->fx_pcrel)
6599 {
6600 if (fixP->fx_addsy != NULL
6601 && S_IS_DEFINED (fixP->fx_addsy)
6602 && S_GET_SEGMENT (fixP->fx_addsy) != seg)
6603 value += md_pcrel_from (fixP);
6604 }
6605
6606 /* Remember value for emit_reloc. */
6607 fixP->fx_addnumber = value;
6608
6609 switch (fixP->fx_r_type)
6610 {
6611 case BFD_RELOC_HI16_S:
6612 if (fixP->fx_done)
6613 { /* For la rd, imm32. */
6614 newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
548c8b2b 6615 HI = value >> 16; /* mul to 2, then take the hi 16 bit. */
c3b7224a
NC
6616 newval |= (HI & 0x3fff) << 1;
6617 newval |= ((HI >> 14) & 0x3) << 16;
6618 s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6619 }
6620 break;
6621 case BFD_RELOC_LO16:
6622 if (fixP->fx_done) /* For la rd, imm32. */
6623 {
6624 newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
548c8b2b 6625 LO = value & 0xffff;
c3b7224a
NC
6626 newval |= (LO & 0x3fff) << 1; /* 16 bit: imm -> 14 bit in lo, 2 bit in hi. */
6627 newval |= ((LO >> 14) & 0x3) << 16;
6628 s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6629 }
6630 break;
6631 case BFD_RELOC_SCORE_JMP:
6632 {
6633 content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6634 value = fixP->fx_offset;
548c8b2b 6635 if (value > 0x1ffffff)
c3b7224a
NC
6636 {
6637 as_bad_where (fixP->fx_file, fixP->fx_line,
6638 _("j or jl truncate (0x%x) [0 ~ 2^25-1]"), (unsigned int) value);
6639 return;
6640 }
6641 content = (content & ~0x3ff7ffe) | ((value << 1) & 0x3ff0000) | (value & 0x7fff);
6642 s7_number_to_chars (buf, content, s7_INSN_SIZE);
6643 }
6644 break;
6645 case BFD_RELOC_SCORE_BRANCH:
6646 if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) || (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
6647 value = fixP->fx_offset;
6648 else
6649 fixP->fx_done = 1;
6650
6651 content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6652 if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0x80008000) != 0x80008000))
6653 {
6654 if ((value & 0x80000000) == 0x80000000)
6655 abs_value = 0xffffffff - value + 1;
6656 if ((abs_value & 0xffffff00) != 0)
6657 {
6658 as_bad_where (fixP->fx_file, fixP->fx_line,
6659 _(" branch relocation truncate (0x%x) [-2^8 ~ 2^8]"), (unsigned int) value);
6660 return;
6661 }
6662 content = s7_md_chars_to_number (buf, s7_INSN16_SIZE);
6663 content &= 0xff00;
6664 content = (content & 0xff00) | ((value >> 1) & 0xff);
6665 s7_number_to_chars (buf, content, s7_INSN16_SIZE);
6666 fixP->fx_r_type = BFD_RELOC_SCORE16_BRANCH;
6667 fixP->fx_size = 2;
6668 }
6669 else
6670 {
6671 if ((value & 0x80000000) == 0x80000000)
6672 abs_value = 0xffffffff - value + 1;
6673 if ((abs_value & 0xfff80000) != 0)
6674 {
6675 as_bad_where (fixP->fx_file, fixP->fx_line,
6676 _(" branch relocation truncate (0x%x) [-2^19 ~ 2^19]"),
6677 (unsigned int) value);
6678 return;
6679 }
6680 content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6681 content &= 0xfc00fc01;
6682 content = (content & 0xfc00fc01) | (value & 0x3fe) | ((value << 6) & 0x3ff0000);
6683 s7_number_to_chars (buf, content, s7_INSN_SIZE);
6684 }
6685 break;
6686 case BFD_RELOC_SCORE16_JMP:
6687 content = s7_md_chars_to_number (buf, s7_INSN16_SIZE);
6688 content &= 0xf001;
6689 value = fixP->fx_offset;
548c8b2b 6690 if (value > 0xfff)
c3b7224a
NC
6691 {
6692 as_bad_where (fixP->fx_file, fixP->fx_line,
6693 _("j! or jl! truncate (0x%x) [0 ~ 2^12-1]"), (unsigned int) value);
6694 return;
6695 }
6696 value = fixP->fx_offset & 0xfff;
6697 content = (content & 0xfc01) | (value & 0xffe);
6698 s7_number_to_chars (buf, content, s7_INSN16_SIZE);
6699 break;
6700 case BFD_RELOC_SCORE16_BRANCH:
6701 content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6702 if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0x80008000) == 0x80008000))
6703 {
6704 if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) ||
6705 (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
6706 value = fixP->fx_offset;
6707 else
6708 fixP->fx_done = 1;
6709
6710 if ((value & 0xfff80000) != 0 && (value & 0xfff80000) != 0xfff80000)
6711 {
6712 as_bad_where (fixP->fx_file, fixP->fx_line,
6713 _(" branch relocation truncate (0x%x) [-2^19 ~ 2^19]"),
6714 (unsigned int) value);
6715 return;
6716 }
6717 content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6718 content = (content & 0xfc00fc01) | (value & 0x3fe) | ((value << 6) & 0x3ff0000);
6719 s7_number_to_chars (buf, content, s7_INSN_SIZE);
6720 fixP->fx_r_type = BFD_RELOC_SCORE_BRANCH;
6721 fixP->fx_size = 4;
6722 break;
6723 }
6724 else
6725 {
2b0f3761 6726 /* In different section. */
c3b7224a
NC
6727 if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) ||
6728 (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
6729 value = fixP->fx_offset;
6730 else
6731 fixP->fx_done = 1;
6732
6733 if ((value & 0xffffff00) != 0 && (value & 0xffffff00) != 0xffffff00)
6734 {
6735 as_bad_where (fixP->fx_file, fixP->fx_line,
6736 _(" branch relocation truncate (0x%x) [-2^8 ~ 2^8]"),
6737 (unsigned int) value);
6738 return;
6739 }
6740 content = s7_md_chars_to_number (buf, s7_INSN16_SIZE);
6741 content = (content & 0xff00) | ((value >> 1) & 0xff);
6742 s7_number_to_chars (buf, content, s7_INSN16_SIZE);
6743 break;
6744 }
6745 case BFD_RELOC_8:
6746 if (fixP->fx_done || fixP->fx_pcrel)
6747 s7_number_to_chars (buf, value, 1);
6748#ifdef OBJ_ELF
6749 else
6750 {
6751 value = fixP->fx_offset;
6752 s7_number_to_chars (buf, value, 1);
6753 }
6754#endif
6755 break;
6756
6757 case BFD_RELOC_16:
6758 if (fixP->fx_done || fixP->fx_pcrel)
6759 s7_number_to_chars (buf, value, 2);
6760#ifdef OBJ_ELF
6761 else
6762 {
6763 value = fixP->fx_offset;
6764 s7_number_to_chars (buf, value, 2);
6765 }
6766#endif
6767 break;
6768 case BFD_RELOC_RVA:
6769 case BFD_RELOC_32:
6770 if (fixP->fx_done || fixP->fx_pcrel)
6771 s7_number_to_chars (buf, value, 4);
6772#ifdef OBJ_ELF
6773 else
6774 {
6775 value = fixP->fx_offset;
6776 s7_number_to_chars (buf, value, 4);
6777 }
6778#endif
6779 break;
6780 case BFD_RELOC_VTABLE_INHERIT:
6781 fixP->fx_done = 0;
6782 if (fixP->fx_addsy && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy))
6783 S_SET_WEAK (fixP->fx_addsy);
6784 break;
6785 case BFD_RELOC_VTABLE_ENTRY:
6786 fixP->fx_done = 0;
6787 break;
6788 case BFD_RELOC_SCORE_GPREL15:
6789 content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6790 if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0xfc1c8000) != 0x94188000))
6791 fixP->fx_r_type = BFD_RELOC_NONE;
6792 fixP->fx_done = 0;
6793 break;
6794 case BFD_RELOC_SCORE_GOT15:
6795 case BFD_RELOC_SCORE_DUMMY_HI16:
6796 case BFD_RELOC_SCORE_GOT_LO16:
6797 case BFD_RELOC_SCORE_CALL15:
6798 case BFD_RELOC_GPREL32:
6799 break;
6800 case BFD_RELOC_NONE:
6801 default:
6802 as_bad_where (fixP->fx_file, fixP->fx_line, _("bad relocation fixup type (%d)"), fixP->fx_r_type);
6803 }
6804}
6805
6806/* Translate internal representation of relocation info to BFD target format. */
6807
6808static arelent **
6809s7_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
6810{
6811 static arelent *retval[MAX_RELOC_EXPANSION + 1]; /* MAX_RELOC_EXPANSION equals 2. */
6812 arelent *reloc;
6813 bfd_reloc_code_real_type code;
585ba040 6814 const char *type;
c3b7224a 6815
325801bd 6816 reloc = retval[0] = XNEW (arelent);
c3b7224a
NC
6817 retval[1] = NULL;
6818
325801bd 6819 reloc->sym_ptr_ptr = XNEW (asymbol *);
c3b7224a
NC
6820 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
6821 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
6822 reloc->addend = fixp->fx_offset;
6823
6824 /* If this is a variant frag, we may need to adjust the existing
6825 reloc and generate a new one. */
6826 if (fixp->fx_frag->fr_opcode != NULL && (fixp->fx_r_type == BFD_RELOC_SCORE_GPREL15))
6827 {
6828 /* Update instruction imm bit. */
6829 offsetT newval;
6830 unsigned short off;
6831 char *buf;
6832
6833 buf = fixp->fx_frag->fr_literal + fixp->fx_frag->insn_addr;
6834 newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6835 off = fixp->fx_offset >> 16;
6836 newval |= (off & 0x3fff) << 1;
6837 newval |= ((off >> 14) & 0x3) << 16;
6838 s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6839
6840 buf += s7_INSN_SIZE;
6841 newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6842 off = fixp->fx_offset & 0xffff;
6843 newval |= ((off & 0x3fff) << 1);
6844 newval |= (((off >> 14) & 0x3) << 16);
6845 s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6846
325801bd 6847 retval[1] = XNEW (arelent);
c3b7224a 6848 retval[2] = NULL;
325801bd 6849 retval[1]->sym_ptr_ptr = XNEW (asymbol *);
c3b7224a
NC
6850 *retval[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
6851 retval[1]->address = (reloc->address + s7_RELAX_RELOC2 (fixp->fx_frag->fr_subtype));
6852
c3b7224a
NC
6853 retval[1]->addend = 0;
6854 retval[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16);
9c2799c2 6855 gas_assert (retval[1]->howto != NULL);
c3b7224a
NC
6856
6857 fixp->fx_r_type = BFD_RELOC_HI16_S;
6858 }
6859
6860 code = fixp->fx_r_type;
6861 switch (fixp->fx_r_type)
6862 {
6863 case BFD_RELOC_32:
6864 if (fixp->fx_pcrel)
6865 {
6866 code = BFD_RELOC_32_PCREL;
6867 break;
6868 }
1a0670f3 6869 /* Fall through. */
c3b7224a
NC
6870 case BFD_RELOC_HI16_S:
6871 case BFD_RELOC_LO16:
6872 case BFD_RELOC_SCORE_JMP:
6873 case BFD_RELOC_SCORE_BRANCH:
6874 case BFD_RELOC_SCORE16_JMP:
6875 case BFD_RELOC_SCORE16_BRANCH:
6876 case BFD_RELOC_VTABLE_ENTRY:
6877 case BFD_RELOC_VTABLE_INHERIT:
6878 case BFD_RELOC_SCORE_GPREL15:
6879 case BFD_RELOC_SCORE_GOT15:
6880 case BFD_RELOC_SCORE_DUMMY_HI16:
6881 case BFD_RELOC_SCORE_GOT_LO16:
6882 case BFD_RELOC_SCORE_CALL15:
6883 case BFD_RELOC_GPREL32:
6884 case BFD_RELOC_NONE:
6885 code = fixp->fx_r_type;
6886 break;
6887 default:
6888 type = _("<unknown>");
6889 as_bad_where (fixp->fx_file, fixp->fx_line,
6890 _("cannot represent %s relocation in this object file format"), type);
6891 return NULL;
6892 }
6893
6894 reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
6895 if (reloc->howto == NULL)
6896 {
6897 as_bad_where (fixp->fx_file, fixp->fx_line,
6898 _("cannot represent %s relocation in this object file format1"),
6899 bfd_get_reloc_code_name (code));
6900 return NULL;
6901 }
6902 /* HACK: Since arm ELF uses Rel instead of Rela, encode the
6903 vtable entry to be used in the relocation's section offset. */
6904 if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
6905 reloc->address = fixp->fx_offset;
6906
6907 return retval;
6908}