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)",