Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions README.riscv64
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ The following ISA base and extensions are currently supported:
| Name | Description | #Instrs | Notes |
| ------------ | --------------------------------- | ------- | -------- |
| RV64I | Base instruction set | 52/52 | |
| RV64M | Integer multiplication & division | 12/13 | (1) |
| RV64A | Atomic | 22/22 | (2) |
| RV64F | Single-precision floating-point | 30/30 | (3) |
| RV64M | Integer multiplication & division | 13/13 | |
| RV64A | Atomic | 22/22 | (1) |
| RV64F | Single-precision floating-point | 30/30 | (2) |
| RV64D | Double-precision floating-point | 32/32 | |
| RV64Zicsr | Control & status register | 3/6 | (4), (5) |
| RV64Zifencei | Instruction-fetch fence | 0/1 | (6) |
| RV64Zicsr | Control & status register | 6/6 | (3) |
| RV64Zifencei | Instruction-fetch fence | 0/1 | (4) |
| RV64C | Compressed | 37/37 | |

Notes:
(1) MULHSU is not recognized.
(2) LR and SC use the VEX "fallback" method which suffers from the ABA problem.
(3) Operations do not check if the input operands are correctly NaN-boxed.
(4) CSRRWI, CSRRSI and CSRRCI are not recognized.
(5) Only registers fflags, frm and fcsr are accepted.
(6) FENCE.I is not recognized.
(1) LR and SC use the VEX "fallback" method which suffers from the ABA problem.
(2) Operations do not check if the input operands are correctly NaN-boxed.
(3) Only registers fflags, frm and fcsr are accepted.
(4) FENCE.I is not recognized.


Implementation tidying-up/TODO notes
Expand Down
169 changes: 117 additions & 52 deletions VEX/priv/guest_riscv64_toIR.c
Original file line number Diff line number Diff line change
Expand Up @@ -1753,76 +1753,89 @@ static Bool dis_RV64M(/*MB_OUT*/ DisResult* dres,
UInt funct3 = INSN(14, 12);
UInt rs1 = INSN(19, 15);
UInt rs2 = INSN(24, 20);
if (funct3 == 0b010) {
/* Invalid {MUL,DIV,REM}<x>, fall through. */
} else if (funct3 == 0b010) {
/* MULHSU, not currently handled, fall through. */
} else {
if (rd != 0) {
IRExpr* expr;
switch (funct3) {
case 0b000:
expr = binop(Iop_Mul64, getIReg64(rs1), getIReg64(rs2));
break;
case 0b001:
expr = unop(Iop_128HIto64,
binop(Iop_MullS64, getIReg64(rs1), getIReg64(rs2)));
break;
case 0b011:
expr = unop(Iop_128HIto64,
binop(Iop_MullU64, getIReg64(rs1), getIReg64(rs2)));
break;
case 0b100:
expr = binop(Iop_DivS64, getIReg64(rs1), getIReg64(rs2));
break;
case 0b101:
expr = binop(Iop_DivU64, getIReg64(rs1), getIReg64(rs2));
break;
case 0b110:
expr =
unop(Iop_128HIto64, binop(Iop_DivModS64to64, getIReg64(rs1),
getIReg64(rs2)));
break;
case 0b111:
expr =
unop(Iop_128HIto64, binop(Iop_DivModU64to64, getIReg64(rs1),
getIReg64(rs2)));
break;
default:
vassert(0);
}
putIReg64(irsb, rd, expr);
}
const HChar* name;
if (rd != 0) {
IRExpr* expr;
switch (funct3) {
case 0b000:
name = "mul";
expr = binop(Iop_Mul64, getIReg64(rs1), getIReg64(rs2));
break;
case 0b001:
name = "mulh";
expr = unop(Iop_128HIto64,
binop(Iop_MullS64, getIReg64(rs1), getIReg64(rs2)));
break;
case 0b010:
/* Inspired by QEMU's mulhsu emulation.
mulhsu(rs1, rs2)
=> ((s128)rs1 * (u128)rs2) >> 64
=> mulhu(rs1, rs2) + mul(rs1 < 0 ? -1 : 0, rs2)
=> mulhu(rs1, rs2) + (rs1 < 0 ? -rs2 : 0)
=> mulhu(rs1, rs2) - (rs1 < 0 ? rs2 : 0)
=> mulhu(rs1, rs2) - (srai(rs1, __riscv_xlen - 1) & rs2)
*/
expr = unop(Iop_128HIto64,
binop(Iop_MullU64, getIReg64(rs1), getIReg64(rs2)));
IRExpr* tmp = binop(Iop_And64,
binop(Iop_Sar64, getIReg64(rs1), mkU8(63)),
getIReg64(rs2));
expr = binop(Iop_Sub64, expr, tmp);
break;
case 0b011:
name = "mulhu";
expr = unop(Iop_128HIto64,
binop(Iop_MullU64, getIReg64(rs1), getIReg64(rs2)));
break;
case 0b100:
name = "div";
expr = binop(Iop_DivS64, getIReg64(rs1), getIReg64(rs2));
break;
case 0b101:
name = "divu";
expr = binop(Iop_DivU64, getIReg64(rs1), getIReg64(rs2));
break;
case 0b110:
name = "rem";
expr =
unop(Iop_128HIto64, binop(Iop_DivModS64to64, getIReg64(rs1),
getIReg64(rs2)));
break;
case 0b111:
name = "remu";
expr =
unop(Iop_128HIto64, binop(Iop_DivModU64to64, getIReg64(rs1),
getIReg64(rs2)));
break;
default:
vassert(0);
}
DIP("%s %s, %s, %s\n", name, nameIReg(rd), nameIReg(rs1),
nameIReg(rs2));
return True;
putIReg64(irsb, rd, expr);
}
const HChar* name;
switch (funct3) {
case 0b000:
name = "mul";
break;
case 0b001:
name = "mulh";
break;
case 0b010:
name = "mulhsu";
break;
case 0b011:
name = "mulhu";
break;
case 0b100:
name = "div";
break;
case 0b101:
name = "divu";
break;
case 0b110:
name = "rem";
break;
case 0b111:
name = "remu";
break;
default:
vassert(0);
}
DIP("%s %s, %s, %s\n", name, nameIReg(rd), nameIReg(rs1),
nameIReg(rs2));
return True;
}

/* ------------------ mulw rd, rs1, rs2 ------------------ */
Expand Down Expand Up @@ -3176,7 +3189,8 @@ static Bool dis_RV64Zicsr(/*MB_OUT*/ DisResult* dres,
UInt funct3 = INSN(14, 12);
UInt rs1 = INSN(19, 15);
UInt csr = INSN(31, 20);
if ((funct3 != 0b001 && funct3 != 0b010 && funct3 != 0b011) ||
UInt imm4_0 = rs1;
if (funct3 == 0b000 || funct3 == 0b100 ||
(csr != 0x001 && csr != 0x002 && csr != 0x003)) {
/* Invalid CSRR{W,S,C}, fall through. */
} else {
Expand Down Expand Up @@ -3206,6 +3220,18 @@ static Bool dis_RV64Zicsr(/*MB_OUT*/ DisResult* dres,
unop(Iop_Not32, binop(Iop_And32, getIReg32(rs1),
mkU32(0x1f))));
break;
case 0b101:
expr = binop(Iop_Or32,
binop(Iop_And32, mkexpr(fcsr), mkU32(0xffffffe0)),
mkU32(imm4_0));
break;
case 0b110:
expr = binop(Iop_Or32, mkexpr(fcsr), mkU32(imm4_0));
break;
case 0b111:
expr = binop(Iop_And32, mkexpr(fcsr),
unop(Iop_Not32, mkU32(imm4_0)));
break;
default:
vassert(0);
}
Expand Down Expand Up @@ -3245,6 +3271,26 @@ static Bool dis_RV64Zicsr(/*MB_OUT*/ DisResult* dres,
binop(Iop_And32, getIReg32(rs1), mkU32(0x7)),
mkU8(5))));
break;
case 0b101:
expr = binop(
Iop_Or32, binop(Iop_And32, mkexpr(fcsr), mkU32(0xffffff1f)),
binop(Iop_Shl32, binop(Iop_And32, mkU32(imm4_0), mkU32(0x7)),
mkU8(5)));
break;
case 0b110:
expr = binop(Iop_Or32, mkexpr(fcsr),
binop(Iop_Shl32,
binop(Iop_And32, mkU32(imm4_0), mkU32(0x7)),
mkU8(5)));
break;
case 0b111:
expr =
binop(Iop_And32, mkexpr(fcsr),
unop(Iop_Not32,
binop(Iop_Shl32,
binop(Iop_And32, mkU32(imm4_0), mkU32(0x7)),
mkU8(5))));
break;
default:
vassert(0);
}
Expand Down Expand Up @@ -3272,6 +3318,16 @@ static Bool dis_RV64Zicsr(/*MB_OUT*/ DisResult* dres,
unop(Iop_Not32, binop(Iop_And32, getIReg32(rs1),
mkU32(0xff))));
break;
case 0b101:
expr = mkU32(imm4_0);
break;
case 0b110:
expr = binop(Iop_Or32, mkexpr(fcsr), mkU32(imm4_0));
break;
case 0b111:
expr = binop(Iop_And32, mkexpr(fcsr),
unop(Iop_Not32, mkU32(imm4_0)));
break;
default:
vassert(0);
}
Expand All @@ -3293,6 +3349,15 @@ static Bool dis_RV64Zicsr(/*MB_OUT*/ DisResult* dres,
case 0b011:
name = "csrrc";
break;
case 0b101:
name = "csrrwi";
break;
case 0b110:
name = "csrrsi";
break;
case 0b111:
name = "csrrci";
break;
default:
vassert(0);
}
Expand Down
75 changes: 72 additions & 3 deletions none/tests/riscv64/csr.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,82 @@ static void test_csr64_shared(void)
TESTINST_1_1_CSR(4, "csrrc a0, fcsr, zero", 0xff, 0x00, a0, fcsr, zero);

/* -------------- csrrwi rd, csr, uimm[4:0] -------------- */
/* Not currently handled. */
/* fflags */
TESTINST_1_1_CSRI(4, "csrrwi a0, fflags, 0x01", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, fflags, 0x1f", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, fflags, 0x1e", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, fflags, 0x00", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi t5, fflags, 0x01", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi zero, fflags, 0x01", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, fflags, 0x00", 0xff, a0, fcsr);

/* frm */
TESTINST_1_1_CSRI(4, "csrrwi a0, frm, 0x1", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, frm, 0x7", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, frm, 0x6", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, frm, 0x0", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi t5, frm, 0x1", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi zero, frm, 0x1", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, frm, 0x0", 0xff, a0, fcsr);

/* fcsr */
TESTINST_1_1_CSRI(4, "csrrwi a0, fcsr, 0x01", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, fcsr, 0x00", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi t5, fcsr, 0x01", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi zero, fcsr, 0x01", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrwi a0, fcsr, 0x00", 0xff, a0, fcsr);

/* -------------- csrrsi rd, csr, uimm[4:0] -------------- */
/* Not currently handled. */
/* fflags */
TESTINST_1_1_CSRI(4, "csrrsi a0, fflags, 0x01", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, fflags, 0x1f", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, fflags, 0x1e", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, fflags, 0x00", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi t5, fflags, 0x01", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi zero, fflags, 0x01", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, fflags, 0x00", 0xff, a0, fcsr);

/* frm */
TESTINST_1_1_CSRI(4, "csrrsi a0, frm, 0x1", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, frm, 0x7", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, frm, 0x6", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, frm, 0x0", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi t5, frm, 0x1", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi zero, frm, 0x1", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, frm, 0x0", 0xff, a0, fcsr);

/* fcsr */
TESTINST_1_1_CSRI(4, "csrrsi a0, fcsr, 0x01", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, fcsr, 0x00", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi t5, fcsr, 0x01", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi zero, fcsr, 0x01", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrsi a0, fcsr, 0x00", 0xff, a0, fcsr);

/* -------------- csrrci rd, csr, uimm[4:0] -------------- */
/* Not currently handled. */
/* fflags */
TESTINST_1_1_CSRI(4, "csrrci a0, fflags, 0x01", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, fflags, 0x1f", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, fflags, 0x1e", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, fflags, 0x00", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci t5, fflags, 0x01", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrci zero, fflags, 0x01", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, fflags, 0x00", 0xff, a0, fcsr);

/* frm */
TESTINST_1_1_CSRI(4, "csrrci a0, frm, 0x1", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, frm, 0x7", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, frm, 0x6", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, frm, 0x0", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci t5, frm, 0x1", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrci zero, frm, 0x1", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, frm, 0x0", 0xff, a0, fcsr);

/* fcsr */
TESTINST_1_1_CSRI(4, "csrrci a0, fcsr, 0x01", 0x00, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, fcsr, 0x00", 0xff, a0, fcsr);
TESTINST_1_1_CSRI(4, "csrrci t5, fcsr, 0x01", 0x00, t5, fcsr);
TESTINST_1_1_CSRI(4, "csrrci zero, fcsr, 0x01", 0xff, zero, fcsr);
TESTINST_1_1_CSRI(4, "csrrci a0, fcsr, 0x00", 0xff, a0, fcsr);
}

int main(void)
Expand Down
Loading