From 3c197b12c4b680a230e8350ecd9a523be804fe3c Mon Sep 17 00:00:00 2001
From: Nagaraju <nmekala@xilinx.com>
Date: Fri, 23 Aug 2019 16:18:43 +0530
Subject: [PATCH 23/34] Added support to new arithmetic single register
 instructions

Conflicts:
	opcodes/microblaze-dis.c

Conflicts:
	gas/config/tc-microblaze.c
	opcodes/microblaze-dis.c

Conflicts:
	gas/config/tc-microblaze.c
signed-off-by:Nagaraju <nmekala@xilinx.com>
	      Mahesh <mbodapat@xilinx.com>
---
 gas/config/tc-microblaze.c | 147 ++++++++++++++++++++++++++++++++++++-
 opcodes/microblaze-dis.c   |  11 +++
 opcodes/microblaze-opc.h   |  43 ++++++++++-
 opcodes/microblaze-opcm.h  |   5 +-
 4 files changed, 200 insertions(+), 6 deletions(-)

diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index a1fb6ccbd44..27544b60ea3 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -423,12 +423,33 @@ void
 md_begin (void)
 {
   const struct op_code_struct * opcode;
+  const char *prev_name = "";
 
   opcode_hash_control = str_htab_create ();
 
   /* Insert unique names into hash table.  */
-  for (opcode = microblaze_opcodes; opcode->name; opcode ++)
-    str_hash_insert (opcode_hash_control, opcode->name, opcode, 0);
+  for (opcode = (struct microblaze_opcodes *)microblaze_opcodes; opcode->name; opcode ++)
+    {
+      if (strcmp (prev_name, opcode->name))
+	{
+	  prev_name = (char *) opcode->name;
+          str_hash_insert (opcode_hash_control, opcode->name, opcode, 0);
+        }
+    }
+}
+
+static int
+is_reg (char * s)
+{
+  int is_reg = 0; 
+  /* Strip leading whitespace.  */
+  while (ISSPACE (* s))
+    ++ s;
+  if (TOLOWER (s[0]) == 'r')
+    {
+	 is_reg =1;
+    }
+  return is_reg;
 }
 
 /* Try to parse a reg name.  */
@@ -986,6 +1007,7 @@ md_assemble (char * str)
 {
   char * op_start;
   char * op_end;
+  char * temp_op_end;
   struct op_code_struct * opcode, *opcode1;
   char * output = NULL;
   int nlen = 0;
@@ -996,9 +1018,10 @@ md_assemble (char * str)
   unsigned reg3;
   unsigned isize;
   unsigned long immed = 0, immed2 = 0, temp;
-  expressionS exp;
+  expressionS exp,exp1;
   char name[20];
   long immedl;
+  int reg=0;
 
   /* Drop leading whitespace.  */
   while (ISSPACE (* str))
@@ -1029,7 +1052,78 @@ md_assemble (char * str)
       as_bad (_("unknown opcode \"%s\""), name);
       return;
     }
-
+   
+  if ((microblaze_arch_size == 64) && (streq (name, "addli") || streq (name, "addlic") ||
+        streq (name, "addlik") || streq (name, "addlikc") || streq (name, "rsubli") 
+	|| streq (name, "rsublic") || streq (name, "rsublik") || streq (name, "rsublikc") 
+	|| streq (name, "andli") || streq (name, "andnli") || streq (name, "orli") 
+	|| streq (name, "xorli")))
+    {
+      temp_op_end = op_end;
+      if (strcmp (temp_op_end, ""))
+        temp_op_end = parse_reg (temp_op_end + 1, &reg1);  /* Get rd.  */
+      if (strcmp (temp_op_end, ""))
+        reg  = is_reg (temp_op_end + 1);
+      if (reg) 
+	{
+          
+ 	  opcode->inst_type=INST_TYPE_RD_R1_IMML;
+          opcode->inst_offset_type = OPCODE_MASK_H;
+          if (streq (name, "addli"))
+ 	    opcode->bit_sequence = ADDLI_MASK;
+          else if (streq (name, "addlic"))
+ 	    opcode->bit_sequence = ADDLIC_MASK;
+          else if (streq (name, "addlik"))
+ 	    opcode->bit_sequence = ADDLIK_MASK;
+          else if (streq (name, "addlikc"))
+ 	    opcode->bit_sequence = ADDLIKC_MASK;
+          else if (streq (name, "rsubli"))
+ 	    opcode->bit_sequence = RSUBLI_MASK;
+          else if (streq (name, "rsublic"))
+ 	    opcode->bit_sequence = RSUBLIC_MASK;
+          else if (streq (name, "rsublik"))
+ 	    opcode->bit_sequence = RSUBLIK_MASK;
+          else if (streq (name, "rsublikc"))
+ 	    opcode->bit_sequence = RSUBLIKC_MASK;
+          else if (streq (name, "andli"))
+ 	    opcode->bit_sequence = ANDLI_MASK;
+          else if (streq (name, "andnli"))
+ 	    opcode->bit_sequence = ANDLNI_MASK;
+          else if (streq (name, "orli"))
+ 	    opcode->bit_sequence = ORLI_MASK;
+          else if (streq (name, "xorli"))
+ 	    opcode->bit_sequence = XORLI_MASK;
+	}
+      else
+        {
+	  opcode->inst_type=INST_TYPE_RD_IMML;
+          opcode->inst_offset_type = OPCODE_MASK_LIMM;
+          if (streq (name, "addli"))
+ 	    opcode->bit_sequence = ADDLI_ONE_REG_MASK;
+          else if (streq (name, "addlic"))
+ 	    opcode->bit_sequence = ADDLIC_ONE_REG_MASK;
+          else if (streq (name, "addlik"))
+ 	    opcode->bit_sequence = ADDLIK_ONE_REG_MASK;
+          else if (streq (name, "addlikc"))
+ 	    opcode->bit_sequence = ADDLIKC_ONE_REG_MASK;
+          else if (streq (name, "rsubli"))
+ 	    opcode->bit_sequence = RSUBLI_ONE_REG_MASK;
+          else if (streq (name, "rsublic"))
+ 	    opcode->bit_sequence = RSUBLIC_ONE_REG_MASK;
+          else if (streq (name, "rsublik"))
+ 	    opcode->bit_sequence = RSUBLIK_ONE_REG_MASK;
+          else if (streq (name, "rsublikc"))
+ 	    opcode->bit_sequence = RSUBLIKC_ONE_REG_MASK;
+          else if (streq (name, "andli"))
+ 	    opcode->bit_sequence = ANDLI_ONE_REG_MASK;
+          else if (streq (name, "andnli"))
+ 	    opcode->bit_sequence = ANDLNI_ONE_REG_MASK;
+          else if (streq (name, "orli"))
+ 	    opcode->bit_sequence = ORLI_ONE_REG_MASK;
+          else if (streq (name, "xorli"))
+ 	    opcode->bit_sequence = XORLI_ONE_REG_MASK;
+        }
+    }
   inst = opcode->bit_sequence;
   isize = 4;
 
@@ -1486,6 +1580,51 @@ md_assemble (char * str)
       inst |= (immed << IMM_LOW) & IMM15_MASK;
       break;
 
+    case INST_TYPE_RD_IMML:
+      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_imml (op_end + 1, & exp, MIN_IMML, MAX_IMML);
+      else
+        as_fatal (_("Error in statement syntax"));
+
+      /* Check for spl registers. */
+      if (check_spl_reg (&reg1))
+        as_fatal (_("Cannot use special register with this instruction"));
+      if (exp.X_op != O_constant)
+	{
+          char *opc = NULL;
+          relax_substateT subtype;
+
+          if (exp.X_md != 0)
+            subtype = get_imm_otype(exp.X_md);
+          else
+            subtype = opcode->inst_offset_type;
+
+          output = frag_var (rs_machine_dependent,
+                             isize * 2, 
+                             isize * 2,
+                             subtype,   
+                             exp.X_add_symbol,
+                             exp.X_add_number,
+                             (char *) opc);
+          immedl = 0L;
+	}		
+      else
+        {
+          output = frag_more (isize);
+          immed = exp.X_add_number;
+        }
+      inst |= (reg1 << RD_LOW) & RD_MASK;
+      inst |= (immed << IMM_LOW) & IMM16_MASK;
+      break;
+	
     case INST_TYPE_R1_RFSL:
       if (strcmp (op_end, ""))
         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
diff --git a/opcodes/microblaze-dis.c b/opcodes/microblaze-dis.c
index d837ebb38e2..b5a78dcfe09 100644
--- a/opcodes/microblaze-dis.c
+++ b/opcodes/microblaze-dis.c
@@ -130,6 +130,14 @@ get_field_imm15 (struct string_buf *buf, long instr)
   return p;
 }
 
+get_field_imm16 (struct string_buf *buf, long instr)
+{
+  char *p = strbuf (buf);
+
+  sprintf (p, "%d", (short)((instr & IMM16_MASK) >> IMM_LOW));
+  return p;
+}
+
 static char *
 get_field_special (struct string_buf *buf, long instr,
 		   const struct op_code_struct *op)
@@ -457,6 +465,9 @@ print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
 	  /* For mbar 16 or sleep insn.  */
 	case INST_TYPE_NONE:
 	  break;
+	case INST_TYPE_RD_IMML:
+	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), get_field_imm16 (&buf, inst));
+          break;
         /* For bit field insns.  */
 	case INST_TYPE_RD_R1_IMMW_IMMS:
           print_func (stream, "\t%s, %s, %s, %s", get_field_rd (&buf, inst),get_field_r1(&buf, inst),get_field_immw (&buf, inst), get_field_imms (&buf, inst));
diff --git a/opcodes/microblaze-opc.h b/opcodes/microblaze-opc.h
index 6b25d12dace..82da7f1179a 100644
--- a/opcodes/microblaze-opc.h
+++ b/opcodes/microblaze-opc.h
@@ -69,6 +69,7 @@
 #define INST_TYPE_RD_R1_IMMW_IMMS  21
 
 #define INST_TYPE_NONE 25
+#define INST_TYPE_RD_IMML 26
 
 
 
@@ -84,6 +85,7 @@
 #define IMMVAL_MASK_MFS 0x0000
 
 #define OPCODE_MASK_H   0xFC000000  /* High 6 bits only.  */
+#define OPCODE_MASK_LIMM 0xFC1F0000 /* High 6 bits and 12-16 bits */
 #define OPCODE_MASK_H1  0xFFE00000  /* High 11 bits.  */
 #define OPCODE_MASK_H2  0xFC1F0000  /* High 6 and bits 20-16.  */
 #define OPCODE_MASK_H12 0xFFFF0000  /* High 16.  */
@@ -106,6 +108,33 @@
 #define OPCODE_MASK_H34C 0xFC0007E0 /* High 6 bits and bits 21-26.  */
 #define OPCODE_MASK_H8  0xFF000000  /* High 8 bits only.  */
 
+/*Defines to identify 64-bit single reg instructions */
+#define ADDLI_ONE_REG_MASK 0x68000000
+#define ADDLIC_ONE_REG_MASK 0x68020000
+#define ADDLIK_ONE_REG_MASK 0x68040000
+#define ADDLIKC_ONE_REG_MASK 0x68060000
+#define RSUBLI_ONE_REG_MASK 0x68010000
+#define RSUBLIC_ONE_REG_MASK 0x68030000
+#define RSUBLIK_ONE_REG_MASK 0x68050000
+#define RSUBLIKC_ONE_REG_MASK 0x68070000
+#define ORLI_ONE_REG_MASK 0x68100000
+#define ANDLI_ONE_REG_MASK 0x68110000
+#define XORLI_ONE_REG_MASK 0x68120000
+#define ANDLNI_ONE_REG_MASK 0x68130000
+#define ADDLI_MASK 0x20000000
+#define ADDLIC_MASK 0x28000000
+#define ADDLIK_MASK 0x30000000
+#define ADDLIKC_MASK 0x38000000
+#define RSUBLI_MASK 0x24000000
+#define RSUBLIC_MASK 0x2C000000
+#define RSUBLIK_MASK 0x34000000
+#define RSUBLIKC_MASK 0x3C000000
+#define ANDLI_MASK 0xA4000000
+#define ANDLNI_MASK 0xAC000000
+#define ORLI_MASK 0xA0000000
+#define XORLI_MASK 0xA8000000
+
+
 /* New Mask for msrset, msrclr insns.  */
 #define OPCODE_MASK_H23N  0xFC1F8000 /* High 6 and bits 11 - 16.  */
 /* Mask for mbar insn.  */
@@ -114,7 +143,7 @@
 #define DELAY_SLOT 1
 #define NO_DELAY_SLOT 0
 
-#define MAX_OPCODES 412
+#define MAX_OPCODES 424
 
 const struct op_code_struct
 {
@@ -444,13 +473,21 @@ const struct op_code_struct
   {"cmpl",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000101, OPCODE_MASK_H4, cmpl, arithmetic_inst },
   {"cmplu",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000103, OPCODE_MASK_H4, cmplu, arithmetic_inst },
   {"addli",   INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+  {"addli", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68000000, OPCODE_MASK_LIMM, addli, arithmetic_inst },
   {"rsubli",  INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+  {"rsubli", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68010000, OPCODE_MASK_LIMM, rsubli, arithmetic_inst },
   {"addlic",  INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+  {"addlic", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68020000, OPCODE_MASK_LIMM, addlic, arithmetic_inst },
   {"rsublic", INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+    {"rsublic", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68030000, OPCODE_MASK_LIMM, rsublic, arithmetic_inst },
   {"addlik",  INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+  {"addlik", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68040000, OPCODE_MASK_LIMM, addlik, arithmetic_inst },
   {"rsublik", INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+  {"rsublik", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68050000, OPCODE_MASK_LIMM, rsublik, arithmetic_inst },
   {"addlikc", INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },   /* Identical to 32-bit */
+  {"addlikc", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68060000, OPCODE_MASK_LIMM, addlikc, arithmetic_inst },
   {"rsublikc",INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst },  /* Identical to 32-bit */
+  {"rsublikc", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68070000, OPCODE_MASK_LIMM, rsublikc, arithmetic_inst },
   {"mull",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000100, OPCODE_MASK_H4, mull, mult_inst },
   {"bslll",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000500, OPCODE_MASK_H3, bslll, barrel_shift_inst },
   {"bslra",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000300, OPCODE_MASK_H3, bslra, barrel_shift_inst },
@@ -501,9 +538,13 @@ const struct op_code_struct
   {"beaged",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9FA00000, OPCODE_MASK_H14, beaged, branch_inst },
   {"bealged", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9FA00100, OPCODE_MASK_H14, bealged, branch_inst },
   {"orli",    INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, invalid_inst, logical_inst },      /* Identical to 32-bit */
+  {"orli", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68100000, OPCODE_MASK_LIMM, orli, arithmetic_inst },
   {"andli",   INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, invalid_inst, logical_inst },      /* Identical to 32-bit */
+  {"andli", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68110000, OPCODE_MASK_LIMM, andli, arithmetic_inst },
   {"xorli",   INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, invalid_inst, logical_inst },      /* Identical to 32-bit */
+  {"xorli", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68120000, OPCODE_MASK_LIMM, xorli, arithmetic_inst },
   {"andnli",  INST_TYPE_RD_R1_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, invalid_inst, logical_inst },      /* Identical to 32-bit */
+  {"andnli", INST_TYPE_RD_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL,0x68130000, OPCODE_MASK_LIMM, andnli, arithmetic_inst },
   {"imml",    INST_TYPE_IMML, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB2000000, OPCODE_MASK_H8, imml, immediate_inst },
   {"breai",   INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8010000, OPCODE_MASK_H12, breai, branch_inst },
   {"breaid",  INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8110000, OPCODE_MASK_H12, breaid, branch_inst },
diff --git a/opcodes/microblaze-opcm.h b/opcodes/microblaze-opcm.h
index b242ea73c7b..5c44a5ff0ac 100644
--- a/opcodes/microblaze-opcm.h
+++ b/opcodes/microblaze-opcm.h
@@ -62,7 +62,9 @@ enum microblaze_instr
   eaputd, teaputd, ecaputd, tecaputd, neaputd, tneaputd, necaputd, tnecaputd,
 
   /* 64-bit instructions */
-  addl, rsubl, addlc, rsublc, addlk, rsublk, addlkc, rsublkc, cmpl, cmplu, mull,
+  addl, addli, addlic, addlik, addlikc, rsubl, rsubli, rsublic, rsublik, rsublikc,
+  addlc, rsublc, addlk, rsublk, addlkc, rsublkc, cmpl, cmplu, mull,
+  andli, andnli, orli, xorli,
   bslll, bslra, bslrl, bsllli, bslrai, bslrli, bslefi, bslifi, orl, andl, xorl,
   andnl, pcmplbf, pcmpleq, pcmplne, srla, srlc, srll, sextl8, sextl16, sextl32,
   brea, bread, breald, beaeq, bealeq, beaeqd, bealeqd, beane, bealne, beaned,
@@ -167,5 +169,6 @@ enum microblaze_instr_type
 
 /* Imm mask for msrset, msrclr instructions.  */
 #define  IMM15_MASK 0x00007FFF
+#define IMM16_MASK 0x0000FFFF
 
 #endif /* MICROBLAZE-OPCM */
-- 
2.37.1 (Apple Git-137.1)

