opcodes: microblaze: Add new bit-field instructions

This patches adds new bsefi and bsifi instructions.
BSEFI- The instruction shall extract a bit field from a
register and place it right-adjusted in the destination register.
The other bits in the destination register shall be set to zero.
BSIFI- The instruction shall insert a right-adjusted bit field
from a register at another position in the destination register.
The rest of the bits in the destination register shall be unchanged.

Further documentation of these instructions can be found here:
https://docs.xilinx.com/v/u/en-US/ug984-vivado-microblaze-ref

This patch has been tested for years of AMD Xilinx Yocto
releases as part of the following patch set:

https://github.com/Xilinx/meta-xilinx/tree/master/meta-microblaze/recipes-devtools/binutils/binutils

Signed-off-by: nagaraju <nagaraju.mekala@amd.com>
Signed-off-by: Ibai Erkiaga <ibai.erkiaga-elorza@amd.com>
Signed-off-by: Neal Frager <neal.frager@amd.com>
Signed-off-by: Michael J. Eager <eager@eagercon.com>
This commit is contained in:
Neal Frager 2023-10-05 13:51:03 +01:00 committed by Michael J. Eager
parent 9a896be332
commit 6bbf249557
10 changed files with 196 additions and 5 deletions

View File

@ -6461,6 +6461,11 @@ value relative to the read-write small data area anchor */
expressions of the form "Symbol Op Symbol" */
BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM,
/* This is a 32 bit reloc that stores the 32 bit pc relative
value in two words (with an imm instruction).No relocation is
done here - only used for relaxing */
BFD_RELOC_MICROBLAZE_32_NONE,
/* This is a 64 bit reloc that stores the 32 bit pc relative
value in two words (with an imm instruction). No relocation is
done here - only used for relaxing */

View File

@ -174,6 +174,21 @@ static reloc_howto_type microblaze_elf_howto_raw[] =
0x0000ffff, /* Dest Mask. */
false), /* PC relative offset? */
/* This reloc does nothing. Used for relaxation. */
HOWTO (R_MICROBLAZE_32_NONE, /* Type. */
0, /* Rightshift. */
2, /* Size (0 = byte, 1 = short, 2 = long). */
32, /* Bitsize. */
true, /* PC_relative. */
0, /* Bitpos. */
complain_overflow_bitfield, /* Complain on overflow. */
NULL, /* Special Function. */
"R_MICROBLAZE_32_NONE",/* Name. */
false, /* Partial Inplace. */
0, /* Source Mask. */
0, /* Dest Mask. */
false), /* PC relative offset? */
/* This reloc does nothing. Used for relaxation. */
HOWTO (R_MICROBLAZE_64_NONE, /* Type. */
0, /* Rightshift. */
@ -560,6 +575,9 @@ microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
case BFD_RELOC_NONE:
microblaze_reloc = R_MICROBLAZE_NONE;
break;
case BFD_RELOC_MICROBLAZE_32_NONE:
microblaze_reloc = R_MICROBLAZE_32_NONE;
break;
case BFD_RELOC_MICROBLAZE_64_NONE:
microblaze_reloc = R_MICROBLAZE_64_NONE;
break;
@ -1954,14 +1972,22 @@ microblaze_elf_relax_section (bfd *abfd,
}
break;
case R_MICROBLAZE_NONE:
case R_MICROBLAZE_32_NONE:
{
/* This was a PC-relative instruction that was
completely resolved. */
size_t sfix, efix;
unsigned int val;
bfd_vma target_address;
target_address = irel->r_addend + irel->r_offset;
sfix = calc_fixup (irel->r_offset, 0, sec);
efix = calc_fixup (target_address, 0, sec);
/* Validate the in-band val. */
val = bfd_get_32 (abfd, contents + irel->r_offset);
if (val != irel->r_addend && ELF32_R_TYPE (irel->r_info) == R_MICROBLAZE_32_NONE) {
fprintf(stderr, "%d: CORRUPT relax reloc %x %lx\n", __LINE__, val, irel->r_addend);
}
irel->r_addend -= (efix - sfix);
/* Should use HOWTO. */
microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset,
@ -2009,6 +2035,49 @@ microblaze_elf_relax_section (bfd *abfd,
irelscanend = irelocs + o->reloc_count;
for (irelscan = irelocs; irelscan < irelscanend; irelscan++)
{
if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_NONE)
{
unsigned int val;
isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
/* hax: We only do the following fixup for debug location lists. */
if (strcmp(".debug_loc", o->name))
continue;
/* This was a PC-relative instruction that was completely resolved. */
if (ocontents == NULL)
{
if (elf_section_data (o)->this_hdr.contents != NULL)
ocontents = elf_section_data (o)->this_hdr.contents;
else
{
/* We always cache the section contents.
Perhaps, if info->keep_memory is FALSE, we
should free them, if we are permitted to. */
if (o->rawsize == 0)
o->rawsize = o->size;
ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
if (ocontents == NULL)
goto error_return;
if (!bfd_get_section_contents (abfd, o, ocontents,
(file_ptr) 0,
o->rawsize))
goto error_return;
elf_section_data (o)->this_hdr.contents = ocontents;
}
}
val = bfd_get_32 (abfd, ocontents + irelscan->r_offset);
if (val != irelscan->r_addend) {
fprintf(stderr, "%d: CORRUPT relax reloc! %x %lx\n", __LINE__, val, irelscan->r_addend);
}
irelscan->r_addend -= calc_fixup (irelscan->r_addend, 0, sec);
microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset,
irelscan->r_addend);
}
if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32)
{
isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
@ -2033,7 +2102,7 @@ microblaze_elf_relax_section (bfd *abfd,
goto error_return;
if (!bfd_get_section_contents (abfd, o, ocontents,
(file_ptr) 0,
o->rawsize))
o->rawsize))
goto error_return;
elf_section_data (o)->this_hdr.contents = ocontents;
}
@ -2068,7 +2137,7 @@ microblaze_elf_relax_section (bfd *abfd,
elf_section_data (o)->this_hdr.contents = ocontents;
}
}
irelscan->r_addend -= calc_fixup (irel->r_addend
irelscan->r_addend -= calc_fixup (irelscan->r_addend
+ isym->st_value,
0,
sec);

View File

@ -3010,6 +3010,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_MICROBLAZE_32_ROSDA",
"BFD_RELOC_MICROBLAZE_32_RWSDA",
"BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM",
"BFD_RELOC_MICROBLAZE_32_NONE",
"BFD_RELOC_MICROBLAZE_64_NONE",
"BFD_RELOC_MICROBLAZE_64_GOTPC",
"BFD_RELOC_MICROBLAZE_64_GOT",

View File

@ -6694,6 +6694,12 @@ ENUM
ENUMDOC
This is a 32 bit reloc for the microblaze to handle
expressions of the form "Symbol Op Symbol"
ENUM
BFD_RELOC_MICROBLAZE_32_NONE
ENUMDOC
This is a 32 bit reloc that stores the 32 bit pc relative
value in two words (with an imm instruction). No relocation is
done here - only used for relaxing
ENUM
BFD_RELOC_MICROBLAZE_64_NONE
ENUMDOC

View File

@ -15279,6 +15279,10 @@ is_8bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
return reloc_type == 54; /* R_RISCV_SET8. */
case EM_Z80:
return reloc_type == 1; /* R_Z80_8. */
case EM_MICROBLAZE:
return reloc_type == 33 /* R_MICROBLAZE_32_NONE. */
|| reloc_type == 0 /* R_MICROBLAZE_NONE. */
|| reloc_type == 9; /* R_MICROBLAZE_64_NONE. */
default:
return false;
}

View File

@ -915,7 +915,7 @@ md_assemble (char * str)
unsigned reg2;
unsigned reg3;
unsigned isize;
unsigned int immed = 0, temp;
unsigned int immed = 0, immed2 = 0, temp;
expressionS exp;
char name[20];
@ -1177,6 +1177,77 @@ md_assemble (char * str)
inst |= (immed << IMM_LOW) & IMM5_MASK;
break;
case INST_TYPE_RD_R1_IMM5_IMM5:
if (strcmp (op_end, ""))
op_end = parse_reg (op_end + 1, &reg1); /* Get rd. */
else
{
as_fatal (_("Error in statement syntax"));
reg1 = 0;
}
if (strcmp (op_end, ""))
op_end = parse_reg (op_end + 1, &reg2); /* Get r1. */
else
{
as_fatal (_("Error in statement syntax"));
reg2 = 0;
}
/* Check for spl registers. */
if (check_spl_reg (&reg1))
as_fatal (_("Cannot use special register with this instruction"));
if (check_spl_reg (&reg2))
as_fatal (_("Cannot use special register with this instruction"));
/* Width immediate value. */
if (strcmp (op_end, ""))
op_end = parse_imm (op_end + 1, &exp, MIN_IMM_WIDTH, MAX_IMM_WIDTH);
else
as_fatal (_("Error in statement syntax"));
if (exp.X_op != O_constant)
{
as_warn (_("Symbol used as immediate width value for bit field instruction"));
immed = 1;
}
else
immed = exp.X_add_number;
if (opcode->instr == bsefi && immed > 31)
as_fatal (_("Width value must be less than 32"));
/* Shift immediate value. */
if (strcmp (op_end, ""))
op_end = parse_imm (op_end + 1, &exp, MIN_IMM, MAX_IMM);
else
as_fatal (_("Error in statement syntax"));
if (exp.X_op != O_constant)
{
as_warn (_("Symbol used as immediate shift value for bit field instruction"));
immed2 = 0;
}
else
{
output = frag_more (isize);
immed2 = exp.X_add_number;
}
if (immed2 != (immed2 % 32))
{
as_warn (_("Shift value greater than 32. using <value %% 32>"));
immed2 = immed2 % 32;
}
/* Check combined value. */
if (immed + immed2 > 32)
as_fatal (_("Width value + shift value must not be greater than 32"));
inst |= (reg1 << RD_LOW) & RD_MASK;
inst |= (reg2 << RA_LOW) & RA_MASK;
if (opcode->instr == bsefi)
inst |= (immed & IMM5_MASK) << IMM_WIDTH_LOW; /* bsefi */
else
inst |= ((immed + immed2 - 1) & IMM5_MASK) << IMM_WIDTH_LOW; /* bsifi */
inst |= (immed2 << IMM_LOW) & IMM5_MASK;
break;
case INST_TYPE_R1_R2:
if (strcmp (op_end, ""))
op_end = parse_reg (op_end + 1, &reg1); /* Get r1. */
@ -2209,9 +2280,12 @@ md_apply_fix (fixS * fixP,
moves code around due to relaxing. */
if (fixP->fx_r_type == BFD_RELOC_64_PCREL)
fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE;
else if (fixP->fx_r_type == BFD_RELOC_32)
fixP->fx_r_type = BFD_RELOC_MICROBLAZE_32_NONE;
else
fixP->fx_r_type = BFD_RELOC_NONE;
fixP->fx_addsy = section_symbol (absolute_section);
fixP->fx_done = 0;
}
return;
}
@ -2432,6 +2506,7 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
switch (fixp->fx_r_type)
{
case BFD_RELOC_NONE:
case BFD_RELOC_MICROBLAZE_32_NONE:
case BFD_RELOC_MICROBLAZE_64_NONE:
case BFD_RELOC_32:
case BFD_RELOC_MICROBLAZE_32_LO:

View File

@ -61,6 +61,7 @@ START_RELOC_NUMBERS (elf_microblaze_reloc_type)
RELOC_NUMBER (R_MICROBLAZE_TEXTPCREL_64, 30) /* PC-relative TEXT offset. */
RELOC_NUMBER (R_MICROBLAZE_TEXTREL_64, 31) /* TEXT Entry offset 64-bit. */
RELOC_NUMBER (R_MICROBLAZE_TEXTREL_32_LO, 32) /* TEXT Entry offset 32-bit. */
RELOC_NUMBER (R_MICROBLAZE_32_NONE, 33)
END_RELOC_NUMBERS (R_MICROBLAZE_max)
/* Global base address names. */

View File

@ -90,6 +90,18 @@ get_field_imm5_mbar (struct string_buf *buf, long instr)
return p;
}
static char *
get_field_imm5width (struct string_buf *buf, long instr)
{
char *p = strbuf (buf);
if (instr & 0x00004000)
sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK) >> IMM_WIDTH_LOW))); /* bsefi */
else
sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK) >> IMM_WIDTH_LOW) - ((instr & IMM5_MASK) >> IMM_LOW) + 1)); /* bsifi */
return p;
}
static char *
get_field_rfsl (struct string_buf *buf, long instr)
{
@ -427,6 +439,10 @@ print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
/* For mbar 16 or sleep insn. */
case INST_TYPE_NONE:
break;
/* For bit field insns. */
case INST_TYPE_RD_R1_IMM5_IMM5:
print_func (stream, "\t%s, %s, %s, %s", get_field_rd (&buf, inst),get_field_r1(&buf, inst),get_field_imm5width (&buf, inst), get_field_imm5 (&buf, inst));
break;
/* For tuqula instruction */
case INST_TYPE_RD:
print_func (stream, "\t%s", get_field_rd (&buf, inst));

View File

@ -59,6 +59,9 @@
/* For mbar. */
#define INST_TYPE_IMM5 20
/* For bsefi and bsifi */
#define INST_TYPE_RD_R1_IMM5_IMM5 21
#define INST_TYPE_NONE 25
@ -89,7 +92,9 @@
#define OPCODE_MASK_H124 0xFFFF07FF /* High 16, and low 11 bits. */
#define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits. */
#define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22. */
#define OPCODE_MASK_H3B 0xFC00C600 /* High 6 bits and bits 16, 17, 21, 22. */
#define OPCODE_MASK_H32 0xFC00FC00 /* High 6 bits and bit 16-21. */
#define OPCODE_MASK_H32B 0xFC00C000 /* High 6 bits and bit 16, 17. */
#define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits. */
#define OPCODE_MASK_H35B 0xFC0004FF /* High 6 bits and low 9 bits. */
#define OPCODE_MASK_H34C 0xFC0007E0 /* High 6 bits and bits 21-26. */
@ -102,7 +107,7 @@
#define DELAY_SLOT 1
#define NO_DELAY_SLOT 0
#define MAX_OPCODES 300
#define MAX_OPCODES 301
const struct op_code_struct
{
@ -159,6 +164,8 @@ const struct op_code_struct
{"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst },
{"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst },
{"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst },
{"bsefi", INST_TYPE_RD_R1_IMM5_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64004000, OPCODE_MASK_H32B, bsefi, barrel_shift_inst },
{"bsifi", INST_TYPE_RD_R1_IMM5_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64008000, OPCODE_MASK_H32B, bsifi, barrel_shift_inst },
{"or", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, microblaze_or, logical_inst },
{"and", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, microblaze_and, logical_inst },
{"xor", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, microblaze_xor, logical_inst },
@ -438,5 +445,8 @@ char pvr_register_prefix[] = "rpvr";
#define MIN_IMM5 ((int) 0x00000000)
#define MAX_IMM5 ((int) 0x0000001f)
#define MIN_IMM_WIDTH ((int) 0x00000001)
#define MAX_IMM_WIDTH ((int) 0x00000020)
#endif /* MICROBLAZE_OPC */

View File

@ -29,7 +29,7 @@ enum microblaze_instr
addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul,
mulh, mulhu, mulhsu, swapb, swaph,
idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput,
ncget, ncput, muli, bslli, bsrai, bsrli, mului,
ncget, ncput, muli, bslli, bsrai, bsrli, bsefi, bsifi, mului,
/* 'or/and/xor' are C++ keywords. */
microblaze_or, microblaze_and, microblaze_xor,
andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16,
@ -130,6 +130,7 @@ enum microblaze_instr_type
#define RB_LOW 11 /* Low bit for RB. */
#define IMM_LOW 0 /* Low bit for immediate. */
#define IMM_MBAR 21 /* low bit for mbar instruction. */
#define IMM_WIDTH_LOW 6 /* Low bit for immediate width */
#define RD_MASK 0x03E00000
#define RA_MASK 0x001F0000
@ -142,6 +143,9 @@ enum microblaze_instr_type
/* Imm mask for mbar. */
#define IMM5_MBAR_MASK 0x03E00000
/* Imm mask for extract/insert width. */
#define IMM5_WIDTH_MASK 0x000007C0
/* FSL imm mask for get, put instructions. */
#define RFSL_MASK 0x000000F