This adds checks for target instruction alignment in jump and branch instructions, and generates exceptions from these instructions if the alignment is wrong. Note, if the C subset is supported, there will be no exceptions generated. PiperOrigin-RevId: 842742707 Change-Id: I86cf0e744e5ab7d73b5e793509a8c886da042d6f
diff --git a/riscv/riscv_i_instructions.cc b/riscv/riscv_i_instructions.cc index 64645ec..feaf111 100644 --- a/riscv/riscv_i_instructions.cc +++ b/riscv/riscv_i_instructions.cc
@@ -24,6 +24,7 @@ #include "mpact/sim/generic/instruction.h" #include "mpact/sim/generic/register.h" #include "mpact/sim/generic/type_helpers.h" +#include "riscv/riscv_csr.h" #include "riscv/riscv_instruction_helpers.h" #include "riscv/riscv_register.h" #include "riscv/riscv_state.h" @@ -140,10 +141,24 @@ UIntReg reg_base = generic::GetInstructionSource<UIntReg>(instruction, 0); UIntReg offset = generic::GetInstructionSource<UIntReg>(instruction, 1); UIntReg target = (offset + reg_base) & ~0x1; + // Check target for proper alignment. + auto* state = static_cast<RiscVState*>(instruction->state()); + auto res = + state->csr_set()->GetCsr(static_cast<uint64_t>(RiscVCsrEnum::kMIsa)); + bool has_c_extension = true; + if (res.ok() || res.value() != nullptr) { + has_c_extension = (res.value()->GetUint64() & + static_cast<uint64_t>(IsaExtensions::kCompressed)) != 0; + } + if (!has_c_extension && ((target & 0x3) != 0)) { + state->Trap(/*is_interrupt*/ false, instruction->address(), + *ExceptionCode::kInstructionAddressMisaligned, + instruction->address(), instruction); + return; + } UIntReg return_address = instruction->address() + instruction->size(); auto* db = instruction->Destination(0)->AllocateDataBuffer(); db->SetSubmit<UIntReg>(0, target); - auto* state = static_cast<RiscVState*>(instruction->state()); state->set_branch(true); auto* reg = static_cast<generic::RegisterDestinationOperand<UIntReg>*>( instruction->Destination(1)) @@ -294,10 +309,24 @@ UIntReg offset = generic::GetInstructionSource<UIntReg>(instruction, 1); UIntReg target = offset + reg_base; target &= (std::numeric_limits<UIntReg>::max() << 1); + // Check target for proper alignment. + auto* state = static_cast<RiscVState*>(instruction->state()); + auto res = + state->csr_set()->GetCsr(static_cast<uint64_t>(RiscVCsrEnum::kMIsa)); + bool has_c_extension = true; + if (res.ok() || res.value() != nullptr) { + has_c_extension = (res.value()->GetUint64() & + static_cast<uint64_t>(IsaExtensions::kCompressed)) != 0; + } + if (!has_c_extension && ((target & 0x3) != 0)) { + state->Trap(/*is_interrupt*/ false, instruction->address(), + *ExceptionCode::kInstructionAddressMisaligned, + instruction->address(), instruction); + return; + } UIntReg return_address = instruction->address() + instruction->size(); auto* db = instruction->Destination(0)->AllocateDataBuffer(); db->SetSubmit<UIntReg>(0, target); - auto* state = static_cast<RiscVState*>(instruction->state()); state->set_branch(true); auto* reg = static_cast<generic::RegisterDestinationOperand<UIntReg>*>( instruction->Destination(1))
diff --git a/riscv/riscv_instruction_helpers.h b/riscv/riscv_instruction_helpers.h index 89d6050..9435bbd 100644 --- a/riscv/riscv_instruction_helpers.h +++ b/riscv/riscv_instruction_helpers.h
@@ -28,6 +28,7 @@ #include "mpact/sim/generic/operand_interface.h" #include "mpact/sim/generic/register.h" #include "mpact/sim/generic/type_helpers.h" +#include "riscv/riscv_csr.h" #include "riscv/riscv_fp_host.h" #include "riscv/riscv_fp_info.h" #include "riscv/riscv_fp_state.h" @@ -348,9 +349,24 @@ if (cond(a, b)) { UIntType offset = generic::GetInstructionSource<UIntType>(instruction, 2); UIntType target = offset + instruction->address(); + // Check target for proper alignment. + auto* state = static_cast<RiscVState*>(instruction->state()); + auto res = + state->csr_set()->GetCsr(static_cast<uint64_t>(RiscVCsrEnum::kMIsa)); + bool has_c_extension = true; + if (res.ok() || res.value() != nullptr) { + has_c_extension = + (res.value()->GetUint64() & + static_cast<uint64_t>(IsaExtensions::kCompressed)) != 0; + } + if (!has_c_extension && ((target & 0x3) != 0)) { + state->Trap(/*is_interrupt*/ false, instruction->address(), + *ExceptionCode::kInstructionAddressMisaligned, + instruction->address(), instruction); + return; + } auto* db = instruction->Destination(0)->AllocateDataBuffer(); db->SetSubmit<UIntType>(0, target); - auto state = static_cast<RiscVState*>(instruction->state()); state->set_branch(true); } }