diff --git a/test/sim/rvcpp/rv.cpp b/test/sim/rvcpp/rv.cpp index fda9ffa..2b8cb9a 100644 --- a/test/sim/rvcpp/rv.cpp +++ b/test/sim/rvcpp/rv.cpp @@ -269,7 +269,7 @@ public: case CSR_MTVEC: mtvec = data & 0xfffffffdu; break; case CSR_MSCRATCH: mscratch = data; break; case CSR_MEPC: mepc = data & 0xfffffffeu; break; - case CSR_MCAUSE: mcause = data & 0x800000ffu; break; + case CSR_MCAUSE: mcause = data & 0x8000000fu; break; case CSR_MTVAL: break; case CSR_MCYCLE: mcycle = data; break; @@ -383,16 +383,7 @@ struct RVCore { rd_wdata = rs1 & rs2; else exception_cause = XCAUSE_INSTR_ILLEGAL; - } - else if (funct7 == 0b01'00000) { - if (funct3 == 0b000) - rd_wdata = rs1 - rs2; - else if (funct3 == 0b101) - rd_wdata = (sx_t)rs1 >> (rs2 & 0x1f); - else - exception_cause = XCAUSE_INSTR_ILLEGAL; - } - else if (funct7 == 0b00'00001) { + } else if (funct7 == 0b00'00001) { if (funct3 < 0b100) { sdx_t mul_op_a = rs1; sdx_t mul_op_b = rs2; @@ -430,8 +421,66 @@ struct RVCore { rd_wdata = rs2 ? rs1 % rs2 : rs1; } } - } - else { + } else if (funct7 == 0b01'00000) { + if (funct3 == 0b000) + rd_wdata = rs1 - rs2; + else if (funct3 == 0b100) + rd_wdata = rs1 ^ ~rs2; // Zbb xnor + else if (funct3 == 0b101) + rd_wdata = (sx_t)rs1 >> (rs2 & 0x1f); + else if (funct3 == 0b110) + rd_wdata = rs1 | ~rs2; // Zbb orn + else if (funct3 == 0b111) + rd_wdata = rs1 & ~rs2; // Zbb andn + else + exception_cause = XCAUSE_INSTR_ILLEGAL; + } else if (RVOPC_MATCH(instr, BCLR)) { + rd_wdata = rs1 & ~(1u << (rs2 & 0x1f)); + } else if (RVOPC_MATCH(instr, BEXT)) { + rd_wdata = (rs1 >> (rs2 & 0x1f)) & 0x1u; + } else if (RVOPC_MATCH(instr, BINV)) { + rd_wdata = rs1 ^ (1u << (rs2 & 0x1f)); + } else if (RVOPC_MATCH(instr, BSET)) { + rd_wdata = rs1 | (1u << (rs2 & 0x1f)); + } else if (RVOPC_MATCH(instr, SH1ADD)) { + rd_wdata = (rs1 << 1) + rs2; + } else if (RVOPC_MATCH(instr, SH2ADD)) { + rd_wdata = (rs1 << 2) + rs2; + } else if (RVOPC_MATCH(instr, SH3ADD)) { + rd_wdata = (rs1 << 3) + rs2; + } else if (RVOPC_MATCH(instr, MAX)) { + rd_wdata = (sx_t)rs1 > (sx_t)rs2 ? rs1 : rs2; + } else if (RVOPC_MATCH(instr, MAXU)) { + rd_wdata = rs1 > rs2 ? rs1 : rs2; + } else if (RVOPC_MATCH(instr, MIN)) { + rd_wdata = (sx_t)rs1 < (sx_t)rs2 ? rs1 : rs2; + } else if (RVOPC_MATCH(instr, MINU)) { + rd_wdata = rs1 < rs2 ? rs1 : rs2; + } else if (RVOPC_MATCH(instr, ROR)) { + uint shamt = rs2 & 0x1f; + rd_wdata = shamt ? (rs1 >> shamt) | (rs1 << (32 - shamt)) : rs1; + } else if (RVOPC_MATCH(instr, ROL)) { + uint shamt = rs2 & 0x1f; + rd_wdata = shamt ? (rs1 << shamt) | (rs1 >> (32 - shamt)) : rs1; + } else if (RVOPC_MATCH(instr, PACK)) { + rd_wdata = (rs1 & 0xffffu) | (rs2 << 16); + } else if (RVOPC_MATCH(instr, PACKH)) { + rd_wdata = (rs1 & 0xffu) | ((rs2 & 0xffu) << 8); + } else if (RVOPC_MATCH(instr, CLMUL) || RVOPC_MATCH(instr, CLMULH) || RVOPC_MATCH(instr, CLMULR)) { + uint64_t product = 0; + for (int i = 0; i < 32; ++i) { + if (rs2 & (1u << i)) { + product ^= (uint64_t)rs1 << i; + } + } + if (RVOPC_MATCH(instr, CLMUL)) { + rd_wdata = product; + } else if (RVOPC_MATCH(instr, CLMULH)) { + rd_wdata = product >> 32; + } else { + rd_wdata = product >> 31; + } + } else { exception_cause = XCAUSE_INSTR_ILLEGAL; } break; @@ -455,14 +504,61 @@ struct RVCore { // shamt is regnum_rs2 if (funct7 == 0b00'00000 && funct3 == 0b001) { rd_wdata = rs1 << regnum_rs2; - } - else if (funct7 == 0b00'00000 && funct3 == 0b101) { + } else if (funct7 == 0b00'00000 && funct3 == 0b101) { rd_wdata = rs1 >> regnum_rs2; - } - else if (funct7 == 0b01'00000 && funct3 == 0b101) { + } else if (funct7 == 0b01'00000 && funct3 == 0b101) { rd_wdata = (sx_t)rs1 >> regnum_rs2; - } - else { + } else if (RVOPC_MATCH(instr, BCLRI)) { + rd_wdata = rs1 & ~(1u << regnum_rs2); + } else if (RVOPC_MATCH(instr, BINVI)) { + rd_wdata = rs1 ^ (1u << regnum_rs2); + } else if (RVOPC_MATCH(instr, BSETI)) { + rd_wdata = rs1 | (1u << regnum_rs2); + } else if (RVOPC_MATCH(instr, CLZ)) { + rd_wdata = rs1 ? __builtin_clz(rs1) : 32; + } else if (RVOPC_MATCH(instr, CPOP)) { + rd_wdata = __builtin_popcount(rs1); + } else if (RVOPC_MATCH(instr, CTZ)) { + rd_wdata = rs1 ? __builtin_ctz(rs1) : 32; + } else if (RVOPC_MATCH(instr, SEXT_B)) { + rd_wdata = (rs1 & 0xffu) - ((rs1 & 0x80u) << 1); + } else if (RVOPC_MATCH(instr, SEXT_H)) { + rd_wdata = (rs1 & 0xffffu) - ((rs1 & 0x8000u) << 1); + } else if (RVOPC_MATCH(instr, ZIP)) { + ux_t accum = 0; + for (int i = 0; i < 32; ++i) { + if (rs1 & (1u << i)) { + accum |= 1u << ((i >> 4) | ((i & 0xf) << 1)); + } + } + rd_wdata = accum; + } else if (RVOPC_MATCH(instr, UNZIP)) { + ux_t accum = 0; + for (int i = 0; i < 32; ++i) { + if (rs1 & (1u << i)) { + accum |= 1u << ((i >> 1) | ((i & 1) << 4)); + } + } + rd_wdata = accum; + } else if (RVOPC_MATCH(instr, BEXTI)) { + rd_wdata = (rs1 >> regnum_rs2) & 0x1u; + } else if (RVOPC_MATCH(instr, BREV8)) { + rd_wdata = + ((rs1 & 0x80808080u) >> 7) | ((rs1 & 0x01010101u) << 7) | + ((rs1 & 0x40404040u) >> 5) | ((rs1 & 0x02020202u) << 5) | + ((rs1 & 0x20202020u) >> 3) | ((rs1 & 0x04040404u) << 3) | + ((rs1 & 0x10101010u) >> 1) | ((rs1 & 0x08080808u) << 1); + } else if (RVOPC_MATCH(instr, ORC_B)) { + rd_wdata = + (rs1 & 0xff000000u ? 0xff000000u : 0u) | + (rs1 & 0x00ff0000u ? 0x00ff0000u : 0u) | + (rs1 & 0x0000ff00u ? 0x0000ff00u : 0u) | + (rs1 & 0x000000ffu ? 0x000000ffu : 0u); + } else if (RVOPC_MATCH(instr, REV8)) { + rd_wdata = __builtin_bswap32(rs1); + } else if (RVOPC_MATCH(instr, RORI)) { + rd_wdata = regnum_rs2 ? ((rs1 << (32 - regnum_rs2)) | (rs1 >> regnum_rs2)) : rs1; + } else { exception_cause = XCAUSE_INSTR_ILLEGAL; } }