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);
+
+