Fellows, I added some polymorph instructions to assembler. They are jump instructions which either long jumps or short jumps depending on a jump distance. So, they are:
COND EXPL SHORT JUMP LONG JUMP =============================================== eq == -> jeq jne +4; br lab ne != -> jne jeq +4; br lab lt < -> jl jge +4; br lab ltnoov < -> jn jn +2; jmp +4; br lab ltu < -> jlo lhs +4; br lab le <= -> NOT IMPLEMENTED leu <= -> NOT IMPLEMENTED gt > -> NOT IMPLEMENTED gtu > -> NOT IMPLEMENTED ge >= -> jge jl +4; br lab genoov >= -> NOT IMPLEMENTED geu >= -> jhs jlo +4; br lab =============================================== New opcodes are (BranchEQ -> beq; and so on...) beq,bne,blt,bltn,bltu,bge,bgeu They usefull for comparisons, presented in a table above. Also, we add 'jump' instruction: jump UNCOND -> jmp br lab These instructions use pc relative mode. For example, jump label will be converted to jmp label ; if jump distance can be fit 10 bits, or to br label ; if not another instruction: bltn label will be jn label ; short or jn +2 jmp +4 br label ; if jump distance is long Not implemented insns can be obtained as a combination of any of above. For example, bgt (> on signed) can be beq .Lskip1 bge label .Lskip1: Another one, bgtu: beq .Lskip2 bqeu label .Lskip2: Why? cause this will simplify gcc a lot! Patch against gas/ attached. To apply this patch do: 1. Obtain binutils-2.15 of current from cvs 2. $ cd binutils-XXX $ patch < msp.diff Have fun. Let me know if something goes wrong. Cheers, ~d P.S. profiling changes can be found in there as well.
Index: include/opcode/msp430.h =================================================================== RCS file: /cvs/src/src/include/opcode/msp430.h,v retrieving revision 1.1 diff -c -3 -p -r1.1 msp430.h *** include/opcode/msp430.h 30 Dec 2002 19:25:12 -0000 1.1 --- include/opcode/msp430.h 17 Aug 2004 16:32:10 -0000 *************** static struct msp430_opcode_s msp430_opc *** 103,111 **** --- 103,187 ---- MSP_INSN (rra, 2, 1, 0x1100, 0xff80), MSP_INSN (swpb, 2, 1, 0x1080, 0xffc0), MSP_INSN (rrc, 2, 1, 0x1000, 0xff80), + MSP_INSN (beq, 4, 0, 0,0), + MSP_INSN (bne, 4, 1, 0,0), + MSP_INSN (blt, 4, 2, 0,0), + MSP_INSN (bltu, 4, 3, 0,0), + MSP_INSN (bge, 4, 4, 0,0), + MSP_INSN (bgeu, 4, 5, 0,0), + MSP_INSN (bltn, 4, 6, 0,0), + MSP_INSN (jump, 4, 7, 0,0), /* End of instruction set. */ { NULL, 0, 0, 0, 0 } }; + /* + GCC uses the some condition codes which we'll implement as + new _ralaxable_ instructions. + NOT IMPLEMENTED means that gcc implements it as a sequence of + some instructions. For example: + ble -> jeq, jl. + + + COND EXPL SHORT JUMP LONG JUMP + =============================================== + eq == -> jeq jne +4; br lab + ne != -> jne jeq +4; br lab + + lt < -> jl jge +4; br lab + ltnoov < -> jn jn +2; jmp +4; br lab + ltu < -> jlo lhs +4; br lab + le <= -> NOT IMPLEMENTED + leu <= -> NOT IMPLEMENTED + + gt > -> NOT IMPLEMENTED + gtu > -> NOT IMPLEMENTED + ge >= -> jge jl +4; br lab + genoov >= -> NOT IMPLEMENTED + geu >= -> jhs jlo +4; br lab + =============================================== + + Therefore, new opcodes are (BranchEQ -> beq; and so on...) + beq,bne,blt,bltn,bltu,bge,bgeu + Also, we add 'jump' instruction: + jump UNCOND -> jmp br lab + they will have fmt == 4, and insn_opnumb == number of instruction. + We will parse them during assembly + + */ + + struct rcodes_s { + char *name; + int index; /* corresponding insn_opnumb */ + int nlen; /* opcode length in words if jump is short enough */ + int sop; /* opcode if jump length is short */ + int smask; /* operand mask */ + /* for long opcodes no mask required */ + long llen; /* long opcode length in words */ + long lpos; /* label position */ + long lop0; /* opcode 1 _word_ (16 bits) */ + long lop1; /* opcode second word */ + long lop2; /* opcode third word */ + long lop3; /* opcode fourth word (not necessary now, may be later) */ + }; + + #define MSP430_RLC(n,i,sop,o1) \ + {#n,i,4,sop,0xfc00,3,2,(o1+2),0x4010,0,0} + + struct rcodes_s msp430_rcodes[] = + { + MSP430_RLC(beq,0,0x2400,0x2000), + MSP430_RLC(bne,1,0x2000,0x2400), + MSP430_RLC(blt,2,0x3800,0x3400), + MSP430_RLC(bltu,3,0x2800,0x2c00), + MSP430_RLC(bge,4,0x3400,0x3800), + MSP430_RLC(bgeu,5,0x2c00,0x2800), + {"bltn",6,6,0x3000,0xfc00,4,3,0x3000+1,0x3c00+2,0x4010,0}, + {"jump",7,4,0x3c00,0xfc00,2,1,0x4010,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0} + }; + + #undef MSP430_RLC + #endif Index: gas/config/tc-msp430.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-msp430.c,v retrieving revision 1.10 diff -c -3 -p -r1.10 tc-msp430.c *** gas/config/tc-msp430.c 26 Jul 2004 12:29:02 -0000 1.10 --- gas/config/tc-msp430.c 17 Aug 2004 16:32:10 -0000 *************** static unsigned int msp430_operands *** 46,65 **** PARAMS ((struct msp430_opcode_s *, char *)); static int msp430_srcoperand PARAMS ((struct msp430_operand_s *, char *, int, int *)); ! static int msp430_dstoperand PARAMS ((struct msp430_operand_s *, char *, int)); ! static char *parse_exp PARAMS ((char *, expressionS *)); ! static inline char *skip_space PARAMS ((char *)); ! static int check_reg ! PARAMS ((char *)); ! static void msp430_set_arch PARAMS ((int)); ! static void show_mcu_list PARAMS ((FILE *)); ! static void del_spaces PARAMS ((char *)); #define MAX_OP_LEN 256 --- 46,116 ---- PARAMS ((struct msp430_opcode_s *, char *)); static int msp430_srcoperand PARAMS ((struct msp430_operand_s *, char *, int, int *)); ! static int msp430_dstoperand PARAMS ((struct msp430_operand_s *, char *, int)); ! static char *parse_exp PARAMS ((char *, expressionS *)); ! static inline char *skip_space PARAMS ((char *)); ! static int check_reg PARAMS ((char *)); ! static void msp430_set_arch PARAMS ((int)); ! static void show_mcu_list PARAMS ((FILE *)); ! static void del_spaces PARAMS ((char *)); + static void msp430_profiler + PARAMS ((int)); + static char *extract_operand + PARAMS ((char *, char *, int)); + + /* Relaxations */ + /* what */ + #define STATE_UNCOND_BRANCH 1 /* jump */ + #define STATE_NOOV_BRANCH 3 /* bltn */ + #define STATE_SIMPLE_BRANCH 2 + + #define CNRL 2 + #define CUBL 4 + #define CNOL 8 + #define CSBL 6 + + /* length */ + #define STATE_BITS10 1 /* wild guess. short jump */ + #define STATE_WORD 2 /* 2 bytes addr more */ + #define STATE_UNDEF 3 /* cannot handle this yet. convert to word mode */ + + #define ENCODE_RELAX(what,length) (((what) << 2) + (length)) + #define RELAX_STATE(s) ((s)&3) + #define RELAX_LEN(s) (s>>2) + #define RELAX_NEXT(a,b) ENCODE_RELAX(a,b+1) + + relax_typeS md_relax_table[] = { + /* unused */ + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0}, + + /* unconditional jump */ + {1, 1, 8, 5}, + {1024, -1024, CNRL, RELAX_NEXT (STATE_UNCOND_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ + {0, 0, CUBL, RELAX_NEXT (STATE_UNCOND_BRANCH, STATE_WORD)}, /* state word */ + {1, 1, CUBL, 0}, /* state undef */ + + /* simple branches */ + {0, 0, 8, 9}, + {1024, -1024, CNRL, RELAX_NEXT (STATE_SIMPLE_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ + {0, 0, CSBL, RELAX_NEXT (STATE_SIMPLE_BRANCH, STATE_WORD)}, /* state word */ + {1, 1, CSBL, 0}, + + /* blt no overflow branch */ + {1, 1, 8, 13}, + {1024, -1024, CNRL, RELAX_NEXT (STATE_NOOV_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ + {0, 0, CNOL, RELAX_NEXT (STATE_NOOV_BRANCH, STATE_WORD)}, /* state word */ + {1, 1, CNOL, 0} + }; + #define MAX_OP_LEN 256 *************** struct mcu_type_s *** 88,114 **** #define CHECK_RELOC_MSP430 ((imm_op || byte_op)?BFD_RELOC_MSP430_16_BYTE:BFD_RELOC_MSP430_16) #define CHECK_RELOC_MSP430_PCREL ((imm_op || byte_op)?BFD_RELOC_MSP430_16_PCREL_BYTE:BFD_RELOC_MSP430_16_PCREL) ! static struct mcu_type_s mcu_types[] = ! { ! {"msp1", MSP430_ISA_11, bfd_mach_msp11}, ! {"msp2", MSP430_ISA_14, bfd_mach_msp14}, {"msp430x110", MSP430_ISA_11, bfd_mach_msp11}, {"msp430x112", MSP430_ISA_11, bfd_mach_msp11}, ! {"msp430x1101",MSP430_ISA_110, bfd_mach_msp110}, ! {"msp430x1111",MSP430_ISA_110, bfd_mach_msp110}, ! {"msp430x1121",MSP430_ISA_110, bfd_mach_msp110}, ! {"msp430x1122",MSP430_ISA_11, bfd_mach_msp110}, ! {"msp430x1132",MSP430_ISA_11, bfd_mach_msp110}, {"msp430x122", MSP430_ISA_12, bfd_mach_msp12}, {"msp430x123", MSP430_ISA_12, bfd_mach_msp12}, ! {"msp430x1222",MSP430_ISA_12, bfd_mach_msp12}, ! {"msp430x1232",MSP430_ISA_12, bfd_mach_msp12}, {"msp430x133", MSP430_ISA_13, bfd_mach_msp13}, {"msp430x135", MSP430_ISA_13, bfd_mach_msp13}, ! {"msp430x1331",MSP430_ISA_13, bfd_mach_msp13}, ! {"msp430x1351",MSP430_ISA_13, bfd_mach_msp13}, {"msp430x147", MSP430_ISA_14, bfd_mach_msp14}, {"msp430x148", MSP430_ISA_14, bfd_mach_msp14}, {"msp430x149", MSP430_ISA_14, bfd_mach_msp14}, --- 139,164 ---- #define CHECK_RELOC_MSP430 ((imm_op || byte_op)?BFD_RELOC_MSP430_16_BYTE:BFD_RELOC_MSP430_16) #define CHECK_RELOC_MSP430_PCREL ((imm_op || byte_op)?BFD_RELOC_MSP430_16_PCREL_BYTE:BFD_RELOC_MSP430_16_PCREL) ! static struct mcu_type_s mcu_types[] = { ! {"msp1", MSP430_ISA_11, bfd_mach_msp11}, ! {"msp2", MSP430_ISA_14, bfd_mach_msp14}, {"msp430x110", MSP430_ISA_11, bfd_mach_msp11}, {"msp430x112", MSP430_ISA_11, bfd_mach_msp11}, ! {"msp430x1101", MSP430_ISA_110, bfd_mach_msp110}, ! {"msp430x1111", MSP430_ISA_110, bfd_mach_msp110}, ! {"msp430x1121", MSP430_ISA_110, bfd_mach_msp110}, ! {"msp430x1122", MSP430_ISA_11, bfd_mach_msp110}, ! {"msp430x1132", MSP430_ISA_11, bfd_mach_msp110}, {"msp430x122", MSP430_ISA_12, bfd_mach_msp12}, {"msp430x123", MSP430_ISA_12, bfd_mach_msp12}, ! {"msp430x1222", MSP430_ISA_12, bfd_mach_msp12}, ! {"msp430x1232", MSP430_ISA_12, bfd_mach_msp12}, {"msp430x133", MSP430_ISA_13, bfd_mach_msp13}, {"msp430x135", MSP430_ISA_13, bfd_mach_msp13}, ! {"msp430x1331", MSP430_ISA_13, bfd_mach_msp13}, ! {"msp430x1351", MSP430_ISA_13, bfd_mach_msp13}, {"msp430x147", MSP430_ISA_14, bfd_mach_msp14}, {"msp430x148", MSP430_ISA_14, bfd_mach_msp14}, {"msp430x149", MSP430_ISA_14, bfd_mach_msp14}, *************** static struct mcu_type_s default_mcu = *** 166,174 **** static struct mcu_type_s *msp430_mcu = &default_mcu; ! const pseudo_typeS md_pseudo_table[] = ! { {"arch", msp430_set_arch, 0}, {NULL, NULL, 0} }; --- 216,224 ---- static struct mcu_type_s *msp430_mcu = &default_mcu; ! const pseudo_typeS md_pseudo_table[] = { {"arch", msp430_set_arch, 0}, + {"profiler", msp430_profiler, 0}, {NULL, NULL, 0} }; *************** const pseudo_typeS md_pseudo_table[] = *** 176,183 **** const char *md_shortopts = "m:"; ! struct option md_longopts[] = ! { {"mmcu", required_argument, NULL, OPTION_MMCU}, {NULL, no_argument, NULL, 0} }; --- 226,232 ---- const char *md_shortopts = "m:"; ! struct option md_longopts[] = { {"mmcu", required_argument, NULL, OPTION_MMCU}, {NULL, no_argument, NULL, 0} }; *************** show_mcu_list (stream) *** 199,205 **** } void ! md_show_usage (FILE *stream) { fprintf (stream, _("MSP430 options:\n" --- 248,254 ---- } void ! md_show_usage (FILE * stream) { fprintf (stream, _("MSP430 options:\n" *************** msp430_set_arch (dummy) *** 263,268 **** --- 312,548 ---- bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach); } + /* + Profiling capability: + It is a performance hit to use gcc's profiling approach for this tiny target. + Even more -- jtag hardware facility does not perform any profiling functions. + However we've got gdb's built-in simulator where we can do anything. + Therefore my suggestion is: + + We define new section ".profiler" which holds all profiling information. + We define new pseudo operation .profiler which will instruct assembler to + add new profile entry to the object file. Profile should take place at the + present address. + + Pseudo-op format: + + .profiler flags,function_to_profile [, cycle_corrector, extra] + + where 'flags' is a combination of the following chars: + s - function entry + x - function exit + i - function is in init section + f - function is in fini section + l - library call + c - libc standard call + d - stack value demand + I - interrupt service routine + P - prologue start + p - prologue end + E - epilogue start + e - epilogue end + j - long jump/ sjlj unwind + a - an arbitrary code fragment + '""' optional: "sil" == sil + + function_to_profile - function address + cycle_corrector - a value which should be added to the cycle + counter, zero if omitted + extra - some extra parameter, TBD, zero if omitted. + + For example: + ------------------------------ + .global fxx + .type fxx,@function + fxx: + .LFrameOffset_fxx=0x08 + .profiler "scdP", fxx ; function entry. + ; we also demand stack value to be saved + push r11 + push r10 + push r9 + push r8 + .profiler "cdp",fxx,0, .LFrameOffset_fxx ; check stack value at this point + ; (this is a prologue end) + ; note, that spare var filled with the farme size + mov r15,r8 + .... + .profiler cdE,fxx ; check stack + pop r8 + pop r9 + pop r10 + pop r11 + .profiler xcde,fxx,3 ; exit adds 3 to the cycle counter + ret ; cause 'ret' insn takes 3 cycles + ------------------------------- + + This profiling approach does not produce any overhead and + absolutely harmless. + So, even profiled code can be uploaded to the MCU. + */ + #define MSP430_PROFILER_FLAG_ENTRY 1 /* s */ + #define MSP430_PROFILER_FLAG_EXIT 2 /* x */ + #define MSP430_PROFILER_FLAG_INITSECT 4 /* i */ + #define MSP430_PROFILER_FLAG_FINISECT 8 /* f */ + #define MSP430_PROFILER_FLAG_LIBCALL 0x10 /* l */ + #define MSP430_PROFILER_FLAG_STDCALL 0x20 /* c */ + #define MSP430_PROFILER_FLAG_STACKDMD 0x40 /* d */ + #define MSP430_PROFILER_FLAG_ISR 0x80 /* I */ + #define MSP430_PROFILER_FLAG_PROLSTART 0x100 /* P */ + #define MSP430_PROFILER_FLAG_PROLEND 0x200 /* p */ + #define MSP430_PROFILER_FLAG_EPISTART 0x400 /* E */ + #define MSP430_PROFILER_FLAG_EPIEND 0x800 /* e */ + #define MSP430_PROFILER_FLAG_JUMP 0x1000 /* j */ + #define MSP430_PROFILER_FLAG_FRAGMENT 0x2000 /* a */ + + static void + msp430_profiler (dummy) + int dummy ATTRIBUTE_UNUSED; + { + char __s[1024]; + char __f[32]; + char *str = __s; + char *flags = __f; + int p_flags = 0; + char *halt; + expressionS exp, exp1; + int ops = 0, left; + char *s; + segT seg; + int subseg; + + + s = input_line_pointer; + + while (*s && *s != '\n') + { + if (*s == ',') + ops++; + s++; + } + + left = 3 - ops; + + if (ops < 1) + { + as_bad (_(".profiler pseudo requires at least three operands")); + return; + } + + input_line_pointer = extract_operand (input_line_pointer, flags, 32); + + while (*flags) + { + switch (*flags) + { + case '"': + break; + case 'a': + p_flags |= MSP430_PROFILER_FLAG_FRAGMENT; + break; + case 'j': + p_flags |= MSP430_PROFILER_FLAG_JUMP; + break; + case 'P': + p_flags |= MSP430_PROFILER_FLAG_PROLSTART; + break; + case 'p': + p_flags |= MSP430_PROFILER_FLAG_PROLEND; + break; + case 'E': + p_flags |= MSP430_PROFILER_FLAG_EPISTART; + break; + case 'e': + p_flags |= MSP430_PROFILER_FLAG_EPIEND; + break; + case 's': + p_flags |= MSP430_PROFILER_FLAG_ENTRY; + break; + case 'x': + p_flags |= MSP430_PROFILER_FLAG_EXIT; + break; + case 'i': + p_flags |= MSP430_PROFILER_FLAG_INITSECT; + break; + case 'f': + p_flags |= MSP430_PROFILER_FLAG_FINISECT; + break; + case 'l': + p_flags |= MSP430_PROFILER_FLAG_LIBCALL; + break; + case 'c': + p_flags |= MSP430_PROFILER_FLAG_STDCALL; + break; + case 'd': + p_flags |= MSP430_PROFILER_FLAG_STACKDMD; + break; + case 'I': + p_flags |= MSP430_PROFILER_FLAG_ISR; + break; + default: + as_warn (_("Unknown flag - ignored.")); + break; + } + flags++; + } + + if ((p_flags & 3) == 3) + { + as_bad (_("Ambigious flags combination.")); + return; + } + + /* generate temp symbol which denotes current location */ + if (now_seg == absolute_section) /* paranoja ? */ + { + exp1.X_op = O_constant; + exp1.X_add_number = abs_section_offset; + as_warn (_("Profiling in absolute section? Hm...")); + } + else + { + exp1.X_op = O_symbol; + exp1.X_add_symbol = symbol_temp_new_now (); + exp1.X_add_number = 0; + } + + /* generate a symbol which holds flags value */ + exp.X_op = O_constant; + exp.X_add_number = p_flags; + + /* save current section */ + seg = now_seg; + subseg = now_subseg; + + /* now turn to .profiler section */ + obj_elf_change_section (".profiler", SHT_PROGBITS, SHF_MASKPROC, 0, 0, 0, 0); + + /* save flags */ + emit_expr (&exp, 2); + + /* save label value */ + emit_expr (&exp1, 2); + + while (ops--) + { + /* now get profiling info */ + halt = extract_operand (input_line_pointer, str, 1024); + /* process like ".word xxx" directive */ + parse_exp (str, &exp); + emit_expr (&exp, 2); + input_line_pointer = halt; + } + + /* fill the rest with zeros */ + exp.X_op = O_constant; + exp.X_add_number = 0; + while (left--) + emit_expr (&exp, 2); + + /* return to current section */ + subseg_set (seg, subseg); + } + int md_parse_option (c, arg) int c; *************** md_parse_option (c, arg) *** 289,294 **** --- 569,575 ---- as_fatal (_("redefinition of mcu type %s' to %s'"), msp430_mcu->name, mcu_types[i].name); return 1; + break; } return 0; *************** extract_cmd (char *from, char *to, int l *** 363,369 **** { int size = 0; ! while (*from && ! ISSPACE (*from) && *from != '.' && limit > size) { *(to + size) = *from; from++; --- 644,650 ---- { int size = 0; ! while (*from && !ISSPACE (*from) && *from != '.' && limit > size) { *(to + size) = *from; from++; *************** md_atof (type, litP, sizeP) *** 420,433 **** return NULL; } - void - md_convert_frag (abfd, sec, fragP) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec ATTRIBUTE_UNUSED; - fragS *fragP ATTRIBUTE_UNUSED; - { - abort (); - } void md_begin () --- 701,706 ---- *************** md_begin () *** 439,444 **** --- 712,718 ---- hash_insert (msp430_hash, opcode->name, (char *) opcode); bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach); + } void *************** msp430_operands (opcode, line) *** 514,520 **** byte_op = 0; /* skip .[bwBW]. */ ! while (! ISSPACE (*line) && *line) line++; if (opcode->insn_opnumb && (!*line || *line == '\n')) --- 788,794 ---- byte_op = 0; /* skip .[bwBW]. */ ! while (!ISSPACE (*line) && *line) line++; if (opcode->insn_opnumb && (!*line || *line == '\n')) *************** msp430_operands (opcode, line) *** 579,585 **** res += msp430_dstoperand (&op2, l2, opcode->bin_opcode); if (res) ! break; /* An error occurred. All warnings were done before. */ bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7)); --- 853,859 ---- res += msp430_dstoperand (&op2, l2, opcode->bin_opcode); if (res) ! break; /* An error occurred. All warnings were done before. */ bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7)); *************** msp430_operands (opcode, line) *** 703,709 **** line = extract_operand (line, l1, sizeof (l1)); res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op); if (res) ! break; /* Error in operand. */ bin |= op1.reg | (op1.am << 4); __is = 1 + op1.ol; --- 977,983 ---- line = extract_operand (line, l1, sizeof (l1)); res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op); if (res) ! break; /* Error in operand. */ bin |= op1.reg | (op1.am << 4); __is = 1 + op1.ol; *************** msp430_operands (opcode, line) *** 810,815 **** --- 1084,1177 ---- } break; + case 4: /* extended jumps */ + line = extract_operand (line, l1, sizeof (l1)); + if (l1[0]) + { + char *m = l1; + expressionS exp; + + if (*m == '#' /* ignore absolute addressing. make it PC relative anyway */ + || *m == '$') + m++; + + parse_exp (m, &exp); + if (exp.X_op == O_constant) + { + int x = exp.X_add_number; + + if (x & 1) + { + as_warn (_("Even number required. Rounded to %d"), x + 1); + x++; + } + + if (x > 512 * 2 || x < -511 * 2 || 1) + { + /* now convert instruction */ + struct rcodes_s rc = msp430_rcodes[opcode->insn_opnumb]; + frag = frag_more (rc.llen * 2); + + /* anyway $ means skip next bytes after jump */ + if ((*l1 == '$' && x > 0) || x < 0) + x -= rc.lpos * 2; + else + x += 2; + + bfd_putl16 ((bfd_vma) rc.lop0, frag); + + if (rc.llen > 2) + { + bfd_putl16 ((bfd_vma) rc.lop1, frag + 2); + + if (rc.llen > 3) + { + bfd_putl16 ((bfd_vma) rc.lop2, frag + 4); + bfd_putl16 ((bfd_vma) (x & 0xffff), frag + 6); + } + else + bfd_putl16 ((bfd_vma) (x & 0xffff), frag + 4); + } + else + { + bfd_putl16 ((bfd_vma) (x & 0xffff), frag + 2); + } + } + else + { + /* no conversion required */ + if ((*l1 == '$' && x > 0) || x < 0) + x -= 2; + x >>= 1; + frag = frag_more (2); + bin = msp430_rcodes[opcode->insn_opnumb].sop; + bin |= x & 0x3ff; + bfd_putl16 ((bfd_vma) bin, frag); + } + } + else if (exp.X_op == O_symbol) + { + /* relaxation required */ + struct rcodes_s rc = msp430_rcodes[opcode->insn_opnumb]; + frag = frag_more (8); + bfd_putl16 ((bfd_vma) msp430_rcodes[opcode->insn_opnumb].sop, + frag); + frag = frag_variant (rs_machine_dependent, 8, /* max_char */ + 2, /* var */ + ENCODE_RELAX (rc.lpos, STATE_BITS10), /* wild guess */ + (exp.X_add_symbol), /* symbol */ + 0, /* offset is zero if jump dist less than 1K */ + (char *) frag /* opcode */ + ); + } + } + else + { + as_bad (_("instruction requires label or absolute displacement")); + break; + } + break; + default: as_bad (_("Ilegal instruction or not implmented opcode.")); } *************** msp430_srcoperand (op, l, bin, imm_op) *** 896,906 **** int rval = 0; /* Check if there is: ! llo(x) - least significant 16 bits, x &= 0xffff ! lhi(x) - x = (x >> 16) & 0xffff, ! hlo(x) - x = (x >> 32) & 0xffff, ! hhi(x) - x = (x >> 48) & 0xffff ! The value _MUST_ be constant expression: #hlo(1231231231). */ *imm_op = 1; --- 1258,1268 ---- int rval = 0; /* Check if there is: ! llo(x) - least significant 16 bits, x &= 0xffff ! lhi(x) - x = (x >> 16) & 0xffff, ! hlo(x) - x = (x >> 32) & 0xffff, ! hhi(x) - x = (x >> 48) & 0xffff ! The value _MUST_ be constant expression: #hlo(1231231231). */ *imm_op = 1; *************** msp430_srcoperand (op, l, bin, imm_op) *** 966,972 **** if (op->exp.X_add_number > 65535 || op->exp.X_add_number < -32768) { ! as_bad (_("value %ld out of range. Use #lo() or #hi()"), x); return 1; } --- 1328,1335 ---- if (op->exp.X_add_number > 65535 || op->exp.X_add_number < -32768) { ! as_bad (_("value %ld out of range. Use #lo() or #hi()"), ! (long) x); return 1; } *************** msp430_srcoperand (op, l, bin, imm_op) *** 1102,1107 **** --- 1465,1477 ---- op->mode = OP_REG; } } + /* redudant (yet) check */ + else if (op->exp.X_op == O_register) + { + as_bad (_ + ("Registers cannot be used within immediate expression [%s]"), + l); + } else { as_bad (_("unknown operand %s"), l); *************** msp430_srcoperand (op, l, bin, imm_op) *** 1132,1137 **** --- 1502,1514 ---- else if (op->exp.X_op == O_symbol) { } + /* redudant (yet) check */ + else if (op->exp.X_op == O_register) + { + as_bad (_ + ("Registers cannot be used within absolute expression [%s]"), + l); + } else { as_bad (_("unknown expression in operand %s"), l); *************** msp430_srcoperand (op, l, bin, imm_op) *** 1159,1165 **** return 1; } ! t++; /* Points to the reg value. */ if (check_reg (t)) { --- 1536,1542 ---- return 1; } ! t++; /* Points to the reg value. */ if (check_reg (t)) { *************** msp430_srcoperand (op, l, bin, imm_op) *** 1203,1209 **** op->am = 1; op->ol = 1; /* Extract a register. */ ! t++; /* Advance pointer. */ if (*t != 'r' && *t != 'R') { --- 1580,1586 ---- op->am = 1; op->ol = 1; /* Extract a register. */ ! t++; /* Advance pointer. */ if (*t != 'r' && *t != 'R') { *************** msp430_srcoperand (op, l, bin, imm_op) *** 1271,1276 **** --- 1648,1660 ---- else if (op->exp.X_op == O_symbol) { } + /* redudant (yet) check */ + else if (op->exp.X_op == O_register) + { + as_bad (_ + ("Registers cannot be used as a prefix of indexed expression [%s]"), + l); + } else { as_bad (_("unknown expression in operand %s"), l); *************** msp430_srcoperand (op, l, bin, imm_op) *** 1309,1329 **** /* Symbolic mode 'mov a, b' == 'mov x(pc), y(pc)'. */ do { char *t = l; - __tl = l; - while (*t) { /* alpha/number underline dot for labels. */ ! if (! ISALNUM (*t) && *t != '_' && *t != '.') { as_bad (_("unknown operand %s"), l); return 1; } t++; } ! op->mode = OP_EXP; op->reg = 0; /* PC relative... be careful. */ op->am = 1; --- 1693,1713 ---- /* Symbolic mode 'mov a, b' == 'mov x(pc), y(pc)'. */ do { + /* allow expression in operand like 'a+123*(1|2)' */ + #if 0 char *t = l; __tl = l; while (*t) { /* alpha/number underline dot for labels. */ ! if (!ISALNUM (*t) && *t != '_' && *t != '.') { as_bad (_("unknown operand %s"), l); return 1; } t++; } ! #endif op->mode = OP_EXP; op->reg = 0; /* PC relative... be careful. */ op->am = 1; *************** md_apply_fix3 (fixp, valuep, seg) *** 1434,1440 **** if (fixp->fx_done) { /* Fetch the instruction, insert the fully resolved operand ! value, and stuff the instruction back again. */ where = fixp->fx_frag->fr_literal + fixp->fx_where; --- 1818,1824 ---- if (fixp->fx_done) { /* Fetch the instruction, insert the fully resolved operand ! value, and stuff the instruction back again. */ where = fixp->fx_frag->fr_literal + fixp->fx_where; *************** parse_exp (s, op) *** 1563,1572 **** int ! md_estimate_size_before_relax (fragp, seg) ! fragS *fragp ATTRIBUTE_UNUSED; ! asection *seg ATTRIBUTE_UNUSED; { ! abort (); ! return 0; } --- 1947,2117 ---- int ! md_estimate_size_before_relax (fragP, segment_type) ! fragS *fragP; ! asection *segment_type; ! { ! if (fragP->fr_symbol && S_GET_SEGMENT (fragP->fr_symbol) == segment_type) ! { ! /* this is a jump -> pcrel mode. Nothing to do here */ ! fragP->fr_subtype = ! ENCODE_RELAX (RELAX_LEN (fragP->fr_subtype), STATE_BITS10); ! } ! else if (fragP->fr_symbol) ! { ! /* Its got a segment, but its not ours, so it will always be long. ! Liker may relax it to short jump */ ! fragP->fr_subtype = ! ENCODE_RELAX (RELAX_LEN (fragP->fr_subtype), STATE_UNDEF); ! } ! else ! { ! /* We know the abs value. may be it is a jump to fixed address. */ ! fragP->fr_subtype = ! ENCODE_RELAX (RELAX_LEN (fragP->fr_subtype), STATE_UNDEF); ! } ! ! return md_relax_table[fragP->fr_subtype].rlx_length; ! } ! ! void ! md_convert_frag (abfd, sec, fragP) ! bfd *abfd ATTRIBUTE_UNUSED; ! asection *sec ATTRIBUTE_UNUSED; ! fragS *fragP; { ! char *where = 0; ! switch (fragP->fr_subtype) ! { ! case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_BITS10): ! case ENCODE_RELAX (STATE_SIMPLE_BRANCH, STATE_BITS10): ! case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_BITS10): ! /* we do not have to convert anything here. ! Just apply a fix */ ! fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, ! TRUE, BFD_RELOC_MSP430_10_PCREL); ! fragP->fr_fix += 2; ! break; ! ! case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_WORD): ! case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_UNDEF): ! { ! /* convert uncond branch jmp lab -> br lab */ ! struct rcodes_s cc = msp430_rcodes[7]; ! where = fragP->fr_literal + fragP->fr_fix; ! bfd_putl16 (cc.lop0, where); ! fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol, ! fragP->fr_offset, TRUE, BFD_RELOC_MSP430_16_PCREL); ! fragP->fr_fix += 4; ! } ! break; ! ! case ENCODE_RELAX (STATE_SIMPLE_BRANCH, STATE_WORD): ! case ENCODE_RELAX (STATE_SIMPLE_BRANCH, STATE_UNDEF): ! { ! /* other simple branches */ ! struct rcodes_s *cc = NULL; ! int i; ! int insn = bfd_getl16 (fragP->fr_opcode); ! insn &= 0xffff; ! for (i = 0; i < 7; i++) ! if (msp430_rcodes[i].sop == insn) ! cc = &msp430_rcodes[i]; ! if (!cc) ! as_fatal (_("internal inconsistency problem in %s: insn %04lx"), ! __FUNCTION__, (long) insn); ! where = fragP->fr_literal + fragP->fr_fix; ! bfd_putl16 (cc->lop0, where); ! bfd_putl16 (cc->lop1, where + 2); ! fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol, ! fragP->fr_offset, TRUE, BFD_RELOC_MSP430_16_PCREL); ! fragP->fr_fix += 6; ! } ! break; ! ! case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_WORD): ! case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_UNDEF): ! { ! struct rcodes_s cc = msp430_rcodes[6]; ! where = fragP->fr_literal + fragP->fr_fix; ! bfd_putl16 (cc.lop0, where); ! bfd_putl16 (cc.lop1, where + 2); ! bfd_putl16 (cc.lop2, where + 4); ! fix_new (fragP, fragP->fr_fix + 6, 2, fragP->fr_symbol, ! fragP->fr_offset, TRUE, BFD_RELOC_MSP430_16_PCREL); ! fragP->fr_fix += 8; ! } ! break; ! ! default: ! as_fatal (_("internal inconsistency problem in %s: %lx"), ! __FUNCTION__, (long) fragP->fr_subtype); ! break; ! } ! } ! ! /* relax fragment. mostly stolen from hc11 and mcore ! which arches I think I know */ ! long ! msp430_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS * fragP, ! long stretch ATTRIBUTE_UNUSED) ! { ! long growth; ! offsetT aim = 0; ! symbolS *symbolP; ! const relax_typeS *this_type; ! const relax_typeS *start_type; ! relax_substateT next_state; ! relax_substateT this_state; ! const relax_typeS *table = md_relax_table; ! ! /* nothing to be done if the frag has a max size */ ! if (RELAX_STATE (fragP->fr_subtype) == (STATE_UNDEF)) ! return 0; ! ! if (RELAX_STATE (fragP->fr_subtype) == (STATE_BITS10)) ! { ! symbolP = fragP->fr_symbol; ! if (symbol_resolved_p (symbolP)) ! as_fatal (_("internal inconsistency problem in %s: resolved symbol"), ! __FUNCTION__); ! aim = S_GET_VALUE (symbolP) - fragP->fr_address - fragP->fr_fix; ! } ! ! this_state = fragP->fr_subtype; ! start_type = this_type = table + this_state; ! ! if (aim < 0) ! { ! /* Look backwards. */ ! for (next_state = this_type->rlx_more; next_state;) ! if (aim >= this_type->rlx_backward) ! next_state = 0; ! else ! { ! /* Grow to next state. */ ! this_state = next_state; ! this_type = table + this_state; ! next_state = this_type->rlx_more; ! } ! } ! else ! { ! /* Look forwards. */ ! for (next_state = this_type->rlx_more; next_state;) ! if (aim <= this_type->rlx_forward) ! next_state = 0; ! else ! { ! /* Grow to next state. */ ! this_state = next_state; ! this_type = table + this_state; ! next_state = this_type->rlx_more; ! } ! } ! ! growth = this_type->rlx_length - start_type->rlx_length; ! if (growth != 0) ! fragP->fr_subtype = this_state; ! return growth; } Index: gas/config/tc-msp430.h =================================================================== RCS file: /cvs/src/src/gas/config/tc-msp430.h,v retrieving revision 1.1 diff -c -3 -p -r1.1 tc-msp430.h *** gas/config/tc-msp430.h 30 Dec 2002 19:25:07 -0000 1.1 --- gas/config/tc-msp430.h 17 Aug 2004 16:32:10 -0000 *************** extern long md_pcrel_from_section PARAMS *** 112,114 **** --- 112,121 ---- should do nothing. Some targets define a `.bss' directive that is also affected by this macro. The default definition will set P2VAR to the truncated power of two of sizes up to eight bytes. */ + + + #define md_relax_frag(SEG, FRAGP, STRETCH) \ + msp430_relax_frag (SEG, FRAGP, STRETCH) + extern long msp430_relax_frag (segT, fragS*, long); + +