From 11e081968e1319af2a2501182c57257e7b5f86d8 Mon Sep 17 00:00:00 2001 From: Fred Fish Date: Tue, 11 Feb 1997 22:44:10 +0000 Subject: [PATCH] * config/tc-tic80.c: Numerous changes and additions to flesh out functions that were previously just stubs, and fix some problems found using the new TIc80 testsuite cases. --- gas/ChangeLog | 8 + gas/config/tc-tic80.c | 458 +++++++++++++++++++++++++++++++++++------- 2 files changed, 389 insertions(+), 77 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 0b2ba3be5b5..672851d0d1c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,11 @@ +start-sanitize-tic80 +Tue Feb 11 15:13:39 1997 Fred Fish + + * config/tc-tic80.c: Numerous changes and additions to flesh + out functions that were previously just stubs, and fix some + problems found using the new TIc80 testsuite cases. + +end-sanitize-tic80 Tue Feb 11 15:52:22 1997 Ian Lance Taylor * config/tc-mips.c (mips16_ip): Handle %gprel modifier. diff --git a/gas/config/tc-tic80.c b/gas/config/tc-tic80.c index b638d8c47d0..e0061f55dce 100644 --- a/gas/config/tc-tic80.c +++ b/gas/config/tc-tic80.c @@ -21,6 +21,11 @@ #include "as.h" #include "opcode/tic80.h" +#define internal_error(what) \ + as_fatal("internal error:%s:%d: %s\n",__FILE__,__LINE__,what) +#define internal_error_a(what,arg) \ + as_fatal("internal error:%s:%d: %s %d\n",__FILE__,__LINE__,what,arg) + /* Generic assembler global variables which must be defined by all targets. */ @@ -31,8 +36,8 @@ const char comment_chars[] = ";"; const char line_comment_chars[] = ";*"; /* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; + single line. */ +const char line_separator_chars[] = ""; /* Characters which are used to indicate an exponent in a floating point number. */ @@ -59,10 +64,12 @@ const pseudo_typeS md_pseudo_table[] = static struct hash_control *tic80_hash; static struct tic80_opcode * find_opcode PARAMS ((struct tic80_opcode *, expressionS [])); -static unsigned long build_insn PARAMS ((struct tic80_opcode *, expressionS *, unsigned long insn)); +static void build_insn PARAMS ((struct tic80_opcode *, expressionS *)); static int get_operands PARAMS ((expressionS exp[])); -static int reg_name_search PARAMS ((char *name)); static int register_name PARAMS ((expressionS *expressionP)); +static int is_bitnum PARAMS ((expressionS *expressionP)); +static int is_ccode PARAMS ((expressionS *expressionP)); +static int const_overflow PARAMS ((unsigned long num, int bits, int flags)); int @@ -70,7 +77,7 @@ md_estimate_size_before_relax (fragP, segment_type) fragS *fragP; segT segment_type; { - as_fatal ("Relaxation is a luxury we can't afford\n"); + internal_error ("Relaxation is a luxury we can't afford"); return (-1); } @@ -140,53 +147,58 @@ md_atof (type, litP, sizeP) return (NULL); } -/* reg_name_search does a binary search of the tic80_pre_defined_registers - array to see if "name" is a valid regiter name. Returns the register - number from the array on success, or -1 on failure. */ +/* register_name() checks the string at input_line_pointer + to see if it is a valid register name */ static int -reg_name_search (name) - char *name; +register_name (expressionP) + expressionS *expressionP; { - int middle, low, high; - int cmp; + int reg_number, class; + char c; + char *p = input_line_pointer; + + while (*p != '\000' && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != '(' && *p != ')') + p++; + + c = *p; + if (c) + { + *p++ = '\000'; + } - low = 0; - high = tic80_num_regs - 1; + /* look to see if it's in the register table */ - do + class = TIC80_OPERAND_FPA | TIC80_OPERAND_CR | TIC80_OPERAND_GPR; + reg_number = tic80_symbol_to_value (input_line_pointer, class); + if (reg_number != -1) { - middle = (low + high) / 2; - cmp = strcasecmp (name, tic80_pre_defined_registers[middle].name); - if (cmp < 0) - { - high = middle - 1; - } - else if (cmp > 0) - { - low = middle + 1; - } - else - { - return (tic80_pre_defined_registers[middle].value); - } + expressionP -> X_op = O_register; + /* temporarily store a pointer to the string here */ + expressionP -> X_op_symbol = (struct symbol *) input_line_pointer; + expressionP -> X_add_number = reg_number; + input_line_pointer = p; + return (1); } - while (low <= high); - return (-1); + if (c) + { + *(p - 1) = c; + } + return (0); } -/* register_name() checks the string at input_line_pointer - to see if it is a valid register name */ +/* is_bitnum() checks the string at input_line_pointer + to see if it is a valid predefined symbol for the BITNUM field */ static int -register_name (expressionP) +is_bitnum (expressionP) expressionS *expressionP; { - int reg_number; + int bitnum_val, class; char c; char *p = input_line_pointer; - while (*p != '\000' && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != ')') + while (*p != '\000' && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != '(' && *p != ')') p++; c = *p; @@ -197,13 +209,15 @@ register_name (expressionP) /* look to see if it's in the register table */ - reg_number = reg_name_search (input_line_pointer); - if (reg_number >= 0) + class = TIC80_OPERAND_BITNUM; + bitnum_val = tic80_symbol_to_value (input_line_pointer, class); + if (bitnum_val != -1) { - expressionP -> X_op = O_register; + expressionP -> X_op = O_constant; /* temporarily store a pointer to the string here */ expressionP -> X_op_symbol = (struct symbol *) input_line_pointer; - expressionP -> X_add_number = reg_number; + /* Bitnums are stored as one's complement */ + expressionP -> X_add_number = ~bitnum_val & 0x1F; input_line_pointer = p; return (1); } @@ -214,6 +228,75 @@ register_name (expressionP) return (0); } +/* is_ccode() checks the string at input_line_pointer + to see if it is a valid predefined symbol for the a condition code */ + +static int +is_ccode (expressionP) + expressionS *expressionP; +{ + int ccode_val, class; + char c; + char *p = input_line_pointer; + + while (*p != '\000' && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != '(' && *p != ')') + p++; + + c = *p; + if (c) + { + *p++ = '\000'; + } + + /* look to see if it's in the register table */ + + class = TIC80_OPERAND_CC; + ccode_val = tic80_symbol_to_value (input_line_pointer, class); + if (ccode_val != -1) + { + expressionP -> X_op = O_constant; + /* temporarily store a pointer to the string here */ + expressionP -> X_op_symbol = (struct symbol *) input_line_pointer; + expressionP -> X_add_number = ccode_val & 0x1F; + input_line_pointer = p; + return (1); + } + if (c) + { + *(p - 1) = c; + } + return (0); +} + +/* Check to see if the constant value in NUM will fit in a field of + width BITS if it has flags FLAGS. */ + +static int +const_overflow (num, bits, flags) + unsigned long num; + int bits; + int flags; +{ + long min, max; + int retval = 0; + + /* Only need to check fields less than 32 bits wide */ + if (bits < 32) + if (flags & TIC80_OPERAND_SIGNED) + { + max = (1 << (bits - 1)) - 1; + min = - (1 << (bits - 1)); + retval = ((long) num > max) || ((long) num < min); + } + else + { + max = (1 << bits) - 1; + min = 0; + retval = (num > max) || (num < min); + } + return (retval); +} + /* get_operands() parses a string of operands and fills in a passed array of expressions in EXP. @@ -307,9 +390,12 @@ get_operands (exp) input_line_pointer = p; - /* Check to see if it might be a register name */ + /* Check to see if it might be a register name or some other + predefined symbol name that translates into a constant value. */ - if (!register_name (&exp[numexp])) + if (!register_name (&exp[numexp]) && + !is_bitnum (&exp[numexp]) && + !is_ccode (&exp[numexp])) { /* parse as an expression */ expression (&exp[numexp]); @@ -334,7 +420,9 @@ get_operands (exp) exp[numexp++].X_add_number = TIC80_OPERAND_PARENS; } - exp[numexp].X_op = 0; + /* Mark the end of the valid operands with an illegal expression. */ + exp[numexp].X_op = O_illegal; + return (numexp); } @@ -347,23 +435,126 @@ get_operands (exp) previous non-O_absent expression, such as ":m" or ":s" modifiers or register numbers enclosed in parens like "(r10)". - It then looks at all opcodes with the same name and use the operands to + It then looks at all opcodes with the same name and uses the operands to choose the correct opcode. */ - static struct tic80_opcode * find_opcode (opcode, myops) struct tic80_opcode *opcode; expressionS myops[]; { - int i, match, done, numops; - struct tic80_opcode *next_opcode; + int numexp; /* Number of expressions from parsing operands */ + int expi; /* Index of current expression to match */ + int opi; /* Index of current operand to match */ + int match = 0; /* Set to 1 when an operand match is found */ + struct tic80_opcode *opc = opcode; /* Pointer to current opcode table entry */ + const struct tic80_opcode *end; /* Pointer to end of opcode table */ + + /* First parse all the operands so we only have to do it once. There may + be more expressions generated than there are operands. */ + + numexp = get_operands (myops); + + /* For each opcode with the same name, try to match it against the parsed + operands. */ + + end = tic80_opcodes + tic80_num_opcodes; + while (!match && (opc < end) && (strcmp (opc -> name, opcode -> name) == 0)) + { + /* Start off assuming a match. If we find a mismatch, then this is + reset and the operand/expr matching loop terminates with match + equal to zero, which allows us to try the next opcode. */ + + match = 1; + + /* For each expression, try to match it against the current operand + for the current opcode. Upon any mismatch, we abandon further + matching for the current opcode table entry. */ - match = 0; + for (expi = 0, opi = -1; (expi < numexp) && match; expi++) + { + int bits, flags, X_op, num; - /* First parse all the operands so we only have to do it once. */ + X_op = myops[expi].X_op; + num = myops[expi].X_add_number; + if (X_op != O_absent) + { + /* The O_absent expressions apply to the previously seen + operand, so only increment the operand index when the + current expression needs to be matched against the next + operand. */ + opi++; + } + flags = tic80_operands[opc -> operands[opi]].flags; + bits = tic80_operands[opc -> operands[opi]].bits; - get_operands (myops); + switch (X_op) + { + case O_register: + /* Also check that registers that are supposed to be even actually + are even. */ + if (((flags & TIC80_OPERAND_GPR) != (num & TIC80_OPERAND_GPR)) || + ((flags & TIC80_OPERAND_FPA) != (num & TIC80_OPERAND_FPA)) || + ((flags & TIC80_OPERAND_CR) != (num & TIC80_OPERAND_CR)) || + ((flags & TIC80_OPERAND_EVEN) && (num & 1)) || + const_overflow (num & ~TIC80_OPERAND_MASK, bits, flags)) + { + match = 0; + } + break; + case O_constant: + if ((flags & TIC80_OPERAND_ENDMASK) && (num == 32)) + { + /* Endmask values of 0 and 32 give identical results */ + num = 0; + } + if ((flags & (TIC80_OPERAND_FPA | TIC80_OPERAND_GPR)) || + const_overflow (num, bits, flags)) + { + match = 0; + } + break; + case O_illegal: + case O_absent: + case O_symbol: + case O_symbol_rva: + case O_big: + case O_uminus: + case O_bit_not: + case O_logical_not: + case O_multiply: + case O_divide: + case O_modulus: + case O_left_shift: + case O_right_shift: + case O_bit_inclusive_or: + case O_bit_or_not: + case O_bit_exclusive_or: + case O_bit_and: + case O_add: + case O_subtract: + case O_eq: + case O_ne: + case O_lt: + case O_le: + case O_ge: + case O_gt: + case O_logical_and: + case O_logical_or: + case O_max: + default: + internal_error_a ("unhandled expression type", X_op); + } + } + if (!match) + { + opc++; + } + } + + return (match ? opc : NULL); + +#if 0 /* Now search the opcode table table for one with operands that matches what we've got. */ @@ -383,23 +574,23 @@ find_opcode (opcode, myops) break; } - if (flags & TIC80_OPERAND_GPR) + if (flags & (TIC80_OPERAND_GPR | TIC80_OPERAND_FPA | TIC80_OPERAND_CR)) { if ((X_op != O_register) || - ((flags & OPERAND_ACC) != (num & OPERAND_ACC)) || - ((flags & OPERAND_FLAG) != (num & OPERAND_FLAG)) || - ((flags & OPERAND_CONTROL) != (num & OPERAND_CONTROL))) + ((flags & TIC80_OPERAND_GPR) != (num & TIC80_OPERAND_GPR)) || + ((flags & TIC80_OPERAND_FPA) != (num & TIC80_OPERAND_FPA)) || + ((flags & TIC80_OPERAND_CR) != (num & TIC80_OPERAND_CR))) { match=0; break; } } - if (((flags & OPERAND_MINUS) && ((X_op != O_absent) || (num != OPERAND_MINUS))) || - ((flags & OPERAND_PLUS) && ((X_op != O_absent) || (num != OPERAND_PLUS))) || - ((flags & OPERAND_ATMINUS) && ((X_op != O_absent) || (num != OPERAND_ATMINUS))) || - ((flags & OPERAND_ATPAR) && ((X_op != O_absent) || (num != OPERAND_ATPAR))) || - ((flags & OPERAND_ATSIGN) && ((X_op != O_absent) || (num != OPERAND_ATSIGN)))) + if (((flags & TIC80_OPERAND_MINUS) && ((X_op != O_absent) || (num != TIC80_OPERAND_MINUS))) || + ((flags & TIC80_OPERAND_PLUS) && ((X_op != O_absent) || (num != TIC80_OPERAND_PLUS))) || + ((flags & TIC80_OPERAND_ATMINUS) && ((X_op != O_absent) || (num != TIC80_OPERAND_ATMINUS))) || + ((flags & TIC80_OPERAND_ATPAR) && ((X_op != O_absent) || (num != TIC80_OPERAND_ATPAR))) || + ((flags & TIC80_OPERAND_ATSIGN) && ((X_op != O_absent) || (num != TIC80_OPERAND_ATSIGN)))) { match=0; break; @@ -431,12 +622,12 @@ find_opcode (opcode, myops) /* fix that here. */ for (i=0; opcode->operands[i]; i++) { - if ((tic80_operands[opcode->operands[i]].flags & OPERAND_EVEN) && + if ((tic80_operands[opcode->operands[i]].flags & TIC80_OPERAND_EVEN) && (myops[i].X_add_number & 1)) - as_fatal("Register number must be EVEN"); + as_fatal ("Register number must be EVEN"); if (myops[i].X_op == O_register) { - if (!(tic80_operands[opcode->operands[i]].flags & OPERAND_REG)) + if (!(tic80_operands[opcode->operands[i]].flags & TIC80_OPERAND_REG)) { myops[i].X_op = O_symbol; myops[i].X_add_symbol = symbol_find_or_make ((char *)myops[i].X_op_symbol); @@ -445,19 +636,134 @@ find_opcode (opcode, myops) } } } - return opcode; + +#endif } /* build_insn takes a pointer to the opcode entry in the opcode table - and the array of operand expressions and returns the instruction */ + and the array of operand expressions and writes out the instruction. */ -static unsigned long -build_insn (opcode, opers, insn) +static void +build_insn (opcode, opers) struct tic80_opcode *opcode; expressionS *opers; - unsigned long insn; { - return (0); + int expi; /* Index of current expression to match */ + int opi; /* Index of current operand to match */ + unsigned long insn[2]; /* Instruction and long immediate (if any) */ + int extended = 0; /* Nonzero if instruction is 8 bytes */ + char *f; /* Temporary pointer to output location */ + + /* Start with the raw opcode bits from the opcode table. */ + insn[0] = opcode -> opcode; + + /* For each operand expression, insert the appropriate bits into the + instruction . */ + for (expi = 0, opi = -1; opers[expi].X_op != O_illegal; expi++) + { + int bits, shift, flags, X_op, num; + + X_op = opers[expi].X_op; + num = opers[expi].X_add_number; + if (X_op != O_absent) + { + /* The O_absent expressions apply to the previously seen + operand, so only increment the operand index when the + current expression needs to be matched against the next + operand. */ + opi++; + } + else + { + /* Found a modifier that applies to the previously + seen operand, so handle it. */ + switch (opers[expi].X_add_number) + { + case TIC80_OPERAND_M_SI | TIC80_OPERAND_M_LI: + internal_error_a ("unhandled operand modifier", opers[expi].X_add_number); + break; + case TIC80_OPERAND_SCALED: + internal_error_a ("unhandled operand modifier", opers[expi].X_add_number); + break; + case TIC80_OPERAND_PARENS: + internal_error_a ("unhandled operand modifier", opers[expi].X_add_number); + break; + default: + internal_error_a ("unhandled operand modifier", opers[expi].X_add_number); + break; + } + } + flags = tic80_operands[opcode -> operands[opi]].flags; + bits = tic80_operands[opcode -> operands[opi]].bits; + shift = tic80_operands[opcode -> operands[opi]].shift; + + switch (X_op) + { + case O_register: + num &= ~TIC80_OPERAND_MASK; + insn[0] = insn[0] | (num << shift); + break; + case O_constant: + if ((flags & TIC80_OPERAND_ENDMASK) && (num == 32)) + { + /* Endmask values of 0 and 32 give identical results */ + num = 0; + } + /* Mask off upper bits, just it case it is signed and is negative */ + if (bits < 32) + { + num &= (1 << bits) - 1; + insn[0] = insn[0] | (num << shift); + } + else + { + extended++; + insn[1] = num; + } + break; + case O_illegal: + case O_absent: + case O_symbol: + case O_symbol_rva: + case O_big: + case O_uminus: + case O_bit_not: + case O_logical_not: + case O_multiply: + case O_divide: + case O_modulus: + case O_left_shift: + case O_right_shift: + case O_bit_inclusive_or: + case O_bit_or_not: + case O_bit_exclusive_or: + case O_bit_and: + case O_add: + case O_subtract: + case O_eq: + case O_ne: + case O_lt: + case O_le: + case O_ge: + case O_gt: + case O_logical_and: + case O_logical_or: + case O_max: + default: + internal_error_a ("unhandled expression", X_op); + break; + } + } + + /* Write out the instruction, either 4 or 8 bytes. */ + + f = frag_more (4); + md_number_to_chars (f, insn[0], 4); + if (extended) + { + f = frag_more (4); + md_number_to_chars (f, insn[1], 4); + } } /* This is the main entry point for the machine-dependent assembler. STR points to a @@ -472,7 +778,7 @@ md_assemble (str) char *scan; unsigned char *input_line_save; struct tic80_opcode *opcode; - expressionS myops[6]; + expressionS myops[16]; unsigned long insn; /* Ensure there is something there to assemble. */ @@ -511,13 +817,11 @@ md_assemble (str) opcode = find_opcode (opcode, myops); if (opcode == NULL) { - return; + as_bad ("Invalid operands: '%s'", input_line_save); } input_line_pointer = input_line_save; - insn = build_insn (opcode, myops, 0); - - /* FIXME - finish this */ + build_insn (opcode, myops); } /* This function is called once, at assembler startup time. It should @@ -588,7 +892,7 @@ md_apply_fix (fixP, val) fixS *fixP; long val; { - as_fatal ("md_apply_fix() not implemented yet\n"); + internal_error ("md_apply_fix() not implemented yet"); abort (); } @@ -602,7 +906,7 @@ long md_pcrel_from (fixP) fixS *fixP; { - as_fatal ("md_pcrel_from() not implemented yet\n"); + internal_error ("md_pcrel_from() not implemented yet"); abort (); } @@ -622,7 +926,7 @@ md_convert_frag (headers, seg, fragP) segT seg; fragS *fragP; { - as_fatal ("md_convert_frag() not implemented yet\n"); + internal_error ("md_convert_frag() not implemented yet"); abort (); } @@ -640,7 +944,7 @@ short tc_coff_fix2rtype (fixP) fixS *fixP; { - as_fatal ("tc_coff_fix2rtype() not implemented yet\n"); + internal_error ("tc_coff_fix2rtype() not implemented yet"); abort (); } -- 2.30.2