Module Name:    src
Committed By:   dholland
Date:           Mon Apr 19 07:55:59 UTC 2021

Modified Files:
        src/sys/arch/riscv/include: insn.h
        src/sys/arch/riscv/riscv: db_disasm.c

Log Message:
Make the riscv disassembler work, as best as I can test from amd64 userspace.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/riscv/include/insn.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/riscv/riscv/db_disasm.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/riscv/include/insn.h
diff -u src/sys/arch/riscv/include/insn.h:1.3 src/sys/arch/riscv/include/insn.h:1.4
--- src/sys/arch/riscv/include/insn.h:1.3	Wed Apr 14 06:32:20 2021
+++ src/sys/arch/riscv/include/insn.h	Mon Apr 19 07:55:59 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: insn.h,v 1.3 2021/04/14 06:32:20 dholland Exp $ */
+/* $NetBSD: insn.h,v 1.4 2021/04/19 07:55:59 dholland Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -241,16 +241,16 @@ union riscv_insn {
  * Quadrant 1 goes FUNCT3 -> FUNCT2a -> FUNCT3b,
  * Quadrant 2 goes FUNCT3 -> FUNCT1b.
  */
-#define INSN16_FUNCT3(insn)	(((insn) && 0xe000) >> 13)
-#define INSN16_FUNCT2a(insn)	(((insn) && 0x0c00) >> 10)
-#define INSN16_FUNCT1b(insn)	(((insn) && 0x1000) >> 12)
-#define INSN16_FUNCT2b(insn)	(((insn) && 0x0060) >> 5)
+#define INSN16_FUNCT3(insn)	(((insn) & 0xe000) >> 13)
+#define INSN16_FUNCT2a(insn)	(((insn) & 0x0c00) >> 10)
+#define INSN16_FUNCT1b(insn)	(((insn) & 0x1000) >> 12)
+#define INSN16_FUNCT2b(insn)	(((insn) & 0x0060) >> 5)
 #define INSN16_FUNCT3c(insn)	\
 	((INSN16_FUNCT1b(insn) << 2) | INSN16_FUNCT2b(insn))
 
 /* full-size register fields */
 #define INSN16_RS1(insn)	(((insn) & 0x0f80) >> 7)  /* bits 7-11 */
-#define INSN16_RS2(insn)	(((insn) & 0x007c) >> 7)  /* bits 2-6 */
+#define INSN16_RS2(insn)	(((insn) & 0x007c) >> 2)  /* bits 2-6 */
 
 /* small register fields, for registers 8-15 */
 #define INSN16_RS1x(insn)	((((insn) & 0x0380) >> 7) + 8)	/* bits 7-9 */
@@ -422,6 +422,12 @@ union riscv_insn {
 #define OPFP_D			0b01
 #define OPFP_Q			0b11
 
+// in some instructions they're an integer operand size instead
+#define OPFP_W			0b00
+#define OPFP_WU			0b01
+#define OPFP_L			0b10
+#define OPFP_LU			0b11
+
 // primary is AMO (0b01011, 11), top 5 bits
 // (bottom two bits are ACQUIRE and RELEASE flags respectively)
 // funct3 gives the operand size
@@ -644,7 +650,7 @@ union riscv_insn {
 
 #define OPCODE16_Q0	0b00	/* quadrant 0 */
 #define OPCODE16_Q1	0b01	/* quadrant 1 */
-#define OPCODE16_Q2	0b11	/* quadrant 2 */
+#define OPCODE16_Q2	0b10	/* quadrant 2 */
 
 /* quadrant 0 */
 #define Q0_ADDI4SPN	0b000

Index: src/sys/arch/riscv/riscv/db_disasm.c
diff -u src/sys/arch/riscv/riscv/db_disasm.c:1.3 src/sys/arch/riscv/riscv/db_disasm.c:1.4
--- src/sys/arch/riscv/riscv/db_disasm.c:1.3	Wed Apr 14 06:32:20 2021
+++ src/sys/arch/riscv/riscv/db_disasm.c	Mon Apr 19 07:55:59 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_disasm.c,v 1.3 2021/04/14 06:32:20 dholland Exp $	*/
+/*	$NetBSD: db_disasm.c,v 1.4 2021/04/19 07:55:59 dholland Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__RCSID("$NetBSD: db_disasm.c,v 1.3 2021/04/14 06:32:20 dholland Exp $");
+__RCSID("$NetBSD: db_disasm.c,v 1.4 2021/04/19 07:55:59 dholland Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -65,6 +65,11 @@ db_print_addr(db_addr_t loc)
 	db_sym_t sym;
 	const char *symname;
 
+/* hack for testing since the test program is ASLR'd */
+#ifndef _KERNEL
+	loc &= 0xfff;
+#endif
+
 	diff = INT_MAX;
 	symname = NULL;
 	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
@@ -101,6 +106,30 @@ db_print_addr(db_addr_t loc)
 #define IN_Q1(op) COMBINE(op, OPCODE16_Q1)
 #define IN_Q2(op) COMBINE(op, OPCODE16_Q2)
 
+/*
+ * All the 16-bit immediate bit-wrangling is done in uint32_t, which
+ * is sufficient, but on RV64 the resulting values should be printed
+ * as 64-bit. Continuing the assumption that we're disassembling for
+ * the size we're built on, do nothing for RV32 and sign-extend from
+ * 32 to 64 for RV64. (And bail on RV128 since it's not clear what
+ * the C type sizes are going to be there anyway...)
+ */
+static
+unsigned long
+maybe_signext64(uint32_t x)
+{
+#if __riscv_xlen == 32
+	return x;
+#elif __riscv_xlen == 64
+	uint64_t xx;
+
+	xx = ((x & 0x80000000) ? 0xffffffff00000000 : 0) | x;
+	return xx;
+#else
+#error Oops.
+#endif
+}
+
 static
 int
 db_disasm_16(db_addr_t loc, uint32_t insn, bool altfmt)
@@ -110,10 +139,15 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 	uint32_t imm;
 	unsigned rd, rs1, rs2;
 
+	//warnx("toot 0x%x", insn);
 	switch (COMBINE(INSN16_FUNCT3(insn), INSN16_QUADRANT(insn))) {
 	    case IN_Q0(Q0_ADDI4SPN):
 		rd = INSN16_RS2x(insn);
 		imm = INSN16_IMM_CIW(insn);
+		if (imm == 0) {
+			/* reserved (all bits 0 -> invalid) */
+			return EINVAL;
+		}
 		db_printf("c.addi4spn %s, 0x%x\n", riscv_registers[rd], imm);
 		break;
 	    case IN_Q0(Q0_FLD_LQ):
@@ -183,11 +217,10 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 #endif
 		break;
 	    case IN_Q1(Q1_NOP_ADDI):
-		rd = INSN16_RS1x(insn);
+		rd = INSN16_RS1(insn);
 		imm = INSN16_IMM_CI_K(insn);
 		if (rd == 0 && imm == 0) {
-			db_printf("c.nop %s, %d(%s)\n", riscv_registers[rs2],
-				  (int32_t)imm, riscv_registers[rs1]);
+			db_printf("c.nop\n");
 		}
 		else if (rd == 0 && imm != 0) {
 			/* undefined hint */
@@ -198,8 +231,10 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 			return EINVAL;
 		}
 		else {
-			db_printf("c.addi %s, %s, 0x%x\n", riscv_registers[rd],
-				  riscv_registers[rd], imm);
+			db_printf("c.addi %s, %s, 0x%lx\n",
+				  riscv_registers[rd],
+				  riscv_registers[rd],
+				  maybe_signext64(imm));
 		}
 		break;
 	    case IN_Q1(Q1_JAL_ADDIW):
@@ -209,25 +244,29 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 		db_print_addr(loc + (int32_t)imm);
 		db_printf("\n");
 #else
-		db_printf("c.addiw %s, %s, 0x%x\n", riscv_registers[rd],
-			  riscv_registers[rd], imm);
+		rd = INSN16_RS1(insn);
+		imm = INSN16_IMM_CI_K(insn);
+		db_printf("c.addiw %s, %s, 0x%lx\n", riscv_registers[rd],
+			  riscv_registers[rd], maybe_signext64(imm));
 #endif
 		break;
 	    case IN_Q1(Q1_LI):
 		rd = INSN16_RS1(insn);
 		imm = INSN16_IMM_CI_K(insn);
-		db_printf("c.li %s, 0x%x\n", riscv_registers[rd], imm);
+		db_printf("c.li %s, 0x%lx\n", riscv_registers[rd],
+			  maybe_signext64(imm));
 		break;
 	    case IN_Q1(Q1_ADDI16SP_LUI):
 		rd = INSN16_RS1(insn);
 		if (rd == 2/*sp*/) {
 			imm = INSN16_IMM_CI_K4(insn);
-			db_printf("c.add16sp sp, 0x%x\n", imm);
+			db_printf("c.add16sp sp, 0x%lx\n",
+				  maybe_signext64(imm));
 		}
 		else {
 			imm = INSN16_IMM_CI_K12(insn);
-			db_printf("c.lui %s, 0x%x\n", riscv_registers[rd],
-				  imm);
+			db_printf("c.lui %s, 0x%lx\n", riscv_registers[rd],
+				  maybe_signext64(imm));
 		}
 		break;
 	    case IN_Q1(Q1_MISC):
@@ -258,7 +297,8 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 				  riscv_registers[rd], imm);
 			break;
 		    case Q1MISC_ANDI:
-			db_printf("c.andi %s, %d\n", riscv_registers[rd], imm);
+			db_printf("c.andi %s, 0x%lx\n", riscv_registers[rd],
+				  maybe_signext64(imm));
 			break;
 		    case Q1MISC_MORE:
 			rs2 = INSN16_RS2x(insn);
@@ -374,10 +414,10 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 #endif
 		break;
 	    case IN_Q2(Q2_MISC):
+		rs1 = INSN16_RS1(insn);
+		rs2 = INSN16_RS2(insn);
 		switch (INSN16_FUNCT1b(insn)) {
 		    case Q2MISC_JR_MV:
-			rs1 = INSN16_RS1(insn);
-			rs2 = INSN16_RS2(insn);
 			if (rs1 == 0) {
 				return EINVAL;
 			}
@@ -448,7 +488,7 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 /* match flags */
 #define CHECK_F3	0x0001		/* check funct3 field */
 #define CHECK_F7	0x0002		/* check funct7 field */
-#define CHECK_F5	0x0004		/* check top of funct7 field only */
+#define CHECK_F5	0x0004		/* check tpo of funct7 field only */
 #define CHECK_RS2	0x0008		/* check rs2 as quaternary opcode */
 #define SHIFT32		0x0010		/* 32-bit immediate shift */
 #define SHIFT64		0x0020		/* 64-bit immediate shift */
@@ -460,7 +500,8 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 #define F3ROUND		0x0800		/* expect fp rounding mode in funct3 */
 #define F7SIZE		0x1000		/* expect fp size in funct7:0-1 */
 #define RS2_FSIZE	0x2000		/* expect fp size in rs2 */
-#define FENCEFM		0x4000		/* fence mode in top 4 bits of imm */
+#define RS2_FSIZE_INT	0x4000		/* expect fp size in rs2 */
+#define FENCEFM		0x8000		/* fence mode in top 4 bits of imm */
 /* do not add more without increasing the field size below */
 
 #ifdef _LP64 /* disassembling ourself so can use our build flags... */
@@ -481,18 +522,20 @@ db_disasm_16(db_addr_t loc, uint32_t ins
 #define RD_FREG		0x100		/* rd is a fpu reg */
 #define RS1_FREG	0x200		/* rs1 is a fpu reg */
 #define RS2_FREG	0x400		/* rs2 is a fpu reg */
+#define ISCVT		0x800		/* is an fpu conversion op */
 /* do not add more without increasing the field size below */
 
 #define ALL_FREG (RD_FREG | RS1_FREG | RS2_FREG)
+#define RS12_FREG (RS1_FREG | RS2_FREG)
 
 /* entries for matching within a major opcode */
 struct riscv_disasm_insn {
 	const char *name;
-	unsigned int matchflags: 15,
+	unsigned int matchflags: 16,
 		funct3: 3,
 		funct7: 7,
 		rs2: 5;
-	unsigned int printflags: 11;
+	unsigned int printflags: 12;
 };
 
 /* format codes */
@@ -613,6 +656,7 @@ static const struct riscv_disasm_insn ri
 };
 
 static const struct riscv_disasm_insn riscv_disasm_opimm[] = {
+	INSN_F3("nop", OP_ADDSUB, RD_0 | RS1_0 | IMM_0, 0),
 	INSN_F3("addi", OP_ADDSUB, 0, 0),
 	INSN_F3("slti", OP_SLT, 0, 0),
 	INSN_F3("sltiu", OP_SLTU, 0, 0),
@@ -632,16 +676,16 @@ static const struct riscv_disasm_insn ri
 };
 
 static const struct riscv_disasm_insn riscv_disasm_store[] = {
-	INSN_F3("sb", STORE_SB, 0, 0),
-	INSN_F3("sh", STORE_SH, 0, 0),
-	INSN_F3("sw", STORE_SW, 0, 0),
-	INSN_F3("sd", STORE_SD, 0, 0),
+	INSN_F3("sb", STORE_SB, 0, MEMORYIMM),
+	INSN_F3("sh", STORE_SH, 0, MEMORYIMM),
+	INSN_F3("sw", STORE_SW, 0, MEMORYIMM),
+	INSN_F3("sd", STORE_SD, 0, MEMORYIMM),
 };
 
 static const struct riscv_disasm_insn riscv_disasm_storefp[] = {
-	INSN_F3("fsw", STOREFP_FSW, 0, RS2_FREG),
-	INSN_F3("fsd", STOREFP_FSD, 0, RS2_FREG),
-	INSN_F3("fsq", STOREFP_FSQ, 0, RS2_FREG),
+	INSN_F3("fsw", STOREFP_FSW, 0, MEMORYIMM | RS2_FREG),
+	INSN_F3("fsd", STOREFP_FSD, 0, MEMORYIMM | RS2_FREG),
+	INSN_F3("fsq", STOREFP_FSQ, 0, MEMORYIMM | RS2_FREG),
 };
 
 static const struct riscv_disasm_insn riscv_disasm_branch[] = {
@@ -659,10 +703,10 @@ static const struct riscv_disasm_insn ri
 	INSN_F3("csrr", SYSTEM_CSRRS, RS1_0, CSRIMM),
 	INSN_F3("csrrs", SYSTEM_CSRRS, 0, CSRIMM),
 	INSN_F3("csrrc", SYSTEM_CSRRC, 0, CSRIMM),
-	INSN_F3("csrwi", SYSTEM_CSRRW, RD_0, CSRIIMM),
-	INSN_F3("csrrwi", SYSTEM_CSRRW, 0, CSRIIMM),
-	INSN_F3("csrrsi", SYSTEM_CSRRS, 0, CSRIIMM),
-	INSN_F3("csrrci", SYSTEM_CSRRC, 0, CSRIIMM),
+	INSN_F3("csrwi", SYSTEM_CSRRWI, RD_0, CSRIIMM),
+	INSN_F3("csrrwi", SYSTEM_CSRRWI, 0, CSRIIMM),
+	INSN_F3("csrrsi", SYSTEM_CSRRSI, 0, CSRIIMM),
+	INSN_F3("csrrci", SYSTEM_CSRRCI, 0, CSRIIMM),
 	INSN_F37("sfence.vma", SYSTEM_PRIV, PRIV_SFENCE_VMA, RD_0, 0),
 	INSN_F37("hfence.bvma", SYSTEM_PRIV, PRIV_HFENCE_BVMA, 0, 0),
 	INSN_F37("hfence.gvma", SYSTEM_PRIV, PRIV_HFENCE_GVMA, 0, 0),
@@ -677,7 +721,7 @@ static const struct riscv_disasm_insn ri
 static const struct riscv_disasm_insn riscv_disasm_amo[] = {
 	INSN_F5("amoadd",  AMO_ADD,  F3AMO, AMOAQRL),
 	INSN_F5("amoswap", AMO_SWAP, F3AMO, AMOAQRL),
-	INSN_F5("lr",      AMO_LR,   F3AMO, AMOAQRL),
+	INSN_F5("lr",      AMO_LR,   F3AMO | RS2_0, AMOAQRL),
 	INSN_F5("sc",      AMO_SC,   F3AMO, AMOAQRL),
 	INSN_F5("amoxor",  AMO_XOR,  F3AMO, AMOAQRL),
 	INSN_F5("amoor",   AMO_OR,   F3AMO, AMOAQRL),
@@ -699,6 +743,14 @@ static const struct riscv_disasm_insn ri
 	INSN_F37("sra", OP_SRX,    OP_NARITH, 0, 0),
 	INSN_F37("or",  OP_OR,     OP_ARITH, 0, 0),
 	INSN_F37("and", OP_AND,    OP_ARITH, 0, 0),
+	INSN_F37("mul", OP_MUL,    OP_MULDIV, 0, 0),
+	INSN_F37("mulh", OP_MULH,  OP_MULDIV, 0, 0),
+	INSN_F37("mulhsu", OP_MULHSU, OP_MULDIV, 0, 0),
+	INSN_F37("mulhu", OP_MULHU, OP_MULDIV, 0, 0),
+	INSN_F37("div", OP_DIV,    OP_MULDIV, 0, 0),
+	INSN_F37("divu", OP_DIVU,  OP_MULDIV, 0, 0),
+	INSN_F37("rem", OP_REM,    OP_MULDIV, 0, 0),
+	INSN_F37("remu", OP_REMU,  OP_MULDIV, 0, 0),
 };
 
 static const struct riscv_disasm_insn riscv_disasm_op32[] = {
@@ -707,6 +759,11 @@ static const struct riscv_disasm_insn ri
 	INSN_F37("sllw", OP_SLL,    OP_ARITH, 0, 0),
 	INSN_F37("srlw", OP_SRX,    OP_ARITH, 0, 0),
 	INSN_F37("sraw", OP_SRX,    OP_NARITH, 0, 0),
+	INSN_F37("mulw", OP_MUL,    OP_MULDIV, 0, 0),
+	INSN_F37("divw", OP_DIV,    OP_MULDIV, 0, 0),
+	INSN_F37("divuw", OP_DIVU,  OP_MULDIV, 0, 0),
+	INSN_F37("remw", OP_REM,    OP_MULDIV, 0, 0),
+	INSN_F37("remuw", OP_REMU,  OP_MULDIV, 0, 0),
 };
 
 static const struct riscv_disasm_insn riscv_disasm_opfp[] = {
@@ -719,24 +776,26 @@ static const struct riscv_disasm_insn ri
 	INSN_F53("fsgnjx", OPFP_SGNJ, SGN_SGNJX, F7SIZE, ALL_FREG),
 	INSN_F53("fmin", OPFP_MINMAX, MINMAX_MIN, F7SIZE, ALL_FREG),
 	INSN_F53("fmax", OPFP_MINMAX, MINMAX_MAX, F7SIZE, ALL_FREG),
-	INSN_F5("fcvt", OPFP_CVTFF, F7SIZE|F3ROUND|RS2_FSIZE, ALL_FREG),
+	INSN_F5("fcvt", OPFP_CVTFF, F7SIZE|F3ROUND|RS2_FSIZE,
+		ISCVT | ALL_FREG),
 	INSN_F5("fsqrt", OPFP_SQRT, F7SIZE|F3ROUND|RS2_0, ALL_FREG),
-	INSN_F53("fle", OPFP_CMP, CMP_LE, F7SIZE, ALL_FREG),
-	INSN_F53("flt", OPFP_CMP, CMP_LT, F7SIZE, ALL_FREG),
-	INSN_F53("feq", OPFP_CMP, CMP_EQ, F7SIZE, ALL_FREG),
-	INSN_F5("fcvt", OPFP_CVTIF, F7SIZE|F3ROUND|RS2_FSIZE,
-		RS2SIZE_FIRST | RD_FREG),
-	INSN_F5("fcvt", OPFP_CVTFI, F7SIZE|F3ROUND|RS2_FSIZE, RS1_FREG),
+	INSN_F53("fle", OPFP_CMP, CMP_LE, F7SIZE, RS12_FREG),
+	INSN_F53("flt", OPFP_CMP, CMP_LT, F7SIZE, RS12_FREG),
+	INSN_F53("feq", OPFP_CMP, CMP_EQ, F7SIZE, RS12_FREG),
+	INSN_F5("fcvt", OPFP_CVTIF, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT,
+		ISCVT | RS2SIZE_FIRST | RS1_FREG),
+	INSN_F5("fcvt", OPFP_CVTFI, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT,
+		ISCVT | RD_FREG),
 	INSN_F53("fclass", OPFP_MVFI_CLASS, MVFI_CLASS_CLASS, F7SIZE|RS2_0,
-		 ALL_FREG),
+		 RS1_FREG),
 	INSN_F73("fmv.x.w", (OPFP_MVFI_CLASS << 2) | OPFP_S, MVFI_CLASS_MVFI,
-		 F7SIZE|RS2_0, RS1_FREG),
+		 RS2_0, RS1_FREG),
 	INSN_F73("fmv.w.x", (OPFP_MVIF << 2) | OPFP_S, 0,
-		 F7SIZE|RS2_0, RD_FREG),
+		 RS2_0, RD_FREG),
 	INSN_F73("fmv.x.d", (OPFP_MVFI_CLASS << 2) | OPFP_D, MVFI_CLASS_MVFI,
-		 F7SIZE|RS2_0, RS1_FREG),
+		 RS2_0, RS1_FREG),
 	INSN_F73("fmv.d.x", (OPFP_MVIF << 2) | OPFP_D, 0,
-		 F7SIZE|RS2_0, RD_FREG),
+		 RS2_0, RD_FREG),
 };
 
 #define TABLE(table) \
@@ -864,7 +923,8 @@ riscv_disasm_match(const struct riscv_di
 			}
 		}
 		if (info->matchflags & F7SIZE) {
-			/* fp size bits at bottom of funct7 */
+			/* fpu size bits at bottom of funct7 */
+			/* always floating sizes */
 			switch (f7 & 3) {
 			    case OPFP_S:
 			    case OPFP_D:
@@ -875,14 +935,29 @@ riscv_disasm_match(const struct riscv_di
 			}
 		}
 		if (info->matchflags & RS2_FSIZE) {
-			/* fp size bits in rs2 field */
-			switch (INSN_RS2(insn)) {
-			    case OPFP_S:
-			    case OPFP_D:
-			    case OPFP_Q:
-				break;
-			    default:
-				continue;
+			/* fpu size bits in rs2 field */
+			if (info->matchflags & RS2_FSIZE_INT) {
+				/* integer sizes */
+				switch (INSN_RS2(insn)) {
+				    case OPFP_W:
+				    case OPFP_WU:
+				    case OPFP_L:
+				    case OPFP_LU:
+					break;
+				    default:
+					continue;
+				}
+			}
+			else {
+				/* floating sizes */
+				switch (INSN_RS2(insn)) {
+				    case OPFP_S:
+				    case OPFP_D:
+				    case OPFP_Q:
+					break;
+				    default:
+					continue;
+				}
 			}
 		}
 		if (info->matchflags & FENCEFM) {
@@ -933,28 +1008,112 @@ db_print_riscv_reg(unsigned reg, bool is
 
 static
 const char *
+riscv_int_size(unsigned fpsize)
+{
+	switch (fpsize) {
+	    case OPFP_W: return ".w";
+	    case OPFP_WU: return ".wu";
+	    case OPFP_L: return ".l";
+	    case OPFP_LU: return ".lu";
+	}
+}
+
+static
+const char *
 riscv_fp_size(unsigned fpsize)
 {
 	switch (fpsize) {
 	    case OPFP_S: return ".s";
 	    case OPFP_D: return ".d";
 	    case OPFP_Q: return ".q";
-	    default: KASSERT(0); return ".?";
+	    default:
+		/* matching should prevent it coming here */
+		KASSERT(0);
+		return ".?";
 	}
 }
 
 static
-const char *
-riscv_fp_round(unsigned round)
+bool larger_f_i(unsigned sz1, unsigned sz2)
+{
+	switch (sz1) {
+	    case OPFP_S:
+		break;
+	    case OPFP_D:
+		switch (sz2) {
+		    case OPFP_W:
+		    case OPFP_WU:
+			return true;
+		    default:
+			break;
+		}
+		break;
+	    case OPFP_Q:
+		switch (sz2) {
+		    case OPFP_W:
+		    case OPFP_WU:
+		    case OPFP_L:
+		    case OPFP_LU:
+			return true;
+		    default:
+			break;
+		}
+		break;
+	    default:
+		/* matching should keep it from coming here */
+		KASSERT(0);
+		break;
+	}
+	return false;
+}
+
+static
+bool larger_f_f(unsigned sz1, unsigned sz2)
+{
+	switch (sz1) {
+	    case OPFP_S:
+		break;
+	    case OPFP_D:
+		switch (sz2) {
+		    case OPFP_S:
+			return true;
+		    default:
+			break;
+		}
+		break;
+	    case OPFP_Q:
+		switch (sz2) {
+		    case OPFP_S:
+		    case OPFP_D:
+			return true;
+		    default:
+			break;
+		}
+		break;
+	    default:
+		/* matching should keep it from coming here */
+		KASSERT(0);
+		break;
+	}
+	return false;
+}
+
+static
+void
+db_print_riscv_fpround(const char *sep, unsigned round)
 {
 	switch (round) {
-	    case ROUND_RNE: return ".rne";
-	    case ROUND_RTZ: return ".rtz";
-	    case ROUND_RDN: return ".rdn";
-	    case ROUND_RUP: return ".rup";
-	    case ROUND_RMM: return ".rmm";
-	    case ROUND_DYN: return "";
-	    default: KASSERT(0); return ".?";
+	    case ROUND_RNE: db_printf("%srne", sep); break;
+	    case ROUND_RTZ: db_printf("%srtz", sep); break;
+	    case ROUND_RDN: db_printf("%srdn", sep); break;
+	    case ROUND_RUP: db_printf("%srup", sep); break;
+	    case ROUND_RMM: db_printf("%srmm", sep); break;
+	    case ROUND_DYN: break;
+	    default:
+		/* matching should prevent it coming here */
+		KASSERT(0);
+		db_printf("%s<unknown-rounding-mode>", sep);
+		break;
 	}
 }
 
@@ -971,17 +1130,24 @@ db_print_riscv_insnname(uint32_t insn, c
 	}
 	if ((info->matchflags & RS2_FSIZE) &&
 	    (info->printflags & RS2SIZE_FIRST)) {
-		db_printf("%s", riscv_fp_size(INSN_RS2(insn)));
+		if (info->matchflags & RS2_FSIZE_INT) {
+			db_printf("%s", riscv_int_size(INSN_RS2(insn)));
+		}
+		else {
+			db_printf("%s", riscv_fp_size(INSN_RS2(insn)));
+		}
 	}
 	if (info->matchflags & F7SIZE) {
 		db_printf("%s", riscv_fp_size(INSN_FUNCT7(insn) & 3));
 	}
 	if ((info->matchflags & RS2_FSIZE) &&
 	    (info->printflags & RS2SIZE_FIRST) == 0) {
-		db_printf("%s", riscv_fp_size(INSN_RS2(insn)));
-	}
-	if (info->matchflags & F3ROUND) {
-		db_printf("%s", riscv_fp_round(INSN_FUNCT3(insn)));
+		if (info->matchflags & RS2_FSIZE_INT) {
+			db_printf("%s", riscv_int_size(INSN_RS2(insn)));
+		}
+		else {
+			db_printf("%s", riscv_fp_size(INSN_RS2(insn)));
+		}
 	}
 	if (info->matchflags & FENCEFM) {
 		/*
@@ -1035,32 +1201,100 @@ db_disasm_32(db_addr_t loc, uint32_t ins
 			sep = ", ";
 		}
 
-		/* rs1 */
-		if ((info->matchflags & RS1_0) == 0) {
-			db_printf("%s", sep);
+		if (info->printflags & CSRIMM) {
+			/*
+			 * CSR instruction; these appear under a major
+			 * opcode with register format, but they
+			 * actually use the I format. Sigh. The
+			 * immediate field contains the CSR number and
+			 * prints _before_ rs1.
+			 */
+			imm = INSN_IMM_I(insn);
+			db_printf("%s0x%x, ", sep, (int32_t)imm);
 			db_print_riscv_reg(INSN_RS1(insn),
 					   info->printflags & RS1_FREG);
-			sep = ", ";
 		}
+		else if (info->printflags & CSRIIMM) {
+			/*
+			 * CSR instruction with immediate; the CSR
+			 * number is in the immediate fiel and the RS1
+			 * field contains the immediate. Bleck.
+			 */
+			imm = INSN_IMM_I(insn);
+			db_printf("%s0x%x, %d", sep, (int32_t)imm,
+				  INSN_RS1(insn));
+		}
+		else {
+			/* rs1 */
+			if ((info->matchflags & RS1_0) == 0) {
+				db_printf("%s", sep);
+				db_print_riscv_reg(INSN_RS1(insn),
+					   info->printflags & RS1_FREG);
+				sep = ", ";
+			}
 
-		/* rs2 */
-		if ((info->matchflags & RS2_0) == 0 &&
-		    (info->matchflags && CHECK_RS2) == 0) {
-			db_printf("%s", sep);
-			db_print_riscv_reg(INSN_RS2(insn),
+			/* rs2 */
+			if ((info->matchflags & RS2_0) == 0 &&
+			    (info->matchflags & CHECK_RS2) == 0 &&
+			    (info->matchflags & RS2_FSIZE) == 0) {
+				db_printf("%s", sep);
+				db_print_riscv_reg(INSN_RS2(insn),
 					   info->printflags & RS2_FREG);
+			}
 		}
-		db_printf("\n");
 
+		if (info->matchflags & F3ROUND) {
+			/*
+			 * Suppress rounding mode print for insns that
+			 * never round, because gas encodes it as 0
+			 * ("rup") rather than the normal default
+			 * ("dyn").
+			 *
+			 * These are: convert float to larger float,
+			 * convert int to float larger than the float.
+			 */
+			bool suppress;
+
+			if (info->printflags & ISCVT) {
+				KASSERT(info->matchflags & F7SIZE);
+				KASSERT(info->matchflags & RS2_FSIZE);
+				if (info->matchflags & RS2SIZE_FIRST) {
+					/* convert to int */
+					suppress = false;
+				}
+				else if (info->matchflags & RS2_FSIZE_INT) {
+					/* convert from int */
+					suppress = larger_f_i(
+						INSN_FUNCT7(insn) & 3,
+						INSN_RS2(insn));
+				}
+				else {
+					/* convert from float */
+					suppress = larger_f_f(
+						INSN_FUNCT7(insn) & 3,
+						INSN_RS2(insn));
+				}
+			}
+			else {
+				suppress = false;
+			}
+
+			if (!suppress) {
+				db_print_riscv_fpround(sep, INSN_FUNCT3(insn));
+			}
+		}
+
+		db_printf("\n");
 		break;
 	    case FMT_R4:
-		db_printf("%s%s%s f%d, f%d, f%d, f%d", d->u.name,
+		db_printf("%s%s f%d, f%d, f%d, f%d", d->u.name,
 			  riscv_fp_size(INSN_FUNCT7(insn) & 3),
-			  riscv_fp_round(INSN_FUNCT3(insn)),
 			  INSN_RD(insn),
 			  INSN_RS1(insn),
 			  INSN_RS2(insn),
 			  INSN_FUNCT7(insn) >> 2);
+		db_print_riscv_fpround(", ", INSN_FUNCT3(insn));
+		db_printf("\n");
 	        break;
 	    case FMT_I:
 		/* immediates */
@@ -1093,23 +1327,10 @@ db_disasm_32(db_addr_t loc, uint32_t ins
 
 		if (info->printflags & MEMORYIMM) {
 			db_printf("%s", sep);
-			db_printf("%d", (int32_t)imm);
+			db_printf("%d(", (int32_t)imm);
 			db_print_riscv_reg(INSN_RS1(insn),
 					   info->printflags & RS1_FREG);
-		}
-		else if (info->printflags & CSRIMM) {
-			db_printf("%s", sep);
-			/* CSR number is the immediate and comes first */
-			db_printf("%d, ", (int32_t)imm);
-			db_print_riscv_reg(INSN_RS1(insn),
-					   info->printflags & RS1_FREG);
-		}
-		else if (info->printflags & CSRIIMM) {
-			db_printf("%s", sep);
-			/* CSR number is the immediate and comes first */
-			db_printf("%d, ", (int32_t)imm);
-			/* the immediate value is in the RS1 field */
-			db_printf("%d", INSN_RS1(insn));
+			db_printf(")");
 		}
 		else {
 			/* rs1 */
@@ -1130,6 +1351,7 @@ db_disasm_32(db_addr_t loc, uint32_t ins
 				/* fm is part of the name, doesn't go here */
 				pred = (imm >> 4) & 0xf;
 				succ = imm & 0xf;
+				db_printf("%s", sep);
 				db_print_riscv_fencebits(pred);
 				db_printf(", ");
 				db_print_riscv_fencebits(succ);
@@ -1145,6 +1367,7 @@ db_disasm_32(db_addr_t loc, uint32_t ins
 				db_printf("%s0x%x", sep, imm);
 			}
 		}
+		db_printf("\n");
 		break;
 	    case FMT_In:
 		/* same as I but funct3 should be 0 so just one case */
@@ -1173,15 +1396,16 @@ db_disasm_32(db_addr_t loc, uint32_t ins
 
 		/* name */
 		db_print_riscv_insnname(insn, info);
+		db_printf(" ");
 
 		db_print_riscv_reg(INSN_RS2(insn),
 				   info->printflags & RS2_FREG);
-		sep = ", ";
+		db_printf(", ", sep);
 
-		db_printf("%s", sep);
-		db_printf("%d", (int32_t)imm);
+		db_printf("%d(", (int32_t)imm);
 		db_print_riscv_reg(INSN_RS1(insn),
 				   info->printflags & RS1_FREG);
+		db_printf(")\n");
 		break;
 	    case FMT_B:
 		/* branches */
@@ -1199,6 +1423,7 @@ db_disasm_32(db_addr_t loc, uint32_t ins
 
 		/* name */
 		db_print_riscv_insnname(insn, info);
+		db_printf(" ");
 
 		db_print_riscv_reg(INSN_RS1(insn),
 				   info->printflags & RS1_FREG);
@@ -1259,11 +1484,13 @@ db_disasm(db_addr_t loc, bool altfmt)
 	unsigned n, i;
 	uint32_t insn32;
 
+#ifdef _KERNEL
 	if ((intptr_t) loc >= 0) {
 		db_printf("%s: %#"PRIxVADDR" is not a kernel address\n",
 		    __func__, loc);
 		return loc;
 	}
+#endif
 
 	/*
 	 * Fetch the instruction. The first halfword tells us how many

Reply via email to