Typo fix.
[deliverable/binutils-gdb.git] / gas / config / tc-xgate.c
CommitLineData
f6c1a2d5
NC
1/* tc-xgate.c -- Assembler code for Freescale XGATE
2 Copyright 2010, 2011, 2012
3 Free Software Foundation, Inc.
4 Contributed by Sean Keys <skeys@ipdatasys.com>
5
6 This file is part of GAS, the GNU Assembler.
7
8 GAS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 GAS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GAS; see the file COPYING. If not, write to
20 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
21 Boston, MA 02110-1301, USA. */
22
23#include "as.h"
24#include "safe-ctype.h"
25#include "subsegs.h"
26#include "opcode/xgate.h"
27#include "dwarf2dbg.h"
28#include "elf/xgate.h"
29
30const char comment_chars[] = ";!";
31const char line_comment_chars[] = "#*";
32const char line_separator_chars[] = "";
33const char EXP_CHARS[] = "eE";
34const char FLT_CHARS[] = "dD";
35
36#define SIXTEENTH_BIT 0x8000
37#define N_BITS_IN_WORD 16
38
39/* #define STATE_CONDITIONAL_BRANCH (1) */
40#define STATE_PC_RELATIVE (2)
41#define REGISTER_P(ptr) (ptr == 'r')
42#define INCREMENT 01
43#define DECREMENT 02
44#define MAXREGISTER 07
45#define MINREGISTER 00
46
47#define OPTION_MMCU 'm'
48
49/* This macro has no side-effects. */
50#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
51
19f55fe4
SK
52/* Each unique opcode name has a handle. That handle may
53 contain pointers to opcodes with the same name but
54 different address modes. */
f6c1a2d5
NC
55struct xgate_opcode_handle
56{
57 int number_of_modes;
58 char *name;
59 struct xgate_opcode *opc0[MAX_OPCODES];
60};
61
62/* LOCAL FUNCTIONS */
63static char *
64xgate_parse_exp (char *, expressionS *);
65static inline char *
66skip_whitespace (char *);
67static void
68get_default_target (void);
69static char *
70extract_word (char *, char *, int);
71static char *
72xgate_new_instruction (int size);
73unsigned short
74xgate_apply_operand (unsigned short, unsigned short *, unsigned short,
75 unsigned char);
76void
77xgate_operands (struct xgate_opcode *, char **);
78static unsigned int
79xgate_operand (struct xgate_opcode *, int *, int where, char **, char **);
80static struct xgate_opcode *
81xgate_find_match (struct xgate_opcode_handle *, int, unsigned int);
82static int
83cmp_opcode (struct xgate_opcode *, struct xgate_opcode *);
84unsigned int
85xgate_detect_format (char *);
86void
87xgate_print_syntax (char *);
88void
89xgate_print_table (void);
90
91/* LOCAL DATA */
92static struct hash_control *xgate_hash;
93
94/* Previous opcode. */
95static unsigned int prev = 0;
96
97static unsigned char fixup_required = 0;
98
99/* Used to enable clipping of 16 bit operands into 8 bit constraints. */
100static unsigned char macroClipping = 0;
101
102static char oper_check;
103static char flag_print_insn_syntax = 0;
104static char flag_print_opcodes = 0;
105
106static int current_architecture;
107static const char *default_cpu;
108
109/* ELF flags to set in the output file header. */
110static int elf_flags = E_XGATE_F64;
111
112/* This table describes how you change sizes for the various types of variable
113 size expressions. This version only supports two kinds. */
114
115/* The fields are:
116 How far Forward this mode will reach.
117 How far Backward this mode will reach.
118 How many bytes this mode will add to the size of the frag.
119 Which mode to go to if the offset won't fit in this one. */
120
121relax_typeS md_relax_table[] =
122{
123 {1, 1, 0, 0}, /* First entries aren't used. */
124 {1, 1, 0, 0}, /* For no good reason except. */
125 {1, 1, 0, 0}, /* that the VAX doesn't either. */
126 {1, 1, 0, 0},
127 /* XGATE 9 and 10 bit pc rel todo complete and test */
128/*{(511), (-512), 0, ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD)},
129 {(1023), (-1024), 0, ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD)}, */
130 {0, 0, 0, 0}
131};
132
133/* XGATE's registers all are 16-bit general purpose. They are numbered according to the specifications. */
134typedef enum register_id
135{
136 REG_NONE = -1,
137 REG_R0 = 0,
138 REG_R1 = 1,
139 REG_R2 = 2,
140 REG_R3 = 3,
141 REG_R4 = 4,
142 REG_R5 = 5,
143 REG_R6 = 6,
144 REG_R7 = 7,
145 REG_PC = 8,
146 REG_CCR = 9
147} register_id;
148
149/* This table describes all the machine specific pseudo-ops the assembler
150 has to support. The fields are: pseudo-op name without dot function to
151 call to execute this pseudo-op Integer arg to pass to the function. */
152const pseudo_typeS md_pseudo_table[] =
153{
154 /* The following pseudo-ops are supported for MRI compatibility. */
155 {0, 0, 0}
156};
157
158const char *md_shortopts = "m:";
159
160struct option md_longopts[] =
161{
162#define OPTION_PRINT_INSN_SYNTAX (OPTION_MD_BASE + 0)
163 { "print-insn-syntax", no_argument, NULL, OPTION_PRINT_INSN_SYNTAX },
164
165#define OPTION_PRINT_OPCODES (OPTION_MD_BASE + 1)
166 { "print-opcodes", no_argument, NULL, OPTION_PRINT_OPCODES },
167
168#define OPTION_GENERATE_EXAMPLE (OPTION_MD_BASE + 2)
169 { "generate-example", no_argument, NULL, OPTION_GENERATE_EXAMPLE },
170
171#define OPTION_MSHORT (OPTION_MD_BASE + 3)
172 { "mshort", no_argument, NULL, OPTION_MSHORT },
173
174#define OPTION_MLONG (OPTION_MD_BASE + 4)
175 { "mlong", no_argument, NULL, OPTION_MLONG },
176
177#define OPTION_MSHORT_DOUBLE (OPTION_MD_BASE + 5)
178 { "mshort-double", no_argument, NULL, OPTION_MSHORT_DOUBLE },
179
180#define OPTION_MLONG_DOUBLE (OPTION_MD_BASE + 6)
181 { "mlong-double", no_argument, NULL, OPTION_MLONG_DOUBLE },
182
183 { NULL, no_argument, NULL, 0 }
184};
185
186size_t md_longopts_size = sizeof(md_longopts);
187
188char *
189md_atof (int type, char *litP, int *sizeP)
190{
191 return ieee_md_atof (type, litP, sizeP, TRUE);
192}
193
194int
195md_parse_option (int c, char *arg)
196{
197 switch (c)
198 {
199 case OPTION_MMCU:
200 if (strcasecmp (arg, "v1") == 0)
201 current_architecture = XGATE_V1;
202 else if (strcasecmp (arg, "v2") == 0)
203 current_architecture = XGATE_V2;
204 else if (strcasecmp (arg, "v3") == 0)
205 current_architecture = XGATE_V3;
206 else
207 as_bad (_(" architecture variant invalid"));
208 break;
209
210 case OPTION_PRINT_INSN_SYNTAX:
211 flag_print_insn_syntax = 1;
212 break;
213
214 case OPTION_PRINT_OPCODES:
215 flag_print_opcodes = 1;
216 break;
217
218 case OPTION_GENERATE_EXAMPLE:
219 flag_print_opcodes = 2;
220 break;
221
222 case OPTION_MSHORT:
223 elf_flags &= ~E_XGATE_I32;
224 break;
225
226 case OPTION_MLONG:
227 elf_flags |= E_XGATE_I32;
228 break;
229
230 case OPTION_MSHORT_DOUBLE:
231 elf_flags &= ~E_XGATE_F64;
232 break;
233
234 case OPTION_MLONG_DOUBLE:
235 elf_flags |= E_XGATE_F64;
236 break;
237
238 default:
239 return 0;
240 }
241 return 1;
242}
243
244const char *
245xgate_arch_format (void)
246{
247 get_default_target ();
248
249 if (current_architecture & cpuxgate)
250 return "elf32-xgate";
251
252 return "error";
253}
254
255static void
256get_default_target (void)
257{
258 const bfd_target *target;
259 bfd abfd;
260
261 if (current_architecture != 0)
262 return;
263
264 default_cpu = "unknown";
265 target = bfd_find_target (0, &abfd);
266
267 if (target && target->name)
268 {
269 if (strcmp (target->name, "elf32-xgate") == 0)
270 {
271 current_architecture = cpuxgate;
272 default_cpu = "XGATE V1";
273 return;
274 }
275
276 as_bad (_("Default target `%s' is not supported."), target->name);
277 }
278}
279
280void
281md_begin (void)
282{
283 struct xgate_opcode *xgate_opcode_ptr = NULL;
284 struct xgate_opcode *xgate_op_table = NULL;
285 struct xgate_opcode_handle *op_handles = 0;
286 char *prev_op_name = 0;
287 int handle_enum = 0;
19f55fe4 288 int number_of_op_handles = 0;
f6c1a2d5
NC
289 int i, j = 0;
290
291 /* Create a local copy of our opcode table
292 including an extra line for NULL termination. */
293 xgate_op_table = (struct xgate_opcode *)
19f55fe4 294 xmalloc ((xgate_num_opcodes) * sizeof (struct xgate_opcode));
f6c1a2d5
NC
295
296 memset (xgate_op_table, 0,
19f55fe4 297 sizeof(struct xgate_opcode) * (xgate_num_opcodes));
f6c1a2d5
NC
298
299 for (xgate_opcode_ptr = (struct xgate_opcode*) xgate_opcodes, i = 0;
300 i < xgate_num_opcodes; i++)
301 xgate_op_table[i] = xgate_opcode_ptr[i];
302
303 qsort (xgate_op_table, xgate_num_opcodes, sizeof(struct xgate_opcode),
304 (int (*)(const void *, const void *)) cmp_opcode);
305
306 /* Calculate number of handles since this will be
307 smaller than the raw number of opcodes in the table. */
19f55fe4
SK
308 prev_op_name = "";
309 for (xgate_opcode_ptr = xgate_op_table, i = 0; i < xgate_num_opcodes;
310 xgate_opcode_ptr++, i++)
f6c1a2d5 311 {
19f55fe4
SK
312 if (strcmp (prev_op_name, xgate_opcode_ptr->name))
313 number_of_op_handles++;
f6c1a2d5
NC
314 prev_op_name = xgate_opcode_ptr->name;
315 }
316
317 op_handles = (struct xgate_opcode_handle *)
19f55fe4 318 xmalloc (sizeof(struct xgate_opcode_handle) * (number_of_op_handles));
f6c1a2d5 319
19f55fe4 320 /* Insert unique opcode names into hash table, aliasing duplicates. */
f6c1a2d5
NC
321 xgate_hash = hash_new ();
322
19f55fe4 323 prev_op_name = "";
f6c1a2d5 324 for (xgate_opcode_ptr = xgate_op_table, i = 0, j = 0; i < xgate_num_opcodes;
19f55fe4 325 i++, xgate_opcode_ptr++)
f6c1a2d5 326 {
19f55fe4
SK
327 if (!strcmp (prev_op_name, xgate_opcode_ptr->name))
328 {
329 handle_enum++;
330 op_handles[j].opc0[handle_enum] = xgate_opcode_ptr;
331 }
332 else
f6c1a2d5
NC
333 {
334 handle_enum = 0;
335 if (i)
19f55fe4 336 j++;
f6c1a2d5
NC
337 op_handles[j].name = xgate_opcode_ptr->name;
338 op_handles[j].opc0[0] = xgate_opcode_ptr;
19f55fe4
SK
339 hash_insert (xgate_hash, (char *) op_handles[j].name,
340 (char *) &(op_handles[j]));
f6c1a2d5
NC
341 }
342 op_handles[j].number_of_modes = handle_enum;
343 prev_op_name = op_handles[j].name;
344 }
345
f6c1a2d5
NC
346 if (flag_print_opcodes == 1)
347 xgate_print_table ();
348}
349
350void
351xgate_init_after_args (void)
352{
353}
354
355void
356md_show_usage (FILE * stream)
357{
358 get_default_target ();
359
360 fprintf (
361 stream,
362 _("\
363 Freescale XGATE co-processor options:\n \
364 -mshort use 16-bit int ABI (default)\n \
365 -mlong use 32-bit int ABI\n \
366 -mshort-double use 32-bit double ABI\n \
367 -mlong-double use 64-bit double ABI (default)\n\
368 --mxgate specify the processor variant[default %s]\n\
369 --print-insn-syntax print the syntax of instruction in case of error\n\
370 --print-opcodes print the list of instructions with syntax\n\
371 --generate-example generate an example of each instruction"),
372 default_cpu);
373}
374
375enum bfd_architecture
376xgate_arch (void)
377{
378 get_default_target ();
379 return bfd_arch_xgate;
380}
381
382int
383xgate_mach (void)
384{
385 return 0;
386}
387
388void
389xgate_print_syntax (char *name)
390{
391 int i;
392
393 for (i = 0; i < xgate_num_opcodes; i++)
394 {
395 if (!strcmp (xgate_opcodes[i].name, name))
396 {
397 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IDR))
398 printf ("\tFormat is %s\tRx, Rx, Rx+|-Rx|Rx\n",
399 xgate_opcodes[i].name);
400 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_INH))
401 printf ("\tFormat is %s\n", xgate_opcodes[i].name);
402 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_TRI))
403 printf ("\tFormat is %s\tRx, Rx, Rx\n", xgate_opcodes[i].name);
404 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_DYA))
405 printf ("\tFormat is %s\tRx, Rx\n", xgate_opcodes[i].name);
406 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_DYA_MON)
407 || !strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON))
408 printf ("\tFormat is %s\tRx\n", xgate_opcodes[i].name);
409 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM3))
410 printf ("\tFormat is %s\t<3-bit value>\n", xgate_opcodes[i].name);
411 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM4))
412 printf ("\tFormat is %s\t<4 -bit value>\n", xgate_opcodes[i].name);
413 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM8))
414 printf ("\tFormat is %s\tRx, <8-bit value>\n",
415 xgate_opcodes[i].name);
416 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM16))
417 printf ("\tFormat is %s\tRx, <16-bit value>\n",
418 xgate_opcodes[i].name);
419 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON_R_C))
420 printf ("\tFormat is %s\tRx, CCR\n", xgate_opcodes[i].name);
421 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON_C_R))
422 printf ("\tFormat is %s\tCCR, Rx\n", xgate_opcodes[i].name);
423 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON_R_P))
424 printf ("\tFormat is %s\tRx, PC\n", xgate_opcodes[i].name);
425 if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM16mLDW))
426 printf ("\tFormat is %s\tRx, <16-bit value>\n",
427 xgate_opcodes[i].name);
428 }
429 }
430}
431
432void
433xgate_print_table (void)
434{
435 int i;
436
437 for (i = 0; i < xgate_num_opcodes; i++)
438 xgate_print_syntax (xgate_opcodes[i].name);
439
440 return;
441}
442
443const char *
444xgate_listing_header (void)
445{
446 if (current_architecture & cpuxgate)
447 return "XGATE GAS ";
448
449 return "ERROR MC9S12X GAS ";
450}
451
452symbolS *
453md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
454{
455 return 0;
456}
457
458/* GAS will call this function for each section at the end of the assembly,
459 to permit the CPU backend to adjust the alignment of a section. */
460
461valueT
462md_section_align (asection * seg, valueT addr)
463{
464 int align = bfd_get_section_alignment (stdoutput, seg);
465 return ((addr + (1 << align) - 1) & (-1 << align));
466}
467
468void
469md_assemble (char *input_line)
470{
471 struct xgate_opcode *opcode = 0;
472 struct xgate_opcode *macro_opcode = 0;
473 struct xgate_opcode_handle *opcode_handle = 0;
474 /* Caller expects it to be returned as it was passed. */
475 char *saved_input_line = input_line;
476 char op_name[9] = { 0 };
477 unsigned int sh_format = 0;
478 char *p = 0;
479
480 fixup_required = 0;
481 oper_check = 0; /* set error flags */
482 input_line = extract_word (input_line, op_name, sizeof(op_name));
483
484 /* Check to make sure we are not reading a bogus line. */
485 if (!op_name[0])
486 as_bad (_("opcode missing or not found on input line"));
487
488 if (!(opcode_handle = (struct xgate_opcode_handle *) hash_find (xgate_hash,
489 op_name)))
490 {
491 as_bad (_("opcode %s not found in opcode hash table"), op_name);
492 }
493 else
494 {
495 /* Detect operand format so we can pull the proper opcode bin. */
496 sh_format = xgate_detect_format (input_line);
497
498 opcode = xgate_find_match (opcode_handle, opcode_handle->number_of_modes,
499 sh_format);
500
501 if (!opcode)
502 {
503 as_bad (_("matching operands to opcode "));
504 xgate_print_syntax (opcode_handle->opc0[0]->name);
505 }
506 else if (opcode->size == 2)
507 {
508 /* Size is one word - assemble that native insn. */
509 xgate_operands (opcode, &input_line);
510 }
511 else
512 {
513 /* Insn is a simplified instruction - expand it out. */
514 macroClipping = 1;
515 unsigned int i;
516
517 /* skip past our ';' separator. */
518 for (i = strlen (opcode->constraints), p = opcode->constraints; i > 0;
519 i--, p++)
520 {
521 if (*p == ';')
522 {
523 p++;
524 break;
525 }
526 }
527 input_line = skip_whitespace (input_line);
528 char *macro_inline = input_line;
529
530 /* Loop though the macro's opcode list and apply operands to each real opcode. */
531 for (i = 0; *p && i < (opcode->size / 2); i++)
532 {
533 /* Loop though macro operand list. */
534 input_line = macro_inline; /* Rewind. */
535 p = extract_word (p, op_name, 10);
536
537 if (!(opcode_handle = (struct xgate_opcode_handle *)
538 hash_find (xgate_hash, op_name)))
539 {
540 as_bad (
541 _(": processing macro, real opcode handle not found in hash"));
542 break;
543 }
544 else
545 {
546 sh_format = xgate_detect_format (input_line);
547 macro_opcode = xgate_find_match (opcode_handle,
548 opcode_handle->number_of_modes, sh_format);
549 xgate_operands (macro_opcode, &input_line);
550 }
551 }
552 }
553 }
554 macroClipping = 0;
555 input_line = saved_input_line;
556}
557
558/* Force truly undefined symbols to their maximum size, and generally set up
559 the frag list to be relaxed. */
560
561int
562md_estimate_size_before_relax (fragS *fragp, asection *seg)
563{
564 /* If symbol is undefined or located in a different section,
565 select the largest supported relocation. */
566 relax_substateT subtype;
567 relax_substateT rlx_state[] =
568 { 0, 2 };
569
570 for (subtype = 0; subtype < ARRAY_SIZE (rlx_state); subtype += 2)
571 {
572 if (fragp->fr_subtype == rlx_state[subtype]
573 && (!S_IS_DEFINED (fragp->fr_symbol)
574 || seg != S_GET_SEGMENT (fragp->fr_symbol)))
575 {
576 fragp->fr_subtype = rlx_state[subtype + 1];
577 break;
578 }
579 }
580
581 if (fragp->fr_subtype >= ARRAY_SIZE (md_relax_table))
582 abort ();
583
584 return md_relax_table[fragp->fr_subtype].rlx_length;
585}
586
587
588/* Relocation, relaxation and frag conversions. */
589
590/* PC-relative offsets are relative to the start of the
591 next instruction. That is, the address of the offset, plus its
592 size, since the offset is always the last part of the insn. */
593
594long
595md_pcrel_from (fixS * fixP)
596{
597 return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
598}
599
600/* If while processing a fixup, a reloc really needs to be created
601 then it is done here. */
602
603arelent *
604tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
605{
606 arelent * reloc;
607
608 reloc = (arelent *) xmalloc (sizeof(arelent));
609 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof(asymbol *));
610 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
611 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
612
613 if (fixp->fx_r_type == 0)
614 {
615 reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
616 }
617 else
618 {
619 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
620 }
621
622 if (reloc->howto == (reloc_howto_type *) NULL)
623 {
624 as_bad_where (fixp->fx_file, fixp->fx_line, _
625 ("Relocation %d is not supported by object file format."),
626 (int) fixp->fx_r_type);
627 return NULL;
628 }
629
630 /* Since we use Rel instead of Rela, encode the vtable entry to be
631 used in the relocation's section offset. */
632 if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
633 reloc->address = fixp->fx_offset;
634 reloc->addend = 0;
635 return reloc;
636}
637
638/* Patch the instruction with the resolved operand. Elf relocation
639 info will also be generated to take care of linker/loader fixups.
640 The XGATE addresses only 16-bit addresses.The BFD_RELOC_32 is necessary
641 for the support of --gstabs. */
642
643void
644md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
645{
646 char *where;
647 long value = *valP;
648 int opcode = 0;
649 ldiv_t result;
650
651 /* If the fixup is done mark it done so no further symbol resolution will take place. */
652 if (fixP->fx_addsy == (symbolS *) NULL)
653 {
654 fixP->fx_done = 1;
655 }
656
657 /* We don't actually support subtracting a symbol. */
658 if (fixP->fx_subsy != (symbolS *) NULL)
659 as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
660
661 where = fixP->fx_frag->fr_literal + fixP->fx_where;
662 opcode = bfd_getl16 (where);
663 int mask = 0;
664
665 switch (fixP->fx_r_type)
666 {
667 case R_XGATE_PCREL_9:
668 if (value < -512 || value > 511)
669 as_bad_where (fixP->fx_file, fixP->fx_line,
670 _("Value %ld too large for 9-bit PC-relative branch."), value);
671 result = ldiv (value, 2); /* from bytes to words */
672 value = result.quot;
673 if (result.rem)
674 as_bad_where (fixP->fx_file, fixP->fx_line, _
675 ("Value %ld not aligned by 2 for 9-bit PC-relative branch."), value);
676 mask = 0x1FF; /* Clip into 8-bit field FIXME I'm sure there is a more proper place for this */
677 value &= mask;
678 number_to_chars_bigendian (where, (opcode | value), 2);
679 break;
680 case R_XGATE_PCREL_10:
681 if (value < -1024 || value > 1023)
682 as_bad_where (fixP->fx_file, fixP->fx_line,
683 _("Value %ld too large for 10-bit PC-relative branch."), value);
684 result = ldiv (value, 2); /* from bytes to words */
685 value = result.quot;
686 if (result.rem)
687 as_bad_where (fixP->fx_file, fixP->fx_line, _
688 ("Value %ld not aligned by 2 for 10-bit PC-relative branch."), value);
689 mask = 0x3FF; /* Clip into 9-bit field FIXME I'm sure there is a more proper place for this */
690 value &= mask;
691 number_to_chars_bigendian (where, (opcode | value), 2);
692 break;
693 case BFD_RELOC_XGATE_IMM8_HI:
694 if (value < -65537 || value > 65535)
695 as_bad_where (fixP->fx_file, fixP->fx_line,
696 _("Value out of 16-bit range."));
697 value >>= 8;
698 value &= 0x00ff;
699 bfd_putb16 ((bfd_vma) value | opcode, (void *) where);
700 break;
701 case BFD_RELOC_XGATE_24:
702 case BFD_RELOC_XGATE_IMM8_LO:
703 if (value < -65537 || value > 65535)
704 as_bad_where (fixP->fx_file, fixP->fx_line,
705 _("Value out of 16-bit range."));
706 value &= 0x00ff;
707 bfd_putb16 ((bfd_vma) value | opcode, (void *) where);
708 break;
709 case BFD_RELOC_XGATE_IMM3:
710 if (value < 0 || value > 7)
711 as_bad_where (fixP->fx_file, fixP->fx_line,
712 _("Value out of 3-bit range."));
713 value <<= 8; /* make big endian */
714 number_to_chars_bigendian (where, (opcode | value), 2);
715 break;
716 case BFD_RELOC_XGATE_IMM4:
717 if (value < 0 || value > 15)
718 as_bad_where (fixP->fx_file, fixP->fx_line,
719 _("Value out of 4-bit range."));
720 value <<= 4; /* align the operand bits */
721 number_to_chars_bigendian (where, (opcode | value), 2);
722 break;
723 case BFD_RELOC_XGATE_IMM5:
724 if (value < 0 || value > 31)
725 as_bad_where (fixP->fx_file, fixP->fx_line,
726 _("Value out of 5-bit range."));
727 value <<= 5; /* align the operand bits */
728 number_to_chars_bigendian (where, (opcode | value), 2);
729 break;
730 case BFD_RELOC_8:
731 ((bfd_byte *) where)[0] = (bfd_byte) value;
732 break;
733 case BFD_RELOC_32:
734 bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
735 /* todo figure out how to make BFD_RELOC_16 the default */
736 break;
737 case BFD_RELOC_16:
738 bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
739 break;
740 default:
741 as_fatal (_("Line %d: unknown relocation type: 0x%x."), fixP->fx_line,
742 fixP->fx_r_type);
743 break;
744 }
745}
746
747/* See whether we need to force a relocation into the output file. */
748
749int
750tc_xgate_force_relocation (fixS * fixP)
751{
752 if (fixP->fx_r_type == BFD_RELOC_XGATE_RL_GROUP)
753 return 1;
754 return generic_force_reloc (fixP);
755}
756
757/* Here we decide which fixups can be adjusted to make them relative
758 to the beginning of the section instead of the symbol. Basically
759 we need to make sure that the linker relaxation is done
760 correctly, so in some cases we force the original symbol to be
761 used. */
762
763int
764tc_xgate_fix_adjustable (fixS * fixP)
765{
766 switch (fixP->fx_r_type)
767 {
768 /* For the linker relaxation to work correctly, these relocs
769 need to be on the symbol itself. */
770 case BFD_RELOC_16:
771 case BFD_RELOC_XGATE_RL_JUMP:
772 case BFD_RELOC_XGATE_RL_GROUP:
773 case BFD_RELOC_VTABLE_INHERIT:
774 case BFD_RELOC_VTABLE_ENTRY:
775 case BFD_RELOC_32:
776 return 0;
777 default:
778 return 1;
779 }
780}
781
782void
783md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
784 asection * sec ATTRIBUTE_UNUSED,
785 fragS * fragP ATTRIBUTE_UNUSED)
786{
787 as_bad (("md_convert_frag not implemented yet"));
788 abort ();
789}
790
791/* Set the ELF specific flags. */
792
793void
794xgate_elf_final_processing (void)
795{
796 elf_flags |= EF_XGATE_MACH;
797 elf_elfheader (stdoutput)->e_flags &= ~EF_XGATE_ABI;
798 elf_elfheader (stdoutput)->e_flags |= elf_flags;
799}
800
801static inline char *
802skip_whitespace (char *s)
803{
804 while (*s == ' ' || *s == '\t' || *s == '(' || *s == ')')
805 s++;
806
807 return s;
808}
809
810/* Extract a word (continuous alpha-numeric chars) from the input line. */
811
812static char *
813extract_word (char *from, char *to, int limit)
814{
815 char *op_end;
816 int size = 0;
817
818 /* Drop leading whitespace. */
819 from = skip_whitespace (from);
820 *to = 0;
821 /* Find the op code end. */
822 for (op_end = from; *op_end != 0 && is_part_of_name (*op_end);)
823 {
824 to[size++] = *op_end++;
825 if (size + 1 >= limit)
826 break;
827 }
828 to[size] = 0;
829 return op_end;
830}
831
832static char *
833xgate_new_instruction (int size)
834{
835 char *f = frag_more (size);
836 dwarf2_emit_insn (size);
837 return f;
838}
839
840unsigned short
841xgate_apply_operand (unsigned short new_mask,
842 unsigned short *availiable_mask_bits,
843 unsigned short mask,
844 unsigned char n_bits)
845{
846 unsigned short n_shifts;
847 unsigned int n_drop_bits;
848
849 /* Shift until you find an available operand bit "1" and record the number of shifts. */
850 for (n_shifts = 0;
851 !(*availiable_mask_bits & SIXTEENTH_BIT) && n_shifts < 16;
852 n_shifts++)
853 *availiable_mask_bits <<= 1;
854
855 /* Shift for the number of bits your operand requires while bits are available. */
856 for (n_drop_bits = n_bits;
857 n_drop_bits && (*availiable_mask_bits & SIXTEENTH_BIT);
858 --n_drop_bits)
859 *availiable_mask_bits <<= 1;
860
861 if (n_drop_bits)
862 as_bad (_(":operand has too many bits"));
863 *availiable_mask_bits >>= n_shifts + n_bits;
864 if ((n_drop_bits == 0) && (*availiable_mask_bits == 0))
865 {
866 oper_check = 1; /* flag operand check as good */
867 }
868 new_mask <<= N_BITS_IN_WORD - (n_shifts + n_bits);
869 mask |= new_mask;
870 return mask;
871}
872
873/* Parse ordinary expression. */
874
875static char *
876xgate_parse_exp (char *s, expressionS * op)
877{
878 input_line_pointer = s;
879 expression(op);
880 if (op->X_op == O_absent)
881 as_bad (_("missing operand"));
882 return input_line_pointer;
883}
884
885/* For testing. Comment out to prevent defined but not used warning
886
887static unsigned int
888xgate_get_constant(char *str, int max)
889{
890 expressionS ex;
891
892 str = skip_whitespace(str);
893 input_line_pointer = str;
894 expression (& ex);
895
896 if (ex.X_op != O_constant)
897 as_bad(_("constant value required"));
898
899 if (ex.X_add_number > max || ex.X_add_number < 0)
900 as_bad(_("number must be positive and less than %d"), max + 1);
901
902 return ex.X_add_number;
903}
904*/
905
906static int
907cmp_opcode (struct xgate_opcode *op1, struct xgate_opcode *op2)
908{
909 return strcmp (op1->name, op2->name);
910}
911
912/* Parse instruction operands. */
913
914void
915xgate_operands (struct xgate_opcode *opcode, char **line)
916{
917 char *frag = xgate_new_instruction (opcode->size);
918 int where = frag - frag_now->fr_literal;
919 char *op = opcode->constraints;
920 unsigned int bin = (int) opcode->bin_opcode;
921 char *str = *line;
922 unsigned short oper_mask = 0;
923 int operand_bit_length = 0;
924 unsigned int operand = 0;
925 char n_operand_bits = 0;
926 char first_operand_equals_second = 0;
927 int i = 0;
928 char c = 0;
929
930 /* Generate available operand bits mask. */
931 for (i = 0; (c = opcode->format[i]); i++)
932 {
933 if (ISDIGIT (c) || (c == 's'))
934 {
935 oper_mask <<= 1;
936 }
937 else
938 {
939 oper_mask <<= 1;
940 oper_mask += 1;
941 n_operand_bits++;
942 }
943 }
944
945 /* Opcode has operands. */
946 /* Parse first operand. */
947 if (*op)
948 {
949 if (*op == '=')
950 {
951 first_operand_equals_second = 1;
952 ++op;
953 }
954 operand = xgate_operand (opcode, &operand_bit_length, where, &op, &str);
955 ++op;
956 bin = xgate_apply_operand (operand, &oper_mask, bin, operand_bit_length);
957 /* Parse second operand. */
958 if (*op)
959 {
960 if (*op == ',')
961 ++op;
962 str = skip_whitespace (str);
963 if (*str++ != ',')
964 {
965 if (first_operand_equals_second)
966 {
967 bin = xgate_apply_operand (operand, &oper_mask, bin,
968 operand_bit_length);
969 ++op;
970 }
971 else
972 {
973 as_bad (_("`,' required before second operand"));
974 }
975 }
976 else
977 {
978 str = skip_whitespace (str);
979 operand = xgate_operand (opcode, &operand_bit_length, where, &op,
980 &str);
981 bin = xgate_apply_operand (operand, &oper_mask, bin,
982 operand_bit_length);
983 ++op;
984 }
985 }
986
987 /* Parse the third register. */
988 if (*op)
989 {
990 if (*op == ',')
991 ++op;
992 str = skip_whitespace (str);
993 if (*str++ != ',')
994 as_bad (_("`,' required before third operand"));
995 str = skip_whitespace (str);
996 operand = xgate_operand (opcode, &operand_bit_length, where, &op,
997 &str);
998 bin = xgate_apply_operand (operand, &oper_mask, bin,
999 operand_bit_length);
1000 }
1001 }
1002 if (opcode->size == 2 && fixup_required)
1003 {
1004 bfd_putl16 (bin, frag);
1005 }
1006 else if ((opcode->sh_format & XG_PCREL))
1007 {
1008 /* Write our data to a frag for further processing. */
1009 bfd_putl16 (opcode->bin_opcode, frag);
1010 }
1011 else
1012 {
1013 /* Apply operand mask(s)to bin opcode and write the output. */
1014 /* Since we are done write this frag in xgate BE format. */
1015 number_to_chars_bigendian (frag, bin, opcode->size);
1016 }
1017 prev = bin;
1018 *line = str;
1019 return;
1020}
1021
1022static unsigned int
1023xgate_operand (struct xgate_opcode *opcode,
1024 int *bit_width,
1025 int where,
1026 char **op_con,
1027 char **line)
1028{
1029 expressionS op_expr;
1030 fixS *fixp = 0;
1031 char *op_constraint = *op_con;
1032 unsigned int op_mask = 0;
1033 char *str = skip_whitespace (*line);
1034 char r_name[20] =
1035 { 0 };
1036 unsigned int pp_fix = 0;
1037 unsigned short max_size = 0;
1038 int i;
1039
1040 *bit_width = 0;
1041 /* Reset. */
1042
1043 switch (*op_constraint)
1044 {
1045 case '+': /* Indexed register operand +/- or plain r. */
1046 /* TODO should be able to combine with with case R. */
1047
1048 /* Default to neither inc or dec. */
1049 pp_fix = 0;
1050 *bit_width = 5;
1051 str = skip_whitespace (str);
1052 while (*str != ' ' && *str != '\t')
1053 {
1054 if (*str == '-')
1055 pp_fix = DECREMENT;
1056 else if (*str == '+')
1057 pp_fix = INCREMENT;
1058 else if (*str == 'r' || *str == 'R')
1059 {
1060 str = extract_word (str, r_name, sizeof(r_name));
1061 if (ISDIGIT (r_name[1]))
1062 {
1063 if (r_name[2] == '\0' && (r_name[1] - '0' < 8))
1064 op_mask = r_name[1] - '0';
1065 if (r_name[2] != '\0' && (r_name[1] - '0' > 7))
1066 as_bad (_(": expected register name r0-r7 read %s"), r_name);
1067 continue;
1068 }
1069 }
1070 str++;
1071 }
1072 op_mask <<= 2;
1073 op_mask |= pp_fix;
1074 break;
1075
1076 case 'r': /* Register operand. */
1077 if (*str == 'r' || *str == 'R')
1078 {
1079 *bit_width = 3;
1080 str = extract_word (str, r_name, sizeof(r_name));
1081 op_mask = 0xff;
1082 if (ISDIGIT (r_name[1]))
1083 {
1084 if (r_name[2] == '\0')
1085 op_mask = r_name[1] - '0';
1086 else if (r_name[1] != '0' && ISDIGIT (r_name[2])
1087 && r_name[3] == '\0')
1088 op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
1089 if (op_mask > MAXREGISTER)
1090 as_bad (_(": expected register name r0-r7 read %s "), r_name);
1091 }
1092 }
1093 else
1094 {
1095 as_bad (_(": expected register name r0-r7 read %s "), r_name);
1096 }
1097 break;
1098
1099 case 'i': /* Immediate value or expression expected. */
1100 /* Advance the original format pointer. */
1101 (*op_con)++;
1102 op_constraint++;
1103 if (ISDIGIT (*op_constraint))
1104 {
1105 *bit_width = (int) *op_constraint - '0';
1106 }
1107 else if (*op_constraint == 'a')
1108 {
1109 *bit_width = 0x0A;
1110 }
1111 else if (*op_constraint == 'f')
1112 {
1113 *bit_width = 0x0F;
1114 }
1115 /* http://tigcc.ticalc.org/doc/gnuasm.html#SEC31 */
1116 if (*str == '#')
1117 str++;
1118 str = xgate_parse_exp (str, &op_expr);
1119 if (op_expr.X_op == O_constant)
1120 {
1121 if (!ISDIGIT (*op_constraint))
1122 as_bad (
1123 _(":expected bit length with constraint type i(# immediate) read %c"),
1124 *op_constraint);
1125 op_mask = op_expr.X_add_number;
1126 if ((opcode->name[strlen (opcode->name) - 1] == 'l') && macroClipping)
1127 {
1128 op_mask &= 0x00FF;
1129 }
1130 else if ((opcode->name[strlen (opcode->name) - 1]) == 'h'
1131 && macroClipping)
1132 {
1133 op_mask >>= 8;
1134 }
1135
1136 /* Make sure it fits. */
1137 for (i = *bit_width; i; i--)
1138 {
1139 max_size <<= 1;
1140 max_size += 1;
1141 }
1142 if (op_mask > max_size)
1143 as_bad (_(":operand value(%d) too big for constraint"), op_mask);
1144 }
1145 else
1146 {
1147 fixup_required = 1;
1148 if (*op_constraint == '8')
1149 {
1150 if ((opcode->name[strlen (opcode->name) - 1] == 'l')
1151 && macroClipping)
1152 {
1153 fixp = fix_new_exp (frag_now, where, 2, &op_expr, FALSE,
1154 BFD_RELOC_XGATE_24);
1155 /* Should be BFD_RELOC_XGATE_IMM8_LO TODO fix. */
1156 fixp->fx_pcrel_adjust = 0;
1157 }
1158 if ((opcode->name[strlen (opcode->name) - 1]) == 'h'
1159 && macroClipping)
1160 {
1161 fixp = fix_new_exp (frag_now, where, 2, &op_expr, FALSE,
1162 BFD_RELOC_XGATE_IMM8_HI);
1163 fixp->fx_pcrel_adjust = 0;
1164 }
1165 if (!fixp)
1166 as_bad (_(":unknown relocation"));
1167 }
1168 else if (*op_constraint == '5')
1169 {
1170 fixp = fix_new_exp (frag_now, where, 2, &op_expr, FALSE,
1171 BFD_RELOC_XGATE_IMM5);
1172 fixp->fx_pcrel_adjust = 0;
1173 }
1174 else if (*op_constraint == '4')
1175 {
1176 fixp = fix_new_exp (frag_now, where, 2, &op_expr, FALSE,
1177 BFD_RELOC_XGATE_IMM4);
1178 fixp->fx_pcrel_adjust = 0;
1179 }
1180 else if (*op_constraint == '3')
1181 {
1182 fixp = fix_new_exp (frag_now, where, 2, &op_expr, FALSE,
1183 BFD_RELOC_XGATE_IMM3);
1184 fixp->fx_pcrel_adjust = 0;
1185 }
1186 else
1187 {
1188 as_bad (_(":unknown relocation constraint size"));
1189 }
1190 }
1191 break;
1192
1193 case 'c': /* CCR register expected. */
1194 if (*str == 'c' || *str == 'C')
1195 {
1196 *bit_width = 0;
1197 str = extract_word (str, r_name, sizeof(r_name));
1198 if (!(strcmp (r_name, "ccr") || strcmp (r_name, "CCR")))
1199 as_bad (_(": expected register name ccr read %s "), r_name);
1200 }
1201 else
1202 {
1203 as_bad (_(": expected character c or C read %c"), *str);
1204 }
1205 break;
1206
1207 case 'p': /* PC register expected. */
1208 if (*str == 'p' || *str == 'P')
1209 {
1210 *bit_width = 0;
1211 str = extract_word (str, r_name, sizeof(r_name));
1212 if (!(strcmp (r_name, "pc") || strcmp (r_name, "PC")))
1213 as_bad (_(": expected register name pc read %s "), r_name);
1214 }
1215 else
1216 {
1217 as_bad (_(": expected character p or P read %c "), *str);
1218 }
1219 break;
1220
1221 case 'b': /* Branch expected. */
1222 str = xgate_parse_exp (str, &op_expr);
1223 (*op_con)++;
1224 op_constraint++;
1225 if (op_expr.X_op != O_register)
1226 {
1227 if (*op_constraint == '9')
1228 {
1229 /* mode == M68XG_OP_REL9 */
1230 fixp = fix_new_exp (frag_now, where, 2, &op_expr, TRUE,
1231 R_XGATE_PCREL_9);
1232 fixp->fx_pcrel_adjust = 1;
1233 }
1234 else if (*op_constraint == 'a')
1235 { /* mode == M68XG_OP_REL10 */
1236 fixp = fix_new_exp (frag_now, where, 2, &op_expr, TRUE,
1237 R_XGATE_PCREL_10);
1238 fixp->fx_pcrel_adjust = 1;
1239 }
1240 }
1241 else
1242 {
1243 as_fatal (_("Operand `%x' not recognized in fixup8."), op_expr.X_op);
1244 }
1245 break;
1246
1247 case '?':
1248 break;
1249
1250 default:
1251 as_bad (_("unknown constraint `%c'"), *op_constraint);
1252 break;
1253 }
1254 *line = str;
1255 return op_mask;
1256}
1257
1258unsigned int
1259xgate_detect_format (char *line_in)
1260{
1261 char num_operands = 0;
1262 char *str = skip_whitespace (line_in);
1263 int i = 0;
1264 int j = 0;
1265 char c = 0;
1266 unsigned int stripped_length = 0;
1267 char sh_format[10] =
1268 { 0 }; /* Shorthand format. */
1269 char operands_stripped[3][20] =
1270 {
1271 { 0 }
1272 };
1273 /* Strings. TODO maybe structure this. */
1274 char *i_string =
1275 { "i" };
1276 char *r_string =
1277 { "r" };
1278 char *r_r_string =
1279 { "r,r" };
1280 char *r_r_r_string =
1281 { "r,r,r" };
1282 char *r_i_string =
1283 { "r,i" };
1284 char *r_c_string =
1285 { "r,c" };
1286 char *c_r_string =
1287 { "c,r" };
1288 char *r_p_string =
1289 { "r,p" };
1290 char *r_r_i_string =
1291 { "r,r,i" };
1292
1293 /* If the length is zero this is an inherent instruction. */
1294 if (strlen (str) == 0)
1295 return XG_INH;
1296
1297 for (i = 0, j = 0, num_operands = 1; (c = TOLOWER (*str)) != 0; str++)
1298 {
1299 if (c == ' ' || c == '\t' || c == '(' || c == ')' || c == '-' || c == '+')
1300 continue;
1301
1302 if (c == ',')
1303 {
1304 j++;
1305 num_operands++;
1306 i = 0;
1307 continue;
1308 }
1309
1310 if (i > MAX_DETECT_CHARS)
1311 continue;
1312
1313 operands_stripped[j][i++] = c;
1314 }
1315
1316 /* Process our substrings to see what we have. */
1317 for (i = 0, j = 0; num_operands > i; i++)
1318 {
1319 stripped_length = strlen (&operands_stripped[i][0]);
1320
1321 /* Add separator if we have more than one operand. */
1322 if (i > 0)
1323 sh_format[j++] = ',';
1324
1325 /* Try to process by length first. */
1326 if (stripped_length > 3)
1327 {
1328 sh_format[j++] = 'i';
1329 }
1330 else if (stripped_length == 1)
1331 {
1332 sh_format[j++] = 'i';
1333 }
1334 else if (stripped_length == 2)
1335 {
1336 if (operands_stripped[i][0]
1337 == 'r' && ISDIGIT (operands_stripped[i][1]))
1338 {
1339 sh_format[j++] = 'r';
1340 }
1341 else if (operands_stripped[i][0] == 'p'
1342 && operands_stripped[i][1] == 'c')
1343 {
1344 sh_format[j++] = 'p';
1345 }
1346 else
1347 {
1348 sh_format[j++] = 'i';
1349 }
1350 }
1351 else if (stripped_length == 3)
1352 {
1353 if (operands_stripped[i][0] == 'c'
1354 && (operands_stripped[i][1] == 'c'
1355 && operands_stripped[i][2] == 'r'))
1356 {
1357 sh_format[j++] = 'c';
1358 }
1359 else if (operands_stripped[i][0] == '#')
1360 {
1361 sh_format[j++] = 'i';
1362 }
1363 else
1364 {
1365 sh_format[j++] = 'i';
1366 }
1367 }
1368 else /* default to immediate */
1369 {
1370 sh_format[j++] = 'i';
1371 }
1372 }
1373
1374 /* See if we have a match. */
1375 if (!strcmp (i_string, sh_format) && num_operands == 1)
1376 return XG_I;
1377 if (!strcmp (r_i_string, sh_format) && num_operands == 2)
1378 return XG_R_I;
1379 if (!strcmp (r_r_r_string, sh_format) && num_operands == 3)
1380 return XG_R_R_R;
1381 if (!strcmp (r_r_string, sh_format) && num_operands == 2)
1382 return XG_R_R;
1383 if (!strcmp (r_string, sh_format) && num_operands == 1)
1384 return XG_R;
1385 if (!strcmp (r_c_string, sh_format) && num_operands == 2)
1386 return XG_R_C;
1387 if (!strcmp (c_r_string, sh_format) && num_operands == 2)
1388 return XG_C_R;
1389 if (!strcmp (r_p_string, sh_format) && num_operands == 2)
1390 return XG_R_P;
1391 if (!strcmp (r_r_i_string, sh_format) && num_operands == 3)
1392 return XG_R_R_I;
1393
1394 return 0;
1395}
1396
1397static struct xgate_opcode *
1398xgate_find_match (struct xgate_opcode_handle *opcode_handle,
1399 int numberOfModes,
1400 unsigned int sh_format)
1401{
1402 int i;
1403
1404 if (numberOfModes == 0)
1405 return opcode_handle->opc0[0];
1406
1407 for (i = 0; i <= numberOfModes; i++)
1408 if (opcode_handle->opc0[i]->sh_format & sh_format)
1409 return opcode_handle->opc0[i];
1410
1411 return NULL;
1412}
fe540416
SK
1413
1414/* Because we are dealing with two different core that view the system
1415 memory with different offsets, we must differentiate what core a
1416 symbol belongs to, in order for the linker to cross-link. */
1417
1418int
1419xgate_frob_symbol (symbolS *sym)
1420{
1421 asymbol *bfdsym;
1422 elf_symbol_type *elfsym;
1423
1424 bfdsym = symbol_get_bfdsym (sym);
1425 elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
1426
1427 gas_assert(elfsym);
1428
1429 /* Mark the symbol as being *from XGATE */
1430 elfsym->internal_elf_sym.st_target_internal = 1;
1431
1432 return 0;
1433}
This page took 0.094438 seconds and 4 git commands to generate.