From f82cb948f1d03a8e0396569445adf92f71db3cf0 Mon Sep 17 00:00:00 2001
From: "max.ma" <max.ma@starfivetech.com>
Date: Tue, 6 Dec 2022 23:05:47 -0800
Subject: [PATCH 2/3] add customer pref insn support

---
 gas/config/tc-riscv.c      | 42 ++++++++++++++++++++++++++++++++++++++
 include/opcode/riscv-opc.h |  1 +
 include/opcode/riscv.h     |  9 ++++++++
 opcodes/riscv-dis.c        |  7 +++++++
 opcodes/riscv-opc.c        |  1 +
 5 files changed, 60 insertions(+)

diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 77c0d2e32a..a90977d8e0 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1334,6 +1334,8 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
 	case ')': break;
 	case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
 	case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
+	case '#': used_bits |= ENCODE_PREF_TIMM (-1U); break;
+	case '+': used_bits |= ENCODE_PREF_SIMM (-1U); break;
 	case 'A': break; /* Macro operand, must be symbol.  */
 	case 'B': break; /* Macro operand, must be symbol or constant.  */
 	case 'c': break; /* Macro operand, must be symbol or constant.  */
@@ -1761,6 +1763,27 @@ check_absolute_expr (struct riscv_cl_insn *ip, expressionS *ex,
   normalize_constant_expr (ex);
 }
 
+/* The pref type should be one of the following:
+    0000 - scalar prefetch L1, fetch data as if for a normal scalar load, 
+           and imply load into all lower cache destination levels.
+    0001 - scalar prefetch L2, fetch data and place the cache-line into L2,
+           and imply load into all lower cache destination levels.
+    0010 - scalar prefetch L3, fetch data and place the cache-line into L3,
+           and imply load into all lower cache destination levels.
+    0011 - scalar prefetch L4, fetch data and place the cache-line into L4,
+           and imply load into all lower cache destination levels
+           (if the L5 is in the cache heirarchy).
+    1000 - vector prefetch L1, fetch data as if for a normal scalar load
+           but place the cache-line into vector buffer (vector L1) ,
+           and imply load into all lower cache destination levels.
+*/
+
+static bfd_boolean check_pref_type(unsigned long type)
+{
+  if (type != 0 && type != 1 && type != 2 && type != 3 && type != 8)
+    as_bad (_("Improper pref type (%lu)"), type);
+}
+
 static symbolS *
 make_internal_label (void)
 {
@@ -3064,6 +3087,25 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 	      asarg = expr_end;
 	      continue;
 
+	    case '#':
+	      my_getExpression (imm_expr, asarg);
+	      check_pref_type((unsigned long)imm_expr->X_add_number);
+	      INSERT_OPERAND (PREF_TYPE, *ip, imm_expr->X_add_number);
+	      imm_expr->X_op = O_absent;
+	      asarg = expr_end;
+	      continue;      
+
+	    case '+':
+	      my_getExpression (imm_expr, asarg);
+	      check_absolute_expr (ip, imm_expr, FALSE);
+	      if (imm_expr->X_add_number > 127 || imm_expr->X_add_number < -128)
+		as_bad (_("Improper pref offset value (%d)"),
+			(long) imm_expr->X_add_number);
+	      INSERT_OPERAND (PREF_OFFSET, *ip, imm_expr->X_add_number);
+	      imm_expr->X_op = O_absent;
+	      asarg = expr_end;
+	      continue;
+
 	    case 'E': /* Control register.  */
 	      insn_with_csr = true;
 	      explicit_priv_attr = true;
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 879eee8471..abbc8548be 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -255,6 +255,7 @@
 #define MASK_SFENCE_VMA  0xfe007fff
 #define MATCH_WFI 0x10500073
 #define MASK_WFI  0xffffffff
+#define MASK_CUSTOMER_PREF 0x7fff
 #define MATCH_CSRRW 0x1073
 #define MASK_CSRRW  0x707f
 #define MATCH_CSRRS 0x2073
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index c3cbde600c..52b57c4846 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -151,6 +151,10 @@ static inline unsigned int riscv_insn_length (insn_t insn)
   (RV_X(x, 0, 10) << 20)
 #define ENCODE_RVV_VC_IMM(x) \
   (RV_X(x, 0, 11) << 20)
+#define ENCODE_PREF_TIMM(x) \
+  (RV_X(x, 0, 4) << 20)
+#define ENCODE_PREF_SIMM(x) \
+  (RV_X(x, 0, 8) << 24)
 
 #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
 #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
@@ -251,6 +255,11 @@ static inline unsigned int riscv_insn_length (insn_t insn)
 #define OP_MASK_FUNCT2		0x3
 #define OP_SH_FUNCT2		25
 
+#define OP_MASK_PREF_TYPE     0x0f
+#define OP_SH_PREF_TYPE       20
+#define OP_MASK_PREF_OFFSET   0xff
+#define OP_SH_PREF_OFFSET     24
+
 /* RVC fields.  */
 
 #define OP_MASK_OP2		0x3
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 0e1f3b4610..0c9eb0bce8 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -517,6 +517,13 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 		 (unsigned)EXTRACT_OPERAND (SHAMTW, l));
 	  break;
 
+	case '#':
+	  print (info->stream, "0x%x", (int)EXTRACT_OPERAND (PREF_TYPE, l));
+	  break;
+
+	case '+':
+	  print (info->stream, "0x%x", (int)EXTRACT_OPERAND (PREF_OFFSET, l));
+
 	case 'S':
 	case 'U':
 	  print (info->stream, dis_style_register, "%s", riscv_fpr_names[rs1]);
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index f4d1cda8b9..6943c922ac 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -448,6 +448,7 @@ const struct riscv_opcode riscv_opcodes[] =
 {"snez",        0, INSN_CLASS_I, "d,t",       MATCH_SLTU, MASK_SLTU|MASK_RS1, match_opcode, INSN_ALIAS },
 {"sltz",        0, INSN_CLASS_I, "d,s",       MATCH_SLT, MASK_SLT|MASK_RS2, match_opcode, INSN_ALIAS },
 {"sgtz",        0, INSN_CLASS_I, "d,t",       MATCH_SLT, MASK_SLT|MASK_RS1, match_opcode, INSN_ALIAS },
+{"pref",        0, INSN_CLASS_I, "#,+(s)",    MATCH_SLTI, MASK_CUSTOMER_PREF, match_opcode, INSN_ALIAS },
 {"slti",        0, INSN_CLASS_I, "d,s,j",     MATCH_SLTI, MASK_SLTI, match_opcode, 0 },
 {"slt",         0, INSN_CLASS_I, "d,s,t",     MATCH_SLT, MASK_SLT, match_opcode, 0 },
 {"slt",         0, INSN_CLASS_I, "d,s,j",     MATCH_SLTI, MASK_SLTI, match_opcode, INSN_ALIAS },
-- 
2.25.1

