📄 tc-mcore.c
字号:
/* tc-mcore.c -- Assemble code for M*Core Copyright 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <stdio.h>#include "as.h"#include "bfd.h"#include "subsegs.h"#define DEFINE_TABLE#include "../opcodes/mcore-opc.h"#include <ctype.h>#include <string.h>#ifdef OBJ_ELF#include "elf/mcore.h"#endif#ifndef streq#define streq(a,b) (strcmp (a, b) == 0)#endif/* Forward declarations for dumb compilers. */static void mcore_s_literals PARAMS ((int));static void mcore_cons PARAMS ((int));static void mcore_float_cons PARAMS ((int));static void mcore_stringer PARAMS ((int));static void mcore_fill PARAMS ((int));static int log2 PARAMS ((unsigned int));static char * parse_reg PARAMS ((char *, unsigned *));static char * parse_creg PARAMS ((char *, unsigned *));static char * parse_exp PARAMS ((char *, expressionS *));static char * parse_rt PARAMS ((char *, char **, int, expressionS *));static char * parse_imm PARAMS ((char *, unsigned *, unsigned, unsigned));static char * parse_mem PARAMS ((char *, unsigned *, unsigned *, unsigned));static char * parse_psrmod PARAMS ((char *, unsigned *));static void make_name PARAMS ((char *, char *, int));static int enter_literal PARAMS ((expressionS *, int));static void dump_literals PARAMS ((int));static void check_literals PARAMS ((int, int));static void mcore_s_text PARAMS ((int));static void mcore_s_data PARAMS ((int));static void mcore_s_section PARAMS ((int));static void mcore_s_bss PARAMS ((int));#ifdef OBJ_ELFstatic void mcore_s_comm PARAMS ((int));#endif/* Several places in this file insert raw instructions into the object. They should use MCORE_INST_XXX macros to get the opcodes and then use these two macros to crack the MCORE_INST value into the appropriate byte values. */#define INST_BYTE0(x) (target_big_endian ? (((x) >> 8) & 0xFF) : ((x) & 0xFF))#define INST_BYTE1(x) (target_big_endian ? ((x) & 0xFF) : (((x) >> 8) & 0xFF))const char comment_chars[] = "#/";const char line_separator_chars[] = ";";const char line_comment_chars[] = "#/";const int md_reloc_size = 8;static int do_jsri2bsr = 0; /* Change here from 1 by Cruess 19 August 97. */static int sifilter_mode = 0;const char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant As in 0f12.456 or 0d1.2345e12 */const char FLT_CHARS[] = "rRsSfFdDxXpP";#define C(what,length) (((what) << 2) + (length))#define GET_WHAT(x) ((x >> 2))/* These are the two types of relaxable instruction */#define COND_JUMP 1#define UNCD_JUMP 2#define UNDEF_DISP 0#define DISP12 1#define DISP32 2#define UNDEF_WORD_DISP 3#define C12_LEN 2#define C32_LEN 10 /* allow for align */#define U12_LEN 2#define U32_LEN 8 /* allow for align */typedef enum{ M210, M340}cpu_type;cpu_type cpu = M340;/* Initialize the relax table. */const relax_typeS md_relax_table[] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* COND_JUMP */ { 0, 0, 0, 0 }, /* UNDEF_DISP */ { 2048, -2046, C12_LEN, C(COND_JUMP, DISP32) }, /* DISP12 */ { 0, 0, C32_LEN, 0 }, /* DISP32 */ { 0, 0, C32_LEN, 0 }, /* UNDEF_WORD_DISP */ /* UNCD_JUMP */ { 0, 0, 0, 0 }, /* UNDEF_DISP */ { 2048, -2046, U12_LEN, C(UNCD_JUMP, DISP32) }, /* DISP12 */ { 0, 0, U32_LEN, 0 }, /* DISP32 */ { 0, 0, U32_LEN, 0 } /* UNDEF_WORD_DISP */};/* Literal pool data structures. */struct literal{ unsigned short refcnt; unsigned char ispcrel; unsigned char unused; expressionS e;};#define MAX_POOL_SIZE (1024/4)static struct literal litpool [MAX_POOL_SIZE];static unsigned poolsize;static unsigned poolnumber;static unsigned long poolspan;/* SPANPANIC: the point at which we get too scared and force a dump of the literal pool, and perhaps put a branch in place. Calculated as: 1024 span of lrw/jmpi/jsri insn (actually span+1) -2 possible alignment at the insn. -2 possible alignment to get the table aligned. -2 an inserted branch around the table. == 1018 at 1018, we might be in trouble. -- so we have to be smaller than 1018 and since we deal with 2-byte instructions, the next good choice is 1016. -- Note we have a test case that fails when we've got 1018 here. */#define SPANPANIC (1016) /* 1024 - 1 entry - 2 byte rounding. */#define SPANCLOSE (900)#define SPANEXIT (600)static symbolS * poolsym; /* label for current pool. */static char poolname[8];static struct hash_control * opcode_hash_control; /* Opcode mnemonics. *//* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: Pseudo-op name without dot Function to call to execute this pseudo-op Integer arg to pass to the function. */const pseudo_typeS md_pseudo_table[] ={ { "export", s_globl, 0 }, { "import", s_ignore, 0 }, { "literals", mcore_s_literals, 0 }, { "page", listing_eject, 0 }, /* The following are to intercept the placement of data into the text section (eg addresses for a switch table), so that the space they occupy can be taken into account when deciding whether or not to dump the current literal pool. XXX - currently we do not cope with the .space and .dcb.d directives. */ { "ascii", mcore_stringer, 0 }, { "asciz", mcore_stringer, 1 }, { "byte", mcore_cons, 1 }, { "dc", mcore_cons, 2 }, { "dc.b", mcore_cons, 1 }, { "dc.d", mcore_float_cons, 'd'}, { "dc.l", mcore_cons, 4 }, { "dc.s", mcore_float_cons, 'f'}, { "dc.w", mcore_cons, 2 }, { "dc.x", mcore_float_cons, 'x'}, { "double", mcore_float_cons, 'd'}, { "float", mcore_float_cons, 'f'}, { "hword", mcore_cons, 2 }, { "int", mcore_cons, 4 }, { "long", mcore_cons, 4 }, { "octa", mcore_cons, 16 }, { "quad", mcore_cons, 8 }, { "short", mcore_cons, 2 }, { "single", mcore_float_cons, 'f'}, { "string", mcore_stringer, 1 }, { "word", mcore_cons, 2 }, { "fill", mcore_fill, 0 }, /* Allow for the effect of section changes. */ { "text", mcore_s_text, 0 }, { "data", mcore_s_data, 0 }, { "bss", mcore_s_bss, 1 },#ifdef OBJ_EF { "comm", mcore_s_comm, 0 },#endif { "section", mcore_s_section, 0 }, { "section.s", mcore_s_section, 0 }, { "sect", mcore_s_section, 0 }, { "sect.s", mcore_s_section, 0 }, { 0, 0, 0 }};static voidmcore_s_literals (ignore) int ignore;{ dump_literals (0); demand_empty_rest_of_line ();}static voidmcore_cons (nbytes) int nbytes;{ if (now_seg == text_section) { char * ptr = input_line_pointer; int commas = 1; /* Count the number of commas on the line. */ while (! is_end_of_line [(unsigned char) * ptr]) commas += * ptr ++ == ','; poolspan += nbytes * commas; } cons (nbytes); /* In theory we ought to call check_literals (2,0) here in case we need to dump the literal table. We cannot do this however, as the directives that we are intercepting may be being used to build a switch table, and we must not interfere with its contents. Instead we cross our fingers and pray... */}static voidmcore_float_cons (float_type) int float_type;{ if (now_seg == text_section) { char * ptr = input_line_pointer; int commas = 1;#ifdef REPEAT_CONS_EXPRESSIONS#error REPEAT_CONS_EXPRESSIONS not handled#endif /* Count the number of commas on the line. */ while (! is_end_of_line [(unsigned char) * ptr]) commas += * ptr ++ == ','; /* We would like to compute "hex_float (float_type) * commas" but hex_float is not exported from read.c */ float_type == 'f' ? 4 : (float_type == 'd' ? 8 : 12); poolspan += float_type * commas; } float_cons (float_type); /* See the comment in mcore_cons () about calling check_literals. It is unlikely that a switch table will be constructed using floating point values, but it is still likely that an indexed table of floating point constants is being created by these directives, so again we must not interfere with their placement. */}static voidmcore_stringer (append_zero) int append_zero;{ if (now_seg == text_section) { char * ptr = input_line_pointer; /* In theory we should compute how many bytes are going to be occupied by the string(s) and add this to the poolspan. To keep things simple however, we just add the number of bytes left on the current line. This will be an over- estimate, which is OK, and automatically allows for the appending a zero byte, since the real string(s) is/are required to be enclosed in double quotes. */ while (! is_end_of_line [(unsigned char) * ptr]) ptr ++; poolspan += ptr - input_line_pointer; } stringer (append_zero); /* We call check_literals here in case a large number of strings are being placed into the text section with a sequence of stringer directives. In theory we could be upsetting something if these strings are actually in an indexed table instead of referenced by individual labels. Let us hope that that never happens. */ check_literals (2, 0);}static voidmcore_fill (unused) int unused;{ if (now_seg == text_section) { char * str = input_line_pointer; int size = 1; int repeat; repeat = atoi (str); /* Look to see if a size has been specified. */ while (*str != '\n' && *str != 0 && *str != ',') ++ str; if (* str == ',') { size = atoi (str + 1); if (size > 8) size = 8; else if (size < 0) size = 0; } poolspan += size * repeat; } s_fill (unused); check_literals (2, 0);}/* Handle the section changing pseudo-ops. These call through to the normal implementations, but they dump the literal pool first. */static voidmcore_s_text (ignore) int ignore;{ dump_literals (0);#ifdef OBJ_ELF obj_elf_text (ignore);#else s_text (ignore);#endif}static voidmcore_s_data (ignore) int ignore;{ dump_literals (0);#ifdef OBJ_ELF obj_elf_data (ignore);#else s_data (ignore);#endif}static voidmcore_s_section (ignore) int ignore;{ /* Scan forwards to find the name of the section. If the section being switched to is ".line" then this is a DWARF1 debug section which is arbitarily placed inside generated code. In this case do not dump the literal pool because it is a) inefficient and b) would require the generation of extra code to jump around the pool. */ char * ilp = input_line_pointer; while (*ilp != 0 && isspace(*ilp)) ++ ilp; if (strncmp (ilp, ".line", 5) == 0 && (isspace (ilp[5]) || *ilp == '\n' || *ilp == '\r')) ; else dump_literals (0);#ifdef OBJ_ELF obj_elf_section (ignore);#endif#ifdef OBJ_COFF obj_coff_section (ignore);#endif}static voidmcore_s_bss (needs_align) int needs_align;{ dump_literals (0); s_lcomm_bytes (needs_align);}#ifdef OBJ_ELFstatic voidmcore_s_comm (needs_align) int needs_align;{ dump_literals (0); obj_elf_common (needs_align);}#endif/* This function is called once, at assembler startup time. This should set up all the tables, etc that the MD part of the assembler needs. */voidmd_begin (){ mcore_opcode_info * opcode; char * prev_name = ""; opcode_hash_control = hash_new (); /* Insert unique names into hash table */ for (opcode = mcore_table; opcode->name; opcode ++) { if (streq (prev_name, opcode->name)) { /* Make all the opcodes with the same name point to the same string. */ opcode->name = prev_name; } else { prev_name = opcode->name; hash_insert (opcode_hash_control, opcode->name, (char *) opcode); } }}static int reg_m;static int reg_n;static expressionS immediate; /* absolute expression *//* Get a log2(val). */static intlog2 (val) unsigned int val;{ int log = -1; while (val != 0) { log ++; val >>= 1; } return log;}/* Try to parse a reg name. */static char *parse_reg (s, reg) char * s; unsigned * reg;{ /* Strip leading whitespace. */ while (isspace (* s)) ++ s; if (tolower (s[0]) == 'r') { if (s[1] == '1' && s[2] >= '0' && s[2] <= '5') { *reg = 10 + s[2] - '0'; return s + 3; } if (s[1] >= '0' && s[1] <= '9') { *reg = s[1] - '0'; return s + 2; } } else if ( tolower (s[0]) == 's' && tolower (s[1]) == 'p' && ! isalnum (s[2])) { * reg = 0; return s + 2; } as_bad (_("register expected, but saw '%.6s'"), s); return s;}static struct Cregs{ char * name; unsigned int crnum;}cregs[] ={ { "psr", 0}, { "vbr", 1}, { "epsr", 2}, { "fpsr", 3}, { "epc", 4}, { "fpc", 5}, { "ss0", 6}, { "ss1", 7}, { "ss2", 8}, { "ss3", 9}, { "ss4", 10}, { "gcr", 11}, { "gsr", 12}, { "", 0}};static char *parse_creg (s, reg) char * s; unsigned * reg;{ int i; /* Strip leading whitespace. */ while (isspace (* s)) ++s; if ((tolower (s[0]) == 'c' && tolower (s[1]) == 'r')) { if (s[2] == '3' && s[3] >= '0' && s[3] <= '1') { *reg = 30 + s[3] - '0'; return s + 4; } if (s[2] == '2' && s[3] >= '0' && s[3] <= '9') { *reg = 20 + s[3] - '0'; return s + 4; } if (s[2] == '1' && s[3] >= '0' && s[3] <= '9') { *reg = 10 + s[3] - '0'; return s + 4; } if (s[2] >= '0' && s[2] <= '9') { *reg = s[2] - '0'; return s + 3; } } /* Look at alternate creg names before giving error. */ for (i = 0; cregs[i].name[0] != '\0'; i++) { char buf [10]; int length; int j; length = strlen (cregs[i].name); for (j = 0; j < length; j++) buf[j] = tolower (s[j]); if (strncmp (cregs[i].name, buf, length) == 0) { *reg = cregs[i].crnum; return s + length; } } as_bad (_("control register expected, but saw '%.6s'"), s); return s;}static char *parse_psrmod (s, reg) char * s; unsigned * reg;{ int i; char buf[10]; static struct psrmods { char * name; unsigned int value; } psrmods[] = { { "ie", 1 }, { "fe", 2 }, { "ee", 4 }, { "af", 8 } /* Really 0 and non-combinable. */ };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -