blob: a621fb05a17aa9624cd14940c353183d5d2b7928 [file] [log] [blame]
From c3e194e231529c1b642f7f1a19a2a7b1ea644bd9 Mon Sep 17 00:00:00 2001
From: Nagaraju Mekala <nmekala@xilix.com>
Date: Fri, 28 Sep 2018 12:04:55 +0530
Subject: [PATCH 19/40] Update MB-x
-Fixed MB-x relocation issues
-Added imml for required MB-x instructions
---
bfd/elf64-microblaze.c | 68 ++++++++++--
gas/config/tc-microblaze.c | 221 +++++++++++++++++++++++++------------
gas/tc.h | 2 +-
3 files changed, 209 insertions(+), 82 deletions(-)
diff --git a/bfd/elf64-microblaze.c b/bfd/elf64-microblaze.c
index d55700fc513..f8f52870639 100644
--- a/bfd/elf64-microblaze.c
+++ b/bfd/elf64-microblaze.c
@@ -1478,8 +1478,17 @@ microblaze_elf_relocate_section (bfd *output_bfd,
relocation -= (input_section->output_section->vma
+ input_section->output_offset
+ offset + INST_WORD_SIZE);
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
+ unsigned long insn = bfd_get_32 (input_bfd, contents + offset +endian);
+ if (insn == 0xb2000000 || insn == 0xb2ffffff)
+ {
+ insn &= ~0x00ffffff;
+ insn |= (relocation >> 16) & 0xffffff;
+ bfd_put_32 (input_bfd, insn,
contents + offset + endian);
+ }
+ else
+ bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
+ contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
contents + offset + endian + INST_WORD_SIZE);
}
@@ -1569,11 +1578,28 @@ microblaze_elf_relocate_section (bfd *output_bfd,
else
{
if (r_type == R_MICROBLAZE_64_PCREL)
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
+ {
+ if (!input_section->output_section->vma &&
+ !input_section->output_offset && !offset)
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + offset);
+ else
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + offset + INST_WORD_SIZE);
+ }
+ unsigned long insn = bfd_get_32 (input_bfd, contents + offset +endian);
+ if (insn == 0xb2000000 || insn == 0xb2ffffff)
+ {
+ insn &= ~0x00ffffff;
+ insn |= (relocation >> 16) & 0xffffff;
+ bfd_put_32 (input_bfd, insn,
contents + offset + endian);
+ }
+ else
+ bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
+ contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
contents + offset + endian + INST_WORD_SIZE);
}
@@ -1677,9 +1703,19 @@ static void
microblaze_bfd_write_imm_value_32 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val)
{
unsigned long instr = bfd_get_32 (abfd, bfd_addr);
- instr &= ~0x0000ffff;
- instr |= (val & 0x0000ffff);
- bfd_put_32 (abfd, instr, bfd_addr);
+
+ if (instr == 0xb2000000 || instr == 0xb2ffffff)
+ {
+ instr &= ~0x00ffffff;
+ instr |= (val & 0xffffff);
+ bfd_put_32 (abfd, instr, bfd_addr);
+ }
+ else
+ {
+ instr &= ~0x0000ffff;
+ instr |= (val & 0x0000ffff);
+ bfd_put_32 (abfd, instr, bfd_addr);
+ }
}
/* Read-modify-write into the bfd, an immediate value into appropriate fields of
@@ -1691,10 +1727,18 @@ microblaze_bfd_write_imm_value_64 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val)
unsigned long instr_lo;
instr_hi = bfd_get_32 (abfd, bfd_addr);
- instr_hi &= ~0x0000ffff;
- instr_hi |= ((val >> 16) & 0x0000ffff);
- bfd_put_32 (abfd, instr_hi, bfd_addr);
-
+ if (instr_hi == 0xb2000000 || instr_hi == 0xb2ffffff)
+ {
+ instr_hi &= ~0x00ffffff;
+ instr_hi |= (val >> 16) & 0xffffff;
+ bfd_put_32 (abfd, instr_hi,bfd_addr);
+ }
+ else
+ {
+ instr_hi &= ~0x0000ffff;
+ instr_hi |= ((val >> 16) & 0x0000ffff);
+ bfd_put_32 (abfd, instr_hi, bfd_addr);
+ }
instr_lo = bfd_get_32 (abfd, bfd_addr + INST_WORD_SIZE);
instr_lo &= ~0x0000ffff;
instr_lo |= (val & 0x0000ffff);
diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index 9c8b6284fb1..f61fdf3b90a 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -391,7 +391,7 @@ microblaze_s_weakext (int ignore ATTRIBUTE_UNUSED)
Integer arg to pass to the function. */
/* If the pseudo-op is not found in this table, it searches in the obj-elf.c,
and then in the read.c table. */
-const pseudo_typeS md_pseudo_table[] =
+pseudo_typeS md_pseudo_table[] =
{
{"lcomm", microblaze_s_lcomm, 1},
{"data", microblaze_s_data, 0},
@@ -400,7 +400,7 @@ const pseudo_typeS md_pseudo_table[] =
{"data32", cons, 4}, /* Same as word. */
{"ent", s_func, 0}, /* Treat ent as function entry point. */
{"end", microblaze_s_func, 1}, /* Treat end as function end point. */
- {"gpword", s_rva, 8}, /* gpword label => store resolved label address in data section. */
+ {"gpword", s_rva, 4}, /* gpword label => store resolved label address in data section. */
{"gpdword", s_rva, 8}, /* gpword label => store resolved label address in data section. */
{"weakext", microblaze_s_weakext, 0},
{"rodata", microblaze_s_rdata, 0},
@@ -538,30 +538,6 @@ parse_reg (char * s, unsigned * reg)
*reg = REG_SP;
return s + 3;
}
- else if (strncasecmp (s, "rfsl", 4) == 0)
- {
- if (ISDIGIT (s[4]) && ISDIGIT (s[5]))
- {
- tmpreg = (s[4] - '0') * 10 + s[5] - '0';
- s += 6;
- }
- else if (ISDIGIT (s[4]))
- {
- tmpreg = s[4] - '0';
- s += 5;
- }
- else
- as_bad (_("register expected, but saw '%.6s'"), s);
-
- if ((int) tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM)
- *reg = tmpreg;
- else
- {
- as_bad (_("Invalid register number at '%.6s'"), s);
- *reg = 0;
- }
- return s;
- }
/* Stack protection registers. */
else if (strncasecmp (s, "rshr", 4) == 0)
{
@@ -605,6 +581,45 @@ parse_reg (char * s, unsigned * reg)
return s;
}
+/* Same as above, but with long(er) register */
+static char *
+parse_regl (char * s, unsigned long * reg)
+{
+ unsigned long tmpreg = 0;
+
+ /* Strip leading whitespace. */
+ while (ISSPACE (* s))
+ ++ s;
+
+ if (strncasecmp (s, "rfsl", 4) == 0)
+ {
+ if (ISDIGIT (s[4]) && ISDIGIT (s[5]))
+ {
+ tmpreg = (s[4] - '0') * 10 + s[5] - '0';
+ s += 6;
+ }
+ else if (ISDIGIT (s[4]))
+ {
+ tmpreg = s[4] - '0';
+ s += 5;
+ }
+ else
+ as_bad (_("register expected, but saw '%.6s'"), s);
+
+ if ((int) tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM)
+ *reg = tmpreg;
+ else
+ {
+ as_bad (_("Invalid register number at '%.6s'"), s);
+ *reg = 0;
+ }
+ return s;
+ }
+ as_bad (_("register expected, but saw '%.6s'"), s);
+ *reg = 0;
+ return s;
+}
+
static char *
parse_exp (char *s, expressionS *e)
{
@@ -995,7 +1010,7 @@ md_assemble (char * str)
unsigned reg2;
unsigned reg3;
unsigned isize;
- unsigned int immed, immed2, temp;
+ unsigned long immed, immed2, temp;
expressionS exp;
char name[20];
long immedl;
@@ -1117,8 +1132,9 @@ md_assemble (char * str)
as_fatal (_("lmi pseudo instruction should not use a label in imm field"));
else if (streq (name, "smi"))
as_fatal (_("smi pseudo instruction should not use a label in imm field"));
-
- if (reg2 == REG_ROSDP)
+ if(streq (name, "lli") || streq (name, "sli"))
+ opc = str_microblaze_64;
+ else if (reg2 == REG_ROSDP)
opc = str_microblaze_ro_anchor;
else if (reg2 == REG_RWSDP)
opc = str_microblaze_rw_anchor;
@@ -1181,31 +1197,55 @@ md_assemble (char * str)
inst |= (immed << IMM_LOW) & IMM_MASK;
}
}
- else
- {
- temp = immed & 0xFFFF8000;
- if ((temp != 0) && (temp != 0xFFFF8000))
- {
+ else if (streq (name, "lli") || streq (name, "sli"))
+ {
+ temp = immed & 0xFFFFFF8000;
+ if (temp != 0 && temp != 0xFFFFFF8000)
+ {
/* Needs an immediate inst. */
- opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm");
+ opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imml");
if (opcode1 == NULL)
{
- as_bad (_("unknown opcode \"%s\""), "imm");
+ as_bad (_("unknown opcode \"%s\""), "imml");
return;
}
-
inst1 = opcode1->bit_sequence;
- inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
+ inst1 |= ((immed & 0xFFFFFFFFFFFF0000L) >> 16) & IMML_MASK;
output[0] = INST_BYTE0 (inst1);
output[1] = INST_BYTE1 (inst1);
output[2] = INST_BYTE2 (inst1);
output[3] = INST_BYTE3 (inst1);
output = frag_more (isize);
- }
- inst |= (reg1 << RD_LOW) & RD_MASK;
- inst |= (reg2 << RA_LOW) & RA_MASK;
- inst |= (immed << IMM_LOW) & IMM_MASK;
- }
+ }
+ inst |= (reg1 << RD_LOW) & RD_MASK;
+ inst |= (reg2 << RA_LOW) & RA_MASK;
+ inst |= (immed << IMM_LOW) & IMM_MASK;
+ }
+ else
+ {
+ temp = immed & 0xFFFF8000;
+ if ((temp != 0) && (temp != 0xFFFF8000))
+ {
+ /* Needs an immediate inst. */
+ opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm");
+ if (opcode1 == NULL)
+ {
+ as_bad (_("unknown opcode \"%s\""), "imm");
+ return;
+ }
+
+ inst1 = opcode1->bit_sequence;
+ inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
+ output[0] = INST_BYTE0 (inst1);
+ output[1] = INST_BYTE1 (inst1);
+ output[2] = INST_BYTE2 (inst1);
+ output[3] = INST_BYTE3 (inst1);
+ output = frag_more (isize);
+ }
+ inst |= (reg1 << RD_LOW) & RD_MASK;
+ inst |= (reg2 << RA_LOW) & RA_MASK;
+ inst |= (immed << IMM_LOW) & IMM_MASK;
+ }
break;
case INST_TYPE_RD_R1_IMMS:
@@ -1400,7 +1440,7 @@ md_assemble (char * str)
reg1 = 0;
}
if (strcmp (op_end, ""))
- op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */
+ op_end = parse_regl (op_end + 1, &immed); /* Get rfslN. */
else
{
as_fatal (_("Error in statement syntax"));
@@ -1454,7 +1494,7 @@ md_assemble (char * str)
reg1 = 0;
}
if (strcmp (op_end, ""))
- op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */
+ op_end = parse_regl (op_end + 1, &immed); /* Get rfslN. */
else
{
as_fatal (_("Error in statement syntax"));
@@ -1472,7 +1512,7 @@ md_assemble (char * str)
case INST_TYPE_RFSL:
if (strcmp (op_end, ""))
- op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */
+ op_end = parse_regl (op_end + 1, &immed); /* Get rfslN. */
else
{
as_fatal (_("Error in statement syntax"));
@@ -1831,12 +1871,20 @@ md_assemble (char * str)
case INST_TYPE_IMM:
if (streq (name, "imm"))
as_fatal (_("An IMM instruction should not be present in the .s file"));
-
- op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
+ if (microblaze_arch_size == 64)
+ op_end = parse_imml (op_end + 1, & exp, MIN_IMML, MAX_IMML);
+ else
+ op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
if (exp.X_op != O_constant)
{
- char *opc = NULL;
+ char *opc;
+ if (microblaze_arch_size == 64 && (streq (name, "breai") ||
+ streq (name, "breaid") ||
+ streq (name, "brai") || streq (name, "braid")))
+ opc = strdup(str_microblaze_64);
+ else
+ opc = NULL;
relax_substateT subtype;
if (exp.X_md != 0)
@@ -1859,27 +1907,54 @@ md_assemble (char * str)
immed = exp.X_add_number;
}
+ if (microblaze_arch_size == 64 && (streq (name, "breai") ||
+ streq (name, "breaid") ||
+ streq (name, "brai") || streq (name, "braid")))
+ {
+ temp = immed & 0xFFFFFF8000;
+ if (temp != 0)
+ {
+ /* Needs an immediate inst. */
+ opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imml");
+ if (opcode1 == NULL)
+ {
+ as_bad (_("unknown opcode \"%s\""), "imml");
+ return;
+ }
- temp = immed & 0xFFFF8000;
- if ((temp != 0) && (temp != 0xFFFF8000))
- {
- /* Needs an immediate inst. */
- opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm");
- if (opcode1 == NULL)
- {
- as_bad (_("unknown opcode \"%s\""), "imm");
- return;
+ inst1 = opcode1->bit_sequence;
+ inst1 |= ((immed & 0xFFFFFFFFFFFF0000L) >> 16) & IMML_MASK;
+ output[0] = INST_BYTE0 (inst1);
+ output[1] = INST_BYTE1 (inst1);
+ output[2] = INST_BYTE2 (inst1);
+ output[3] = INST_BYTE3 (inst1);
+ output = frag_more (isize);
}
+ inst |= (immed << IMM_LOW) & IMM_MASK;
+ }
+ else
+ {
+ temp = immed & 0xFFFF8000;
+ if ((temp != 0) && (temp != 0xFFFF8000))
+ {
+ /* Needs an immediate inst. */
+ opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm");
+ if (opcode1 == NULL)
+ {
+ as_bad (_("unknown opcode \"%s\""), "imm");
+ return;
+ }
- inst1 = opcode1->bit_sequence;
- inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
- output[0] = INST_BYTE0 (inst1);
- output[1] = INST_BYTE1 (inst1);
- output[2] = INST_BYTE2 (inst1);
- output[3] = INST_BYTE3 (inst1);
- output = frag_more (isize);
- }
- inst |= (immed << IMM_LOW) & IMM_MASK;
+ inst1 = opcode1->bit_sequence;
+ inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
+ output[0] = INST_BYTE0 (inst1);
+ output[1] = INST_BYTE1 (inst1);
+ output[2] = INST_BYTE2 (inst1);
+ output[3] = INST_BYTE3 (inst1);
+ output = frag_more (isize);
+ }
+ inst |= (immed << IMM_LOW) & IMM_MASK;
+ }
break;
case INST_TYPE_NONE:
@@ -2455,7 +2530,7 @@ md_apply_fix (fixS * fixP,
inst1 = opcode1->bit_sequence;
if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
- inst1 |= ((val & 0xFFFFFFFFFFFF0000L) >> 16) & IMML_MASK;
+ inst1 |= ((val & 0xFFFFFF0000L) >> 16) & IMML_MASK;
if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64)
fixP->fx_r_type = BFD_RELOC_64;
if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PCREL)
@@ -2623,7 +2698,14 @@ md_estimate_size_before_relax (fragS * fragP,
}
else
{
- fragP->fr_subtype = UNDEFINED_PC_OFFSET;
+ if (fragP->fr_opcode != NULL) {
+ if (streq (fragP->fr_opcode, str_microblaze_64))
+ fragP->fr_subtype = DEFINED_64_PC_OFFSET;
+ else
+ fragP->fr_subtype = UNDEFINED_PC_OFFSET;
+ }
+ else
+ fragP->fr_subtype = UNDEFINED_PC_OFFSET;
fragP->fr_var = INST_WORD_SIZE*2;
}
break;
@@ -2900,6 +2982,7 @@ md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED)
case OPTION_M64:
//if (arg != NULL && strcmp (arg, "64") == 0)
microblaze_arch_size = 64;
+ md_pseudo_table[7].poc_val = 8;
break;
default:
return 0;
diff --git a/gas/tc.h b/gas/tc.h
index da1738d67a8..5bdfe5c3475 100644
--- a/gas/tc.h
+++ b/gas/tc.h
@@ -22,7 +22,7 @@
/* In theory (mine, at least!) the machine dependent part of the assembler
should only have to include one file. This one. -- JF */
-extern const pseudo_typeS md_pseudo_table[];
+extern pseudo_typeS md_pseudo_table[];
const char * md_atof (int, char *, int *);
int md_parse_option (int, const char *);
--
2.17.1