No public description
PiperOrigin-RevId: 638333178
Change-Id: I35d12b0c2af0e182c4b1ce1344d07b54966c4196
diff --git a/cheriot/cheriot_register.cc b/cheriot/cheriot_register.cc
index d4c64f3..11dc8cb 100644
--- a/cheriot/cheriot_register.cc
+++ b/cheriot/cheriot_register.cc
@@ -317,6 +317,8 @@
return (object_type() == kSentry) ||
(object_type() == kInterruptEnablingSentry) ||
(object_type() == kInterruptDisablingSentry) ||
+ (object_type() == kInterruptEnablingReturnSentry) ||
+ (object_type() == kInterruptDisablingReturnSentry) ||
(object_type() == kSealedExecutable6) ||
(object_type() == kSealedExecutable7);
} else {
@@ -357,6 +359,8 @@
case kSentry:
case kInterruptEnablingSentry:
case kInterruptDisablingSentry:
+ case kInterruptEnablingReturnSentry:
+ case kInterruptDisablingReturnSentry:
case kSealedExecutable6:
case kSealedExecutable7:
// The sealing type is ok.
@@ -429,7 +433,12 @@
bool CheriotRegister::IsSentry() const {
return !is_null_ && (object_type() >= kSentry) &&
- (object_type() <= kInterruptEnablingSentry);
+ (object_type() <= kInterruptEnablingReturnSentry);
+}
+
+bool CheriotRegister::IsBackwardSentry() const {
+ return !is_null_ && ((object_type() == kInterruptEnablingReturnSentry) ||
+ (object_type() == kInterruptDisablingReturnSentry));
}
void CheriotRegister::CopyFrom(const CheriotRegister &other) {
diff --git a/cheriot/cheriot_register.h b/cheriot/cheriot_register.h
index 57c19f2..c62ddbb 100644
--- a/cheriot/cheriot_register.h
+++ b/cheriot/cheriot_register.h
@@ -72,8 +72,8 @@
kSentry = 1,
kInterruptDisablingSentry = 2,
kInterruptEnablingSentry = 3,
- kReserved4 = 4,
- kReserved5 = 5,
+ kInterruptDisablingReturnSentry = 4,
+ kInterruptEnablingReturnSentry = 5,
kSealedExecutable6 = 6,
kSealedExecutable7 = 7,
kReserved8 = 8,
@@ -149,6 +149,8 @@
bool IsUnsealed() const;
// Returns true if the capability is a sentry.
bool IsSentry() const;
+ // Returns true if the capability is a backward sentry.
+ bool IsBackwardSentry() const;
// Clears the tag.
void Invalidate() { set_tag(false); }
// Set bounds, return true if they're precise, i.e., that the base and length
diff --git a/cheriot/cheriot_state.cc b/cheriot/cheriot_state.cc
index 49e8183..525c5c8 100644
--- a/cheriot/cheriot_state.cc
+++ b/cheriot/cheriot_state.cc
@@ -613,7 +613,8 @@
void CheriotState::Trap(bool is_interrupt, uint64_t trap_value,
uint64_t exception_code, uint64_t epc,
const Instruction *inst) {
- // Call the handler.
+ // LOG(INFO) << "Trap: " << std::hex << is_interrupt << " " << trap_value << "
+ // " << exception_code << " " << epc; Call the handler.
if (on_trap_ != nullptr) {
bool res = on_trap_(is_interrupt, trap_value, exception_code, epc, inst);
// If the handler returns true, the trap has been handled. Just return.
diff --git a/cheriot/cheriot_test_rig_decoder.cc b/cheriot/cheriot_test_rig_decoder.cc
index 5038397..c1ff08f 100644
--- a/cheriot/cheriot_test_rig_decoder.cc
+++ b/cheriot/cheriot_test_rig_decoder.cc
@@ -79,7 +79,6 @@
cheriot_encoding_->ParseInstruction(inst_word);
auto format = cheriot_encoding_->GetFormat(SlotEnum::kRiscv32Cheriot, 0);
auto opcode = cheriot_encoding_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0);
-
// Extract the numerical register specifies of the instruction.
int rd = 0;
int rs1 = 0;
@@ -124,11 +123,13 @@
rs2 = 0;
break;
}
+ /*
case FormatEnum::kR4Type: // 4 reg operands, rd, rs1, rs3, and rs4.
rd = encoding::r4_type::ExtractRd(inst_word);
rs1 = encoding::r4_type::ExtractRs1(inst_word);
rs2 = encoding::r4_type::ExtractRs2(inst_word);
break;
+ */
case FormatEnum::kRType: // 3 reg operands: rd, rs1, and rs2.
rd = encoding::r_type::ExtractRd(inst_word);
rs1 = encoding::r_type::ExtractRs1(inst_word);
@@ -220,7 +221,7 @@
rs1 = encoding::c_r::ExtractRs1(inst_word16);
rs2 = 0;
break;
- case OpcodeEnum::kCheriotCjalr:
+ case OpcodeEnum::kCheriotCjalrCra:
rd = 1;
rs1 = encoding::c_r::ExtractRs1(inst_word16);
rs2 = 0;
@@ -263,6 +264,11 @@
if (opcode == OpcodeEnum::kCslli) {
rs1 = 0;
}
+ if ((opcode == OpcodeEnum::kHint) || (opcode == OpcodeEnum::kChint)) {
+ rs1 = 0;
+ rs2 = 0;
+ rd = 0;
+ }
decode_info.rd = rd;
decode_info.rs1 = rs1;
decode_info.rs2 = rs2;
diff --git a/cheriot/debug_command_shell.cc b/cheriot/debug_command_shell.cc
index 3b24c1d..70727f8 100644
--- a/cheriot/debug_command_shell.cc
+++ b/cheriot/debug_command_shell.cc
@@ -1422,8 +1422,9 @@
// If it's not a jump-and-link, it's a single step.
if ((inst->opcode() != *isa32::OpcodeEnum::kCheriotJal) &&
(inst->opcode() != *isa32::OpcodeEnum::kCheriotJalr) &&
+ (inst->opcode() != *isa32::OpcodeEnum::kCheriotJalrCra) &&
(inst->opcode() != *isa32::OpcodeEnum::kCheriotCjal) &&
- (inst->opcode() != *isa32::OpcodeEnum::kCheriotCjalr)) {
+ (inst->opcode() != *isa32::OpcodeEnum::kCheriotCjalrCra)) {
return core_access_[current_core_].debug_interface->Step(1).status();
}
// If it is a jump-and-link, we have to set a breakpoint on the instruction
diff --git a/cheriot/riscv_cheriot_encoding.cc b/cheriot/riscv_cheriot_encoding.cc
index d3c66eb..df9b3cd 100644
--- a/cheriot/riscv_cheriot_encoding.cc
+++ b/cheriot/riscv_cheriot_encoding.cc
@@ -188,6 +188,7 @@
auto *csr = res.value();
return new generic::ImmediateOperand<uint32_t>(csr_indx, csr->name());
});
+ /*
source_op_getters_.emplace(*SourceOpEnum::kFrs1, [this]() {
int num = encoding::r_type::ExtractRs1(inst_word_);
return GetRegisterSourceOp<RVFpRegister>(
@@ -206,6 +207,7 @@
state_, absl::StrCat(CheriotState::kFregPrefix, num),
kFRegisterAliases[num]);
});
+ */
source_op_getters_.emplace(*SourceOpEnum::kICbImm8, [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst16_format::ExtractBimm(inst_word_));
@@ -289,6 +291,7 @@
source_op_getters_.emplace(*SourceOpEnum::kPcc, [this]() {
return GetRegisterSourceOp<CheriotRegister>(state_, "pcc", "pcc");
});
+ /*
source_op_getters_.emplace(*SourceOpEnum::kRm,
[this]() -> SourceOperandInterface * {
uint32_t rm = (inst_word_ >> 12) & 0x7;
@@ -313,6 +316,7 @@
return nullptr;
}
});
+ */
source_op_getters_.emplace(
*SourceOpEnum::kRd, [this]() -> SourceOperandInterface * {
int num = encoding::r_type::ExtractRd(inst_word_);
@@ -482,9 +486,11 @@
state_, absl::StrCat(CheriotState::kXregPrefix, 1), latency,
kXRegisterAliases[1]);
});
+ /*
dest_op_getters_.emplace(*DestOpEnum::kFflags, [this](int latency) {
return GetCSRSetBitsDestinationOp<uint32_t>(state_, "fflags", latency, "");
});
+ */
dest_op_getters_.emplace(*DestOpEnum::kNone,
[](int latency) { return nullptr; });
}
diff --git a/cheriot/riscv_cheriot_instructions.cc b/cheriot/riscv_cheriot_instructions.cc
index b97e720..a23bc7d 100644
--- a/cheriot/riscv_cheriot_instructions.cc
+++ b/cheriot/riscv_cheriot_instructions.cc
@@ -202,8 +202,8 @@
cd->set_address(instruction->address() + instruction->size());
bool interrupt_enable = state->mstatus()->mie();
(void)cd->Seal(*state->sealing_root(),
- interrupt_enable ? CapReg::kInterruptEnablingSentry
- : CapReg::kInterruptDisablingSentry);
+ interrupt_enable ? CapReg::kInterruptEnablingReturnSentry
+ : CapReg::kInterruptDisablingReturnSentry);
// Update pcc.
pcc->set_address(new_pc);
state->set_branch(true);
@@ -222,14 +222,24 @@
// Helper function to check for exceptions for Jr and Jalr.
static bool CheriotCJrCheck(const Instruction *instruction, uint64_t new_pc,
- uint32_t offset, const CheriotRegister *cs1) {
+ uint32_t offset, const CheriotRegister *cs1,
+ bool has_dest, bool uses_ra) {
auto *state = static_cast<CheriotState *>(instruction->state());
if (!cs1->tag()) {
state->HandleCheriRegException(instruction, instruction->address(),
EC::kCapExTagViolation, cs1);
return false;
}
- if (cs1->IsSealed() && (!cs1->IsSentry() || offset != 0)) {
+ bool ok = false;
+ ok |= !has_dest && uses_ra && cs1->IsBackwardSentry();
+ ok |= !has_dest && !uses_ra &&
+ ((cs1->object_type() == CapReg::kUnsealed) ||
+ (cs1->object_type() == CapReg::kSentry));
+ ok |= has_dest && ((cs1->object_type() == CapReg::kUnsealed) ||
+ (cs1->object_type() == CapReg::kSentry));
+ ok |= has_dest && uses_ra && (cs1->object_type() >= CapReg::kUnsealed) &&
+ (cs1->object_type() <= CapReg::kInterruptEnablingSentry);
+ if ((cs1->IsSealed() && offset != 0) || !ok) {
state->HandleCheriRegException(instruction, instruction->address(),
EC::kCapExSealViolation, cs1);
return false;
@@ -248,63 +258,41 @@
return true;
}
-void CheriotCJalr(const Instruction *instruction) {
- // TODO(torerik): fix this mess.
+static inline void CheriotCJalrHelper(const Instruction *instruction,
+ bool has_dest, bool uses_ra) {
auto *state = static_cast<CheriotState *>(instruction->state());
auto *cs1 = GetCapSource(instruction, 0);
auto offset = generic::GetInstructionSource<uint32_t>(instruction, 1);
auto *pcc = state->pcc();
auto new_pc = offset + cs1->address();
new_pc &= ~0b1ULL;
- if (!CheriotCJrCheck(instruction, new_pc, offset, cs1)) {
+ if (!CheriotCJrCheck(instruction, new_pc, offset, cs1, has_dest, uses_ra)) {
return;
}
- // Update link register.
- state->temp_reg()->CopyFrom(*pcc);
- state->temp_reg()->set_address(instruction->address() + instruction->size());
auto *mstatus = state->mstatus();
- bool interrupt_enable = (mstatus->GetUint32() & 0b1000) != 0;
- auto status = state->temp_reg()->Seal(
- *state->sealing_root(), interrupt_enable
- ? CapReg::kInterruptEnablingSentry
- : CapReg::kInterruptDisablingSentry);
- if (!status.ok()) {
- LOG(ERROR) << "Failed to seal: " << status;
- return;
- }
- // Update pcc.
- pcc->CopyFrom(*cs1);
- // If the new pcc is a sentry, unseal and set/clear mie accordingly.
- if (pcc->IsSentry()) {
- if (pcc->object_type() != CapReg::kSentry) {
- interrupt_enable = pcc->object_type() == CapReg::kInterruptEnablingSentry;
- mstatus->set_mie(interrupt_enable);
- mstatus->Submit();
+ if (has_dest) {
+ // Update link register.
+ state->temp_reg()->CopyFrom(*pcc);
+ state->temp_reg()->set_address(instruction->address() +
+ instruction->size());
+ bool interrupt_enable = (mstatus->GetUint32() & 0b1000) != 0;
+ auto status = state->temp_reg()->Seal(
+ *state->sealing_root(), interrupt_enable
+ ? CapReg::kInterruptEnablingReturnSentry
+ : CapReg::kInterruptDisablingReturnSentry);
+ if (!status.ok()) {
+ LOG(ERROR) << "Failed to seal: " << status;
+ return;
}
- (void)pcc->Unseal(*state->sealing_root(), pcc->object_type());
}
- pcc->set_address(new_pc);
- state->set_branch(true);
- auto *cd = GetCapDest(instruction, 0);
- cd->CopyFrom(*state->temp_reg());
-}
-
-void CheriotCJr(const Instruction *instruction) {
- auto *state = static_cast<CheriotState *>(instruction->state());
- auto *cs1 = GetCapSource(instruction, 0);
- auto offset = generic::GetInstructionSource<uint32_t>(instruction, 1);
- auto *pcc = state->pcc();
- auto new_pc = offset + cs1->address();
- new_pc &= ~0b1ULL;
- if (!CheriotCJrCheck(instruction, new_pc, offset, cs1)) return;
// Update pcc.
pcc->CopyFrom(*cs1);
// If the new pcc is a sentry, unseal and set/clear mie accordingly.
if (pcc->IsSentry()) {
if (pcc->object_type() != CapReg::kSentry) {
bool interrupt_enable =
- pcc->object_type() == CapReg::kInterruptEnablingSentry;
- auto *mstatus = state->mstatus();
+ (pcc->object_type() == CapReg::kInterruptEnablingSentry) |
+ (pcc->object_type() == CapReg::kInterruptEnablingReturnSentry);
mstatus->set_mie(interrupt_enable);
mstatus->Submit();
}
@@ -312,6 +300,33 @@
}
pcc->set_address(new_pc);
state->set_branch(true);
+ if (has_dest) {
+ auto *cd = GetCapDest(instruction, 0);
+ cd->CopyFrom(*state->temp_reg());
+ }
+}
+
+void CheriotCJalr(const Instruction *instruction) {
+ CheriotCJalrHelper(instruction, /*has_dest=*/true, /*uses_ra=*/false);
+}
+
+void CheriotCJalrCra(const Instruction *instruction) {
+ CheriotCJalrHelper(instruction, /*has_dest=*/true, /*uses_ra=*/true);
+}
+
+void CheriotCJrCra(const Instruction *instruction) {
+ CheriotCJalrHelper(instruction, /*has_dest=*/false, /*uses_ra=*/true);
+}
+
+void CheriotCJr(const Instruction *instruction) {
+ CheriotCJalrHelper(instruction, /*has_dest=*/false, /*uses_ra=*/false);
+}
+
+void CheriotCJalrZero(const Instruction *instruction) {
+ auto *state = static_cast<CheriotState *>(instruction->state());
+ auto *cs1 = GetCapSource(instruction, 0);
+ state->HandleCheriRegException(instruction, instruction->address(),
+ EC::kCapExTagViolation, cs1);
}
void CheriotCLc(const Instruction *instruction) {
diff --git a/cheriot/riscv_cheriot_instructions.h b/cheriot/riscv_cheriot_instructions.h
index 346bc24..ec59f87 100644
--- a/cheriot/riscv_cheriot_instructions.h
+++ b/cheriot/riscv_cheriot_instructions.h
@@ -81,6 +81,15 @@
// This instruction takes 2 sources. Source 0 is the source capability, source 1
// is the offset. The pcc is implied.
void CheriotCJr(const Instruction *instruction);
+// This instruction takes 2 sources and one destination operand. Source 0 is the
+// source capability, source 1 is the offset. Destination 0 is the link
+// capability. The pcc is implied.
+void CheriotCJalrCra(const Instruction *instruction);
+// This instruction takes 2 sources. Source 0 is the source capability, source 1
+// is the offset. The pcc is implied.
+void CheriotCJrCra(const Instruction *instruction);
+// This instruction takes no sources, no destinations.
+void CheriotCJalrZero(const Instruction *instruction);
// This takes 2 source operands and 1 destination operand. Source 0 is the
// address source capability, source 1 is the integer offset. Destination 0 is
// the target capability.
diff --git a/cheriot/test/cheriot_register_test.cc b/cheriot/test/cheriot_register_test.cc
index d698060..2753ffd 100644
--- a/cheriot/test/cheriot_register_test.cc
+++ b/cheriot/test/cheriot_register_test.cc
@@ -349,6 +349,8 @@
if ((i == ObjectType::kSentry) ||
(i == ObjectType::kInterruptDisablingSentry) ||
(i == ObjectType::kInterruptEnablingSentry) ||
+ (i == ObjectType::kInterruptDisablingReturnSentry) ||
+ (i == ObjectType::kInterruptEnablingReturnSentry) ||
(i == ObjectType::kSealedExecutable6) ||
(i == ObjectType::kSealedExecutable7)) {
EXPECT_TRUE(status.ok()) << status.message();
@@ -415,7 +417,7 @@
// Copy from null capability.
cap_reg()->ResetNull();
cap_reg()->data_buffer()->Set<uint32_t>(0, kAddress);
- cap_reg()->set_object_type(ObjectType::kReserved4);
+ cap_reg()->set_object_type(ObjectType::kReserved8);
cap_reg()->set_reserved(1);
cap_reg_copy->CopyFrom(*cap_reg());
EXPECT_FALSE(cap_reg_copy->IsValid());
@@ -430,7 +432,7 @@
// Copy from memory root capability.
cap_reg()->ResetMemoryRoot();
cap_reg()->data_buffer()->Set<uint32_t>(0, kAddress);
- cap_reg()->set_object_type(ObjectType::kReserved4);
+ cap_reg()->set_object_type(ObjectType::kReserved8);
cap_reg()->set_reserved(1);
(void)cap_reg()->SetBounds(kBase, kAddress + 1);
cap_reg_copy->CopyFrom(*cap_reg());
@@ -445,7 +447,7 @@
// Copy from execute root capability.
cap_reg()->ResetExecuteRoot();
cap_reg()->data_buffer()->Set<uint32_t>(0, kAddress);
- cap_reg()->set_object_type(ObjectType::kReserved4);
+ cap_reg()->set_object_type(ObjectType::kReserved8);
cap_reg()->set_reserved(1);
(void)cap_reg()->SetBounds(kBase, kAddress + 1);
cap_reg_copy->CopyFrom(*cap_reg());
@@ -460,7 +462,7 @@
// Copy from sealing root capability.
cap_reg()->ResetSealingRoot();
cap_reg()->data_buffer()->Set<uint32_t>(0, kAddress);
- cap_reg()->set_object_type(ObjectType::kReserved4);
+ cap_reg()->set_object_type(ObjectType::kReserved8);
cap_reg()->set_reserved(1);
(void)cap_reg()->SetBounds(kBase, kAddress + 1);
cap_reg_copy->CopyFrom(*cap_reg());
diff --git a/cheriot/test/riscv_cheriot_encoding_test.cc b/cheriot/test/riscv_cheriot_encoding_test.cc
index 04fc563..2f941e7 100644
--- a/cheriot/test/riscv_cheriot_encoding_test.cc
+++ b/cheriot/test/riscv_cheriot_encoding_test.cc
@@ -140,33 +140,6 @@
// constexpr uint32_t kAmomaxw = 0b10100'0'0'00000'00000'010'00000'0101111;
// constexpr uint32_t kAmominuw = 0b11000'0'0'00000'00000'010'00000'0101111;
// constexpr uint32_t kAmomaxuw = 0b11100'0'0'00000'00000'010'00000'0101111;
-// RV32F
-constexpr uint32_t kFlw = 0b000000000000'00000'010'00000'0000111;
-constexpr uint32_t kFsw = 0b0000000'00000'00000'010'00000'0100111;
-constexpr uint32_t kFmadds = 0b00000'00'00000'00000'000'00000'1000011;
-constexpr uint32_t kFmsubs = 0b00000'00'00000'00000'000'00000'1000111;
-constexpr uint32_t kFnmsubs = 0b00000'00'00000'00000'000'00000'1001011;
-constexpr uint32_t kFnmadds = 0b00000'00'00000'00000'000'00000'1001111;
-constexpr uint32_t kFadds = 0b0000000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFsubs = 0b0000100'00000'00000'000'00000'1010011;
-constexpr uint32_t kFmuls = 0b0001000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFdivs = 0b0001100'00000'00000'000'00000'1010011;
-constexpr uint32_t kFsqrts = 0b0101100'00000'00000'000'00000'1010011;
-constexpr uint32_t kFsgnjs = 0b0010000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFsgnjns = 0b0010000'00000'00000'001'00000'1010011;
-constexpr uint32_t kFsgnjxs = 0b0010000'00000'00000'010'00000'1010011;
-constexpr uint32_t kFmins = 0b0010100'00000'00000'000'00000'1010011;
-constexpr uint32_t kFmaxs = 0b0010100'00000'00000'001'00000'1010011;
-constexpr uint32_t kFcvtws = 0b1100000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFcvtwus = 0b1100000'00001'00000'000'00000'1010011;
-constexpr uint32_t kFmvxw = 0b1110000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFeqs = 0b1010000'00000'00000'010'00000'1010011;
-constexpr uint32_t kFlts = 0b1010000'00000'00000'001'00000'1010011;
-constexpr uint32_t kFles = 0b1010000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFclasss = 0b1110000'00000'00000'001'00000'1010011;
-constexpr uint32_t kFcvtsw = 0b1101000'00000'00000'000'00000'1010011;
-constexpr uint32_t kFcvtswu = 0b1101000'00001'00000'000'00000'1010011;
-constexpr uint32_t kFmvwx = 0b1111000'00000'00000'000'00000'1010011;
// RV32C
constexpr uint32_t kClwsp = 0b010'0'00000'00000'10;
constexpr uint32_t kCldsp = 0b011'0'00000'00000'10;
@@ -265,7 +238,7 @@
OpcodeEnum::kCheriotJal);
enc_->ParseInstruction(SetRd(kCheriotJalr, kRdValue));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kCheriotJalr);
+ OpcodeEnum::kCheriotJalrCra);
enc_->ParseInstruction(kBeq);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kBeq);
enc_->ParseInstruction(kBne);
@@ -429,72 +402,6 @@
// OpcodeEnum::kAmomaxuw);
// }
-TEST_F(RiscVCheriotEncodingTest, RV32FOpcodes) {
- // RV32F
- enc_->ParseInstruction(kFlw);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFlw);
- enc_->ParseInstruction(kFsw);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFsw);
- enc_->ParseInstruction(kFmadds);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFmaddS);
- enc_->ParseInstruction(kFmsubs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFmsubS);
- enc_->ParseInstruction(kFnmsubs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFnmsubS);
- enc_->ParseInstruction(kFnmadds);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFnmaddS);
- enc_->ParseInstruction(kFadds);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFaddS);
- enc_->ParseInstruction(kFsubs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFsubS);
- enc_->ParseInstruction(kFmuls);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFmulS);
- enc_->ParseInstruction(kFdivs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFdivS);
- enc_->ParseInstruction(kFsqrts);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFsqrtS);
- enc_->ParseInstruction(kFsgnjs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFsgnjS);
- enc_->ParseInstruction(kFsgnjns);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFsgnjnS);
- enc_->ParseInstruction(kFsgnjxs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFsgnjxS);
- enc_->ParseInstruction(kFmins);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFminS);
- enc_->ParseInstruction(kFmaxs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFmaxS);
- enc_->ParseInstruction(kFcvtws);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFcvtWs);
- enc_->ParseInstruction(kFcvtwus);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFcvtWus);
- enc_->ParseInstruction(kFmvxw);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFmvXw);
- enc_->ParseInstruction(kFeqs);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFcmpeqS);
- enc_->ParseInstruction(kFlts);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFcmpltS);
- enc_->ParseInstruction(kFles);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFcmpleS);
- enc_->ParseInstruction(kFclasss);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFclassS);
- enc_->ParseInstruction(kFcvtsw);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFcvtSw);
- enc_->ParseInstruction(kFcvtswu);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kFcvtSwu);
- enc_->ParseInstruction(kFmvwx);
- EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kFmvWx);
-}
-
// Test for decoding compact opcodes.
TEST_F(RiscVCheriotEncodingTest, RV32COpcodes) {
enc_->ParseInstruction(Set16Rd(kClwsp, 1));
@@ -530,10 +437,10 @@
OpcodeEnum::kCheriotCjal);
enc_->ParseInstruction(Set16Rd(kCheriotCjr, 1));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kCheriotCjr);
+ OpcodeEnum::kCheriotCjrCra);
enc_->ParseInstruction(Set16Rd(kCheriotCjalr, 1));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kCheriotCjalr);
+ OpcodeEnum::kCheriotCjalrCra);
enc_->ParseInstruction(kCbeqz);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0), OpcodeEnum::kCbeqz);
enc_->ParseInstruction(kCbnez);
@@ -626,13 +533,13 @@
OpcodeEnum::kCheriotJal);
enc_->ParseInstruction(SetRd(kCheriotJalr, kRdValue));
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kCheriotJalr);
+ OpcodeEnum::kCheriotJalrCra);
enc_->ParseInstruction(kCheriotJal);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
OpcodeEnum::kCheriotJ);
enc_->ParseInstruction(kCheriotJalr);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
- OpcodeEnum::kCheriotJr);
+ OpcodeEnum::kCheriotJalrZero);
enc_->ParseInstruction(kCheriotLc);
EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Cheriot, 0),
OpcodeEnum::kCheriotLc);
diff --git a/cheriot/test/riscv_cheriot_instructions_test.cc b/cheriot/test/riscv_cheriot_instructions_test.cc
index e43d550..c0bc046 100644
--- a/cheriot/test/riscv_cheriot_instructions_test.cc
+++ b/cheriot/test/riscv_cheriot_instructions_test.cc
@@ -64,7 +64,7 @@
using ::mpact::sim::cheriot::CheriotCGetType;
using ::mpact::sim::cheriot::CheriotCIncAddr;
using ::mpact::sim::cheriot::CheriotCJal;
-using ::mpact::sim::cheriot::CheriotCJalr;
+using ::mpact::sim::cheriot::CheriotCJalrCra;
using ::mpact::sim::cheriot::CheriotCLc;
using ::mpact::sim::cheriot::CheriotCLcChild;
using ::mpact::sim::cheriot::CheriotCMove;
@@ -83,12 +83,13 @@
using ::mpact::sim::cheriot::CheriotCTestSubset;
using ::mpact::sim::cheriot::CheriotCUnseal;
// Register name definitions.
-constexpr char kC1[] = "c1";
-constexpr char kC2[] = "c2";
-constexpr char kC3[] = "c3";
-constexpr char kC4[] = "c4";
+constexpr char kCra[] = "c1";
+constexpr char kC1[] = "c11";
+constexpr char kC2[] = "c12";
+constexpr char kC3[] = "c13";
+constexpr char kC4[] = "c14";
// Register number definitions.
-constexpr int kC1Num = 1;
+constexpr int kC1Num = 11;
constexpr int kPccNum = 0b1'00000;
constexpr uint32_t kInstAddress = 0x2468;
@@ -111,7 +112,8 @@
{kC1, &c1_reg_},
{kC2, &c2_reg_},
{kC3, &c3_reg_},
- {kC4, &c4_reg_}}) {
+ {kC4, &c4_reg_},
+ {kCra, &cra_reg_}}) {
*cap_reg_ptr = state_->GetRegister<CheriotRegister>(reg_name).first;
}
state_->set_on_trap([this](bool is_interrupt, uint64_t trap_value,
@@ -213,6 +215,7 @@
CheriotRegister *c2_reg() { return c2_reg_; }
CheriotRegister *c3_reg() { return c3_reg_; }
CheriotRegister *c4_reg() { return c4_reg_; }
+ CheriotRegister *cra_reg() { return cra_reg_; }
absl::BitGen &bitgen() { return bitgen_; }
bool trap_taken() { return trap_taken_; }
bool trap_is_interrupt() { return trap_is_interrupt_; }
@@ -229,6 +232,7 @@
CheriotRegister *c2_reg_;
CheriotRegister *c3_reg_;
CheriotRegister *c4_reg_;
+ CheriotRegister *cra_reg_;
absl::BitGen bitgen_;
bool trap_taken_ = false;
bool trap_is_interrupt_ = false;
@@ -554,7 +558,7 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(c3_reg()->tag());
EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingSentry);
+ EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingReturnSentry);
EXPECT_TRUE(state()->pcc()->tag());
// Set interrupt enable to false.
state()->mstatus()->set_mie(0);
@@ -566,7 +570,7 @@
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
EXPECT_TRUE(c3_reg()->tag());
EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingSentry);
+ EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingReturnSentry);
EXPECT_TRUE(state()->pcc()->tag());
}
@@ -606,8 +610,8 @@
// Jump and link register (capability) indirect - no traps, unsealed source.
TEST_F(RiscVCheriotInstructionsTest, CJalr) {
- inst()->set_semantic_function(&CheriotCJalr);
- AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
+ inst()->set_semantic_function(&CheriotCJalrCra);
+ AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
@@ -622,9 +626,9 @@
EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
<< " value: " << trap_value();
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
- EXPECT_TRUE(c3_reg()->tag());
- EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingSentry);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_TRUE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingReturnSentry);
EXPECT_TRUE(state()->pcc()->tag());
// Set interrupt enable to false.
state()->mstatus()->set_mie(0);
@@ -634,16 +638,16 @@
EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
<< " value: " << trap_value();
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
- EXPECT_TRUE(c3_reg()->tag());
- EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingSentry);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_TRUE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingReturnSentry);
EXPECT_TRUE(state()->pcc()->tag());
}
// Jump and link register (capability) indirect - no traps, sentry.
TEST_F(RiscVCheriotInstructionsTest, CJalrSentry) {
- inst()->set_semantic_function(&CheriotCJalr);
- AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
+ inst()->set_semantic_function(&CheriotCJalrCra);
+ AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
@@ -661,9 +665,9 @@
EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
<< " value: " << trap_value();
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
- EXPECT_TRUE(c3_reg()->tag());
- EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptDisablingSentry);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_TRUE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptDisablingReturnSentry);
EXPECT_TRUE(state()->pcc()->tag());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
@@ -680,16 +684,16 @@
EXPECT_FALSE(trap_taken()) << "ec: " << std::hex << trap_exception_code()
<< " value: " << trap_value();
EXPECT_EQ(state()->pcc()->address(), inst()->address() + 0x200);
- EXPECT_TRUE(c3_reg()->tag());
- EXPECT_TRUE(c3_reg()->IsSentry());
- EXPECT_EQ(c3_reg()->object_type(), OT::kInterruptEnablingSentry);
+ EXPECT_TRUE(cra_reg()->tag());
+ EXPECT_TRUE(cra_reg()->IsSentry());
+ EXPECT_EQ(cra_reg()->object_type(), OT::kInterruptEnablingReturnSentry);
EXPECT_TRUE(state()->pcc()->tag());
}
// Verify an unset tag generates a tag violation exception.
TEST_F(RiscVCheriotInstructionsTest, CJalrTagViolation) {
- inst()->set_semantic_function(&CheriotCJalr);
- AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
+ inst()->set_semantic_function(&CheriotCJalrCra);
+ AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
@@ -715,8 +719,8 @@
// For a jalr with a sentry, the immediate has to be zero or it will cause
// an exception. Make sure the exception happens.
TEST_F(RiscVCheriotInstructionsTest, CJalrSentryNonZeroImmediate) {
- inst()->set_semantic_function(&CheriotCJalr);
- AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
+ inst()->set_semantic_function(&CheriotCJalrCra);
+ AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
@@ -742,8 +746,8 @@
// If the source capability does not have execute permission, there should
// be an exception.
TEST_F(RiscVCheriotInstructionsTest, CJalrExecuteViolation) {
- inst()->set_semantic_function(&CheriotCJalr);
- AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
+ inst()->set_semantic_function(&CheriotCJalrCra);
+ AppendCapabilityOperands(inst(), {kC1, kC2}, {kCra});
state()->pcc()->set_address(inst()->address());
// Set up the destination capability.
c1_reg()->ResetExecuteRoot();
@@ -770,7 +774,7 @@
// If the architecture does not have compact instructions, then misaligned
// access on two byte boundary should cause an exception.
TEST_F(RiscVCheriotInstructionsTest, CJalrAlignmentViolation) {
- inst()->set_semantic_function(&CheriotCJalr);
+ inst()->set_semantic_function(&CheriotCJalrCra);
AppendCapabilityOperands(inst(), {kC1, kC2}, {kC3});
state()->pcc()->set_address(inst()->address());
// Set up the destination capability.
diff --git a/riscv_cheriot.bin_fmt b/riscv_cheriot.bin_fmt
index 7ad4346..db6799c 100644
--- a/riscv_cheriot.bin_fmt
+++ b/riscv_cheriot.bin_fmt
@@ -211,12 +211,22 @@
cheriot_gettype : R2Type : func7 == 0x7f, func5 == 0x01, func3 == 0, opcode == 0x5b;
cheriot_incaddr : RType : func7 == 0x11, func3 == 0, opcode == 0x5b;
cheriot_incaddrimm : IType : func3 == 0x1, opcode == 0x5b;
- cheriot_jal : JType : rd != 0, opcode == 0x6f;
- cheriot_j : JType : rd == 0, opcode == 0x6f;
- cheriot_jalr : IType : func3 == 0x0, rd != 0, opcode == 0x67;
- cheriot_jr : IType : func3 == 0x0, rd == 0, opcode == 0x67;
- cheriot_lc : IType : func3 == 0x3, opcode == 0x03;
- cheriot_move : RType : func7 == 0x7f, rs2 == 0xa, func3 == 0, opcode == 0x5b;
+ cheriot_jal : JType : rd != 0, opcode == 0x6f;
+ cheriot_j : JType : rd == 0, opcode == 0x6f;
+ // For jalr and jr, need to differentiate when the destination (jalr) or the
+ // source (jr) designates the cra register.
+ // Function call (dest != cra) (unsealed or interrupt inheriting forward sentry {0, 1})
+ cheriot_jalr : IType : func3 == 0x0, rd > 1, opcode == 0x67;
+ // Function call (dest == cra) (unsealed or forward sentries {0, 1, 2, 3}).
+ cheriot_jalr_cra : IType : func3 == 0x0, rd == 1, opcode == 0x67;
+ // Tail call src != cra (unsealed or interrupt inheriting forward sentry {0, 1})
+ cheriot_jr : IType : func3 == 0x0, rd == 0, rs1 > 1, opcode == 0x67;
+ // Function return src == cra (return sentries only {4, 5})
+ cheriot_jr_cra : IType : func3 == 0x0, rd == 0, rs1 == 1, opcode == 0x67;
+ // Jalr causing exception: both rd and rs1 are 0.
+ cheriot_jalr_zero: IType : func3 == 0x0, rd == 0, rs1 == 0, opcode == 0x67;
+ cheriot_lc : IType : func3 == 0x3, opcode == 0x03;
+ cheriot_move : RType : func7 == 0x7f, rs2 == 0xa, func3 == 0, opcode == 0x5b;
cheriot_representablealignmentmask : R2Type : func7 == 0x7f, func5 == 0x9, func3 == 0, opcode == 0x5b;
cheriot_roundrepresentablelength : R2Type : func7 == 0x7f, func5 == 0x8, func3 == 0, opcode == 0x5b;
cheriot_sc : SType : func3 == 0x3, opcode == 0x23;
@@ -255,33 +265,6 @@
amomaxw : AType : func5 == 0b1'0100, func3 == 0b010, opcode == 0b010'1111;
amominuw : AType : func5 == 0b1'1000, func3 == 0b010, opcode == 0b010'1111;
amomaxuw : AType : func5 == 0b1'1100, func3 == 0b010, opcode == 0b010'1111;
- // RiscV32 single precision floating point instructions.
- flw : IType : func3 == 0b010, opcode == 0b000'0111;
- fsw : SType : func3 == 0b010, opcode == 0b010'0111;
- fmadd_s : R4Type : func2 == 0b00, opcode == 0b100'0011;
- fmsub_s : R4Type : func2 == 0b00, opcode == 0b100'0111;
- fnmsub_s : R4Type : func2 == 0b00, opcode == 0b100'1011;
- fnmadd_s : R4Type : func2 == 0b00, opcode == 0b100'1111;
- fadd_s : RType : func7 == 0b000'0000, opcode == 0b101'0011;
- fsub_s : RType : func7 == 0b000'0100, opcode == 0b101'0011;
- fmul_s : RType : func7 == 0b000'1000, opcode == 0b101'0011;
- fdiv_s : RType : func7 == 0b000'1100, opcode == 0b101'0011;
- fsqrt_s : R2Type : func7 == 0b010'1100, func5 == 0, opcode == 0b101'0011;
- fsgnj_s : RType : func7 == 0b001'0000, func3 == 0b000, opcode == 0b101'0011;
- fsgnjn_s : RType : func7 == 0b001'0000, func3 == 0b001, opcode == 0b101'0011;
- fsgnjx_s : RType : func7 == 0b001'0000, func3 == 0b010, opcode == 0b101'0011;
- fmin_s : RType : func7 == 0b001'0100, func3 == 0b000, opcode == 0b101'0011;
- fmax_s : RType : func7 == 0b001'0100, func3 == 0b001, opcode == 0b101'0011;
- fcvt_ws : R2Type : func7 == 0b110'0000, func5 == 0, opcode == 0b101'0011;
- fcvt_wus : R2Type : func7 == 0b110'0000, func5 == 1, opcode == 0b101'0011;
- fmv_xw : R2Type : func7 == 0b111'0000, func5 == 0, func3 == 0b000, opcode == 0b101'0011;
- fcmpeq_s : RType : func7 == 0b101'0000, func3 == 0b010, opcode == 0b101'0011;
- fcmplt_s : RType : func7 == 0b101'0000, func3 == 0b001, opcode == 0b101'0011;
- fcmple_s : RType : func7 == 0b101'0000, func3 == 0b000, opcode == 0b101'0011;
- fclass_s : R2Type : func7 == 0b111'0000, func5 == 0, func3 == 0b001, opcode == 0b101'0011;
- fcvt_sw : R2Type : func7 == 0b110'1000, func5 == 0, opcode == 0b101'0011;
- fcvt_swu : R2Type : func7 == 0b110'1000, func5 == 1, opcode == 0b101'0011;
- fmv_wx : R2Type : func7 == 0b111'1000, func5 == 0, func3 == 0b000, opcode == 0b101'0011;
// RiscV32 CSR manipulation instructions.
csrrw : IType : func3 == 0b001, rd != 0, opcode == 0b111'0011;
csrrs : IType : func3 == 0b010, rs1 != 0, rd != 0, opcode == 0b111'0011;
@@ -456,15 +439,21 @@
csw : CS : func3 == 0b110, op == 0b00;
csd : CS : func3 == 0b111, op == 0b00;
cnop : CI : func3 == 0b000, imm1 == 0, rs1 == 0, imm5 == 0, op == 0b01;
+ chint : CI : func3 == 0b000, imm6 != 0, rs1 == 0, op == 0b01;
caddi : CI : func3 == 0b000, imm6 != 0, rd != 0, op == 0b01;
+ chint : CI : func3 == 0b000, imm6 == 0, rd != 0, op == 0b01;
cli : CI : func3 == 0b010, rd != 0, op == 0b01;
+ chint : CI : func3 == 0b010, rd == 0, op == 0b01;
caddi16sp : CI : func3 == 0b011, ci_imm10 != 0, rd == 2, op == 0b01;
clui : CI : func3 == 0b011, rd != 0, rd != 2, imm18 != 0, op == 0b01;
+ chint : CI : func3 == 0b011, rd == 0, imm18 != 0, op == 0b01;
// TODO(torerik): The following two instructions should have imm1 == 0 and
// imm5 != 0 instead of imm6 != 0 in the constraints, but that has been
// temporarily removed so as to make it easier to verify in TestRIG
csrli : CSH : func3 == 0b100, op2 == 0b00, uimm6 != 0, op == 0b01;
+ chint : CSH : func3 == 0b100, op2 == 0b00, uimm6 == 0, op == 0b01;
csrai : CSH : func3 == 0b100, op2 == 0b01, uimm6 != 0, op == 0b01;
+ chint : CSH : func3 == 0b100, op2 == 0b01, uimm6 == 0, op == 0b01;
candi : CSH : func3 == 0b100, op2 == 0b10, op == 0b01;
csub : CA : func6 == 0b100'011, func2 == 0b00, op == 0b01;
cxor : CA : func6 == 0b100'011, func2 == 0b01, op == 0b01;
@@ -473,15 +462,19 @@
cbeqz : CB : func3 == 0b110, op == 0b01;
cbnez : CB : func3 == 0b111, op == 0b01;
cslli : CI : func3 == 0b000, imm1 == 0, imm5 != 0, rs1 != 0, op == 0b10;
+ chint : CI : func3 == 0b000, imm1 == 0, rs1 == 0, imm5 != 0, op == 0b10;
+ chint : CI : func3 == 0b000, imm6 == 0, op == 0b10;
clwsp : CI : func3 == 0b010, rd != 0, op == 0b10;
cldsp : CI : func3 == 0b011, rd != 0, op == 0b10;
cmv : CR : func4 == 0b1000, rs1 != 0, rs2 != 0, op == 0b10;
cebreak : Inst16Format : func3 == 0b100, bits == 0b1'00000'00000, op == 0b10;
cadd : CR : func4 == 0b1001, rs1 != 0, rs2 != 0, op == 0b10;
+ chint : CR : func4 == 0b1001, rs1 == 0, rs2 != 0, op == 0b10;
cswsp : CSS: func3 == 0b110, op == 0b10;
csdsp : CSS: func3 == 0b111, op == 0b10;
- cheriot_cj : CJ : func3 == 0b101, op == 0b01;
- cheriot_cjal : CJ : func3 == 0b001, op == 0b01;
- cheriot_cjr : CR : func4 == 0b1000, rs1 != 0, rs2 == 0, op == 0b10;
- cheriot_cjalr : CR : func4 == 0b1001, rs1 != 0, rs2 == 0, op == 0b10;
+ cheriot_cj : CJ : func3 == 0b101, op == 0b01;
+ cheriot_cjal : CJ : func3 == 0b001, op == 0b01;
+ cheriot_cjr : CR : func4 == 0b1000, rs1 > 1, rs2 == 0, op == 0b10;
+ cheriot_cjr_cra : CR : func4 == 0b1000, rs1 == 1, rs2 == 0, op == 0b10;
+ cheriot_cjalr_cra : CR : func4 == 0b1001, rs1 != 0, rs2 == 0, op == 0b10;
};
diff --git a/riscv_cheriot.isa b/riscv_cheriot.isa
index 28fec73..5e0386b 100644
--- a/riscv_cheriot.isa
+++ b/riscv_cheriot.isa
@@ -200,9 +200,18 @@
cheriot_jalr{: cs1, J_imm12 : cd},
disasm: "cjalr", "%cd, %cs1, 0x%(J_imm12:08x)",
semfunc: "&CheriotCJalr";
+ cheriot_jalr_cra{: cs1, J_imm12 : cd},
+ disasm: "cjalr", "%cd, %cs1, 0x%(J_imm12:08x)",
+ semfunc: "&CheriotCJalrCra";
cheriot_jr{: cs1, J_imm12 : },
disasm: "cjalr", "%cs1, 0x%(J_imm12:08x)",
semfunc: "&CheriotCJr";
+ cheriot_jr_cra{: cs1, J_imm12 : },
+ disasm: "cjalr", "%cs1, 0x%(J_imm12:08x)",
+ semfunc: "&CheriotCJrCra";
+ cheriot_jalr_zero{: cs1 :},
+ disasm: "cjalr", "czero, czero, 0",
+ semfunc: "&CheriotCJalrZero";
cheriot_lc{(: cs1, I_imm12 :),(: : cd)},
disasm: "clc", "%cd, %cs1, 0x%(I_imm12:08x)",
semfunc: "&CheriotCLc", "&CheriotCLcChild";
@@ -442,95 +451,6 @@
}
}
-// RiscV32 F (single precision floating point) instructions.
-slot riscv32f {
- includes {
- #include "cheriot/riscv_cheriot_f_instructions.h"
- }
- default size = 4;
- default latency = global_latency;
- opcodes {
- flw{(: rs1, I_imm12 : ), (: : frd)},
- semfunc: "&RiscVILw", "&RiscVIFlwChild",
- disasm: "flw", "%frd, %I_imm12(%rs1)";
- fsw{: rs1, S_imm12, frs2},
- semfunc: "&RiscVFSw",
- disasm: "fsw", "%frs2, %S_imm12(%rs1)";
- fadd_s{: frs1, frs2, rm : frd},
- semfunc: "&RiscVFAdd",
- disasm: "fadd", "%frd, %frs1, %frs2";
- fsub_s{: frs1, frs2, rm : frd},
- semfunc: "&RiscVFSub",
- disasm: "fsub", "%frd, %frs1, %frs2";
- fmul_s{: frs1, frs2, rm : frd},
- semfunc: "&RiscVFMul",
- disasm: "fmul", "%frd, %frs1, %frs2";
- fdiv_s{: frs1, frs2, rm : frd},
- semfunc: "&RiscVFDiv",
- disasm: "fdiv", "%frd, %frs1, %frs2";
- fsqrt_s{: frs1, rm : frd},
- semfunc: "&RiscVFSqrt",
- disasm: "fsqrt", "%frd, %frs1";
- fmin_s{: frs1, frs2 : frd, fflags},
- semfunc: "&RiscVFMin",
- disasm: "fmin", "%frd, %frs1, %frs2";
- fmax_s{: frs1, frs2 : frd, fflags},
- semfunc: "&RiscVFMax",
- disasm: "fmax", "%frd, %frs1, %frs2";
- fmadd_s{: frs1, frs2, frs3, rm : frd, fflags},
- semfunc: "&RiscVFMadd",
- disasm: "fmadd", "%frd, %frs1, %frs2, %frs3";
- fmsub_s{: frs1, frs2, frs3, rm : frd, fflags},
- semfunc: "&RiscVFMsub",
- disasm: "fmsub", "%frd, %frs1, %frs2, %frs3";
- fnmadd_s{: frs1, frs2, frs3, rm : frd, fflags},
- semfunc: "&RiscVFNmadd",
- disasm: "fnmadd", "%frd, %frs1, %frs2, %frs3";
- fnmsub_s{: frs1, frs2, frs3, rm : frd, fflags},
- semfunc: "&RiscVFNmsub",
- disasm: "fnmsub", "%frd, %frs1, %frs2, %frs3";
- fcvt_ws{: frs1, rm : rd, fflags},
- semfunc: "&RiscVFCvtWs",
- disasm: "fcvt.w.s", "%rd, %frs1";
- fcvt_sw{: rs1, rm : frd},
- semfunc: "&RiscVFCvtSw",
- disasm: "fcvt.s.w", "%frd, %rs1";
- fcvt_wus{: frs1, rm : rd, fflags},
- semfunc: "&RiscVFCvtWus",
- disasm: "fcvt.wu.s", "%rd, %frs1";
- fcvt_swu{: rs1, rm : frd},
- semfunc: "&RiscVFCvtSwu",
- disasm: "fcvt.s.wu", "%frd, %rs1";
- fsgnj_s{: frs1, frs2 : frd},
- semfunc: "&RiscVFSgnj",
- disasm: "fsgn.s", "%frd, %frs1, %frs2";
- fsgnjn_s{: frs1, frs2 : frd},
- semfunc: "&RiscVFSgnjn",
- disasm: "fsgnjx.s", "%frd, %frs1, %frs2";
- fsgnjx_s{: frs1, frs2 : frd},
- semfunc: "&RiscVFSgnjx",
- disasm: "fsgnjx.s", "%frd, %frs1, %frs2";
- fmv_xw{: frs1 : rd},
- disasm: "mv.x.w", "%rd, %frs1",
- semfunc: "&RiscVFMvxw";
- fmv_wx{: rs1 : frd},
- disasm: "mv.w.x", "%frd, %rs1",
- semfunc: "&RiscVFMvwx";
- fcmpeq_s{: frs1, frs2 : rd, fflags},
- semfunc: "&RiscVFCmpeq",
- disasm: "fcmpeq", "%rd, %frs1, %frs2";
- fcmplt_s{: frs1, frs2 : rd, fflags},
- semfunc: "&RiscVFCmplt",
- disasm: "fcmplt", "%rd, %frs1, %frs2";
- fcmple_s{: frs1, frs2 : rd, fflags},
- semfunc: "&RiscVFCmple",
- disasm: "fcmple", "%rd, %frs1, %frs2";
- fclass_s{: frs1 : rd},
- semfunc: "&RiscVFClass",
- disasm: "fclass", "%rd, %frs1";
- }
-}
-
// RISCV32 C (compact instructions).
slot riscv32c {
default size = 2;
@@ -591,9 +511,12 @@
cheriot_cjr{: crs1, x0 :},
disasm: "c.jr", "%crs1",
semfunc: "&CheriotCJr";
- cheriot_cjalr{: crs1, x0 : x1},
+ cheriot_cjr_cra{: crs1, x0 :},
+ disasm: "c.jr", "%crs1",
+ semfunc: "&CheriotCJrCra";
+ cheriot_cjalr_cra{: crs1, x0 : x1},
disasm: "c.jalr", "%crs1",
- semfunc: "&CheriotCJalr";
+ semfunc: "&CheriotCJalrCra";
cbeqz{: c3rs1, x0, I_cb_imm8 : },
disasm: "c.beqz", "%c3rs1, %(@+I_cb_imm8:08x)",
semfunc: "&RiscVIBeq";
@@ -649,6 +572,9 @@
cnop{},
disasm: "c.nop",
semfunc: "&RiscVINop";
+ chint{},
+ disasm: "c.hint",
+ semfunc: "&RiscVINop";
cebreak{},
disasm: "c.ebreak",
semfunc: "&RiscVIEbreak";
@@ -657,7 +583,7 @@
// This should be the RiscV32 CHERIoT set.
slot riscv32_cheriot : riscv32i, cheriot, riscv32_amo_arithmetic, riscv32c,
- riscv32m, riscv32f, zicsr, privileged {
+ riscv32m, zicsr, privileged {
default size = 4;
default opcode =
disasm: "Illegal instruction at 0x%(@:08x)",