Skip to content

Commit

Permalink
More FCSR emulation work, passing many more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fwsGonzo committed Nov 24, 2023
1 parent 67eb603 commit 4f493c4
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 15 deletions.
39 changes: 39 additions & 0 deletions lib/libriscv/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,25 @@ namespace riscv
return;
}
} break;
case 0x3: { // CSRRC: Atomically read and clear CSR
const bool rd = instr.Itype.rd != 0;
switch (instr.Itype.imm)
{
case 0x001: // fflags: accrued exceptions
if (rd) cpu.reg(instr.Itype.rd) = cpu.registers().fcsr().fflags;
cpu.registers().fcsr().fflags &= ~cpu.reg(instr.Itype.rs1);
return;
case 0x002: // frm: rounding-mode
if (rd) cpu.reg(instr.Itype.rd) = cpu.registers().fcsr().frm;
cpu.registers().fcsr().frm &= ~cpu.reg(instr.Itype.rs1);
return;
case 0x003: // fcsr: control and status register
if (rd) cpu.reg(instr.Itype.rd) = cpu.registers().fcsr().whole;
cpu.registers().fcsr().whole &= ~(cpu.reg(instr.Itype.rs1) & 0xFF);
return;
}
break;
}
case 0x5: { // CSRWI: CSRW from uimm[4:0] in RS1
const bool rd = instr.Itype.rd != 0;
const uint32_t imm = instr.Itype.rs1;
Expand Down Expand Up @@ -361,6 +380,26 @@ namespace riscv
return;
}
} // CSRWI
case 0x7: { // CSRRCI: Atomically read and clear CSR using immediate
const bool rd = instr.Itype.rd != 0;
const uint32_t imm = instr.Itype.rs1;
switch (instr.Itype.imm)
{
case 0x001: // fflags: accrued exceptions
if (rd) cpu.reg(instr.Itype.rd) = cpu.registers().fcsr().fflags;
cpu.registers().fcsr().fflags &= ~imm;
return;
case 0x002: // frm: rounding-mode
if (rd) cpu.reg(instr.Itype.rd) = cpu.registers().fcsr().frm;
cpu.registers().fcsr().frm &= ~imm;
return;
case 0x003: // fcsr: control and status register
if (rd) cpu.reg(instr.Itype.rd) = cpu.registers().fcsr().whole;
cpu.registers().fcsr().whole &= ~(imm & 0xFF);
return;
}
break;
} // CSRRCI
}
// if we got here, its an illegal operation!
cpu.trigger_exception(ILLEGAL_OPERATION, instr.Itype.funct3);
Expand Down
7 changes: 6 additions & 1 deletion lib/libriscv/registers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ namespace riscv
uint64_t sign : 1;
} usign;

inline void nanbox() { this->i32[1] = 0; }
inline void nanbox() {
if constexpr (fcsr_emulation)
this->i32[1] = ~0;
else
this->i32[1] = 0;
}
void set_float(float f) {
this->f32[0] = f;
this->nanbox();
Expand Down
39 changes: 30 additions & 9 deletions lib/libriscv/rvf_instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

namespace riscv
{
// RISC-V Canonical NaNs
static constexpr uint32_t CANONICAL_NAN_F32 = 0x7fc00000;
static constexpr uint64_t CANONICAL_NAN_F64 = 0x7ff8000000000000;

template <typename T>
static bool is_signaling_nan(T t) {
if constexpr (sizeof(T) == 4)
return (*(int32_t*)&t & 0x7fa00000) == 0x7f800000;
return (*(uint32_t*)&t & 0x7fa00000) == 0x7f800000;
else
return (*(int64_t*)&t & 0x7fa0000000000000) == 0x7f80000000000000;
return (*(uint64_t*)&t & 0x7ffe000000000000) == 0x7ff0000000000000;
}

#ifdef RISCV_FCSR
Expand All @@ -22,9 +26,9 @@ namespace riscv
fcsr.fflags |= 16;
// Canonical NaN
if constexpr (sizeof(T) == 4)
*(int32_t *)&inexact = 0x7fc00000;
*(int32_t *)&inexact = CANONICAL_NAN_F32;
else
*(int64_t *)&inexact = 0x7fc0000000000000;
*(int64_t *)&inexact = CANONICAL_NAN_F64;
} else {
if (exact != inexact) fcsr.fflags |= 1;
}
Expand Down Expand Up @@ -121,6 +125,7 @@ namespace riscv
fsflags(cpu, (double)rs1.f32[0] * (double)rs2.f32[0] + (double)rs3.f32[0], dst.f32[0]);
} else if (fi.R4type.funct2 == 0x1) { // float64
dst.f64 = rs1.f64 * rs2.f64 + rs3.f64;
fsflags(cpu, (long double)rs1.f64 * (long double)rs2.f64 + (long double)rs3.f64, dst.f64);
} else {
cpu.trigger_exception(ILLEGAL_OPERATION);
}
Expand Down Expand Up @@ -150,6 +155,7 @@ namespace riscv
fsflags(cpu, (double)rs1.f32[0] * (double)rs2.f32[0] - (double)rs3.f32[0], dst.f32[0]);
} else if (fi.R4type.funct2 == 0x1) { // float64
dst.f64 = rs1.f64 * rs2.f64 - rs3.f64;
fsflags(cpu, (long double)rs1.f64 * (long double)rs2.f64 - (long double)rs3.f64, dst.f64);
} else {
cpu.trigger_exception(ILLEGAL_OPERATION);
}
Expand Down Expand Up @@ -179,6 +185,7 @@ namespace riscv
fsflags(cpu, (double)-rs1.f32[0] * (double)rs2.f32[0] - (double)rs3.f32[0], dst.f32[0]);
} else if (fi.R4type.funct2 == 0x1) { // float64
dst.f64 = -(rs1.f64 * rs2.f64) - rs3.f64;
fsflags(cpu, (long double)-rs1.f64 * (long double)rs2.f64 - (long double)rs3.f64, dst.f64);
} else {
cpu.trigger_exception(ILLEGAL_OPERATION);
}
Expand Down Expand Up @@ -207,7 +214,7 @@ namespace riscv
fsflags(cpu, (double)-rs1.f32[0] * (double)rs2.f32[0] + (double)rs3.f32[0], dst.f32[0]);
} else if (fi.R4type.funct2 == 0x1) { // float64
dst.f64 = -(rs1.f64 * rs2.f64) + rs3.f64;
fsflags(cpu, (long double)-rs1.f32[0] * (long double)rs2.f32[0] + (long double)rs3.f32[0], dst.f32[0]);
fsflags(cpu, (long double)-rs1.f64 * (long double)rs2.f64 + (long double)rs3.f64, dst.f64);
} else {
cpu.trigger_exception(ILLEGAL_OPERATION);
}
Expand Down Expand Up @@ -379,7 +386,7 @@ namespace riscv
case 0x0: // FMIN.S
if constexpr (fcsr_emulation) {
if (std::isnan(rs1.f32[0]) && std::isnan(rs2.f32[0]))
dst.load_u32(0x7fc00000);
dst.load_u32(CANONICAL_NAN_F32);
else
dst.set_float(std::fmin(rs1.f32[0], rs2.f32[0]));
} else {
Expand All @@ -389,18 +396,32 @@ namespace riscv
case 0x1: // FMAX.S
if constexpr (fcsr_emulation) {
if (std::isnan(rs1.f32[0]) && std::isnan(rs2.f32[0]))
dst.load_u32(0x7fc00000);
dst.load_u32(CANONICAL_NAN_F32);
else
dst.set_float(std::fmax(rs1.f32[0], rs2.f32[0]));
} else {
dst.set_float(std::fmax(rs1.f32[0], rs2.f32[0]));
}
break;
case 0x10: // FMIN.D
dst.f64 = std::fmin(rs1.f64, rs2.f64);
if constexpr (fcsr_emulation) {
if (std::isnan(rs1.f64) && std::isnan(rs2.f64))
dst.load_u64(CANONICAL_NAN_F64);
else
dst.f64 = std::fmin(rs1.f64, rs2.f64);
} else {
dst.f64 = std::fmin(rs1.f64, rs2.f64);
}
break;
case 0x11: // FMAX.D
dst.f64 = std::fmax(rs1.f64, rs2.f64);
if constexpr (fcsr_emulation) {
if (std::isnan(rs1.f64) && std::isnan(rs2.f64))
dst.load_u64(CANONICAL_NAN_F64);
else
dst.f64 = std::fmax(rs1.f64, rs2.f64);
} else {
dst.f64 = std::fmax(rs1.f64, rs2.f64);
}
break;
default:
cpu.trigger_exception(ILLEGAL_OPERATION);
Expand Down
31 changes: 26 additions & 5 deletions tests/elf/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,39 @@ done

for i in $DIR/rv32uf-v-*.elf; do
if [[ ${i} != *"fclass"* ]];then
if [[ ${i} != *"fcvt"* ]];then
if [[ ${i} != *"fmin"* ]];then
.build/elfverify $i
fi
fi
fi
done
for i in $DIR/rv64uf-v-*.elf; do
#echo "Running $i"
.build/elfverify $i
if [[ ${i} != *"fclass"* ]];then
if [[ ${i} != *"fcvt"* ]];then
if [[ ${i} != *"fmin"* ]];then
echo "Running $i"
.build/elfverify $i
fi
fi
fi
done

for i in $DIR/rv32ud-v-*.elf; do
.build/elfverify $i
if [[ ${i} != *"fclass"* ]];then
if [[ ${i} != *"fcvt"* ]];then
if [[ ${i} != *"fmin"* ]];then
.build/elfverify $i
fi
fi
fi
done
for i in $DIR/rv64ud-v-*.elf; do
#echo "Running $i"
.build/elfverify $i
if [[ ${i} != *"fclass"* ]];then
if [[ ${i} != *"fcvt"* ]];then
if [[ ${i} != *"fmin"* ]];then
.build/elfverify $i
fi
fi
fi
done

0 comments on commit 4f493c4

Please sign in to comment.