// -*- mode:c++ -*- // Copyright (c) 2015 RISC-V Foundation // Copyright (c) 2017 The University of Virginia // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer; // redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution; // neither the name of the copyright holders nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: Alec Roelke //////////////////////////////////////////////////////////////////// // // The RISC-V ISA decoder // decode QUADRANT default Unknown::unknown() { 0x0: decode COPCODE { 0x0: CIOp::c_addi4spn({{ imm = CIMM8<1:1> << 2 | CIMM8<0:0> << 3 | CIMM8<7:6> << 4 | CIMM8<5:2> << 6; }}, {{ if (machInst == 0) fault = make_shared("zero instruction"); Rp2 = sp + imm; }}, uint64_t); format CompressedLoad { 0x1: c_fld({{ offset = CIMM3 << 3 | CIMM2 << 6; }}, {{ Fp2_bits = Mem; }}, {{ EA = Rp1 + offset; }}); 0x2: c_lw({{ offset = CIMM2<1:1> << 2 | CIMM3 << 3 | CIMM2<0:0> << 6; }}, {{ Rp2_sd = Mem_sw; }}, {{ EA = Rp1 + offset; }}); 0x3: c_ld({{ offset = CIMM3 << 3 | CIMM2 << 6; }}, {{ Rp2_sd = Mem_sd; }}, {{ EA = Rp1 + offset; }}); } format CompressedStore { 0x5: c_fsd({{ offset = CIMM3 << 3 | CIMM2 << 6; }}, {{ Mem = Fp2_bits; }}, {{ EA = Rp1 + offset; }}); 0x6: c_sw({{ offset = CIMM2<1:1> << 2 | CIMM3 << 3 | CIMM2<0:0> << 6; }}, {{ Mem_uw = Rp2_uw; }}, ea_code={{ EA = Rp1 + offset; }}); 0x7: c_sd({{ offset = CIMM3 << 3 | CIMM2 << 6; }}, {{ Mem_ud = Rp2_ud; }}, {{ EA = Rp1 + offset; }}); } } 0x1: decode COPCODE { format CIOp { 0x0: c_addi({{ imm = CIMM5; if (CIMM1 > 0) imm |= ~((uint64_t)0x1F); }}, {{ if ((RC1 == 0) != (imm == 0)) { if (RC1 == 0) { fault = make_shared("source reg x0"); } else // imm == 0 fault = make_shared("immediate = 0"); } Rc1_sd = Rc1_sd + imm; }}); 0x1: c_addiw({{ imm = CIMM5; if (CIMM1 > 0) imm |= ~((uint64_t)0x1F); }}, {{ assert(RC1 != 0); Rc1_sd = (int32_t)Rc1_sd + imm; }}); 0x2: c_li({{ imm = CIMM5; if (CIMM1 > 0) imm |= ~((uint64_t)0x1F); }}, {{ assert(RC1 != 0); Rc1_sd = imm; }}); 0x3: decode RC1 { 0x2: c_addi16sp({{ imm = CIMM5<4:4> << 4 | CIMM5<0:0> << 5 | CIMM5<3:3> << 6 | CIMM5<2:1> << 7; if (CIMM1 > 0) imm |= ~((int64_t)0x1FF); }}, {{ assert(imm != 0); sp_sd = sp_sd + imm; }}); default: c_lui({{ imm = CIMM5 << 12; if (CIMM1 > 0) imm |= ~((uint64_t)0x1FFFF); }}, {{ assert(RC1 != 0 && RC1 != 2); assert(imm != 0); Rc1_sd = imm; }}); } } 0x4: decode CFUNCT2HIGH { format CIOp { 0x0: c_srli({{ imm = CIMM5 | (CIMM1 << 5); assert(imm != 0); }}, {{ Rp1 = Rp1 >> imm; }}, uint64_t); 0x1: c_srai({{ imm = CIMM5 | (CIMM1 << 5); assert(imm != 0); }}, {{ Rp1_sd = Rp1_sd >> imm; }}, uint64_t); 0x2: c_andi({{ imm = CIMM5; if (CIMM1 > 0) imm |= ~((uint64_t)0x1F); }}, {{ Rp1 = Rp1 & imm; }}, uint64_t); } format ROp { 0x3: decode CFUNCT1 { 0x0: decode CFUNCT2LOW { 0x0: c_sub({{ Rp1 = Rp1 - Rp2; }}); 0x1: c_xor({{ Rp1 = Rp1 ^ Rp2; }}); 0x2: c_or({{ Rp1 = Rp1 | Rp2; }}); 0x3: c_and({{ Rp1 = Rp1 & Rp2; }}); } 0x1: decode CFUNCT2LOW { 0x0: c_subw({{ Rp1_sd = (int32_t)Rp1_sd - Rp2_sw; }}); 0x1: c_addw({{ Rp1_sd = (int32_t)Rp1_sd + Rp2_sw; }}); } } } } 0x5: JOp::c_j({{ int64_t offset = CJUMPIMM<3:1> << 1 | CJUMPIMM<9:9> << 4 | CJUMPIMM<0:0> << 5 | CJUMPIMM<5:5> << 6 | CJUMPIMM<4:4> << 7 | CJUMPIMM<8:7> << 8 | CJUMPIMM<6:6> << 10; if (CJUMPIMM<10:10> > 0) offset |= ~((int64_t)0x7FF); NPC = PC + offset; }}, IsIndirectControl, IsUncondControl, IsCall); format CBOp { 0x6: c_beqz({{ if (Rp1 == 0) NPC = PC + imm; else NPC = NPC; }}, IsDirectControl, IsCondControl); 0x7: c_bnez({{ if (Rp1 != 0) NPC = PC + imm; else NPC = NPC; }}, IsDirectControl, IsCondControl); } } 0x2: decode COPCODE { 0x0: CIOp::c_slli({{ imm = CIMM5 | (CIMM1 << 5); assert(imm != 0); }}, {{ assert(RC1 != 0); Rc1 = Rc1 << imm; }}, uint64_t); format CompressedLoad { 0x1: c_fldsp({{ offset = CIMM5<4:3> << 3 | CIMM1 << 5 | CIMM5<2:0> << 6; }}, {{ Fc1_bits = Mem; }}, {{ EA = sp + offset; }}); 0x2: c_lwsp({{ offset = CIMM5<4:2> << 2 | CIMM1 << 5 | CIMM5<1:0> << 6; }}, {{ assert(RC1 != 0); Rc1_sd = Mem_sw; }}, {{ EA = sp + offset; }}); 0x3: c_ldsp({{ offset = CIMM5<4:3> << 3 | CIMM1 << 5 | CIMM5<2:0> << 6; }}, {{ assert(RC1 != 0); Rc1_sd = Mem_sd; }}, {{ EA = sp + offset; }}); } 0x4: decode CFUNCT1 { 0x0: decode RC2 { 0x0: Jump::c_jr({{ assert(RC1 != 0); NPC = Rc1; }}, IsIndirectControl, IsUncondControl, IsCall); default: CROp::c_mv({{ assert(RC1 != 0); Rc1 = Rc2; }}); } 0x1: decode RC1 { 0x0: SystemOp::c_ebreak({{ assert(RC2 == 0); fault = make_shared(); }}, IsSerializeAfter, IsNonSpeculative, No_OpClass); default: decode RC2 { 0x0: Jump::c_jalr({{ assert(RC1 != 0); ra = NPC; NPC = Rc1; }}, IsIndirectControl, IsUncondControl, IsCall); default: ROp::c_add({{ Rc1_sd = Rc1_sd + Rc2_sd; }}); } } } format CompressedStore { 0x5: c_fsdsp({{ offset = CIMM6<5:3> << 3 | CIMM6<2:0> << 6; }}, {{ Mem_ud = Fc2_bits; }}, {{ EA = sp + offset; }}); 0x6: c_swsp({{ offset = CIMM6<5:2> << 2 | CIMM6<1:0> << 6; }}, {{ Mem_uw = Rc2_uw; }}, {{ EA = sp + offset; }}); 0x7: c_sdsp({{ offset = CIMM6<5:3> << 3 | CIMM6<2:0> << 6; }}, {{ Mem = Rc2; }}, {{ EA = sp + offset; }}); } } 0x3: decode OPCODE { 0x00: decode FUNCT3 { format Load { 0x0: lb({{ Rd_sd = Mem_sb; }}); 0x1: lh({{ Rd_sd = Mem_sh; }}); 0x2: lw({{ Rd_sd = Mem_sw; }}); 0x3: ld({{ Rd_sd = Mem_sd; }}); 0x4: lbu({{ Rd = Mem_ub; }}); 0x5: lhu({{ Rd = Mem_uh; }}); 0x6: lwu({{ Rd = Mem_uw; }}); } } 0x01: decode FUNCT3 { format Load { 0x2: flw({{ Fd_bits = (uint64_t)Mem_uw; }}, inst_flags=FloatMemReadOp); 0x3: fld({{ Fd_bits = Mem; }}, inst_flags=FloatMemReadOp); } } 0x03: decode FUNCT3 { format IOp { 0x0: fence({{ }}, uint64_t, IsNonSpeculative, IsMemBarrier, No_OpClass); 0x1: fence_i({{ }}, uint64_t, IsNonSpeculative, IsSerializeAfter, No_OpClass); } } 0x04: decode FUNCT3 { format IOp { 0x0: addi({{ Rd_sd = Rs1_sd + imm; }}); 0x1: slli({{ Rd = Rs1 << SHAMT6; }}); 0x2: slti({{ Rd = (Rs1_sd < imm) ? 1 : 0; }}); 0x3: sltiu({{ Rd = (Rs1 < imm) ? 1 : 0; }}, uint64_t); 0x4: xori({{ Rd = Rs1 ^ imm; }}, uint64_t); 0x5: decode SRTYPE { 0x0: srli({{ Rd = Rs1 >> SHAMT6; }}); 0x1: srai({{ Rd_sd = Rs1_sd >> SHAMT6; }}); } 0x6: ori({{ Rd = Rs1 | imm; }}, uint64_t); 0x7: andi({{ Rd = Rs1 & imm; }}, uint64_t); } } 0x05: UOp::auipc({{ Rd = PC + imm; }}); 0x06: decode FUNCT3 { format IOp { 0x0: addiw({{ Rd_sd = Rs1_sw + imm; }}, int32_t); 0x1: slliw({{ Rd_sd = Rs1_sw << SHAMT5; }}); 0x5: decode SRTYPE { 0x0: srliw({{ Rd = Rs1_uw >> SHAMT5; }}); 0x1: sraiw({{ Rd_sd = Rs1_sw >> SHAMT5; }}); } } } 0x08: decode FUNCT3 { format Store { 0x0: sb({{ Mem_ub = Rs2_ub; }}); 0x1: sh({{ Mem_uh = Rs2_uh; }}); 0x2: sw({{ Mem_uw = Rs2_uw; }}); 0x3: sd({{ Mem_ud = Rs2_ud; }}); } } 0x09: decode FUNCT3 { format Store { 0x2: fsw({{ Mem_uw = (uint32_t)Fs2_bits; }}, inst_flags=FloatMemWriteOp); 0x3: fsd({{ Mem_ud = Fs2_bits; }}, inst_flags=FloatMemWriteOp); } } 0x0b: decode FUNCT3 { 0x2: decode AMOFUNCT { 0x2: LoadReserved::lr_w({{ Rd_sd = Mem_sw; }}, mem_flags=LLSC); 0x3: StoreCond::sc_w({{ Mem_uw = Rs2_uw; }}, {{ Rd = result; }}, inst_flags=IsStoreConditional, mem_flags=LLSC); format AtomicMemOp { 0x0: amoadd_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = Rs2_sw + Rt_sd; Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x1: amoswap_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = Rs2_uw; Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x4: amoxor_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = Rs2_uw^Rt_sd; Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x8: amoor_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = Rs2_uw | Rt_sd; Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0xc: amoand_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = Rs2_uw&Rt_sd; Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x10: amomin_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = min(Rs2_sw, Rt_sd); Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x14: amomax_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = max(Rs2_sw, Rt_sd); Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x18: amominu_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = min(Rs2_uw, Rt_sd); Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x1c: amomaxu_w({{Rt_sd = Mem_sw;}}, {{ Mem_sw = max(Rs2_uw, Rt_sd); Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); } } 0x3: decode AMOFUNCT { 0x2: LoadReserved::lr_d({{ Rd_sd = Mem_sd; }}, mem_flags=LLSC); 0x3: StoreCond::sc_d({{ Mem = Rs2; }}, {{ Rd = result; }}, mem_flags=LLSC, inst_flags=IsStoreConditional); format AtomicMemOp { 0x0: amoadd_d({{Rt_sd = Mem_sd;}}, {{ Mem_sd = Rs2_sd + Rt_sd; Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x1: amoswap_d({{Rt = Mem;}}, {{ Mem = Rs2; Rd = Rt; }}, {{EA = Rs1;}}); 0x4: amoxor_d({{Rt = Mem;}}, {{ Mem = Rs2^Rt; Rd = Rt; }}, {{EA = Rs1;}}); 0x8: amoor_d({{Rt = Mem;}}, {{ Mem = Rs2 | Rt; Rd = Rt; }}, {{EA = Rs1;}}); 0xc: amoand_d({{Rt = Mem;}}, {{ Mem = Rs2&Rt; Rd = Rt; }}, {{EA = Rs1;}}); 0x10: amomin_d({{Rt_sd = Mem_sd;}}, {{ Mem_sd = min(Rs2_sd, Rt_sd); Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x14: amomax_d({{Rt_sd = Mem_sd;}}, {{ Mem_sd = max(Rs2_sd, Rt_sd); Rd_sd = Rt_sd; }}, {{EA = Rs1;}}); 0x18: amominu_d({{Rt = Mem;}}, {{ Mem = min(Rs2, Rt); Rd = Rt; }}, {{EA = Rs1;}}); 0x1c: amomaxu_d({{Rt = Mem;}}, {{ Mem = max(Rs2, Rt); Rd = Rt; }}, {{EA = Rs1;}}); } } } 0x0c: decode FUNCT3 { format ROp { 0x0: decode FUNCT7 { 0x0: add({{ Rd = Rs1_sd + Rs2_sd; }}); 0x1: mul({{ Rd = Rs1_sd*Rs2_sd; }}, IntMultOp); 0x20: sub({{ Rd = Rs1_sd - Rs2_sd; }}); } 0x1: decode FUNCT7 { 0x0: sll({{ Rd = Rs1 << Rs2<5:0>; }}); 0x1: mulh({{ bool negate = (Rs1_sd < 0) != (Rs2_sd < 0); uint64_t Rs1_lo = (uint32_t)abs(Rs1_sd); uint64_t Rs1_hi = (uint64_t)abs(Rs1_sd) >> 32; uint64_t Rs2_lo = (uint32_t)abs(Rs2_sd); uint64_t Rs2_hi = (uint64_t)abs(Rs2_sd) >> 32; uint64_t hi = Rs1_hi*Rs2_hi; uint64_t mid1 = Rs1_hi*Rs2_lo; uint64_t mid2 = Rs1_lo*Rs2_hi; uint64_t lo = Rs2_lo*Rs1_lo; uint64_t carry = ((uint64_t)(uint32_t)mid1 + (uint64_t)(uint32_t)mid2 + (lo >> 32)) >> 32; uint64_t res = hi + (mid1 >> 32) + (mid2 >> 32) + carry; Rd = negate ? ~res + (Rs1_sd*Rs2_sd == 0 ? 1 : 0) : res; }}, IntMultOp); } 0x2: decode FUNCT7 { 0x0: slt({{ Rd = (Rs1_sd < Rs2_sd) ? 1 : 0; }}); 0x1: mulhsu({{ bool negate = Rs1_sd < 0; uint64_t Rs1_lo = (uint32_t)abs(Rs1_sd); uint64_t Rs1_hi = (uint64_t)abs(Rs1_sd) >> 32; uint64_t Rs2_lo = (uint32_t)Rs2; uint64_t Rs2_hi = Rs2 >> 32; uint64_t hi = Rs1_hi*Rs2_hi; uint64_t mid1 = Rs1_hi*Rs2_lo; uint64_t mid2 = Rs1_lo*Rs2_hi; uint64_t lo = Rs1_lo*Rs2_lo; uint64_t carry = ((uint64_t)(uint32_t)mid1 + (uint64_t)(uint32_t)mid2 + (lo >> 32)) >> 32; uint64_t res = hi + (mid1 >> 32) + (mid2 >> 32) + carry; Rd = negate ? ~res + (Rs1_sd*Rs2 == 0 ? 1 : 0) : res; }}, IntMultOp); } 0x3: decode FUNCT7 { 0x0: sltu({{ Rd = (Rs1 < Rs2) ? 1 : 0; }}); 0x1: mulhu({{ uint64_t Rs1_lo = (uint32_t)Rs1; uint64_t Rs1_hi = Rs1 >> 32; uint64_t Rs2_lo = (uint32_t)Rs2; uint64_t Rs2_hi = Rs2 >> 32; uint64_t hi = Rs1_hi*Rs2_hi; uint64_t mid1 = Rs1_hi*Rs2_lo; uint64_t mid2 = Rs1_lo*Rs2_hi; uint64_t lo = Rs1_lo*Rs2_lo; uint64_t carry = ((uint64_t)(uint32_t)mid1 + (uint64_t)(uint32_t)mid2 + (lo >> 32)) >> 32; Rd = hi + (mid1 >> 32) + (mid2 >> 32) + carry; }}, IntMultOp); } 0x4: decode FUNCT7 { 0x0: xor({{ Rd = Rs1 ^ Rs2; }}); 0x1: div({{ if (Rs2_sd == 0) { Rd_sd = -1; } else if (Rs1_sd == numeric_limits::min() && Rs2_sd == -1) { Rd_sd = numeric_limits::min(); } else { Rd_sd = Rs1_sd/Rs2_sd; } }}, IntDivOp); } 0x5: decode FUNCT7 { 0x0: srl({{ Rd = Rs1 >> Rs2<5:0>; }}); 0x1: divu({{ if (Rs2 == 0) { Rd = numeric_limits::max(); } else { Rd = Rs1/Rs2; } }}, IntDivOp); 0x20: sra({{ Rd_sd = Rs1_sd >> Rs2<5:0>; }}); } 0x6: decode FUNCT7 { 0x0: or({{ Rd = Rs1 | Rs2; }}); 0x1: rem({{ if (Rs2_sd == 0) { Rd = Rs1_sd; } else if (Rs1_sd == numeric_limits::min() && Rs2_sd == -1) { Rd = 0; } else { Rd = Rs1_sd%Rs2_sd; } }}, IntDivOp); } 0x7: decode FUNCT7 { 0x0: and({{ Rd = Rs1 & Rs2; }}); 0x1: remu({{ if (Rs2 == 0) { Rd = Rs1; } else { Rd = Rs1%Rs2; } }}, IntDivOp); } } } 0x0d: UOp::lui({{ Rd = (uint64_t)imm; }}); 0x0e: decode FUNCT3 { format ROp { 0x0: decode FUNCT7 { 0x0: addw({{ Rd_sd = Rs1_sw + Rs2_sw; }}); 0x1: mulw({{ Rd_sd = (int32_t)(Rs1_sw*Rs2_sw); }}, IntMultOp); 0x20: subw({{ Rd_sd = Rs1_sw - Rs2_sw; }}); } 0x1: sllw({{ Rd_sd = Rs1_sw << Rs2<4:0>; }}); 0x4: divw({{ if (Rs2_sw == 0) { Rd_sd = -1; } else if (Rs1_sw == numeric_limits::min() && Rs2_sw == -1) { Rd_sd = numeric_limits::min(); } else { Rd_sd = Rs1_sw/Rs2_sw; } }}, IntDivOp); 0x5: decode FUNCT7 { 0x0: srlw({{ Rd_uw = Rs1_uw >> Rs2<4:0>; }}); 0x1: divuw({{ if (Rs2_uw == 0) { Rd_sd = numeric_limits::max(); } else { Rd_sd = (int32_t)(Rs1_uw/Rs2_uw); } }}, IntDivOp); 0x20: sraw({{ Rd_sd = Rs1_sw >> Rs2<4:0>; }}); } 0x6: remw({{ if (Rs2_sw == 0) { Rd_sd = Rs1_sw; } else if (Rs1_sw == numeric_limits::min() && Rs2_sw == -1) { Rd_sd = 0; } else { Rd_sd = Rs1_sw%Rs2_sw; } }}, IntDivOp); 0x7: remuw({{ if (Rs2_uw == 0) { Rd_sd = (int32_t)Rs1_uw; } else { Rd_sd = (int32_t)(Rs1_uw%Rs2_uw); } }}, IntDivOp); } } format FPROp { 0x10: decode FUNCT2 { 0x0: fmadd_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fs3 = reinterpret_cast(temp = Fs3_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) { if (issignalingnan(fs1) || issignalingnan(fs2) || issignalingnan(fs3)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else if (std::isinf(fs1) || std::isinf(fs2) || std::isinf(fs3)) { if (signbit(fs1) == signbit(fs2) && !std::isinf(fs3)) { fd = numeric_limits::infinity(); } else if (signbit(fs1) != signbit(fs2) && !std::isinf(fs3)) { fd = -numeric_limits::infinity(); } else { // Fs3_sf is infinity fd = fs3; } } else { fd = fs1*fs2 + fs3; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMultAccOp); 0x1: fmadd_d({{ if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) { if (issignalingnan(Fs1) || issignalingnan(Fs2) || issignalingnan(Fs3)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else if (std::isinf(Fs1) || std::isinf(Fs2) || std::isinf(Fs3)) { if (signbit(Fs1) == signbit(Fs2) && !std::isinf(Fs3)) { Fd = numeric_limits::infinity(); } else if (signbit(Fs1) != signbit(Fs2) && !std::isinf(Fs3)) { Fd = -numeric_limits::infinity(); } else { Fd = Fs3; } } else { Fd = Fs1*Fs2 + Fs3; } }}, FloatMultAccOp); } 0x11: decode FUNCT2 { 0x0: fmsub_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fs3 = reinterpret_cast(temp = Fs3_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) { if (issignalingnan(fs1) || issignalingnan(fs2) || issignalingnan(fs3)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else if (std::isinf(fs1) || std::isinf(fs2) || std::isinf(fs3)) { if (signbit(fs1) == signbit(fs2) && !std::isinf(fs3)) { fd = numeric_limits::infinity(); } else if (signbit(fs1) != signbit(fs2) && !std::isinf(fs3)) { fd = -numeric_limits::infinity(); } else { // Fs3_sf is infinity fd = -fs3; } } else { fd = fs1*fs2 - fs3; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMultAccOp); 0x1: fmsub_d({{ if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) { if (issignalingnan(Fs1) || issignalingnan(Fs2) || issignalingnan(Fs3)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else if (std::isinf(Fs1) || std::isinf(Fs2) || std::isinf(Fs3)) { if (signbit(Fs1) == signbit(Fs2) && !std::isinf(Fs3)) { Fd = numeric_limits::infinity(); } else if (signbit(Fs1) != signbit(Fs2) && !std::isinf(Fs3)) { Fd = -numeric_limits::infinity(); } else { Fd = -Fs3; } } else { Fd = Fs1*Fs2 - Fs3; } }}, FloatMultAccOp); } 0x12: decode FUNCT2 { 0x0: fnmsub_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fs3 = reinterpret_cast(temp = Fs3_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) { if (issignalingnan(fs1) || issignalingnan(fs2) || issignalingnan(fs3)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else if (std::isinf(fs1) || std::isinf(fs2) || std::isinf(fs3)) { if (signbit(fs1) == signbit(fs2) && !std::isinf(fs3)) { fd = -numeric_limits::infinity(); } else if (signbit(fs1) != signbit(fs2) && !std::isinf(fs3)) { fd = numeric_limits::infinity(); } else { // Fs3_sf is infinity fd = fs3; } } else { fd = -(fs1*fs2 - fs3); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMultAccOp); 0x1: fnmsub_d({{ if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) { if (issignalingnan(Fs1) || issignalingnan(Fs2) || issignalingnan(Fs3)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else if (std::isinf(Fs1) || std::isinf(Fs2) || std::isinf(Fs3)) { if (signbit(Fs1) == signbit(Fs2) && !std::isinf(Fs3)) { Fd = -numeric_limits::infinity(); } else if (signbit(Fs1) != signbit(Fs2) && !std::isinf(Fs3)) { Fd = numeric_limits::infinity(); } else { Fd = Fs3; } } else { Fd = -(Fs1*Fs2 - Fs3); } }}, FloatMultAccOp); } 0x13: decode FUNCT2 { 0x0: fnmadd_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fs3 = reinterpret_cast(temp = Fs3_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) { if (issignalingnan(fs1) || issignalingnan(fs2) || issignalingnan(fs3)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else if (std::isinf(fs1) || std::isinf(fs2) || std::isinf(fs3)) { if (signbit(fs1) == signbit(fs2) && !std::isinf(fs3)) { fd = -numeric_limits::infinity(); } else if (signbit(fs1) != signbit(fs2) && !std::isinf(fs3)) { fd = numeric_limits::infinity(); } else { // Fs3_sf is infinity fd = -fs3; } } else { fd = -(fs1*fs2 + fs3); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMultAccOp); 0x1: fnmadd_d({{ if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) { if (issignalingnan(Fs1) || issignalingnan(Fs2) || issignalingnan(Fs3)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else if (std::isinf(Fs1) || std::isinf(Fs2) || std::isinf(Fs3)) { if (signbit(Fs1) == signbit(Fs2) && !std::isinf(Fs3)) { Fd = -numeric_limits::infinity(); } else if (signbit(Fs1) != signbit(Fs2) && !std::isinf(Fs3)) { Fd = numeric_limits::infinity(); } else { Fd = -Fs3; } } else { Fd = -(Fs1*Fs2 + Fs3); } }}, FloatMultAccOp); } 0x14: decode FUNCT7 { 0x0: fadd_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2)) { if (issignalingnan(fs1) || issignalingnan(fs2)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else { fd = fs1 + fs2; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatAddOp); 0x1: fadd_d({{ if (std::isnan(Fs1) || std::isnan(Fs2)) { if (issignalingnan(Fs1) || issignalingnan(Fs2)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else { Fd = Fs1 + Fs2; } }}, FloatAddOp); 0x4: fsub_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2)) { if (issignalingnan(fs1) || issignalingnan(fs2)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else { fd = fs1 - fs2; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatAddOp); 0x5: fsub_d({{ if (std::isnan(Fs1) || std::isnan(Fs2)) { if (issignalingnan(Fs1) || issignalingnan(Fs2)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else { Fd = Fs1 - Fs2; } }}, FloatAddOp); 0x8: fmul_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2)) { if (issignalingnan(fs1) || issignalingnan(fs2)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else { fd = fs1*fs2; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMultOp); 0x9: fmul_d({{ if (std::isnan(Fs1) || std::isnan(Fs2)) { if (issignalingnan(Fs1) || issignalingnan(Fs2)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else { Fd = Fs1*Fs2; } }}, FloatMultOp); 0xc: fdiv_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (std::isnan(fs1) || std::isnan(fs2)) { if (issignalingnan(fs1) || issignalingnan(fs2)) { FFLAGS |= FloatInvalid; } fd = numeric_limits::quiet_NaN(); } else { fd = fs1/fs2; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatDivOp); 0xd: fdiv_d({{ if (std::isnan(Fs1) || std::isnan(Fs2)) { if (issignalingnan(Fs1) || issignalingnan(Fs2)) { FFLAGS |= FloatInvalid; } Fd = numeric_limits::quiet_NaN(); } else { Fd = Fs1/Fs2; } }}, FloatDivOp); 0x10: decode ROUND_MODE { 0x0: fsgnj_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (issignalingnan(fs1)) { fd = numeric_limits::signaling_NaN(); feclearexcept(FE_INVALID); } else { fd = copysign(fs1, fs2); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMiscOp); 0x1: fsgnjn_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (issignalingnan(fs1)) { fd = numeric_limits::signaling_NaN(); feclearexcept(FE_INVALID); } else { fd = copysign(fs1, -fs2); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMiscOp); 0x2: fsgnjx_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (issignalingnan(fs1)) { fd = numeric_limits::signaling_NaN(); feclearexcept(FE_INVALID); } else { fd = fs1*(signbit(fs2) ? -1.0 : 1.0); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatMiscOp); } 0x11: decode ROUND_MODE { 0x0: fsgnj_d({{ if (issignalingnan(Fs1)) { Fd = numeric_limits::signaling_NaN(); feclearexcept(FE_INVALID); } else { Fd = copysign(Fs1, Fs2); } }}, FloatMiscOp); 0x1: fsgnjn_d({{ if (issignalingnan(Fs1)) { Fd = numeric_limits::signaling_NaN(); feclearexcept(FE_INVALID); } else { Fd = copysign(Fs1, -Fs2); } }}, FloatMiscOp); 0x2: fsgnjx_d({{ if (issignalingnan(Fs1)) { Fd = numeric_limits::signaling_NaN(); feclearexcept(FE_INVALID); } else { Fd = Fs1*(signbit(Fs2) ? -1.0 : 1.0); } }}, FloatMiscOp); } 0x14: decode ROUND_MODE { 0x0: fmin_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (issignalingnan(fs2)) { fd = fs1; FFLAGS |= FloatInvalid; } else if (issignalingnan(fs1)) { fd = fs2; FFLAGS |= FloatInvalid; } else { fd = fmin(fs1, fs2); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatCmpOp); 0x1: fmax_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); float fd; if (issignalingnan(fs2)) { fd = fs1; FFLAGS |= FloatInvalid; } else if (issignalingnan(fs1)) { fd = fs2; FFLAGS |= FloatInvalid; } else { fd = fmax(fs1, fs2); } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatCmpOp); } 0x15: decode ROUND_MODE { 0x0: fmin_d({{ if (issignalingnan(Fs2)) { Fd = Fs1; FFLAGS |= FloatInvalid; } else if (issignalingnan(Fs1)) { Fd = Fs2; FFLAGS |= FloatInvalid; } else { Fd = fmin(Fs1, Fs2); } }}, FloatCmpOp); 0x1: fmax_d({{ if (issignalingnan(Fs2)) { Fd = Fs1; FFLAGS |= FloatInvalid; } else if (issignalingnan(Fs1)) { Fd = Fs2; FFLAGS |= FloatInvalid; } else { Fd = fmax(Fs1, Fs2); } }}, FloatCmpOp); } 0x20: fcvt_s_d({{ assert(CONV_SGN == 1); float fd; if (issignalingnan(Fs1)) { fd = numeric_limits::quiet_NaN(); FFLAGS |= FloatInvalid; } else { fd = (float)Fs1; } Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatCvtOp); 0x21: fcvt_d_s({{ assert(CONV_SGN == 0); uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); if (issignalingnan(fs1)) { Fd = numeric_limits::quiet_NaN(); FFLAGS |= FloatInvalid; } else { Fd = (double)fs1; } }}, FloatCvtOp); 0x2c: fsqrt_s({{ assert(RS2 == 0); uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fd; if (issignalingnan(Fs1_sf)) { FFLAGS |= FloatInvalid; } fd = sqrt(fs1); Fd_bits = (uint64_t)reinterpret_cast(fd); }}, FloatSqrtOp); 0x2d: fsqrt_d({{ assert(RS2 == 0); Fd = sqrt(Fs1); }}, FloatSqrtOp); 0x50: decode ROUND_MODE { 0x0: fle_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); if (std::isnan(fs1) || std::isnan(fs2)) { FFLAGS |= FloatInvalid; Rd = 0; } else { Rd = fs1 <= fs2 ? 1 : 0; } }}, FloatCmpOp); 0x1: flt_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); if (std::isnan(fs1) || std::isnan(fs2)) { FFLAGS |= FloatInvalid; Rd = 0; } else { Rd = fs1 < fs2 ? 1 : 0; } }}, FloatCmpOp); 0x2: feq_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); float fs2 = reinterpret_cast(temp = Fs2_bits); if (issignalingnan(fs1) || issignalingnan(fs2)) { FFLAGS |= FloatInvalid; } Rd = fs1 == fs2 ? 1 : 0; }}, FloatCmpOp); } 0x51: decode ROUND_MODE { 0x0: fle_d({{ if (std::isnan(Fs1) || std::isnan(Fs2)) { FFLAGS |= FloatInvalid; Rd = 0; } else { Rd = Fs1 <= Fs2 ? 1 : 0; } }}, FloatCmpOp); 0x1: flt_d({{ if (std::isnan(Fs1) || std::isnan(Fs2)) { FFLAGS |= FloatInvalid; Rd = 0; } else { Rd = Fs1 < Fs2 ? 1 : 0; } }}, FloatCmpOp); 0x2: feq_d({{ if (issignalingnan(Fs1) || issignalingnan(Fs2)) { FFLAGS |= FloatInvalid; } Rd = Fs1 == Fs2 ? 1 : 0; }}, FloatCmpOp); } 0x60: decode CONV_SGN { 0x0: fcvt_w_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); if (std::isnan(fs1)) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (fs1 >= numeric_limits::max()) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (fs1 <= numeric_limits::min()) { Rd_sd = numeric_limits::min(); FFLAGS |= FloatInvalid; } else { Rd_sd = (int32_t)fs1; } }}, FloatCvtOp); 0x1: fcvt_wu_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); if (std::isnan(fs1)) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (fs1 < 0.0) { Rd = 0; FFLAGS |= FloatInvalid; } else if (fs1 > numeric_limits::max()) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else { Rd = (uint32_t)fs1; } }}, FloatCvtOp); 0x2: fcvt_l_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); if (std::isnan(fs1)) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (fs1 > numeric_limits::max()) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (fs1 < numeric_limits::min()) { Rd_sd = numeric_limits::min(); FFLAGS |= FloatInvalid; } else { Rd_sd = (int64_t)fs1; } }}, FloatCvtOp); 0x3: fcvt_lu_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); if (std::isnan(fs1)) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (fs1 < 0.0) { Rd = 0; FFLAGS |= FloatInvalid; } else if (fs1 > numeric_limits::max()) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else { Rd = (uint64_t)fs1; } }}, FloatCvtOp); } 0x61: decode CONV_SGN { 0x0: fcvt_w_d({{ if (std::isnan(Fs1)) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (Fs1 > numeric_limits::max()) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (Fs1 < numeric_limits::min()) { Rd_sd = numeric_limits::min(); FFLAGS |= FloatInvalid; } else { Rd_sd = (int32_t)Fs1; } }}, FloatCvtOp); 0x1: fcvt_wu_d({{ if (std::isnan(Fs1)) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (Fs1 < 0) { Rd = 0; FFLAGS |= FloatInvalid; } else if (Fs1 > numeric_limits::max()) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else { Rd = (uint32_t)Fs1; } }}, FloatCvtOp); 0x2: fcvt_l_d({{ if (std::isnan(Fs1)) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (Fs1 > numeric_limits::max()) { Rd_sd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (Fs1 < numeric_limits::min()) { Rd_sd = numeric_limits::min(); FFLAGS |= FloatInvalid; } else { Rd_sd = Fs1; } }}, FloatCvtOp); 0x3: fcvt_lu_d({{ if (std::isnan(Fs1)) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else if (Fs1 < 0) { Rd = 0; FFLAGS |= FloatInvalid; } else if (Fs1 > numeric_limits::max()) { Rd = numeric_limits::max(); FFLAGS |= FloatInvalid; } else { Rd = Fs1; } }}, FloatCvtOp); } 0x68: decode CONV_SGN { 0x0: fcvt_s_w({{ float temp = (float)Rs1_sw; Fd_bits = (uint64_t)reinterpret_cast(temp); }}, FloatCvtOp); 0x1: fcvt_s_wu({{ float temp = (float)Rs1_uw; Fd_bits = (uint64_t)reinterpret_cast(temp); }}, FloatCvtOp); 0x2: fcvt_s_l({{ float temp = (float)Rs1_sd; Fd_bits = (uint64_t)reinterpret_cast(temp); }}, FloatCvtOp); 0x3: fcvt_s_lu({{ float temp = (float)Rs1; Fd_bits = (uint64_t)reinterpret_cast(temp); }}, FloatCvtOp); } 0x69: decode CONV_SGN { 0x0: fcvt_d_w({{ Fd = (double)Rs1_sw; }}, FloatCvtOp); 0x1: fcvt_d_wu({{ Fd = (double)Rs1_uw; }}, FloatCvtOp); 0x2: fcvt_d_l({{ Fd = (double)Rs1_sd; }}, FloatCvtOp); 0x3: fcvt_d_lu({{ Fd = (double)Rs1; }}, FloatCvtOp); } 0x70: decode ROUND_MODE { 0x0: fmv_x_s({{ Rd = (uint32_t)Fs1_bits; if ((Rd&0x80000000) != 0) { Rd |= (0xFFFFFFFFULL << 32); } }}, FloatCvtOp); 0x1: fclass_s({{ uint32_t temp; float fs1 = reinterpret_cast(temp = Fs1_bits); switch (fpclassify(fs1)) { case FP_INFINITE: if (signbit(fs1)) { Rd = 1 << 0; } else { Rd = 1 << 7; } break; case FP_NAN: if (issignalingnan(fs1)) { Rd = 1 << 8; } else { Rd = 1 << 9; } break; case FP_ZERO: if (signbit(fs1)) { Rd = 1 << 3; } else { Rd = 1 << 4; } break; case FP_SUBNORMAL: if (signbit(fs1)) { Rd = 1 << 2; } else { Rd = 1 << 5; } break; case FP_NORMAL: if (signbit(fs1)) { Rd = 1 << 1; } else { Rd = 1 << 6; } break; default: panic("Unknown classification for operand."); break; } }}, FloatMiscOp); } 0x71: decode ROUND_MODE { 0x0: fmv_x_d({{ Rd = Fs1_bits; }}, FloatCvtOp); 0x1: fclass_d({{ switch (fpclassify(Fs1)) { case FP_INFINITE: if (signbit(Fs1)) { Rd = 1 << 0; } else { Rd = 1 << 7; } break; case FP_NAN: if (issignalingnan(Fs1)) { Rd = 1 << 8; } else { Rd = 1 << 9; } break; case FP_ZERO: if (signbit(Fs1)) { Rd = 1 << 3; } else { Rd = 1 << 4; } break; case FP_SUBNORMAL: if (signbit(Fs1)) { Rd = 1 << 2; } else { Rd = 1 << 5; } break; case FP_NORMAL: if (signbit(Fs1)) { Rd = 1 << 1; } else { Rd = 1 << 6; } break; default: panic("Unknown classification for operand."); break; } }}, FloatMiscOp); } 0x78: fmv_s_x({{ Fd_bits = (uint64_t)Rs1_uw; }}, FloatCvtOp); 0x79: fmv_d_x({{ Fd_bits = Rs1; }}, FloatCvtOp); } } 0x18: decode FUNCT3 { format BOp { 0x0: beq({{ if (Rs1 == Rs2) { NPC = PC + imm; } else { NPC = NPC; } }}, IsDirectControl, IsCondControl); 0x1: bne({{ if (Rs1 != Rs2) { NPC = PC + imm; } else { NPC = NPC; } }}, IsDirectControl, IsCondControl); 0x4: blt({{ if (Rs1_sd < Rs2_sd) { NPC = PC + imm; } else { NPC = NPC; } }}, IsDirectControl, IsCondControl); 0x5: bge({{ if (Rs1_sd >= Rs2_sd) { NPC = PC + imm; } else { NPC = NPC; } }}, IsDirectControl, IsCondControl); 0x6: bltu({{ if (Rs1 < Rs2) { NPC = PC + imm; } else { NPC = NPC; } }}, IsDirectControl, IsCondControl); 0x7: bgeu({{ if (Rs1 >= Rs2) { NPC = PC + imm; } else { NPC = NPC; } }}, IsDirectControl, IsCondControl); } } 0x19: decode FUNCT3 { 0x0: Jump::jalr({{ Rd = NPC; NPC = (imm + Rs1) & (~0x1); }}, IsIndirectControl, IsUncondControl, IsCall); } 0x1b: JOp::jal({{ Rd = NPC; NPC = PC + imm; }}, IsDirectControl, IsUncondControl, IsCall); 0x1c: decode FUNCT3 { format SystemOp { 0x0: decode FUNCT12 { 0x0: ecall({{ fault = make_shared(); }}, IsSerializeAfter, IsNonSpeculative, IsSyscall, No_OpClass); 0x1: ebreak({{ fault = make_shared(); }}, IsSerializeAfter, IsNonSpeculative, No_OpClass); 0x100: eret({{ fault = make_shared("eret"); }}, No_OpClass); } } format CSROp { 0x1: csrrw({{ Rd = xc->readMiscReg(csr); xc->setMiscReg(csr, Rs1); }}, IsNonSpeculative, No_OpClass); 0x2: csrrs({{ Rd = xc->readMiscReg(csr); if (Rs1 != 0) { xc->setMiscReg(csr, Rd | Rs1); } }}, IsNonSpeculative, No_OpClass); 0x3: csrrc({{ Rd = xc->readMiscReg(csr); if (Rs1 != 0) { xc->setMiscReg(csr, Rd & ~Rs1); } }}, IsNonSpeculative, No_OpClass); 0x5: csrrwi({{ Rd = xc->readMiscReg(csr); xc->setMiscReg(csr, uimm); }}, IsNonSpeculative, No_OpClass); 0x6: csrrsi({{ Rd = xc->readMiscReg(csr); if (uimm != 0) { xc->setMiscReg(csr, Rd | uimm); } }}, IsNonSpeculative, No_OpClass); 0x7: csrrci({{ Rd = xc->readMiscReg(csr); if (uimm != 0) { xc->setMiscReg(csr, Rd & ~uimm); } }}, IsNonSpeculative, No_OpClass); } } } }