Adds opcodes for "unimp" and "c.unimp" unimplemented instructions. These instructions will still generate invalid instruction exceptions, but will not create log messages, as these are considered intentional unimplemented instructions. Also fixes an issue w.r.t. clearing and seeing status of breakpoints on control-flow, interrupts, and exceptions for mpact-cheriot. PiperOrigin-RevId: 720727822 Change-Id: I705274e42a1c7ba929a92776c38e00bc29f5ce18
diff --git a/riscv/riscv32g.bin_fmt b/riscv/riscv32g.bin_fmt index 3d984b8..8f8c6ff 100644 --- a/riscv/riscv32g.bin_fmt +++ b/riscv/riscv32g.bin_fmt
@@ -267,6 +267,7 @@ csrrwi_nr: IType : func3 == 0b101, rd == 0, opcode == 0b111'0011; csrrsi_nw: IType : func3 == 0b110, rs1 == 0, opcode == 0b111'0011; csrrci_nw: IType : func3 == 0b111, rs1 == 0, opcode == 0b111'0011; + unimp : IType : func3 == 0b001, rs1 == 0, rd == 0, opcode == 0b111'0011; // RiscV32 Privileged instructions. uret : Inst32Format : bits == 0b000'0000'00010'00000'000'00000, opcode == 0b111'0011; sret : Inst32Format : bits == 0b000'1000'00010'00000'000'00000, opcode == 0b111'0011; @@ -440,4 +441,5 @@ cfsdsp : CSS: func3 == 0b101, op == 0b10; cswsp : CSS: func3 == 0b110, op == 0b10; cfswsp : CSS: func3 == 0b111, op == 0b10; + cunimp : Inst16Format : func3 == 0b000, bits == 0b000'0000'0000, op == 0b00; };
diff --git a/riscv/riscv32g.isa b/riscv/riscv32g.isa index a1f9fee..31e1537 100644 --- a/riscv/riscv32g.isa +++ b/riscv/riscv32g.isa
@@ -212,6 +212,9 @@ ebreak{}, disasm: "ebreak", semfunc: "&RiscVIEbreak"; + unimp{}, + disasm: "unimp", + semfunc: "&RiscVIUnimplemented"; } } @@ -850,6 +853,10 @@ disasm: "ebreak", resources: {next_pc}, semfunc: "&RiscVIEbreak"; + cunimp{}, + disasm: "unimp", + resources: {next_pc}, + semfunc: "&RiscVIUnimplemented"; } }
diff --git a/riscv/riscv64g.bin_fmt b/riscv/riscv64g.bin_fmt index 57054f3..3c98c51 100644 --- a/riscv/riscv64g.bin_fmt +++ b/riscv/riscv64g.bin_fmt
@@ -330,6 +330,7 @@ csrrwi_nr: IType : func3 == 0b101, rd == 0, opcode == 0b111'0011; csrrsi_nw: IType : func3 == 0b110, rs1 == 0, opcode == 0b111'0011; csrrci_nw: IType : func3 == 0b111, rs1 == 0, opcode == 0b111'0011; + unimp : IType : func3 == 0b001, rd == 0, rs1 == 0, opcode == 0b111'0011; // RiscV32 Privileged instructions. uret : Inst32Format : bits == 0b000'0000'00010'00000'000'00000, opcode == 0b111'0011; sret : Inst32Format : bits == 0b000'1000'00010'00000'000'00000, opcode == 0b111'0011; @@ -505,4 +506,5 @@ cfsdsp : CSS: func3 == 0b101, op == 0b10; cswsp : CSS: func3 == 0b110, op == 0b10; csdsp : CSS: func3 == 0b111, op == 0b10; + cunimp : Inst16Format : func3 == 0b000, bits == 0b000'0000'0000, op == 0b00; };
diff --git a/riscv/riscv64g.isa b/riscv/riscv64g.isa index 467e57c..78f92cf 100644 --- a/riscv/riscv64g.isa +++ b/riscv/riscv64g.isa
@@ -278,6 +278,9 @@ ebreak{}, disasm: "ebreak", semfunc: "&RiscVIEbreak"; + unimp{}, + disasm: "unimp", + semfunc: "&RiscVIUnimplemented"; } } @@ -1039,5 +1042,9 @@ disasm: "c.ebreak", resources: {next_pc}, semfunc: "&RiscVIEbreak"; + cunimp{}, + disasm: "c.unimp", + resources: {next_pc}, + semfunc: "&RiscVIUnimplemented"; } }
diff --git a/riscv/riscv_i_instructions.cc b/riscv/riscv_i_instructions.cc index eb17c54..2376214 100644 --- a/riscv/riscv_i_instructions.cc +++ b/riscv/riscv_i_instructions.cc
@@ -547,6 +547,21 @@ } // namespace RV64 +void RiscVIUnimplemented(const Instruction *instruction) { + auto *state = static_cast<RiscVState *>(instruction->state()); + // Get instruction word, as it needs to be used as trap value. + uint64_t address = instruction->address(); + auto db = state->db_factory()->Allocate<uint32_t>(1); + state->LoadMemory(instruction, address, db, nullptr, nullptr); + uint32_t inst_word = db->Get<uint32_t>(0); + db->DecRef(); + // See if the instruction is interpreted as 32 or 16 bit instruction. + if ((inst_word & 0b11) != 0b11) inst_word &= 0xffff; + state->Trap(/*is_interrupt=*/false, /*trap_value=*/inst_word, + *ExceptionCode::kIllegalInstruction, + /*epc=*/instruction->address(), instruction); +} + void RiscVIFence(const Instruction *instruction) { int pred = generic::GetInstructionSource<uint32_t>(instruction, 0) & 0xf; int succ = generic::GetInstructionSource<uint32_t>(instruction, 1) & 0xf;
diff --git a/riscv/riscv_i_instructions.h b/riscv/riscv_i_instructions.h index 05cdbd9..f0770cb 100644 --- a/riscv/riscv_i_instructions.h +++ b/riscv/riscv_i_instructions.h
@@ -184,6 +184,12 @@ } // namespace RV64 +// Unimplemented instruction. This is executed when either the unimp or the +// c.unimp instructions are issued. The instruction takes an unknown instruction +// exception, but does not print a log message. +// The instruction does not take any operands. +void RiscVIUnimplemented(const Instruction *instruction); + // The Fence instruction takes two source operands, the 4 bit values of the // predecessor and successor sets. void RiscVIFence(const Instruction *instruction);
diff --git a/riscv/test/riscv32g_encoding_test.cc b/riscv/test/riscv32g_encoding_test.cc index 3f2cfe2..b130664 100644 --- a/riscv/test/riscv32g_encoding_test.cc +++ b/riscv/test/riscv32g_encoding_test.cc
@@ -388,7 +388,7 @@ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCsrrs); enc_->ParseInstruction(SetRd(SetRs1(kCsrc, kRdValue), kRdValue)); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCsrrc); - enc_->ParseInstruction(kCsrw); + enc_->ParseInstruction(SetRs1(kCsrw, kRdValue)); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCsrrwNr); enc_->ParseInstruction(kCsrs); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCsrrsNw); @@ -406,6 +406,8 @@ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCsrrsiNw); enc_->ParseInstruction(kCsrci); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCsrrciNw); + enc_->ParseInstruction(kCsrw); + EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kUnimp); } TEST_F(RiscV32GEncodingTest, RV32MOpcodes) { @@ -638,6 +640,8 @@ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCnop); enc_->ParseInstruction(kCebreak); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCebreak); + enc_->ParseInstruction(0x0000); + EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32g, 0), OpcodeEnum::kCunimp); } TEST_F(RiscV32GEncodingTest, RV32PrivilegedOpcodes) {