xref: /netbsd-src/external/gpl3/binutils.old/dist/gas/config/tc-score7.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1 /* tc-score7.c -- Assembler for Score7
2    Copyright (C) 2009-2022 Free Software Foundation, Inc.
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"
30 #include "libiberty.h"
31 
32 #ifdef OBJ_ELF
33 #include "elf/score.h"
34 #include "dwarf2dbg.h"
35 #endif
36 
37 static void s7_do_ldst_insn (char *);
38 static void s7_do_crdcrscrsimm5 (char *);
39 static void s7_do_ldst_unalign (char *);
40 static void s7_do_ldst_atomic (char *);
41 static void s7_do_ldst_cop (char *);
42 static void s7_do_macro_li_rdi32 (char *);
43 static void s7_do_macro_la_rdi32 (char *);
44 static void s7_do_macro_rdi32hi (char *);
45 static void s7_do_macro_rdi32lo (char *);
46 static void s7_do_macro_mul_rdrsrs (char *);
47 static void s7_do_macro_ldst_label (char *);
48 static void s7_do_branch (char *);
49 static void s7_do_jump (char *);
50 static void s7_do_empty (char *);
51 static void s7_do_rdrsrs (char *);
52 static void s7_do_rdsi16 (char *);
53 static void s7_do_rdrssi14 (char *);
54 static void s7_do_sub_rdsi16 (char *);
55 static void s7_do_sub_rdrssi14 (char *);
56 static void s7_do_rdrsi5 (char *);
57 static void s7_do_rdrsi14 (char *);
58 static void s7_do_rdi16 (char *);
59 static void s7_do_xrsi5 (char *);
60 static void s7_do_rdrs (char *);
61 static void s7_do_rdxrs (char *);
62 static void s7_do_rsrs (char *);
63 static void s7_do_rdcrs (char *);
64 static void s7_do_rdsrs (char *);
65 static void s7_do_rd (char *);
66 static void s7_do_rs (char *);
67 static void s7_do_i15 (char *);
68 static void s7_do_xi5x (char *);
69 static void s7_do_ceinst (char *);
70 static void s7_do_cache (char *);
71 static void s7_do16_rdrs (char *);
72 static void s7_do16_rs (char *);
73 static void s7_do16_xrs (char *);
74 static void s7_do16_mv_rdrs (char *);
75 static void s7_do16_hrdrs (char *);
76 static void s7_do16_rdhrs (char *);
77 static void s7_do16_rdi4 (char *);
78 static void s7_do16_rdi5 (char *);
79 static void s7_do16_xi5 (char *);
80 static void s7_do16_ldst_insn (char *);
81 static void s7_do16_ldst_imm_insn (char *);
82 static void s7_do16_push_pop (char *);
83 static void s7_do16_branch (char *);
84 static void s7_do16_jump (char *);
85 static void s7_do_rdi16_pic (char *);
86 static void s7_do_addi_s_pic (char *);
87 static void s7_do_addi_u_pic (char *);
88 static 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 
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 
153 
154 /* Enumeration matching entries in table above.  */
155 enum 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 
164 enum s7_score_pic_level
165 {
166   s7_NO_PIC,
167   s7_PIC
168 };
169 static enum s7_score_pic_level s7_score_pic = s7_NO_PIC;
170 
171 enum 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 
190 struct s7_insn_to_dependency
191 {
192   const char *insn_name;
193   enum s7_insn_type_for_dependency type;
194 };
195 
196 struct 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 
207 static 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},
325   /* move special instruction.  */
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 
396 static 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},
402   /* Status register.  */
403   {s7_D_mtcr, "cr0", s7_D_all_insn, "", 5, 4, 0},
404   /* CCR register.  */
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 
425 
426 /* Used to contain constructed error messages.  */
427 static char s7_err_msg[255];
428 static int s7_fix_data_dependency = 0;
429 static int s7_warn_fix_data_dependency = 1;
430 
431 static int s7_in_my_get_expression = 0;
432 
433 /* Default, pop warning message when using r1.  */
434 static int s7_nor1 = 1;
435 
436 /* Default will do instruction relax, -O0 will set s7_g_opt = 0.  */
437 static unsigned int s7_g_opt = 1;
438 
439 /* The size of the small data section.  */
440 static unsigned int s7_g_switch_value = 8;
441 
442 static segT s7_pdr_seg;
443 
444 struct 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 };
463 static struct s7_score_it s7_inst;
464 
465 typedef 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;
476 static s7_procS s7_cur_proc;
477 static s7_procS *s7_cur_proc_ptr;
478 static int s7_numprocs;
479 
480 /* Structure for a hash table entry for a register.  */
481 struct s7_reg_entry
482 {
483   const char *name;
484   int number;
485 };
486 
487 static 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 
500 static const struct s7_reg_entry s7_score_srn_table[] =
501 {
502   {"sr0", 0}, {"sr1", 1}, {"sr2", 2},
503   {NULL, 0}
504 };
505 
506 static 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 
519 struct s7_reg_map
520 {
521   const struct s7_reg_entry *names;
522   int max_regno;
523   htab_t htab;
524   const char *expected;
525 };
526 
527 static 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 
534 static htab_t s7_score_ops_hsh = NULL;
535 static htab_t s7_dependency_insn_hsh = NULL;
536 
537 
538 struct s7_datafield_range
539 {
540   int data_type;
541   int bits;
542   int range[2];
543 };
544 
545 static 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 
595 struct s7_asm_opcode
596 {
597   /* Instruction name.  */
598   const char *template_name;
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 
616 static 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 
644 static 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 
1089 static int s7_university_version = 0;
1090 static int s7_vector_size = s7_SCORE7_PIPELINE;
1091 static struct s7_score_it s7_dependency_vector[s7_SCORE7_PIPELINE];
1092 
1093 static int s7_score7d = 1;
1094 
1095 
1096 
1097 static int
s7_end_of_line(char * str)1098 s7_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 
1114 static int
s7_score_reg_parse(char ** ccp,htab_t htab)1115 s7_score_reg_parse (char **ccp, htab_t htab)
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;
1132   reg = (struct s7_reg_entry *) str_hash_find (htab, start);
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.  */
1144 static int
s7_reg_required_here(char ** str,int shift,enum s7_score_reg_type reg_type)1145 s7_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 
1183 static int
s7_skip_past_comma(char ** str)1184 s7_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 
1210 static void
s7_do_rdrsrs(char * str)1211 s7_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 
1243 static int
s7_walk_no_bignums(symbolS * sp)1244 s7_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 
1257 static int
s7_my_get_expression(expressionS * ep,char ** str)1258 s7_my_get_expression (expressionS * ep, char **str)
1259 {
1260   char *save_in;
1261 
1262   save_in = input_line_pointer;
1263   input_line_pointer = *str;
1264   s7_in_my_get_expression = 1;
1265 
1266   (void) expression (ep);
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 
1313 static bfd_signed_vma
s7_validate_immediate(bfd_signed_vma val,unsigned int data_type,int hex_p)1314 s7_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 
1458 static int
s7_data_op2(char ** str,int shift,enum score_data_type data_type)1459 s7_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 
1685 static void
s7_do_rdsi16(char * str)1686 s7_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 
1718 static void
s7_do_sub_rdsi16(char * str)1719 s7_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 
1732 static void
s7_do_rdrssi14(char * str)1733 s7_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 
1746 static void
s7_do_sub_rdrssi14(char * str)1747 s7_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 
1761 static void
s7_do_rdrsi5(char * str)1762 s7_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 
1786 static void
s7_do_rdrsi14(char * str)1787 s7_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 
1801 static void
s7_do_xrsi5(char * str)1802 s7_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 
1823 static void
s7_do_rdi16(char * str)1824 s7_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 
1835 static void
s7_do_macro_rdi32hi(char * str)1836 s7_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 
1846 static void
s7_do_macro_rdi32lo(char * str)1847 s7_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 
1859 static void
s7_do_rdi16_pic(char * str)1860 s7_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 
1872 static void
s7_do_addi_s_pic(char * str)1873 s7_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 
1885 static void
s7_do_addi_u_pic(char * str)1886 s7_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 
1898 static void
s7_do_rd(char * str)1899 s7_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 
1907 static void
s7_do_rs(char * str)1908 s7_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 
1925 static void
s7_do_i15(char * str)1926 s7_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 
1934 static void
s7_do_xi5x(char * str)1935 s7_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 
1949 static void
s7_do_rdrs(char * str)1950 s7_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.  */
2003 static void
s7_do_rdcrs(char * str)2004 s7_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 
2016 static void
s7_do_rdsrs(char * str)2017 s7_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 
2039 static void
s7_do_rdxrs(char * str)2040 s7_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>.  */
2061 static void
s7_do_rsrs(char * str)2062 s7_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 
2082 static void
s7_do_ceinst(char * str)2083 s7_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 
2111 static int
s7_reglow_required_here(char ** str,int shift)2112 s7_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 
2143 static void
s7_do16_rdrs(char * str)2144 s7_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 
2181 static void
s7_do16_rs(char * str)2182 s7_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 
2202 static void
s7_do16_xrs(char * str)2203 s7_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 
2219 static int
s7_reghigh_required_here(char ** str,int shift)2220 s7_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 
2245 static void
s7_do16_hrdrs(char * str)2246 s7_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 
2263 static void
s7_do16_rdhrs(char * str)2264 s7_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 
2286 static fixS *
s7_fix_new_score(fragS * frag,int where,short int size,expressionS * exp,int pc_rel,int reloc)2287 s7_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 
2306 static void
s7_init_dependency_vector(void)2307 s7_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 
2317 static enum s7_insn_type_for_dependency
s7_dependency_type_from_insn(char * insn_name)2318 s7_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);
2324   tmp = (const struct s7_insn_to_dependency *)
2325     str_hash_find (s7_dependency_insn_hsh, name);
2326 
2327   if (tmp)
2328     return tmp->type;
2329 
2330   return s7_D_all_insn;
2331 }
2332 
2333 static int
s7_check_dependency(char * pre_insn,char * pre_reg,char * cur_insn,char * cur_reg,int * warn_or_error)2334 s7_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 
2374 static void
s7_number_to_chars(char * buf,valueT val,int n)2375 s7_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 
2383 static void
s7_build_one_frag(struct s7_score_it one_inst)2384 s7_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 
2419 static void
s7_handle_dependency(struct s7_score_it * theinst)2420 s7_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)
2493 		    as_warn (_("Fix data dependency: %s %s -- %s %s (insert %d nop!/%d)"),
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)
2512 		    as_warn (_("Fix data dependency: %s %s -- %s %s (insert 1 pflush/%d)"),
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 		{
2528                   as_bad (_("data dependency: %s %s -- %s %s (%d/%d bubble)"),
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 		{
2535                   as_warn (_("data dependency: %s %s -- %s %s (%d/%d bubble)"),
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 
2545 static enum insn_class
s7_get_insn_class_from_type(enum score_insn_type type)2546 s7_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 
2621 static unsigned long
s7_adjust_paritybit(unsigned long m_code,enum insn_class i_class)2622 s7_adjust_paritybit (unsigned long m_code, enum insn_class i_class)
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 
2630   if (i_class == INSN_CLASS_32)
2631     {
2632       pb_high = 0x80000000;
2633       pb_low = 0x00008000;
2634     }
2635   else if (i_class == INSN_CLASS_16)
2636     {
2637       pb_high = 0;
2638       pb_low = 0;
2639     }
2640   else if (i_class == INSN_CLASS_PCE)
2641     {
2642       pb_high = 0;
2643       pb_low = 0x00008000;
2644     }
2645   else if (i_class == INSN_CLASS_SYN)
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 
2664 static void
s7_gen_insn_frag(struct s7_score_it * part_1,struct s7_score_it * part_2)2665 s7_gen_insn_frag (struct s7_score_it *part_1, struct s7_score_it *part_2)
2666 {
2667   char *p;
2668   bool pce_p = false;
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 
2675   pce_p = inst2 != NULL;
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
2725      actually will call frag_wane.
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 
2772 static void
s7_parse_16_32_inst(char * insnstr,bool gen_frag_p)2773 s7_parse_16_32_inst (char *insnstr, bool gen_frag_p)
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 
2793   opcode = (const struct s7_asm_opcode *) str_hash_find (s7_score_ops_hsh,
2794 							 operator);
2795   *p = c;
2796 
2797   memset (&s7_inst, '\0', sizeof (s7_inst));
2798   strcpy (s7_inst.str, insnstr);
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;
2807       strcpy (s7_inst.name, opcode->template_name);
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 
2822 static int
s7_append_insn(char * str,bool gen_frag_p)2823 s7_append_insn (char *str, bool gen_frag_p)
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;  */
2842 static void
s7_do16_mv_rdrs(char * str)2843 s7_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);
2875               if (s7_append_insn (append_str, true) == (int) s7_FAIL)
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);
2894               if (s7_append_insn (append_str, true) == (int) s7_FAIL)
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 
2904 static void
s7_do16_rdi4(char * str)2905 s7_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 
2947 static void
s7_do16_rdi5(char * str)2948 s7_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 
2967 static void
s7_do16_xi5(char * str)2968 s7_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 
2984 static int
s7_validate_immediate_align(int val,unsigned int data_type)2985 s7_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 
3007 static int
s7_exp_ldst_offset(char ** str,int shift,unsigned int data_type)3008 s7_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 
3092 static void
s7_do_ldst_insn(char * str)3093 s7_do_ldst_insn (char *str)
3094 {
3095   int pre_inc = 0;
3096   int conflict_reg;
3097   int value;
3098   char * temp;
3099   char *dataptr;
3100   int reg;
3101   int ldst_idx = 0;
3102 
3103   int hex_p = 0;
3104 
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             {
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.  */
3606 static void
s7_do_cache(char * str)3607 s7_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 
3669 static void
s7_do_crdcrscrsimm5(char * str)3670 s7_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.  */
3699 static void
s7_do_ldst_cop(char * str)3700 s7_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 
3737 static void
s7_do16_ldst_insn(char * str)3738 s7_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 
3780 static void
s7_do16_ldst_imm_insn(char * str)3781 s7_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 
3853 static void
s7_do16_push_pop(char * str)3854 s7_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.  */
3934 static void
s7_do_ldst_unalign(char * str)3935 s7_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 
4034 static void
s7_do_ldst_atomic(char * str)4035 s7_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 
4078 static void
s7_build_relax_frag(struct s7_score_it fix_insts[s7_RELAX_INST_NUM],int fix_num ATTRIBUTE_UNUSED,struct s7_score_it var_insts[s7_RELAX_INST_NUM],int var_num,symbolS * add_symbol)4079 s7_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 
4178 static void
s7_build_la_pic(int reg_rd,expressionS exp)4179 s7_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)  */
4203       sprintf (tmp, "lw_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
4204       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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));
4217       sprintf (tmp, "addi_s_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
4218       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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)  */
4227       sprintf (tmp, "lw_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
4228       if (s7_append_insn (tmp, true) == (int) s7_FAIL)
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);
4237       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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)  */
4244       sprintf (tmp, "addi_s_pic r%d, %s + %d", reg_rd,
4245 	       S_GET_NAME (add_symbol), (int) add_number);
4246       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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)  */
4258       sprintf (tmp, "lw_pic r%d, %s", reg_rd, S_GET_NAME (add_symbol));
4259       if (s7_append_insn (tmp, true) == (int) s7_FAIL)
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);
4268       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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>
4275          but, if lo is out of 16 bit, make hi plus 1  */
4276       if ((lo < -0x8000) || (lo > 0x7fff))
4277 	{
4278 	  hi += 1;
4279 	}
4280       sprintf (tmp, "ldis_pic r1, %d", hi);
4281       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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);
4293       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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)  */
4300       sprintf (tmp, "addi_u_pic r1, %s + %d", S_GET_NAME (add_symbol), lo);
4301       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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);
4309       if (s7_append_insn (tmp, true) == (int) s7_FAIL)
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 
4321 static void
s7_do_macro_la_rdi32(char * str)4322 s7_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);
4374                   if (s7_append_insn (append_str, true) == (int) s7_FAIL)
4375 		    return;
4376 
4377                   sprintf (append_str, "ld_i32lo r%d, %s", reg_rd, keep_data);
4378                   if (s7_append_insn (append_str, true) == (int) s7_FAIL)
4379 		    return;
4380 		}
4381 	      else
4382 		{
4383 		  gas_assert (s7_inst.reloc.exp.X_add_symbol);
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 
4396 static void
s7_do_macro_li_rdi32(char * str)4397 s7_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 
4454               if (s7_append_insn (append_str, true) == (int) s7_FAIL)
4455 		return;
4456               else
4457                 {
4458                   sprintf (append_str, "ld_i32lo r%d, %s", reg_rd, keep_data);
4459                   if (s7_append_insn (append_str, true) == (int) s7_FAIL)
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 
4472 static void
s7_do_macro_mul_rdrsrs(char * str)4473 s7_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.  */
4538           if (s7_append_insn (append_str, true) == (int) s7_FAIL)
4539 	    return;
4540 
4541           /* Output mfcel or mfceh.  */
4542           if (s7_append_insn (append_str1, true) == (int) s7_FAIL)
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 
4551 static void
s7_exp_macro_ldst_abs(char * str)4552 s7_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);
4577   s7_append_insn (append_str, true);
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 
4586 static int
s7_nopic_need_relax(symbolS * sym,int before_relaxing)4587 s7_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
4629 	      && !startswith (segname, ".sdata.")
4630 	      && !startswith (segname, ".gnu.linkonce.s."));
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 
4640 static void
s7_build_lwst_pic(int reg_rd,expressionS exp,const char * insn_name)4641 s7_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)  */
4665       sprintf (tmp, "lw_pic r1, %s", S_GET_NAME (add_symbol));
4666       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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));
4677       sprintf (tmp, "addi_s_pic r1, %s", S_GET_NAME (add_symbol));
4678       if (s7_append_insn (tmp, false) == (int) s7_FAIL)
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);
4686       if (s7_append_insn (tmp, true) == (int) s7_FAIL)
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 
4701 static void
s7_do_macro_ldst_label(char * str)4702 s7_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;
4790           s7_build_lwst_pic (reg_rd, s7_inst.reloc.exp,
4791                              s7_score_ldst_insns[ldst_idx * 3 + 0].template_name);
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     {
4830       if (s7_append_insn (append_str[i], false) == (int) s7_FAIL)
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 
4902 static void
s7_do_lw_pic(char * str)4903 s7_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 
4930 static void
s7_do_empty(char * str)4931 s7_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 
4961 static void
s7_do_jump(char * str)4962 s7_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 
4991 static void
s7_do16_jump(char * str)4992 s7_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 
5016 static void
s7_do_branch(char * str)5017 s7_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 
5057 static void
s7_do16_branch(char * str)5058 s7_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 
5084 static void
s7_build_score_ops_hsh(void)5085 s7_build_score_ops_hsh (void)
5086 {
5087   unsigned int i;
5088   static struct obstack insn_obstack;
5089 
5090   obstack_begin (&insn_obstack, 4000);
5091   for (i = 0; i < sizeof (s7_score_insns) / sizeof (struct s7_asm_opcode); i++)
5092     {
5093       const struct s7_asm_opcode *insn = s7_score_insns + i;
5094       size_t len = strlen (insn->template_name);
5095       struct s7_asm_opcode *new_opcode;
5096       char *template_name;
5097       new_opcode = (struct s7_asm_opcode *)
5098           obstack_alloc (&insn_obstack, sizeof (struct s7_asm_opcode));
5099       template_name = (char *) obstack_alloc (&insn_obstack, len + 1);
5100 
5101       strcpy (template_name, insn->template_name);
5102       new_opcode->template_name = template_name;
5103       new_opcode->parms = insn->parms;
5104       new_opcode->value = insn->value;
5105       new_opcode->relax_value = insn->relax_value;
5106       new_opcode->type = insn->type;
5107       new_opcode->bitmask = insn->bitmask;
5108       str_hash_insert (s7_score_ops_hsh, new_opcode->template_name,
5109 		       new_opcode, 0);
5110     }
5111 }
5112 
5113 static void
s7_build_dependency_insn_hsh(void)5114 s7_build_dependency_insn_hsh (void)
5115 {
5116   unsigned int i;
5117   static struct obstack dependency_obstack;
5118 
5119   obstack_begin (&dependency_obstack, 4000);
5120   for (i = 0; i < ARRAY_SIZE (s7_insn_to_dependency_table); i++)
5121     {
5122       const struct s7_insn_to_dependency *tmp = s7_insn_to_dependency_table + i;
5123       size_t len = strlen (tmp->insn_name);
5124       struct s7_insn_to_dependency *new_i2d;
5125       char *insn_name;
5126 
5127       new_i2d = (struct s7_insn_to_dependency *)
5128           obstack_alloc (&dependency_obstack,
5129                          sizeof (struct s7_insn_to_dependency));
5130       insn_name = (char *) obstack_alloc (&dependency_obstack, len + 1);
5131 
5132       strcpy (insn_name, tmp->insn_name);
5133       new_i2d->insn_name = insn_name;
5134       new_i2d->type = tmp->type;
5135       str_hash_insert (s7_dependency_insn_hsh, new_i2d->insn_name, new_i2d, 0);
5136     }
5137 }
5138 
5139 static valueT
s7_md_chars_to_number(char * buf,int n)5140 s7_md_chars_to_number (char *buf, int n)
5141 {
5142   valueT result = 0;
5143   unsigned char *where = (unsigned char *) buf;
5144 
5145   if (target_big_endian)
5146     {
5147       while (n--)
5148         {
5149           result <<= 8;
5150           result |= (*where++ & 255);
5151         }
5152     }
5153   else
5154     {
5155       while (n--)
5156         {
5157           result <<= 8;
5158           result |= (where[n] & 255);
5159         }
5160     }
5161 
5162   return result;
5163 }
5164 
5165 /* Return true if the given symbol should be considered local for s7_PIC.  */
5166 
5167 static bool
s7_pic_need_relax(symbolS * sym,asection * segtype)5168 s7_pic_need_relax (symbolS *sym, asection *segtype)
5169 {
5170   asection *symsec;
5171   bool linkonce;
5172 
5173   /* Handle the case of a symbol equated to another symbol.  */
5174   while (symbol_equated_reloc_p (sym))
5175     {
5176       symbolS *n;
5177 
5178       /* It's possible to get a loop here in a badly written
5179 	 program.  */
5180       n = symbol_get_value_expression (sym)->X_add_symbol;
5181       if (n == sym)
5182 	break;
5183       sym = n;
5184     }
5185 
5186   symsec = S_GET_SEGMENT (sym);
5187 
5188   /* Duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
5189   linkonce = false;
5190   if (symsec != segtype && ! S_IS_LOCAL (sym))
5191     {
5192       if ((bfd_section_flags (symsec) & SEC_LINK_ONCE) != 0)
5193 	linkonce = true;
5194 
5195       /* The GNU toolchain uses an extension for ELF: a section
5196 	  beginning with the magic string .gnu.linkonce is a linkonce
5197 	  section.  */
5198       if (startswith (segment_name (symsec), ".gnu.linkonce"))
5199 	linkonce = true;
5200     }
5201 
5202   /* This must duplicate the test in adjust_reloc_syms.  */
5203   return (!bfd_is_und_section (symsec)
5204 	  && !bfd_is_abs_section (symsec)
5205 	  && !bfd_is_com_section (symsec)
5206 	  && !linkonce
5207 #ifdef OBJ_ELF
5208 	  /* A global or weak symbol is treated as external.  */
5209 	  && (OUTPUT_FLAVOR != bfd_target_elf_flavour
5210 	      || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
5211 #endif
5212 	  );
5213 }
5214 
5215 static int
s7_judge_size_before_relax(fragS * fragp,asection * sec)5216 s7_judge_size_before_relax (fragS * fragp, asection *sec)
5217 {
5218   int change = 0;
5219 
5220   if (s7_score_pic == s7_NO_PIC)
5221     change = s7_nopic_need_relax (fragp->fr_symbol, 0);
5222   else
5223     change = s7_pic_need_relax (fragp->fr_symbol, sec);
5224 
5225   if (change == 1)
5226     {
5227       /* Only at the first time determining whether s7_GP instruction relax should be done,
5228          return the difference between instruction size and instruction relax size.  */
5229       if (fragp->fr_opcode == NULL)
5230 	{
5231 	  fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype);
5232 	  fragp->fr_opcode = fragp->fr_literal + s7_RELAX_RELOC1 (fragp->fr_subtype);
5233           return s7_RELAX_NEW (fragp->fr_subtype) - s7_RELAX_OLD (fragp->fr_subtype);
5234 	}
5235     }
5236 
5237   return 0;
5238 }
5239 
5240 static int
s7_b32_relax_to_b16(fragS * fragp)5241 s7_b32_relax_to_b16 (fragS * fragp)
5242 {
5243   int grows = 0;
5244   int relaxable_p = 0;
5245   int frag_addr = fragp->fr_address + fragp->insn_addr;
5246 
5247   addressT symbol_address = 0;
5248   symbolS *s;
5249   offsetT offset;
5250   unsigned long value;
5251   unsigned long abs_value;
5252 
5253   /* FIXME : here may be able to modify better .
5254      I don't know how to get the fragp's section ,
5255      so in relax stage , it may be wrong to calculate the symbol's offset when the frag's section
5256      is different from the symbol's.  */
5257 
5258   relaxable_p = s7_RELAX_OPT (fragp->fr_subtype);
5259 
5260   s = fragp->fr_symbol;
5261   /* b/bl immediate  */
5262   if (s == NULL)
5263     frag_addr = 0;
5264   else
5265     symbol_address = (addressT) symbol_get_frag (s)->fr_address;
5266 
5267   value = s7_md_chars_to_number (fragp->fr_literal, s7_INSN_SIZE);
5268 
5269   /* b 32's offset : 20 bit, b 16's tolerate field : 0xff.  */
5270   offset = ((value & 0x3ff0000) >> 6) | (value & 0x3fe);
5271   if ((offset & 0x80000) == 0x80000)
5272     offset |= 0xfff00000;
5273 
5274   abs_value = offset + symbol_address - frag_addr;
5275   if ((abs_value & 0x80000000) == 0x80000000)
5276     abs_value = 0xffffffff - abs_value + 1;
5277 
5278   /* Relax branch 32 to branch 16.  */
5279   if (relaxable_p && ((abs_value & 0xffffff00) == 0)
5280       && (S_IS_DEFINED (s) && !S_IS_COMMON (s) && !S_IS_EXTERNAL (s)))
5281     {
5282       /* do nothing.  */
5283     }
5284   else
5285     {
5286       /* Branch 32 can not be relaxed to b 16, so clear OPT bit.  */
5287       fragp->fr_opcode = NULL;
5288       fragp->fr_subtype = s7_RELAX_OPT_CLEAR (fragp->fr_subtype);
5289     }
5290 
5291   return grows;
5292 }
5293 
5294 static void
s7_parse_pce_inst(char * insnstr)5295 s7_parse_pce_inst (char *insnstr)
5296 {
5297   char c;
5298   char *p;
5299   char *q;
5300   char first[s7_MAX_LITERAL_POOL_SIZE];
5301   char second[s7_MAX_LITERAL_POOL_SIZE];
5302   struct s7_score_it pec_part_1;
5303 
5304   /* Get first part string of PCE.  */
5305   p = strstr (insnstr, "||");
5306   c = *p;
5307   *p = '\0';
5308   strcpy (first, insnstr);
5309 
5310   /* Get second part string of PCE.  */
5311   *p = c;
5312   p += 2;
5313   strcpy (second, p);
5314 
5315   s7_parse_16_32_inst (first, false);
5316   if (s7_inst.error)
5317     return;
5318 
5319   memcpy (&pec_part_1, &s7_inst, sizeof (s7_inst));
5320 
5321   q = second;
5322   while (q && *q)
5323     {
5324       *q = TOLOWER (*q);
5325       q++;
5326     }
5327 
5328   s7_parse_16_32_inst (second, false);
5329   if (s7_inst.error)
5330     return;
5331 
5332   if (   ((pec_part_1.size == s7_INSN_SIZE) && (s7_inst.size == s7_INSN_SIZE))
5333       || ((pec_part_1.size == s7_INSN_SIZE) && (s7_inst.size == s7_INSN16_SIZE))
5334       || ((pec_part_1.size == s7_INSN16_SIZE) && (s7_inst.size == s7_INSN_SIZE)))
5335     {
5336       s7_inst.error = _("pce instruction error (16 bit || 16 bit)'");
5337       strcpy (s7_inst.str, insnstr);
5338       return;
5339     }
5340 
5341   if (!s7_inst.error)
5342     s7_gen_insn_frag (&pec_part_1, &s7_inst);
5343 }
5344 
5345 
5346 
5347 static void
s7_insert_reg(const struct s7_reg_entry * r,htab_t htab)5348 s7_insert_reg (const struct s7_reg_entry *r, htab_t htab)
5349 {
5350   int i = 0;
5351   int len = strlen (r->name) + 2;
5352   char *buf = XNEWVEC (char, len);
5353   char *buf2 = XNEWVEC (char, len);
5354 
5355   strcpy (buf + i, r->name);
5356   for (i = 0; buf[i]; i++)
5357     {
5358       buf2[i] = TOUPPER (buf[i]);
5359     }
5360   buf2[i] = '\0';
5361 
5362   str_hash_insert (htab, buf, r, 0);
5363   str_hash_insert (htab, buf2, r, 0);
5364 }
5365 
5366 static void
s7_build_reg_hsh(struct s7_reg_map * map)5367 s7_build_reg_hsh (struct s7_reg_map *map)
5368 {
5369   const struct s7_reg_entry *r;
5370 
5371   map->htab = str_htab_create ();
5372   for (r = map->names; r->name != NULL; r++)
5373     s7_insert_reg (r, map->htab);
5374 }
5375 
5376 
5377 
5378 /* If we change section we must dump the literal pool first.  */
5379 static void
s7_s_score_bss(int ignore ATTRIBUTE_UNUSED)5380 s7_s_score_bss (int ignore ATTRIBUTE_UNUSED)
5381 {
5382   subseg_set (bss_section, (subsegT) get_absolute_expression ());
5383   demand_empty_rest_of_line ();
5384 }
5385 
5386 static void
s7_s_score_text(int ignore)5387 s7_s_score_text (int ignore)
5388 {
5389   obj_elf_text (ignore);
5390   record_alignment (now_seg, 2);
5391 }
5392 
5393 static void
s7_s_section(int ignore)5394 s7_s_section (int ignore)
5395 {
5396   obj_elf_section (ignore);
5397   if ((bfd_section_flags (now_seg) & SEC_CODE) != 0)
5398     record_alignment (now_seg, 2);
5399 
5400 }
5401 
5402 static void
s7_s_change_sec(int sec)5403 s7_s_change_sec (int sec)
5404 {
5405   segT seg;
5406 
5407 #ifdef OBJ_ELF
5408   /* The ELF backend needs to know that we are changing sections, so
5409      that .previous works correctly.  We could do something like check
5410      for an obj_section_change_hook macro, but that might be confusing
5411      as it would not be appropriate to use it in the section changing
5412      functions in read.c, since obj-elf.c intercepts those.  FIXME:
5413      This should be cleaner, somehow.  */
5414   obj_elf_section_change_hook ();
5415 #endif
5416   switch (sec)
5417     {
5418     case 'r':
5419       seg = subseg_new (s7_RDATA_SECTION_NAME, (subsegT) get_absolute_expression ());
5420       bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_READONLY
5421 				   | SEC_RELOC | SEC_DATA));
5422       if (strcmp (TARGET_OS, "elf") != 0)
5423         record_alignment (seg, 4);
5424       demand_empty_rest_of_line ();
5425       break;
5426     case 's':
5427       seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
5428       bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_RELOC
5429 				   | SEC_DATA | SEC_SMALL_DATA));
5430       if (strcmp (TARGET_OS, "elf") != 0)
5431         record_alignment (seg, 4);
5432       demand_empty_rest_of_line ();
5433       break;
5434     }
5435 }
5436 
5437 static void
s7_s_score_mask(int reg_type ATTRIBUTE_UNUSED)5438 s7_s_score_mask (int reg_type  ATTRIBUTE_UNUSED)
5439 {
5440   long mask, off;
5441 
5442   if (s7_cur_proc_ptr == NULL)
5443     {
5444       as_warn (_(".mask outside of .ent"));
5445       demand_empty_rest_of_line ();
5446       return;
5447     }
5448   if (get_absolute_expression_and_terminator (&mask) != ',')
5449     {
5450       as_warn (_("Bad .mask directive"));
5451       --input_line_pointer;
5452       demand_empty_rest_of_line ();
5453       return;
5454     }
5455   off = get_absolute_expression ();
5456   s7_cur_proc_ptr->reg_mask = mask;
5457   s7_cur_proc_ptr->reg_offset = off;
5458   demand_empty_rest_of_line ();
5459 }
5460 
5461 static symbolS *
s7_get_symbol(void)5462 s7_get_symbol (void)
5463 {
5464   int c;
5465   char *name;
5466   symbolS *p;
5467 
5468   c = get_symbol_name (&name);
5469   p = (symbolS *) symbol_find_or_make (name);
5470   (void) restore_line_pointer (c);
5471   return p;
5472 }
5473 
5474 static long
s7_get_number(void)5475 s7_get_number (void)
5476 {
5477   int negative = 0;
5478   long val = 0;
5479 
5480   if (*input_line_pointer == '-')
5481     {
5482       ++input_line_pointer;
5483       negative = 1;
5484     }
5485   if (!ISDIGIT (*input_line_pointer))
5486     as_bad (_("expected simple number"));
5487   if (input_line_pointer[0] == '0')
5488     {
5489       if (input_line_pointer[1] == 'x')
5490         {
5491           input_line_pointer += 2;
5492           while (ISXDIGIT (*input_line_pointer))
5493             {
5494               val <<= 4;
5495               val |= hex_value (*input_line_pointer++);
5496             }
5497           return negative ? -val : val;
5498         }
5499       else
5500         {
5501           ++input_line_pointer;
5502           while (ISDIGIT (*input_line_pointer))
5503             {
5504               val <<= 3;
5505               val |= *input_line_pointer++ - '0';
5506             }
5507           return negative ? -val : val;
5508         }
5509     }
5510   if (!ISDIGIT (*input_line_pointer))
5511     {
5512       printf (_(" *input_line_pointer == '%c' 0x%02x\n"), *input_line_pointer, *input_line_pointer);
5513       as_warn (_("invalid number"));
5514       return -1;
5515     }
5516   while (ISDIGIT (*input_line_pointer))
5517     {
5518       val *= 10;
5519       val += *input_line_pointer++ - '0';
5520     }
5521   return negative ? -val : val;
5522 }
5523 
5524 /* The .aent and .ent directives.  */
5525 
5526 static void
s7_s_score_ent(int aent)5527 s7_s_score_ent (int aent)
5528 {
5529   symbolS *symbolP;
5530   int maybe_text;
5531 
5532   symbolP = s7_get_symbol ();
5533   if (*input_line_pointer == ',')
5534     ++input_line_pointer;
5535   SKIP_WHITESPACE ();
5536   if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
5537     s7_get_number ();
5538 
5539   if ((bfd_section_flags (now_seg) & SEC_CODE) != 0)
5540     maybe_text = 1;
5541   else
5542     maybe_text = 0;
5543   if (!maybe_text)
5544     as_warn (_(".ent or .aent not in text section."));
5545   if (!aent && s7_cur_proc_ptr)
5546     as_warn (_("missing .end"));
5547   if (!aent)
5548     {
5549       s7_cur_proc_ptr = &s7_cur_proc;
5550       s7_cur_proc_ptr->reg_mask = 0xdeadbeaf;
5551       s7_cur_proc_ptr->reg_offset = 0xdeadbeaf;
5552       s7_cur_proc_ptr->fpreg_mask = 0xdeafbeaf;
5553       s7_cur_proc_ptr->leaf = 0xdeafbeaf;
5554       s7_cur_proc_ptr->frame_offset = 0xdeafbeaf;
5555       s7_cur_proc_ptr->frame_reg = 0xdeafbeaf;
5556       s7_cur_proc_ptr->pc_reg = 0xdeafbeaf;
5557       s7_cur_proc_ptr->isym = symbolP;
5558       symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
5559       ++s7_numprocs;
5560       if (debug_type == DEBUG_STABS)
5561         stabs_generate_asm_func (S_GET_NAME (symbolP), S_GET_NAME (symbolP));
5562     }
5563   demand_empty_rest_of_line ();
5564 }
5565 
5566 static void
s7_s_score_frame(int ignore ATTRIBUTE_UNUSED)5567 s7_s_score_frame (int ignore ATTRIBUTE_UNUSED)
5568 {
5569   char *backupstr;
5570   char str[30];
5571   long val;
5572   int i = 0;
5573 
5574   backupstr = input_line_pointer;
5575 
5576 #ifdef OBJ_ELF
5577   if (s7_cur_proc_ptr == NULL)
5578     {
5579       as_warn (_(".frame outside of .ent"));
5580       demand_empty_rest_of_line ();
5581       return;
5582     }
5583   s7_cur_proc_ptr->frame_reg = s7_reg_required_here ((&backupstr), 0, s7_REG_TYPE_SCORE);
5584   SKIP_WHITESPACE ();
5585   s7_skip_past_comma (&backupstr);
5586   while (*backupstr != ',')
5587     {
5588       str[i] = *backupstr;
5589       i++;
5590       backupstr++;
5591     }
5592   str[i] = '\0';
5593   val = atoi (str);
5594 
5595   SKIP_WHITESPACE ();
5596   s7_skip_past_comma (&backupstr);
5597   s7_cur_proc_ptr->frame_offset = val;
5598   s7_cur_proc_ptr->pc_reg = s7_reg_required_here ((&backupstr), 0, s7_REG_TYPE_SCORE);
5599 
5600   SKIP_WHITESPACE ();
5601   s7_skip_past_comma (&backupstr);
5602   i = 0;
5603   while (*backupstr != '\n')
5604     {
5605       str[i] = *backupstr;
5606       i++;
5607       backupstr++;
5608     }
5609   str[i] = '\0';
5610   val = atoi (str);
5611   s7_cur_proc_ptr->leaf = val;
5612   SKIP_WHITESPACE ();
5613   s7_skip_past_comma (&backupstr);
5614 
5615 #endif /* OBJ_ELF */
5616   while (input_line_pointer != backupstr)
5617     input_line_pointer++;
5618 }
5619 
5620 /* The .end directive.  */
5621 
5622 static void
s7_s_score_end(int x ATTRIBUTE_UNUSED)5623 s7_s_score_end (int x ATTRIBUTE_UNUSED)
5624 {
5625   symbolS *p;
5626   int maybe_text;
5627 
5628   /* Generate a .pdr section.  */
5629   segT saved_seg = now_seg;
5630   subsegT saved_subseg = now_subseg;
5631   expressionS exp;
5632   char *fragp;
5633 
5634   if (!is_end_of_line[(unsigned char)*input_line_pointer])
5635     {
5636       p = s7_get_symbol ();
5637       demand_empty_rest_of_line ();
5638     }
5639   else
5640     p = NULL;
5641 
5642   if ((bfd_section_flags (now_seg) & SEC_CODE) != 0)
5643     maybe_text = 1;
5644   else
5645     maybe_text = 0;
5646 
5647   if (!maybe_text)
5648     as_warn (_(".end not in text section"));
5649   if (!s7_cur_proc_ptr)
5650     {
5651       as_warn (_(".end directive without a preceding .ent directive."));
5652       demand_empty_rest_of_line ();
5653       return;
5654     }
5655   if (p != NULL)
5656     {
5657       gas_assert (S_GET_NAME (p));
5658       if (strcmp (S_GET_NAME (p), S_GET_NAME (s7_cur_proc_ptr->isym)))
5659         as_warn (_(".end symbol does not match .ent symbol."));
5660       if (debug_type == DEBUG_STABS)
5661         stabs_generate_asm_endfunc (S_GET_NAME (p), S_GET_NAME (p));
5662     }
5663   else
5664     as_warn (_(".end directive missing or unknown symbol"));
5665 
5666   if ((s7_cur_proc_ptr->reg_mask == 0xdeadbeaf) ||
5667       (s7_cur_proc_ptr->reg_offset == 0xdeadbeaf) ||
5668       (s7_cur_proc_ptr->leaf == 0xdeafbeaf) ||
5669       (s7_cur_proc_ptr->frame_offset == 0xdeafbeaf) ||
5670       (s7_cur_proc_ptr->frame_reg == 0xdeafbeaf) || (s7_cur_proc_ptr->pc_reg == 0xdeafbeaf));
5671 
5672   else
5673     {
5674       (void) frag_now_fix ();
5675       gas_assert (s7_pdr_seg);
5676       subseg_set (s7_pdr_seg, 0);
5677       /* Write the symbol.  */
5678       exp.X_op = O_symbol;
5679       exp.X_add_symbol = p;
5680       exp.X_add_number = 0;
5681       emit_expr (&exp, 4);
5682       fragp = frag_more (7 * 4);
5683       s7_number_to_chars (fragp, (valueT) s7_cur_proc_ptr->reg_mask, 4);
5684       s7_number_to_chars (fragp + 4, (valueT) s7_cur_proc_ptr->reg_offset, 4);
5685       s7_number_to_chars (fragp + 8, (valueT) s7_cur_proc_ptr->fpreg_mask, 4);
5686       s7_number_to_chars (fragp + 12, (valueT) s7_cur_proc_ptr->leaf, 4);
5687       s7_number_to_chars (fragp + 16, (valueT) s7_cur_proc_ptr->frame_offset, 4);
5688       s7_number_to_chars (fragp + 20, (valueT) s7_cur_proc_ptr->frame_reg, 4);
5689       s7_number_to_chars (fragp + 24, (valueT) s7_cur_proc_ptr->pc_reg, 4);
5690       subseg_set (saved_seg, saved_subseg);
5691 
5692     }
5693   s7_cur_proc_ptr = NULL;
5694 }
5695 
5696 /* Handle the .set pseudo-op.  */
5697 
5698 static void
s7_s_score_set(int x ATTRIBUTE_UNUSED)5699 s7_s_score_set (int x ATTRIBUTE_UNUSED)
5700 {
5701   int i = 0;
5702   char name[s7_MAX_LITERAL_POOL_SIZE];
5703   char * orig_ilp = input_line_pointer;
5704 
5705   while (!is_end_of_line[(unsigned char)*input_line_pointer])
5706     {
5707       name[i] = (char) * input_line_pointer;
5708       i++;
5709       ++input_line_pointer;
5710     }
5711 
5712   name[i] = '\0';
5713 
5714   if (strcmp (name, "nwarn") == 0)
5715     {
5716       s7_warn_fix_data_dependency = 0;
5717     }
5718   else if (strcmp (name, "fixdd") == 0)
5719     {
5720       s7_fix_data_dependency = 1;
5721     }
5722   else if (strcmp (name, "nofixdd") == 0)
5723     {
5724       s7_fix_data_dependency = 0;
5725     }
5726   else if (strcmp (name, "r1") == 0)
5727     {
5728       s7_nor1 = 0;
5729     }
5730   else if (strcmp (name, "nor1") == 0)
5731     {
5732       s7_nor1 = 1;
5733     }
5734   else if (strcmp (name, "optimize") == 0)
5735     {
5736       s7_g_opt = 1;
5737     }
5738   else if (strcmp (name, "volatile") == 0)
5739     {
5740       s7_g_opt = 0;
5741     }
5742   else if (strcmp (name, "pic") == 0)
5743     {
5744       s7_score_pic = s7_PIC;
5745     }
5746   else
5747     {
5748       input_line_pointer = orig_ilp;
5749       s_set (0);
5750     }
5751 }
5752 
5753 /* Handle the .cpload pseudo-op.  This is used when generating s7_PIC code.  It sets the
5754    $gp register for the function based on the function address, which is in the register
5755    named in the argument. This uses a relocation against GP_DISP_LABEL, which is handled
5756    specially by the linker.  The result is:
5757    ldis gp, %hi(GP_DISP_LABEL)
5758    ori  gp, %low(GP_DISP_LABEL)
5759    add  gp, gp, .cpload argument
5760    The .cpload argument is normally r29.  */
5761 
5762 static void
s7_s_score_cpload(int ignore ATTRIBUTE_UNUSED)5763 s7_s_score_cpload (int ignore ATTRIBUTE_UNUSED)
5764 {
5765   int reg;
5766   char insn_str[s7_MAX_LITERAL_POOL_SIZE];
5767 
5768   /* If we are not generating s7_PIC code, .cpload is ignored.  */
5769   if (s7_score_pic == s7_NO_PIC)
5770     {
5771       s_ignore (0);
5772       return;
5773     }
5774 
5775   if ((reg = s7_reg_required_here (&input_line_pointer, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
5776     return;
5777 
5778   demand_empty_rest_of_line ();
5779 
5780   sprintf (insn_str, "ld_i32hi r%d, %s", s7_GP, GP_DISP_LABEL);
5781   if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5782     return;
5783 
5784   sprintf (insn_str, "ld_i32lo r%d, %s", s7_GP, GP_DISP_LABEL);
5785   if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5786     return;
5787 
5788   sprintf (insn_str, "add r%d, r%d, r%d", s7_GP, s7_GP, reg);
5789   if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5790     return;
5791 }
5792 
5793 /* Handle the .cprestore pseudo-op.  This stores $gp into a given
5794    offset from $sp.  The offset is remembered, and after making a s7_PIC
5795    call $gp is restored from that location.  */
5796 
5797 static void
s7_s_score_cprestore(int ignore ATTRIBUTE_UNUSED)5798 s7_s_score_cprestore (int ignore ATTRIBUTE_UNUSED)
5799 {
5800   int reg;
5801   int cprestore_offset;
5802   char insn_str[s7_MAX_LITERAL_POOL_SIZE];
5803 
5804   /* If we are not generating s7_PIC code, .cprestore is ignored.  */
5805   if (s7_score_pic == s7_NO_PIC)
5806     {
5807       s_ignore (0);
5808       return;
5809     }
5810 
5811   if ((reg = s7_reg_required_here (&input_line_pointer, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL
5812       || s7_skip_past_comma (&input_line_pointer) == (int) s7_FAIL)
5813     {
5814       return;
5815     }
5816 
5817   cprestore_offset = get_absolute_expression ();
5818 
5819   if (cprestore_offset <= 0x3fff)
5820     {
5821       sprintf (insn_str, "sw r%d, [r%d, %d]", s7_GP, reg, cprestore_offset);
5822       if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5823         return;
5824     }
5825   else
5826     {
5827       int r1_bak;
5828 
5829       r1_bak = s7_nor1;
5830       s7_nor1 = 0;
5831 
5832       sprintf (insn_str, "li r1, %d", cprestore_offset);
5833       if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5834         return;
5835 
5836       sprintf (insn_str, "add r1, r1, r%d", reg);
5837       if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5838         return;
5839 
5840       sprintf (insn_str, "sw r%d, [r1]", s7_GP);
5841       if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5842         return;
5843 
5844       s7_nor1 = r1_bak;
5845     }
5846 
5847   demand_empty_rest_of_line ();
5848 }
5849 
5850 /* Handle the .gpword pseudo-op.  This is used when generating s7_PIC
5851    code.  It generates a 32 bit s7_GP relative reloc.  */
5852 
5853 static void
s7_s_score_gpword(int ignore ATTRIBUTE_UNUSED)5854 s7_s_score_gpword (int ignore ATTRIBUTE_UNUSED)
5855 {
5856   expressionS ex;
5857   char *p;
5858 
5859   /* When not generating s7_PIC code, this is treated as .word.  */
5860   if (s7_score_pic == s7_NO_PIC)
5861     {
5862       cons (4);
5863       return;
5864     }
5865   expression (&ex);
5866   if (ex.X_op != O_symbol || ex.X_add_number != 0)
5867     {
5868       as_bad (_("Unsupported use of .gpword"));
5869       ignore_rest_of_line ();
5870     }
5871   p = frag_more (4);
5872   s7_number_to_chars (p, (valueT) 0, 4);
5873   fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, false, BFD_RELOC_GPREL32);
5874   demand_empty_rest_of_line ();
5875 }
5876 
5877 /* Handle the .cpadd pseudo-op.  This is used when dealing with switch
5878    tables in s7_PIC code.  */
5879 
5880 static void
s7_s_score_cpadd(int ignore ATTRIBUTE_UNUSED)5881 s7_s_score_cpadd (int ignore ATTRIBUTE_UNUSED)
5882 {
5883   int reg;
5884   char insn_str[s7_MAX_LITERAL_POOL_SIZE];
5885 
5886   /* If we are not generating s7_PIC code, .cpload is ignored.  */
5887   if (s7_score_pic == s7_NO_PIC)
5888     {
5889       s_ignore (0);
5890       return;
5891     }
5892 
5893   if ((reg = s7_reg_required_here (&input_line_pointer, -1, s7_REG_TYPE_SCORE)) == (int) s7_FAIL)
5894     {
5895       return;
5896     }
5897   demand_empty_rest_of_line ();
5898 
5899   /* Add $gp to the register named as an argument.  */
5900   sprintf (insn_str, "add r%d, r%d, r%d", reg, reg, s7_GP);
5901   if (s7_append_insn (insn_str, true) == (int) s7_FAIL)
5902     return;
5903 }
5904 
5905 #ifndef TC_IMPLICIT_LCOMM_ALIGNMENT
5906 #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR)        	\
5907     do								\
5908     {                                                   	\
5909     if ((SIZE) >= 8)                                      	\
5910     (P2VAR) = 3;                                        	\
5911     else if ((SIZE) >= 4)                                 	\
5912     (P2VAR) = 2;                                        	\
5913     else if ((SIZE) >= 2)                                 	\
5914     (P2VAR) = 1;                                        	\
5915     else                                                  	\
5916     (P2VAR) = 0;                                        	\
5917     }								\
5918   while (0)
5919 #endif
5920 
5921 static void
s7_s_score_lcomm(int bytes_p)5922 s7_s_score_lcomm (int bytes_p)
5923 {
5924   char *name;
5925   char c;
5926   char *p;
5927   int temp;
5928   symbolS *symbolP;
5929   segT current_seg = now_seg;
5930   subsegT current_subseg = now_subseg;
5931   const int max_alignment = 15;
5932   int align = 0;
5933   segT bss_seg = bss_section;
5934   int needs_align = 0;
5935 
5936   c = get_symbol_name (&name);
5937   p = input_line_pointer;
5938   *p = c;
5939 
5940   if (name == p)
5941     {
5942       as_bad (_("expected symbol name"));
5943       discard_rest_of_line ();
5944       return;
5945     }
5946 
5947   SKIP_WHITESPACE_AFTER_NAME ();
5948 
5949   /* Accept an optional comma after the name.  The comma used to be
5950      required, but Irix 5 cc does not generate it.  */
5951   if (*input_line_pointer == ',')
5952     {
5953       ++input_line_pointer;
5954       SKIP_WHITESPACE ();
5955     }
5956 
5957   if (is_end_of_line[(unsigned char)*input_line_pointer])
5958     {
5959       as_bad (_("missing size expression"));
5960       return;
5961     }
5962 
5963   if ((temp = get_absolute_expression ()) < 0)
5964     {
5965       as_warn (_("BSS length (%d) < 0 ignored"), temp);
5966       ignore_rest_of_line ();
5967       return;
5968     }
5969 
5970 #if defined (TC_SCORE)
5971   if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour || OUTPUT_FLAVOR == bfd_target_elf_flavour)
5972     {
5973       /* For Score and Alpha ECOFF or ELF, small objects are put in .sbss.  */
5974       if ((unsigned) temp <= bfd_get_gp_size (stdoutput))
5975 	{
5976 	  bss_seg = subseg_new (".sbss", 1);
5977 	  seg_info (bss_seg)->bss = 1;
5978 	  if (!bfd_set_section_flags (bss_seg, SEC_ALLOC | SEC_SMALL_DATA))
5979 	    as_warn (_("error setting flags for \".sbss\": %s"),
5980 		     bfd_errmsg (bfd_get_error ()));
5981 	}
5982     }
5983 #endif
5984 
5985   SKIP_WHITESPACE ();
5986   if (*input_line_pointer == ',')
5987     {
5988       ++input_line_pointer;
5989       SKIP_WHITESPACE ();
5990 
5991       if (is_end_of_line[(unsigned char)*input_line_pointer])
5992         {
5993           as_bad (_("missing alignment"));
5994           return;
5995         }
5996       else
5997         {
5998           align = get_absolute_expression ();
5999           needs_align = 1;
6000         }
6001     }
6002 
6003   if (!needs_align)
6004     {
6005       TC_IMPLICIT_LCOMM_ALIGNMENT (temp, align);
6006 
6007       /* Still zero unless TC_IMPLICIT_LCOMM_ALIGNMENT set it.  */
6008       if (align)
6009         record_alignment (bss_seg, align);
6010     }
6011 
6012   if (needs_align)
6013     {
6014       if (bytes_p)
6015         {
6016           /* Convert to a power of 2.  */
6017           if (align != 0)
6018             {
6019               unsigned int i;
6020 
6021               for (i = 0; align != 0; align >>= 1, ++i)
6022                 ;
6023               align = i - 1;
6024             }
6025         }
6026 
6027       if (align > max_alignment)
6028         {
6029           align = max_alignment;
6030           as_warn (_("alignment too large; %d assumed"), align);
6031         }
6032       else if (align < 0)
6033         {
6034           align = 0;
6035           as_warn (_("alignment negative; 0 assumed"));
6036         }
6037 
6038       record_alignment (bss_seg, align);
6039     }
6040   else
6041     {
6042       /* Assume some objects may require alignment on some systems.  */
6043 #if defined (TC_ALPHA) && ! defined (VMS)
6044       if (temp > 1)
6045         {
6046           align = ffs (temp) - 1;
6047           if (temp % (1 << align))
6048             abort ();
6049         }
6050 #endif
6051     }
6052 
6053   *p = 0;
6054   symbolP = symbol_find_or_make (name);
6055   *p = c;
6056 
6057   if (
6058 #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
6059        (OUTPUT_FLAVOR != bfd_target_aout_flavour
6060         || (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) &&
6061 #endif
6062        (S_GET_SEGMENT (symbolP) == bss_seg || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0)))
6063     {
6064       char *pfrag;
6065 
6066       subseg_set (bss_seg, 1);
6067 
6068       if (align)
6069         frag_align (align, 0, 0);
6070 
6071       /* Detach from old frag.  */
6072       if (S_GET_SEGMENT (symbolP) == bss_seg)
6073         symbol_get_frag (symbolP)->fr_symbol = NULL;
6074 
6075       symbol_set_frag (symbolP, frag_now);
6076       pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, (offsetT) temp, NULL);
6077       *pfrag = 0;
6078 
6079 
6080       S_SET_SEGMENT (symbolP, bss_seg);
6081 
6082 #ifdef OBJ_COFF
6083       /* The symbol may already have been created with a preceding
6084          ".globl" directive -- be careful not to step on storage class
6085          in that case.  Otherwise, set it to static.  */
6086       if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
6087         {
6088           S_SET_STORAGE_CLASS (symbolP, C_STAT);
6089         }
6090 #endif /* OBJ_COFF */
6091 
6092 #ifdef S_SET_SIZE
6093       S_SET_SIZE (symbolP, temp);
6094 #endif
6095     }
6096   else
6097     as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP));
6098 
6099   subseg_set (current_seg, current_subseg);
6100 
6101   demand_empty_rest_of_line ();
6102 }
6103 
6104 
6105 
6106 static void
s7_begin(void)6107 s7_begin (void)
6108 {
6109   unsigned int i;
6110   segT seg;
6111   subsegT subseg;
6112 
6113   s7_score_ops_hsh = str_htab_create ();
6114 
6115   s7_build_score_ops_hsh ();
6116 
6117   s7_dependency_insn_hsh = str_htab_create ();
6118 
6119   s7_build_dependency_insn_hsh ();
6120 
6121   for (i = (int) REG_TYPE_FIRST; i < (int) s7_REG_TYPE_MAX; i++)
6122     s7_build_reg_hsh (s7_all_reg_maps + i);
6123 
6124   /* Initialize dependency vector.  */
6125   s7_init_dependency_vector ();
6126 
6127   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
6128   seg = now_seg;
6129   subseg = now_subseg;
6130   s7_pdr_seg = subseg_new (".pdr", (subsegT) 0);
6131   bfd_set_section_flags (s7_pdr_seg, SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
6132   bfd_set_section_alignment (s7_pdr_seg, 2);
6133   subseg_set (seg, subseg);
6134 
6135   if (s7_USE_GLOBAL_POINTER_OPT)
6136     bfd_set_gp_size (stdoutput, s7_g_switch_value);
6137 }
6138 
6139 static void
s7_assemble(char * str)6140 s7_assemble (char *str)
6141 {
6142   know (str);
6143   know (strlen (str) < s7_MAX_LITERAL_POOL_SIZE);
6144 
6145   memset (&s7_inst, '\0', sizeof (s7_inst));
6146   if (s7_INSN_IS_PCE_P (str))
6147     s7_parse_pce_inst (str);
6148   else
6149     s7_parse_16_32_inst (str, true);
6150 
6151   if (s7_inst.error)
6152     as_bad (_("%s -- `%s'"), s7_inst.error, s7_inst.str);
6153 }
6154 
6155 /* We handle all bad expressions here, so that we can report the faulty
6156    instruction in the error message.  */
6157 
6158 static void
s7_operand(expressionS * exp)6159 s7_operand (expressionS * exp)
6160 {
6161   if (s7_in_my_get_expression)
6162     {
6163       exp->X_op = O_illegal;
6164       if (s7_inst.error == NULL)
6165         {
6166           s7_inst.error = _("bad expression");
6167         }
6168     }
6169 }
6170 
6171 /* Turn a string in input_line_pointer into a floating point constant
6172    of type TYPE, and store the appropriate bytes in *LITP.  The number
6173    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
6174    returned, or NULL on OK.
6175 
6176    Note that fp constants aren't represent in the normal way on the ARM.
6177    In big endian mode, things are as expected.  However, in little endian
6178    mode fp constants are big-endian word-wise, and little-endian byte-wise
6179    within the words.  For example, (double) 1.1 in big endian mode is
6180    the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
6181    the byte sequence 99 99 f1 3f 9a 99 99 99.  */
6182 
6183 static const char *
s7_atof(int type,char * litP,int * sizeP)6184 s7_atof (int type, char *litP, int *sizeP)
6185 {
6186   int prec;
6187   LITTLENUM_TYPE words[MAX_LITTLENUMS];
6188   char *t;
6189   int i;
6190 
6191   switch (type)
6192     {
6193     case 'f':
6194     case 'F':
6195     case 's':
6196     case 'S':
6197       prec = 2;
6198       break;
6199     case 'd':
6200     case 'D':
6201     case 'r':
6202     case 'R':
6203       prec = 4;
6204       break;
6205     case 'x':
6206     case 'X':
6207     case 'p':
6208     case 'P':
6209       prec = 6;
6210       break;
6211     default:
6212       *sizeP = 0;
6213       return _("bad call to MD_ATOF()");
6214     }
6215 
6216   t = atof_ieee (input_line_pointer, type, words);
6217   if (t)
6218     input_line_pointer = t;
6219   *sizeP = prec * 2;
6220 
6221   if (target_big_endian)
6222     {
6223       for (i = 0; i < prec; i++)
6224         {
6225           s7_number_to_chars (litP, (valueT) words[i], 2);
6226           litP += 2;
6227         }
6228     }
6229   else
6230     {
6231       for (i = 0; i < prec; i += 2)
6232         {
6233           s7_number_to_chars (litP, (valueT) words[i + 1], 2);
6234           s7_number_to_chars (litP + 2, (valueT) words[i], 2);
6235           litP += 4;
6236         }
6237     }
6238 
6239   return 0;
6240 }
6241 
6242 /* Implementation of md_frag_check.
6243    Called after md_convert_frag().  */
6244 
6245 static void
s7_frag_check(fragS * fragp ATTRIBUTE_UNUSED)6246 s7_frag_check (fragS * fragp ATTRIBUTE_UNUSED)
6247 {
6248   know (fragp->insn_addr <= s7_RELAX_PAD_BYTE);
6249 }
6250 
6251 /* Implementation of TC_VALIDATE_FIX.
6252    Called before md_apply_fix() and after md_convert_frag().  */
6253 
6254 static void
s7_validate_fix(fixS * fixP)6255 s7_validate_fix (fixS *fixP)
6256 {
6257   fixP->fx_where += fixP->fx_frag->insn_addr;
6258 }
6259 
6260 static int
s7_force_relocation(struct fix * fixp)6261 s7_force_relocation (struct fix *fixp)
6262 {
6263   int retval = 0;
6264 
6265   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
6266       || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
6267       || fixp->fx_r_type == BFD_RELOC_SCORE_JMP
6268       || fixp->fx_r_type == BFD_RELOC_SCORE_BRANCH
6269       || fixp->fx_r_type == BFD_RELOC_SCORE16_JMP
6270       || fixp->fx_r_type == BFD_RELOC_SCORE16_BRANCH)
6271     {
6272       retval = 1;
6273     }
6274 
6275   return retval;
6276 }
6277 
6278 static bool
s7_fix_adjustable(fixS * fixP)6279 s7_fix_adjustable (fixS * fixP)
6280 {
6281   if (fixP->fx_addsy == NULL)
6282     {
6283       return 1;
6284     }
6285   else if (OUTPUT_FLAVOR == bfd_target_elf_flavour
6286       && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)))
6287     {
6288       return 0;
6289     }
6290   else if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
6291            || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
6292            || fixP->fx_r_type == BFD_RELOC_SCORE_JMP
6293            || fixP->fx_r_type == BFD_RELOC_SCORE16_JMP)
6294     {
6295       return 0;
6296     }
6297 
6298   return 1;
6299 }
6300 
6301 static void
s7_elf_final_processing(void)6302 s7_elf_final_processing (void)
6303 {
6304   unsigned long val = E_SCORE_MACH_SCORE7;
6305 
6306   elf_elfheader (stdoutput)->e_machine = EM_SCORE;
6307   elf_elfheader (stdoutput)->e_flags &= ~EF_SCORE_MACH;
6308   elf_elfheader (stdoutput)->e_flags |= val;
6309 
6310   if (s7_fix_data_dependency == 1)
6311     {
6312       elf_elfheader (stdoutput)->e_flags |= EF_SCORE_FIXDEP;
6313     }
6314   if (s7_score_pic == s7_PIC)
6315     {
6316       elf_elfheader (stdoutput)->e_flags |= EF_SCORE_PIC;
6317     }
6318 }
6319 
6320 /* In this function, we determine whether s7_GP instruction should do relaxation,
6321    for the label being against was known now.
6322    Doing this here but not in md_relax_frag() can induce iteration times
6323    in stage of doing relax.  */
6324 
6325 static int
s7_estimate_size_before_relax(fragS * fragp,asection * sec)6326 s7_estimate_size_before_relax (fragS * fragp, asection * sec)
6327 {
6328   if ((s7_RELAX_TYPE (fragp->fr_subtype) == Insn_GP)
6329       || (s7_RELAX_TYPE (fragp->fr_subtype) == Insn_PIC))
6330     return s7_judge_size_before_relax (fragp, sec);
6331 
6332   return 0;
6333 }
6334 
6335 static int
s7_relax_frag(asection * sec ATTRIBUTE_UNUSED,fragS * fragp,long stretch ATTRIBUTE_UNUSED)6336 s7_relax_frag (asection * sec ATTRIBUTE_UNUSED,
6337 	       fragS * fragp,
6338 	       long stretch ATTRIBUTE_UNUSED)
6339 {
6340   int grows = 0;
6341   int insn_size;
6342   int do_relax_p = 0;           /* Indicate doing relaxation for this frag.  */
6343   int relaxable_p = 0;
6344   bool word_align_p = false;
6345   fragS *next_fragp;
6346 
6347   /* If the instruction address is odd, make it half word align first.  */
6348   if ((fragp->fr_address) % 2 != 0)
6349     {
6350       if ((fragp->fr_address + fragp->insn_addr) % 2 != 0)
6351 	{
6352           fragp->insn_addr = 1;
6353           grows += 1;
6354 	}
6355     }
6356 
6357   word_align_p = (fragp->fr_address + fragp->insn_addr) % 4 == 0;
6358 
6359   /* Get instruction size and relax size after the last relaxation.  */
6360   if (fragp->fr_opcode)
6361     insn_size = s7_RELAX_NEW (fragp->fr_subtype);
6362   else
6363     insn_size = s7_RELAX_OLD (fragp->fr_subtype);
6364 
6365   /* Handle specially for s7_GP instruction.  for, s7_judge_size_before_relax() has already determine
6366      whether the s7_GP instruction should do relax.  */
6367   if ((s7_RELAX_TYPE (fragp->fr_subtype) == Insn_GP)
6368       || (s7_RELAX_TYPE (fragp->fr_subtype) == Insn_PIC))
6369     {
6370       if (!word_align_p)
6371         {
6372           if (fragp->insn_addr < 2)
6373             {
6374               fragp->insn_addr += 2;
6375               grows += 2;
6376             }
6377           else
6378             {
6379               fragp->insn_addr -= 2;
6380               grows -= 2;
6381             }
6382         }
6383 
6384       if (fragp->fr_opcode)
6385 	fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype) + fragp->insn_addr;
6386       else
6387 	fragp->fr_fix = s7_RELAX_OLD (fragp->fr_subtype) + fragp->insn_addr;
6388     }
6389   else
6390     {
6391       if (s7_RELAX_TYPE (fragp->fr_subtype) == PC_DISP19div2)
6392 	s7_b32_relax_to_b16 (fragp);
6393 
6394       relaxable_p = s7_RELAX_OPT (fragp->fr_subtype);
6395       next_fragp = fragp->fr_next;
6396       while ((next_fragp) && (next_fragp->fr_type != rs_machine_dependent))
6397 	{
6398           next_fragp = next_fragp->fr_next;
6399 	}
6400 
6401       if (next_fragp)
6402         {
6403           int n_insn_size;
6404           int n_relaxable_p = 0;
6405 
6406           if (next_fragp->fr_opcode)
6407             {
6408               n_insn_size = s7_RELAX_NEW (next_fragp->fr_subtype);
6409             }
6410           else
6411             {
6412               n_insn_size = s7_RELAX_OLD (next_fragp->fr_subtype);
6413             }
6414 
6415           if (s7_RELAX_TYPE (next_fragp->fr_subtype) == PC_DISP19div2)
6416             s7_b32_relax_to_b16 (next_fragp);
6417           n_relaxable_p = s7_RELAX_OPT (next_fragp->fr_subtype);
6418 
6419           if (word_align_p)
6420             {
6421               if (insn_size == 4)
6422                 {
6423                   /* 32 -> 16.  */
6424                   if (relaxable_p && ((n_insn_size == 2) || n_relaxable_p))
6425                     {
6426                       grows -= 2;
6427                       do_relax_p = 1;
6428                     }
6429                 }
6430               else if (insn_size == 2)
6431                 {
6432                   /* 16 -> 32.  */
6433                   if (relaxable_p && (((n_insn_size == 4) && !n_relaxable_p) || (n_insn_size > 4)))
6434                     {
6435                       grows += 2;
6436                       do_relax_p = 1;
6437                     }
6438                 }
6439               else
6440                 {
6441 		  abort ();
6442                 }
6443             }
6444           else
6445             {
6446               if (insn_size == 4)
6447                 {
6448                   /* 32 -> 16.  */
6449                   if (relaxable_p)
6450                     {
6451                       grows -= 2;
6452                       do_relax_p = 1;
6453                     }
6454                   /* Make the 32 bit instruction word align.  */
6455                   else
6456                     {
6457                       fragp->insn_addr += 2;
6458                       grows += 2;
6459 		    }
6460                 }
6461               else if (insn_size == 2)
6462                 {
6463                   /* Do nothing.  */
6464                 }
6465               else
6466                 {
6467 		  abort ();
6468                 }
6469             }
6470         }
6471       else
6472         {
6473 	  /* Here, try best to do relax regardless fragp->fr_next->fr_type.  */
6474           if (!word_align_p)
6475             {
6476               if (insn_size % 4 == 0)
6477                 {
6478                   /* 32 -> 16.  */
6479                   if (relaxable_p)
6480                     {
6481                       grows -= 2;
6482                       do_relax_p = 1;
6483                     }
6484                   else
6485                     {
6486                       fragp->insn_addr += 2;
6487                       grows += 2;
6488                     }
6489                 }
6490             }
6491           else
6492             {
6493 	      /* Do nothing.  */
6494             }
6495         }
6496 
6497       /* fragp->fr_opcode indicates whether this frag should be relaxed.  */
6498       if (do_relax_p)
6499         {
6500           if (fragp->fr_opcode)
6501             {
6502               fragp->fr_opcode = NULL;
6503 	      /* Guarantee estimate stage is correct.  */
6504               fragp->fr_fix = s7_RELAX_OLD (fragp->fr_subtype);
6505               fragp->fr_fix += fragp->insn_addr;
6506             }
6507           else
6508             {
6509               fragp->fr_opcode = fragp->fr_literal + s7_RELAX_RELOC1 (fragp->fr_subtype);
6510 	      /* Guarantee estimate stage is correct.  */
6511               fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype);
6512               fragp->fr_fix += fragp->insn_addr;
6513             }
6514         }
6515       else
6516 	{
6517           if (fragp->fr_opcode)
6518             {
6519 	      /* Guarantee estimate stage is correct.  */
6520               fragp->fr_fix = s7_RELAX_NEW (fragp->fr_subtype);
6521               fragp->fr_fix += fragp->insn_addr;
6522             }
6523           else
6524             {
6525 	      /* Guarantee estimate stage is correct.  */
6526               fragp->fr_fix = s7_RELAX_OLD (fragp->fr_subtype);
6527               fragp->fr_fix += fragp->insn_addr;
6528             }
6529 	}
6530     }
6531 
6532   return grows;
6533 }
6534 
6535 static void
s7_convert_frag(bfd * abfd ATTRIBUTE_UNUSED,segT sec ATTRIBUTE_UNUSED,fragS * fragp)6536 s7_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
6537 		 segT sec ATTRIBUTE_UNUSED,
6538 		 fragS * fragp)
6539 {
6540   unsigned int r_old;
6541   unsigned int r_new;
6542   char backup[20];
6543   fixS *fixp;
6544 
6545   r_old = s7_RELAX_OLD (fragp->fr_subtype);
6546   r_new = s7_RELAX_NEW (fragp->fr_subtype);
6547 
6548   /* fragp->fr_opcode indicates whether this frag should be relaxed.  */
6549   if (fragp->fr_opcode == NULL)
6550     {
6551       memcpy (backup, fragp->fr_literal, r_old);
6552       fragp->fr_fix = r_old;
6553     }
6554   else
6555     {
6556       memcpy (backup, fragp->fr_literal + r_old, r_new);
6557       fragp->fr_fix = r_new;
6558     }
6559 
6560   fixp = fragp->tc_frag_data.fixp;
6561   while (fixp && fixp->fx_frag == fragp && fixp->fx_where < r_old)
6562     {
6563       if (fragp->fr_opcode)
6564 	fixp->fx_done = 1;
6565       fixp = fixp->fx_next;
6566     }
6567   while (fixp && fixp->fx_frag == fragp)
6568     {
6569       if (fragp->fr_opcode)
6570 	fixp->fx_where -= r_old + fragp->insn_addr;
6571       else
6572 	fixp->fx_done = 1;
6573       fixp = fixp->fx_next;
6574     }
6575 
6576   if (fragp->insn_addr)
6577     {
6578       s7_number_to_chars (fragp->fr_literal, 0x0, fragp->insn_addr);
6579     }
6580   memcpy (fragp->fr_literal + fragp->insn_addr, backup, fragp->fr_fix);
6581   fragp->fr_fix += fragp->insn_addr;
6582 }
6583 
6584 static long
s7_pcrel_from(fixS * fixP)6585 s7_pcrel_from (fixS * fixP)
6586 {
6587   long retval = 0;
6588 
6589   if (fixP->fx_addsy
6590       && (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
6591       && (fixP->fx_subsy == NULL))
6592     {
6593       retval = 0;
6594     }
6595   else
6596     {
6597       retval = fixP->fx_where + fixP->fx_frag->fr_address;
6598     }
6599 
6600   return retval;
6601 }
6602 
6603 /* Round up a section size to the appropriate boundary.  */
6604 static valueT
s7_section_align(segT segment,valueT size)6605 s7_section_align (segT segment, valueT size)
6606 {
6607   int align = bfd_section_alignment (segment);
6608 
6609   return ((size + (1 << align) - 1) & -(1 << align));
6610 }
6611 
6612 static void
s7_apply_fix(fixS * fixP,valueT * valP,segT seg)6613 s7_apply_fix (fixS *fixP, valueT *valP, segT seg)
6614 {
6615   valueT value = *valP;
6616   valueT abs_value = 0;
6617   valueT newval;
6618   valueT content;
6619   valueT HI, LO;
6620 
6621   char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
6622 
6623   gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
6624   if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
6625     {
6626       if (fixP->fx_r_type != BFD_RELOC_SCORE_DUMMY_HI16)
6627         fixP->fx_done = 1;
6628     }
6629 
6630   /* If this symbol is in a different section then we need to leave it for
6631      the linker to deal with.  Unfortunately, md_pcrel_from can't tell,
6632      so we have to undo it's effects here.  */
6633   if (fixP->fx_pcrel)
6634     {
6635       if (fixP->fx_addsy != NULL
6636 	  && S_IS_DEFINED (fixP->fx_addsy)
6637 	  && S_GET_SEGMENT (fixP->fx_addsy) != seg)
6638 	value += md_pcrel_from (fixP);
6639     }
6640 
6641   /* Remember value for emit_reloc.  */
6642   fixP->fx_addnumber = value;
6643 
6644   switch (fixP->fx_r_type)
6645     {
6646     case BFD_RELOC_HI16_S:
6647       if (fixP->fx_done)
6648         {                       /* For la rd, imm32.  */
6649           newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6650           HI = value >> 16;   /* mul to 2, then take the hi 16 bit.  */
6651           newval |= (HI & 0x3fff) << 1;
6652           newval |= ((HI >> 14) & 0x3) << 16;
6653           s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6654         }
6655       break;
6656     case BFD_RELOC_LO16:
6657       if (fixP->fx_done)        /* For la rd, imm32.  */
6658         {
6659           newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6660           LO = value & 0xffff;
6661           newval |= (LO & 0x3fff) << 1; /* 16 bit: imm -> 14 bit in lo, 2 bit in hi.  */
6662           newval |= ((LO >> 14) & 0x3) << 16;
6663           s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6664         }
6665       break;
6666     case BFD_RELOC_SCORE_JMP:
6667       {
6668         content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6669         value = fixP->fx_offset;
6670         if (value > 0x1ffffff)
6671           {
6672             as_bad_where (fixP->fx_file, fixP->fx_line,
6673                           _("j or jl truncate (0x%x)  [0 ~ 2^25-1]"), (unsigned int) value);
6674             return;
6675           }
6676         content = (content & ~0x3ff7ffe) | ((value << 1) & 0x3ff0000) | (value & 0x7fff);
6677         s7_number_to_chars (buf, content, s7_INSN_SIZE);
6678       }
6679       break;
6680     case BFD_RELOC_SCORE_BRANCH:
6681       if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) || (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
6682         value = fixP->fx_offset;
6683       else
6684         fixP->fx_done = 1;
6685 
6686       content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6687       if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0x80008000) != 0x80008000))
6688         {
6689           if ((value & 0x80000000) == 0x80000000)
6690             abs_value = 0xffffffff - value + 1;
6691           if ((abs_value & 0xffffff00) != 0)
6692             {
6693               as_bad_where (fixP->fx_file, fixP->fx_line,
6694                             _(" branch relocation truncate (0x%x) [-2^8 ~ 2^8]"), (unsigned int) value);
6695               return;
6696             }
6697           content = s7_md_chars_to_number (buf, s7_INSN16_SIZE);
6698           content &= 0xff00;
6699           content = (content & 0xff00) | ((value >> 1) & 0xff);
6700           s7_number_to_chars (buf, content, s7_INSN16_SIZE);
6701           fixP->fx_r_type = BFD_RELOC_SCORE16_BRANCH;
6702           fixP->fx_size = 2;
6703         }
6704       else
6705         {
6706           if ((value & 0x80000000) == 0x80000000)
6707             abs_value = 0xffffffff - value + 1;
6708           if ((abs_value & 0xfff80000) != 0)
6709             {
6710               as_bad_where (fixP->fx_file, fixP->fx_line,
6711                             _(" branch relocation truncate (0x%x) [-2^19 ~ 2^19]"),
6712 			    (unsigned int) value);
6713               return;
6714             }
6715           content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6716           content &= 0xfc00fc01;
6717           content = (content & 0xfc00fc01) | (value & 0x3fe) | ((value << 6) & 0x3ff0000);
6718           s7_number_to_chars (buf, content, s7_INSN_SIZE);
6719         }
6720       break;
6721     case BFD_RELOC_SCORE16_JMP:
6722       content = s7_md_chars_to_number (buf, s7_INSN16_SIZE);
6723       content &= 0xf001;
6724       value = fixP->fx_offset;
6725       if (value > 0xfff)
6726         {
6727           as_bad_where (fixP->fx_file, fixP->fx_line,
6728                         _("j! or jl! truncate (0x%x)  [0 ~ 2^12-1]"), (unsigned int) value);
6729           return;
6730         }
6731       value = fixP->fx_offset & 0xfff;
6732       content = (content & 0xfc01) | (value & 0xffe);
6733       s7_number_to_chars (buf, content, s7_INSN16_SIZE);
6734       break;
6735     case BFD_RELOC_SCORE16_BRANCH:
6736       content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6737       if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0x80008000) == 0x80008000))
6738         {
6739           if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) ||
6740               (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
6741             value = fixP->fx_offset;
6742           else
6743             fixP->fx_done = 1;
6744 
6745           if ((value & 0xfff80000) != 0 && (value & 0xfff80000) != 0xfff80000)
6746             {
6747               as_bad_where (fixP->fx_file, fixP->fx_line,
6748                             _(" branch relocation truncate (0x%x) [-2^19 ~ 2^19]"),
6749 			    (unsigned int) value);
6750               return;
6751             }
6752           content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6753           content = (content & 0xfc00fc01) | (value & 0x3fe) | ((value << 6) & 0x3ff0000);
6754           s7_number_to_chars (buf, content, s7_INSN_SIZE);
6755           fixP->fx_r_type = BFD_RELOC_SCORE_BRANCH;
6756           fixP->fx_size = 4;
6757           break;
6758         }
6759       else
6760         {
6761           /* In different section.  */
6762           if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) ||
6763               (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
6764             value = fixP->fx_offset;
6765           else
6766             fixP->fx_done = 1;
6767 
6768           if ((value & 0xffffff00) != 0 && (value & 0xffffff00) != 0xffffff00)
6769             {
6770               as_bad_where (fixP->fx_file, fixP->fx_line,
6771                             _(" branch relocation truncate (0x%x)  [-2^8 ~ 2^8]"),
6772 			    (unsigned int) value);
6773               return;
6774             }
6775           content = s7_md_chars_to_number (buf, s7_INSN16_SIZE);
6776           content = (content & 0xff00) | ((value >> 1) & 0xff);
6777           s7_number_to_chars (buf, content, s7_INSN16_SIZE);
6778           break;
6779         }
6780     case BFD_RELOC_8:
6781       if (fixP->fx_done || fixP->fx_pcrel)
6782 	s7_number_to_chars (buf, value, 1);
6783 #ifdef OBJ_ELF
6784       else
6785         {
6786           value = fixP->fx_offset;
6787           s7_number_to_chars (buf, value, 1);
6788         }
6789 #endif
6790       break;
6791 
6792     case BFD_RELOC_16:
6793       if (fixP->fx_done || fixP->fx_pcrel)
6794         s7_number_to_chars (buf, value, 2);
6795 #ifdef OBJ_ELF
6796       else
6797         {
6798           value = fixP->fx_offset;
6799           s7_number_to_chars (buf, value, 2);
6800         }
6801 #endif
6802       break;
6803     case BFD_RELOC_RVA:
6804     case BFD_RELOC_32:
6805       if (fixP->fx_done || fixP->fx_pcrel)
6806         s7_number_to_chars (buf, value, 4);
6807 #ifdef OBJ_ELF
6808       else
6809         {
6810           value = fixP->fx_offset;
6811           s7_number_to_chars (buf, value, 4);
6812         }
6813 #endif
6814       break;
6815     case BFD_RELOC_VTABLE_INHERIT:
6816       fixP->fx_done = 0;
6817       if (fixP->fx_addsy && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy))
6818         S_SET_WEAK (fixP->fx_addsy);
6819       break;
6820     case BFD_RELOC_VTABLE_ENTRY:
6821       fixP->fx_done = 0;
6822       break;
6823     case BFD_RELOC_SCORE_GPREL15:
6824       content = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6825       if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0xfc1c8000) != 0x94188000))
6826         fixP->fx_r_type = BFD_RELOC_NONE;
6827       fixP->fx_done = 0;
6828       break;
6829     case BFD_RELOC_SCORE_GOT15:
6830     case BFD_RELOC_SCORE_DUMMY_HI16:
6831     case BFD_RELOC_SCORE_GOT_LO16:
6832     case BFD_RELOC_SCORE_CALL15:
6833     case BFD_RELOC_GPREL32:
6834       break;
6835     case BFD_RELOC_NONE:
6836     default:
6837       as_bad_where (fixP->fx_file, fixP->fx_line, _("bad relocation fixup type (%d)"), fixP->fx_r_type);
6838     }
6839 }
6840 
6841 /* Translate internal representation of relocation info to BFD target format.  */
6842 
6843 static arelent **
s7_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixp)6844 s7_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
6845 {
6846   static arelent *retval[MAX_RELOC_EXPANSION + 1];  /* MAX_RELOC_EXPANSION equals 2.  */
6847   arelent *reloc;
6848   bfd_reloc_code_real_type code;
6849   const char *type;
6850 
6851   reloc = retval[0] = XNEW (arelent);
6852   retval[1] = NULL;
6853 
6854   reloc->sym_ptr_ptr = XNEW (asymbol *);
6855   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
6856   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
6857   reloc->addend = fixp->fx_offset;
6858 
6859   /* If this is a variant frag, we may need to adjust the existing
6860      reloc and generate a new one.  */
6861   if (fixp->fx_frag->fr_opcode != NULL && (fixp->fx_r_type == BFD_RELOC_SCORE_GPREL15))
6862     {
6863       /* Update instruction imm bit.  */
6864       offsetT newval;
6865       unsigned short off;
6866       char *buf;
6867 
6868       buf = fixp->fx_frag->fr_literal + fixp->fx_frag->insn_addr;
6869       newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6870       off = fixp->fx_offset >> 16;
6871       newval |= (off & 0x3fff) << 1;
6872       newval |= ((off >> 14) & 0x3) << 16;
6873       s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6874 
6875       buf += s7_INSN_SIZE;
6876       newval = s7_md_chars_to_number (buf, s7_INSN_SIZE);
6877       off = fixp->fx_offset & 0xffff;
6878       newval |= ((off & 0x3fff) << 1);
6879       newval |= (((off >> 14) & 0x3) << 16);
6880       s7_number_to_chars (buf, newval, s7_INSN_SIZE);
6881 
6882       retval[1] = XNEW (arelent);
6883       retval[2] = NULL;
6884       retval[1]->sym_ptr_ptr = XNEW (asymbol *);
6885       *retval[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
6886       retval[1]->address = (reloc->address + s7_RELAX_RELOC2 (fixp->fx_frag->fr_subtype));
6887 
6888       retval[1]->addend = 0;
6889       retval[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16);
6890       gas_assert (retval[1]->howto != NULL);
6891 
6892       fixp->fx_r_type = BFD_RELOC_HI16_S;
6893     }
6894 
6895   code = fixp->fx_r_type;
6896   switch (fixp->fx_r_type)
6897     {
6898     case BFD_RELOC_32:
6899       if (fixp->fx_pcrel)
6900         {
6901           code = BFD_RELOC_32_PCREL;
6902           break;
6903         }
6904       /* Fall through.  */
6905     case BFD_RELOC_HI16_S:
6906     case BFD_RELOC_LO16:
6907     case BFD_RELOC_SCORE_JMP:
6908     case BFD_RELOC_SCORE_BRANCH:
6909     case BFD_RELOC_SCORE16_JMP:
6910     case BFD_RELOC_SCORE16_BRANCH:
6911     case BFD_RELOC_VTABLE_ENTRY:
6912     case BFD_RELOC_VTABLE_INHERIT:
6913     case BFD_RELOC_SCORE_GPREL15:
6914     case BFD_RELOC_SCORE_GOT15:
6915     case BFD_RELOC_SCORE_DUMMY_HI16:
6916     case BFD_RELOC_SCORE_GOT_LO16:
6917     case BFD_RELOC_SCORE_CALL15:
6918     case BFD_RELOC_GPREL32:
6919     case BFD_RELOC_NONE:
6920       code = fixp->fx_r_type;
6921       break;
6922     default:
6923       type = _("<unknown>");
6924       as_bad_where (fixp->fx_file, fixp->fx_line,
6925                     _("cannot represent %s relocation in this object file format"), type);
6926       return NULL;
6927     }
6928 
6929   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
6930   if (reloc->howto == NULL)
6931     {
6932       as_bad_where (fixp->fx_file, fixp->fx_line,
6933                     _("cannot represent %s relocation in this object file format1"),
6934                     bfd_get_reloc_code_name (code));
6935       return NULL;
6936     }
6937   /* HACK: Since arm ELF uses Rel instead of Rela, encode the
6938      vtable entry to be used in the relocation's section offset.  */
6939   if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
6940     reloc->address = fixp->fx_offset;
6941 
6942   return retval;
6943 }
6944