Changed interface to riscv_top/cheriot_top to make it easier to reuse the class.
PiperOrigin-RevId: 643133613
Change-Id: I8a6e201483394e112e85cc9ff7e2361a81d183bc
diff --git a/cheriot/BUILD b/cheriot/BUILD
index 17501f1..e2750df 100644
--- a/cheriot/BUILD
+++ b/cheriot/BUILD
@@ -220,6 +220,7 @@
":debug_command_shell",
":instrumentation",
":riscv_cheriot",
+ ":riscv_cheriot_decoder",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
"@com_google_absl//absl/flags:usage",
@@ -337,6 +338,7 @@
":debug_command_shell",
":instrumentation",
":riscv_cheriot",
+ ":riscv_cheriot_decoder",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/log",
diff --git a/cheriot/cheriot_decoder.cc b/cheriot/cheriot_decoder.cc
index ba5e4d7..63e6103 100644
--- a/cheriot/cheriot_decoder.cc
+++ b/cheriot/cheriot_decoder.cc
@@ -44,7 +44,7 @@
// Need a data buffer to load instructions from memory. Allocate a single
// buffer that can be reused for each instruction word.
- inst_db_ = state_->db_factory()->Allocate<uint32_t>(1);
+ inst_db_ = db_factory_.Allocate<uint32_t>(1);
// Allocate the isa factory class, the top level isa decoder instance, and
// the encoding parser.
cheriot_isa_factory_ = new CheriotIsaFactory();
diff --git a/cheriot/cheriot_decoder.h b/cheriot/cheriot_decoder.h
index 93442f3..7912734 100644
--- a/cheriot/cheriot_decoder.h
+++ b/cheriot/cheriot_decoder.h
@@ -64,6 +64,15 @@
// instance will raise an internal simulator error when executed.
generic::Instruction *DecodeInstruction(uint64_t address) override;
+ // Return the number of opcodes supported by this decoder.
+ int GetNumOpcodes() const override {
+ return static_cast<int>(OpcodeEnum::kPastMaxValue);
+ }
+ // Return the name of the opcode at the given index.
+ const char *GetOpcodeName(int index) const override {
+ return isa32::kOpcodeNames[index];
+ }
+
// Getter.
isa32::RiscVCheriotEncoding *cheriot_encoding() const {
return cheriot_encoding_;
@@ -73,6 +82,7 @@
CheriotState *state_;
util::MemoryInterface *memory_;
std::unique_ptr<generic::ProgramError> decode_error_;
+ generic::DataBufferFactory db_factory_;
generic::DataBuffer *inst_db_;
isa32::RiscVCheriotEncoding *cheriot_encoding_;
isa32::RiscVCheriotInstructionSetFactory *cheriot_isa_factory_;
diff --git a/cheriot/cheriot_renode.cc b/cheriot/cheriot_renode.cc
index aad6ac0..e308fa9 100644
--- a/cheriot/cheriot_renode.cc
+++ b/cheriot/cheriot_renode.cc
@@ -35,6 +35,7 @@
#include "cheriot/cheriot_cli_forwarder.h"
#include "cheriot/cheriot_debug_info.h"
#include "cheriot/cheriot_debug_interface.h"
+#include "cheriot/cheriot_decoder.h"
#include "cheriot/cheriot_instrumentation_control.h"
#include "cheriot/cheriot_renode_cli_top.h"
#include "cheriot/cheriot_renode_register_info.h"
@@ -104,10 +105,13 @@
mem_profiler_ = new TaggedMemoryUseProfiler(data_memory);
data_memory = mem_profiler_;
mem_profiler_->set_is_enabled(false);
+ cheriot_state_ = new CheriotState(
+ "CherIoT", data_memory, static_cast<AtomicMemoryOpInterface *>(router_));
+ cheriot_decoder_ = new CheriotDecoder(
+ cheriot_state_, static_cast<MemoryInterface *>(router_));
+
// Instantiate cheriot_top.
- cheriot_top_ =
- new CheriotTop(name, static_cast<MemoryInterface *>(router_), data_memory,
- static_cast<MemoryInterface *>(router_));
+ cheriot_top_ = new CheriotTop("Cheriot", cheriot_state_, cheriot_decoder_);
// Initialize minstret/minstreth. Bind the instruction counter to those
// registers.
auto minstret_res = cheriot_top_->state()->csr_set()->GetCsr("minstret");
@@ -142,9 +146,10 @@
CHECK_OK(renode_router_->AddDefaultTarget<MemoryInterface>(tagged_memory_));
// Set up semihosting.
- semihost_ = new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord32,
- cheriot_top_->inst_memory(),
- cheriot_top_->data_memory());
+ semihost_ =
+ new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord32,
+ static_cast<MemoryInterface *>(router_),
+ static_cast<MemoryInterface *>(renode_router_));
// Set up special handlers (ebreak, wfi, ecall).
cheriot_top_->state()->AddEbreakHandler([this](const Instruction *inst) {
if (this->semihost_->IsSemihostingCall(inst)) {
@@ -217,6 +222,8 @@
delete socket_cli_;
delete cheriot_renode_cli_top_;
delete cheriot_cli_forwarder_;
+ delete cheriot_decoder_;
+ delete cheriot_state_;
delete cheriot_top_;
delete semihost_;
delete router_;
diff --git a/cheriot/cheriot_renode.h b/cheriot/cheriot_renode.h
index 377c01f..0f2717c 100644
--- a/cheriot/cheriot_renode.h
+++ b/cheriot/cheriot_renode.h
@@ -24,8 +24,10 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "cheriot/cheriot_cli_forwarder.h"
+#include "cheriot/cheriot_decoder.h"
#include "cheriot/cheriot_instrumentation_control.h"
#include "cheriot/cheriot_renode_cli_top.h"
+#include "cheriot/cheriot_state.h"
#include "cheriot/cheriot_top.h"
#include "cheriot/debug_command_shell.h"
#include "mpact/sim/generic/core_debug_interface.h"
@@ -138,6 +140,8 @@
std::string name_;
MemoryInterface *renode_sysbus_ = nullptr;
TaggedMemoryInterface *tagged_sysbus_ = nullptr;
+ CheriotState *cheriot_state_ = nullptr;
+ CheriotDecoder *cheriot_decoder_ = nullptr;
CheriotTop *cheriot_top_ = nullptr;
RiscVArmSemihost *semihost_ = nullptr;
SingleInitiatorRouter *router_ = nullptr;
diff --git a/cheriot/cheriot_state.cc b/cheriot/cheriot_state.cc
index 525c5c8..1842f29 100644
--- a/cheriot/cheriot_state.cc
+++ b/cheriot/cheriot_state.cc
@@ -289,11 +289,6 @@
// Create the other CSRs.
csr_set_ = new RiscVCsrSet();
CreateCsrs<uint32_t>(this, csr_vec_);
- if (tagged_memory_ == nullptr) {
- owned_tagged_memory_ = new util::TaggedFlatDemandMemory(
- CheriotRegister::kCapabilitySizeInBytes);
- tagged_memory_ = owned_tagged_memory_;
- }
pc_src_operand_ = new RiscVCheri32PcSourceOperand(this);
set_pc_operand(pc_src_operand_);
// Create the revocation data buffer.
@@ -308,7 +303,6 @@
delete executable_root_;
delete sealing_root_;
delete memory_root_;
- delete owned_tagged_memory_;
delete pc_src_operand_;
for (auto *csr : csr_vec_) delete csr;
delete csr_set_;
diff --git a/cheriot/cheriot_state.h b/cheriot/cheriot_state.h
index 7df9bba..c14c73e 100644
--- a/cheriot/cheriot_state.h
+++ b/cheriot/cheriot_state.h
@@ -168,8 +168,6 @@
util::AtomicMemoryOpInterface *atomic_memory);
CheriotState(std::string_view id, util::TaggedMemoryInterface *memory)
: CheriotState(id, memory, nullptr) {}
- explicit CheriotState(std::string_view id)
- : CheriotState(id, nullptr, nullptr) {}
~CheriotState() override;
// Deleted constructors and operators.
@@ -283,7 +281,7 @@
inline void reset_is_interrupt_available() {
is_interrupt_available_ = false;
}
- void set_memory(util::TaggedMemoryInterface *tagged_memory) {
+ void set_tagged_memory(util::TaggedMemoryInterface *tagged_memory) {
tagged_memory_ = tagged_memory;
}
util::TaggedMemoryInterface *tagged_memory() const { return tagged_memory_; }
@@ -387,7 +385,6 @@
uint64_t max_physical_address_;
uint64_t min_physical_address_ = 0;
int num_tags_per_load_;
- util::TaggedMemoryInterface *owned_tagged_memory_ = nullptr;
util::TaggedMemoryInterface *tagged_memory_;
util::AtomicMemoryOpInterface *atomic_tagged_memory_;
RiscVCsrSet *csr_set_;
diff --git a/cheriot/cheriot_top.cc b/cheriot/cheriot_top.cc
index a8b7221..5321f0d 100644
--- a/cheriot/cheriot_top.cc
+++ b/cheriot/cheriot_top.cc
@@ -38,6 +38,7 @@
#include "cheriot/riscv_cheriot_register_aliases.h"
#include "mpact/sim/generic/component.h"
#include "mpact/sim/generic/core_debug_interface.h"
+#include "mpact/sim/generic/counters.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/generic/decode_cache.h"
#include "mpact/sim/generic/type_helpers.h"
@@ -62,71 +63,11 @@
using EC = ::mpact::sim::cheriot::ExceptionCode;
using PB = ::mpact::sim::cheriot::CheriotRegister::PermissionBits;
-CheriotTop::CheriotTop(std::string name)
+CheriotTop::CheriotTop(std::string name, CheriotState *state,
+ CheriotDecoder *decoder)
: Component(name),
- owns_memory_(true),
- counter_num_instructions_("num_instructions", 0),
- counter_num_cycles_("num_cycles", 0),
- counter_pc_("pc", 0),
- cap_reg_re_{
- R"((\w+)\.(top|base|length|tag|permissions|object_type|reserved))"} {
- data_memory_ = new util::TaggedFlatDemandMemory(8);
- inst_memory_ = data_memory_;
- Initialize();
-}
-
-CheriotTop::CheriotTop(std::string name, util::TaggedMemoryInterface *memory)
- : Component(name),
- inst_memory_(memory),
- data_memory_(memory),
- atomic_memory_(nullptr),
- owns_memory_(false),
- counter_num_instructions_("num_instructions", 0),
- counter_num_cycles_("num_cycles", 0),
- counter_pc_("pc", 0),
- cap_reg_re_{
- R"((\w+)\.(top|base|length|tag|permissions|object_type|reserved))"} {
- Initialize();
-}
-
-CheriotTop::CheriotTop(std::string name, util::MemoryInterface *inst_memory,
- util::TaggedMemoryInterface *data_memory)
- : Component(name),
- inst_memory_(inst_memory),
- data_memory_(data_memory),
- atomic_memory_(nullptr),
- owns_memory_(false),
- counter_num_instructions_("num_instructions", 0),
- counter_num_cycles_("num_cycles", 0),
- counter_pc_("pc", 0),
- cap_reg_re_{
- R"((\w+)\.(top|base|length|tag|permissions|object_type|reserved))"} {
- Initialize();
-}
-
-CheriotTop::CheriotTop(std::string name, util::TaggedMemoryInterface *memory,
- util::MemoryInterface *atomic_memory_if)
- : Component(name),
- inst_memory_(memory),
- data_memory_(memory),
- atomic_memory_if_(atomic_memory_if),
- owns_memory_(false),
- counter_num_instructions_("num_instructions", 0),
- counter_num_cycles_("num_cycles", 0),
- counter_pc_("pc", 0),
- cap_reg_re_{
- R"((\w+)\.(top|base|length|tag|permissions|object_type|reserved))"} {
- Initialize();
-}
-
-CheriotTop::CheriotTop(std::string name, util::MemoryInterface *inst_memory,
- util::TaggedMemoryInterface *data_memory,
- util::MemoryInterface *atomic_memory_if)
- : Component(name),
- inst_memory_(inst_memory),
- data_memory_(data_memory),
- atomic_memory_if_(atomic_memory_if),
- owns_memory_(false),
+ state_(state),
+ cheriot_decoder_(decoder),
counter_num_instructions_("num_instructions", 0),
counter_num_cycles_("num_cycles", 0),
counter_pc_("pc", 0),
@@ -148,32 +89,35 @@
delete rv_bp_manager_;
delete cheriot_decode_cache_;
- delete cheriot_decoder_;
- delete state_;
- delete tagged_watcher_;
- delete atomic_watcher_;
delete atomic_memory_;
- if (owns_memory_) delete inst_memory_;
+ delete tagged_watcher_;
+ delete memory_watcher_;
}
void CheriotTop::Initialize() {
- // Create the simulation state.
- tagged_watcher_ = new util::TaggedMemoryWatcher(data_memory_);
- atomic_watcher_ = new util::MemoryWatcher(atomic_memory_if_);
- atomic_memory_ = new util::AtomicMemory(atomic_watcher_);
- state_ = new CheriotState(kCheriotName, tagged_watcher_, atomic_memory_);
+ // Create the watchers.
+ auto *memory = static_cast<util::MemoryInterface *>(state_->tagged_memory());
+ tagged_watcher_ = new util::TaggedMemoryWatcher(state_->tagged_memory());
+ memory_watcher_ = new util::MemoryWatcher(memory);
+
+ atomic_memory_ = new util::AtomicMemory(memory_watcher_);
+ state_->set_tagged_memory(tagged_watcher_);
+ state_->set_atomic_tagged_memory(atomic_memory_);
+
pcc_ = static_cast<CheriotRegister *>(
state_->registers()->at(CheriotState::kPcName));
- // Set up the decoder and decode cache.
- cheriot_decoder_ = new CheriotDecoder(state_, inst_memory_);
- // Register instruction opcode counters.
- for (int i = 0; i < static_cast<int>(isa32::OpcodeEnum::kPastMaxValue); i++) {
- counter_opcode_[i].Initialize(absl::StrCat("num_", isa32::kOpcodeNames[i]),
- 0);
+
+ // Register opcode counters.
+ int num_opcodes = cheriot_decoder_->GetNumOpcodes();
+ counter_opcode_.resize(num_opcodes);
+ for (int i = 0; i < num_opcodes; i++) {
+ counter_opcode_.push_back(generic::SimpleCounter<uint64_t>());
+ counter_opcode_[i].Initialize(
+ absl::StrCat("num_", cheriot_decoder_->GetOpcodeName(i)), 0);
CHECK_OK(AddCounter(&counter_opcode_[i]))
- << absl::StrCat("Failed to register opcode counter for :'",
- isa32::kOpcodeNames[i], "'");
+ << "Failed to register opcode counter";
}
+
cheriot_decode_cache_ =
generic::DecodeCache::Create({16 * 1024, 2}, cheriot_decoder_);
// Register instruction counter.
@@ -184,8 +128,8 @@
// Breakpoints.
rv_action_point_manager_ = new riscv::RiscVActionPointManager(
- inst_memory_, absl::bind_front(&generic::DecodeCache::Invalidate,
- cheriot_decode_cache_));
+ memory, absl::bind_front(&generic::DecodeCache::Invalidate,
+ cheriot_decode_cache_));
rv_bp_manager_ = new riscv::RiscVBreakpointManager(
rv_action_point_manager_,
[this](HaltReason halt_reason) { RequestHalt(halt_reason, nullptr); });
@@ -231,21 +175,25 @@
}
bool CheriotTop::ExecuteInstruction(Instruction *inst) {
+ // Check that pcc has tag set.
if (!pcc_->tag()) {
state_->HandleCheriRegException(inst, inst->address(),
EC::kCapExTagViolation, pcc_);
return true;
}
+ // Check that pcc has execute permission.
if (!pcc_->HasPermission(PB::kPermitExecute)) {
state_->HandleCheriRegException(inst, inst->address(),
EC::kCapExPermitExecuteViolation, pcc_);
return true;
}
+ // Check that pcc is within bounds.
if (!pcc_->IsInBounds(inst->address(), inst->size())) {
state_->HandleCheriRegException(inst, inst->address(),
EC::kCapExBoundsViolation, pcc_);
return true;
}
+ // Execute the instruction.
inst->Execute(nullptr);
counter_pc_.SetValue(inst->address());
// Comment out instruction logging during execution.
@@ -859,7 +807,7 @@
});
if (!rd_tagged_status.ok()) return rd_tagged_status;
- auto rd_atomic_status = atomic_watcher_->SetLoadWatchCallback(
+ auto rd_atomic_status = memory_watcher_->SetLoadWatchCallback(
util::MemoryWatcher::AddressRange(address, address + length - 1),
[this](uint64_t address, int size) {
set_halt_string(absl::StrFormat(
@@ -885,12 +833,12 @@
if (access_type == AccessType::kLoadStore) {
// Error recovery - ignore return value.
(void)tagged_watcher_->ClearLoadWatchCallback(address);
- (void)atomic_watcher_->ClearLoadWatchCallback(address);
+ (void)memory_watcher_->ClearLoadWatchCallback(address);
}
return wr_tagged_status;
}
- auto wr_atomic_status = atomic_watcher_->SetStoreWatchCallback(
+ auto wr_atomic_status = memory_watcher_->SetStoreWatchCallback(
util::MemoryWatcher::AddressRange(address, address + length - 1),
[this](uint64_t address, int size) {
set_halt_string(absl::StrFormat(
@@ -902,7 +850,7 @@
(void)tagged_watcher_->ClearStoreWatchCallback(address);
if (access_type == AccessType::kLoadStore) {
(void)tagged_watcher_->ClearLoadWatchCallback(address);
- (void)atomic_watcher_->ClearLoadWatchCallback(address);
+ (void)memory_watcher_->ClearLoadWatchCallback(address);
}
return wr_atomic_status;
}
@@ -917,7 +865,7 @@
auto rd_tagged_status = tagged_watcher_->ClearLoadWatchCallback(address);
if (!rd_tagged_status.ok()) return rd_tagged_status;
- auto rd_atomic_status = atomic_watcher_->ClearLoadWatchCallback(address);
+ auto rd_atomic_status = memory_watcher_->ClearLoadWatchCallback(address);
if (!rd_atomic_status.ok()) return rd_atomic_status;
}
if ((access_type == AccessType::kStore) ||
@@ -925,7 +873,7 @@
auto wr_tagged_status = tagged_watcher_->ClearStoreWatchCallback(address);
if (!wr_tagged_status.ok()) return wr_tagged_status;
- auto wr_atomic_status = atomic_watcher_->ClearStoreWatchCallback(address);
+ auto wr_atomic_status = memory_watcher_->ClearStoreWatchCallback(address);
if (!wr_atomic_status.ok()) return wr_atomic_status;
}
return absl::OkStatus();
diff --git a/cheriot/cheriot_top.h b/cheriot/cheriot_top.h
index 98d0421..4fc8d17 100644
--- a/cheriot/cheriot_top.h
+++ b/cheriot/cheriot_top.h
@@ -20,6 +20,7 @@
#include <cstddef>
#include <cstdint>
#include <string>
+#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
@@ -27,6 +28,7 @@
#include "absl/status/statusor.h"
#include "absl/synchronization/notification.h"
#include "cheriot/cheriot_debug_interface.h"
+#include "cheriot/cheriot_decoder.h"
#include "cheriot/cheriot_register.h"
#include "cheriot/cheriot_state.h"
#include "cheriot/riscv_cheriot_enums.h"
@@ -63,22 +65,7 @@
using RunStatus = generic::CoreDebugInterface::RunStatus;
using HaltReason = generic::CoreDebugInterface::HaltReason;
- // Simple constructor, the memories are created and owned by the CheriotTop
- // instance.
- explicit CheriotTop(std::string name);
- // Constructors without the atomic memory interface. Either one (unified),
- // or two (inst and data) interfaces are passed in.
- CheriotTop(std::string name, util::TaggedMemoryInterface *memory);
- CheriotTop(std::string name, util::MemoryInterface *inst_memory,
- util::TaggedMemoryInterface *data_memory);
- // Constructors with the memory interface to be used with atomic memory
- // operations. Either one (unified), or two (inst and data) interfaces are
- // passed in.
- CheriotTop(std::string name, util::TaggedMemoryInterface *memory,
- util::MemoryInterface *atomic_memory_if);
- CheriotTop(std::string name, util::MemoryInterface *inst_memory,
- util::TaggedMemoryInterface *data_memory,
- util::MemoryInterface *atomic_memory_if);
+ CheriotTop(std::string name, CheriotState *state, CheriotDecoder *decoder);
~CheriotTop() override;
// Methods inherited from CoreDebugInterface.
@@ -138,8 +125,6 @@
// Accessors.
CheriotState *state() const { return state_; }
- util::TaggedMemoryInterface *data_memory() const { return data_memory_; }
- util::MemoryInterface *inst_memory() const { return inst_memory_; }
// The following are not const as callers may need to call non-const methods
// of the counter.
generic::SimpleCounter<uint64_t> *counter_num_instructions() {
@@ -151,7 +136,7 @@
generic::SimpleCounter<uint64_t> *counter_pc() { return &counter_pc_; }
// Memory watchers used for data watch points.
util::TaggedMemoryWatcher *tagged_watcher() { return tagged_watcher_; }
- util::MemoryWatcher *atomic_watcher() { return atomic_watcher_; }
+ util::MemoryWatcher *memory_watcher() { return memory_watcher_; }
const std::string &halt_string() const { return halt_string_; }
void set_halt_string(std::string halt_string) { halt_string_ = halt_string; }
@@ -192,13 +177,9 @@
generic::DecoderInterface *cheriot_decoder_ = nullptr;
// Decode cache, memory and memory watcher.
generic::DecodeCache *cheriot_decode_cache_ = nullptr;
- util::MemoryInterface *inst_memory_ = nullptr;
- util::TaggedMemoryInterface *data_memory_ = nullptr;
- util::MemoryInterface *atomic_memory_if_ = nullptr;
util::AtomicMemoryOpInterface *atomic_memory_ = nullptr;
- bool owns_memory_ = false;
util::TaggedMemoryWatcher *tagged_watcher_ = nullptr;
- util::MemoryWatcher *atomic_watcher_ = nullptr;
+ util::MemoryWatcher *memory_watcher_ = nullptr;
// Branch trace info - uses a circular buffer. The size is defined by the
// constant kBranchTraceSize in the .cc file.
BranchTraceEntry *branch_trace_;
@@ -211,8 +192,7 @@
int branch_trace_mask_ = kBranchTraceSize - 1;
int branch_trace_size_ = kBranchTraceSize;
// Counter for the number of instructions simulated.
- generic::SimpleCounter<uint64_t>
- counter_opcode_[*isa32::OpcodeEnum::kPastMaxValue];
+ std::vector<generic::SimpleCounter<uint64_t>> counter_opcode_;
generic::SimpleCounter<uint64_t> counter_num_instructions_;
generic::SimpleCounter<uint64_t> counter_num_cycles_;
// Counter used for profiling by connecting it to a profiler. This allows
diff --git a/cheriot/mpact_cheriot.cc b/cheriot/mpact_cheriot.cc
index 65dce13..9174c63 100644
--- a/cheriot/mpact_cheriot.cc
+++ b/cheriot/mpact_cheriot.cc
@@ -39,6 +39,7 @@
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
+#include "cheriot/cheriot_decoder.h"
#include "cheriot/cheriot_instrumentation_control.h"
#include "cheriot/cheriot_top.h"
#include "cheriot/debug_command_shell.h"
@@ -63,9 +64,11 @@
#include "riscv//riscv_clint.h"
#include "src/google/protobuf/text_format.h"
-using ::mpact::sim::proto::ComponentData;
using AddressRange = mpact::sim::util::MemoryWatcher::AddressRange;
+using ::mpact::sim::cheriot::CheriotDecoder;
using ::mpact::sim::cheriot::CheriotInstrumentationControl;
+using ::mpact::sim::cheriot::CheriotState;
+using ::mpact::sim::proto::ComponentData;
using ::mpact::sim::util::InstructionProfiler;
using ::mpact::sim::util::TaggedMemoryUseProfiler;
@@ -251,8 +254,12 @@
memory_use_profiler->set_is_enabled(false);
data_memory = memory_use_profiler;
}
- CheriotTop cheriot_top("Cheriot", static_cast<MemoryInterface *>(router),
- data_memory, static_cast<MemoryInterface *>(router));
+ CheriotState cheriot_state("CherIoT", data_memory,
+ static_cast<AtomicMemoryOpInterface *>(router));
+ CheriotDecoder cheriot_decoder(&cheriot_state,
+ static_cast<MemoryInterface *>(router));
+
+ CheriotTop cheriot_top("Cheriot", &cheriot_state, &cheriot_decoder);
// Enable instruction profiling if the flag is set.
InstructionProfiler *inst_profiler = nullptr;
@@ -343,9 +350,10 @@
}
// Set up semihosting.
- auto *semihost = new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord32,
- cheriot_top.inst_memory(),
- cheriot_top.data_memory());
+ auto *memory = static_cast<MemoryInterface *>(router);
+ auto *semihost =
+ new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord32, memory, memory);
+
cheriot_top.state()->AddEbreakHandler([semihost](const Instruction *inst) {
if (semihost->IsSemihostingCall(inst)) {
semihost->OnEBreak(inst);
diff --git a/cheriot/test/BUILD b/cheriot/test/BUILD
index bcac027..c4920c9 100644
--- a/cheriot/test/BUILD
+++ b/cheriot/test/BUILD
@@ -16,27 +16,6 @@
package(default_applicable_licenses = ["//:license"])
-cc_library(
- name = "riscv_cheriot_fp_test_base",
- testonly = True,
- hdrs = ["riscv_cheriot_fp_test_base.h"],
- copts = [
- "-ffp-model=strict",
- "-fprotect-parens",
- ],
- tags = ["not_run:arm"],
- deps = [
- "//cheriot:riscv_cheriot",
- "@com_google_absl//absl/random",
- "@com_google_absl//absl/strings",
- "@com_google_absl//absl/types:span",
- "@com_google_googletest//:gtest_for_library_testonly",
- "@com_google_mpact-riscv//riscv:riscv_state",
- "@com_google_mpact-sim//mpact/sim/generic:instruction",
- "@com_google_mpact-sim//mpact/sim/util/memory",
- ],
-)
-
cc_test(
name = "cheriot_register_test",
size = "small",
@@ -102,6 +81,7 @@
"@com_google_mpact-sim//mpact/sim/generic:core",
"@com_google_mpact-sim//mpact/sim/generic:instruction",
"@com_google_mpact-sim//mpact/sim/generic:type_helpers",
+ "@com_google_mpact-sim//mpact/sim/util/memory",
],
)
@@ -118,6 +98,7 @@
"@com_google_mpact-sim//mpact/sim/generic:core",
"@com_google_mpact-sim//mpact/sim/generic:instruction",
"@com_google_mpact-sim//mpact/sim/generic:type_helpers",
+ "@com_google_mpact-sim//mpact/sim/util/memory",
],
)
@@ -137,6 +118,7 @@
"@com_google_mpact-riscv//riscv:riscv_state",
"@com_google_mpact-sim//mpact/sim/generic:core",
"@com_google_mpact-sim//mpact/sim/generic:instruction",
+ "@com_google_mpact-sim//mpact/sim/util/memory",
],
)
@@ -152,6 +134,7 @@
"//cheriot:riscv_cheriot_isa",
"@com_google_googletest//:gtest_main",
"@com_google_mpact-sim//mpact/sim/generic:type_helpers",
+ "@com_google_mpact-sim//mpact/sim/util/memory",
],
)
diff --git a/cheriot/test/cheriot_state_test.cc b/cheriot/test/cheriot_state_test.cc
index 28c0c04..85c728e 100644
--- a/cheriot/test/cheriot_state_test.cc
+++ b/cheriot/test/cheriot_state_test.cc
@@ -30,6 +30,7 @@
using ::mpact::sim::cheriot::CheriotRegister;
using ::mpact::sim::cheriot::CheriotState;
+using ::mpact::sim::util::TaggedFlatDemandMemory;
using RVEC = ::mpact::sim::riscv::ExceptionCode;
constexpr int kPcValue = 0x1000;
@@ -40,7 +41,9 @@
// additional functionality over the ArchState class.
TEST(CheriotStateTest, Basic) {
- auto *state = new CheriotState("test");
+ TaggedFlatDemandMemory mem(8);
+
+ auto *state = new CheriotState("test", &mem, nullptr);
// Make sure pc has been created.
auto iter = state->registers()->find("pcc");
auto *ptr = (iter != state->registers()->end()) ? iter->second : nullptr;
@@ -56,7 +59,9 @@
}
TEST(CheriotStateTest, Memory) {
- auto *state = new CheriotState("test");
+ TaggedFlatDemandMemory mem(8);
+
+ auto *state = new CheriotState("test", &mem, nullptr);
auto *db = state->db_factory()->Allocate<uint32_t>(1);
state->LoadMemory(nullptr, kMemAddr, db, nullptr, nullptr);
EXPECT_EQ(db->Get<uint32_t>(0), 0);
@@ -70,7 +75,9 @@
}
TEST(CheriotStateTest, OutOfBoundLoad) {
- auto *state = new CheriotState("test");
+ TaggedFlatDemandMemory mem(8);
+
+ auto *state = new CheriotState("test", &mem, nullptr);
state->set_max_physical_address(kMemAddr - 4);
state->set_on_trap([](bool is_interrupt, uint64_t trap_value,
uint64_t exception_code, uint64_t epc,
diff --git a/cheriot/test/riscv_cheriot_encoding_test.cc b/cheriot/test/riscv_cheriot_encoding_test.cc
index 2f941e7..31604ba 100644
--- a/cheriot/test/riscv_cheriot_encoding_test.cc
+++ b/cheriot/test/riscv_cheriot_encoding_test.cc
@@ -20,15 +20,17 @@
#include "cheriot/riscv_cheriot_enums.h"
#include "googlemock/include/gmock/gmock.h"
#include "mpact/sim/generic/type_helpers.h"
+#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
namespace {
using ::mpact::sim::cheriot::CheriotState;
using ::mpact::sim::cheriot::isa32::kOpcodeNames;
using ::mpact::sim::cheriot::isa32::RiscVCheriotEncoding;
+using ::mpact::sim::generic::operator*; // NOLINT: is used below (clang error).
+using ::mpact::sim::util::TaggedFlatDemandMemory;
using SlotEnum = mpact::sim::cheriot::isa32::SlotEnum;
using OpcodeEnum = mpact::sim::cheriot::isa32::OpcodeEnum;
-using ::mpact::sim::generic::operator*; // NOLINT: is used below (clang error).
// Constexpr for opcodes for RV32 CHERIoT instructions grouped by isa group.
@@ -186,14 +188,17 @@
class RiscVCheriotEncodingTest : public testing::Test {
protected:
RiscVCheriotEncodingTest() {
- state_ = new CheriotState("test");
+ mem_ = new TaggedFlatDemandMemory(8);
+ state_ = new CheriotState("test", mem_, nullptr);
enc_ = new RiscVCheriotEncoding(state_);
}
~RiscVCheriotEncodingTest() override {
delete enc_;
+ delete mem_;
delete state_;
}
+ TaggedFlatDemandMemory *mem_;
CheriotState *state_;
RiscVCheriotEncoding *enc_;
};
diff --git a/cheriot/test/riscv_cheriot_fp_test_base.h b/cheriot/test/riscv_cheriot_fp_test_base.h
deleted file mode 100644
index b47923d..0000000
--- a/cheriot/test/riscv_cheriot_fp_test_base.h
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Copyright 2024 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MPACT_CHERIOT___TEST_RISCV_CHERIOT_FP_TEST_BASE_H_
-#define MPACT_CHERIOT___TEST_RISCV_CHERIOT_FP_TEST_BASE_H_
-
-#include <cmath>
-#include <cstdint>
-#include <functional>
-#include <ios>
-#include <limits>
-#include <string>
-#include <tuple>
-#include <type_traits>
-#include <vector>
-
-#include "absl/random/random.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-#include "cheriot/cheriot_register.h"
-#include "cheriot/cheriot_state.h"
-#include "cheriot/riscv_cheriot_fp_state.h"
-#include "googlemock/include/gmock/gmock.h"
-#include "mpact/sim/generic/instruction.h"
-#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
-#include "riscv//riscv_fp_host.h"
-#include "riscv//riscv_fp_info.h"
-#include "riscv//riscv_register.h"
-
-namespace mpact {
-namespace sim {
-namespace cheriot {
-namespace test {
-
-using ::mpact::sim::cheriot::CheriotRegister;
-using ::mpact::sim::cheriot::CheriotState;
-using ::mpact::sim::cheriot::RiscVCheriotFPState;
-using ::mpact::sim::generic::Instruction;
-using ::mpact::sim::riscv::FPRoundingMode;
-using ::mpact::sim::riscv::RV64Register;
-using ::mpact::sim::riscv::RVFpRegister;
-using ::mpact::sim::riscv::ScopedFPRoundingMode;
-using ::mpact::sim::riscv::ScopedFPStatus;
-using ::mpact::sim::util::TaggedFlatDemandMemory;
-
-constexpr int kTestValueLength = 256;
-
-constexpr uint32_t kInstAddress = 0x1000;
-constexpr uint32_t kDataLoadAddress = 0x1'0000;
-constexpr uint32_t kDataStoreAddress = 0x2'0000;
-
-// Templated helper structs to provide information about floating point types.
-template <typename T>
-struct FPTypeInfo {
- using IntType = T;
- static const int kBitSize = 8 * sizeof(T);
- static const int kExpSize = 0;
- static const int kSigSize = 0;
- static bool IsNaN(T value) { return false; }
- static constexpr IntType kQNaN = 0;
- static constexpr IntType kSNaN = 0;
- static constexpr IntType kPosInf = std::numeric_limits<T>::max();
- static constexpr IntType kNegInf = std::numeric_limits<T>::min();
- static constexpr IntType kPosZero = 0;
- static constexpr IntType kNegZero = 0;
- static constexpr IntType kPosDenorm = 0;
- static constexpr IntType kNegDenorm = 0;
-};
-
-template <>
-struct FPTypeInfo<float> {
- using T = float;
- using IntType = uint32_t;
- static const int kExpBias = 127;
- static const int kBitSize = sizeof(float) << 3;
- static const int kExpSize = 8;
- static const int kSigSize = kBitSize - kExpSize - 1;
- static const IntType kExpMask = ((1ULL << kExpSize) - 1) << kSigSize;
- static const IntType kSigMask = (1ULL << kSigSize) - 1;
- static const IntType kQNaN = kExpMask | (1ULL << (kSigSize - 1)) | 1;
- static const IntType kSNaN = kExpMask | 1;
- static const IntType kPosInf = kExpMask;
- static const IntType kNegInf = kExpMask | (1ULL << (kBitSize - 1));
- static const IntType kPosZero = 0;
- static const IntType kNegZero = 1ULL << (kBitSize - 1);
- static const IntType kPosDenorm = 1ULL << (kSigSize - 2);
- static const IntType kNegDenorm =
- (1ULL << (kBitSize - 1)) | (1ULL << (kSigSize - 2));
- static const IntType kCanonicalNaN = 0x7fc0'0000ULL;
- static bool IsNaN(T value) { return std::isnan(value); }
-};
-
-template <>
-struct FPTypeInfo<double> {
- using T = double;
- using IntType = uint64_t;
- static const int kExpBias = 1023;
- static const int kBitSize = sizeof(double) << 3;
- static const int kExpSize = 11;
- static const int kSigSize = kBitSize - kExpSize - 1;
- static const IntType kExpMask = ((1ULL << kExpSize) - 1) << kSigSize;
- static const IntType kSigMask = (1ULL << kSigSize) - 1;
- static const IntType kQNaN = kExpMask | (1ULL << (kSigSize - 1)) | 1;
- static const IntType kSNaN = kExpMask | 1;
- static const IntType kPosInf = kExpMask;
- static const IntType kNegInf = kExpMask | (1ULL << (kBitSize - 1));
- static const IntType kPosZero = 0;
- static const IntType kNegZero = 1ULL << (kBitSize - 1);
- static const IntType kPosDenorm = 1ULL << (kSigSize - 2);
- static const IntType kNegDenorm =
- (1ULL << (kBitSize - 1)) | (1ULL << (kSigSize - 2));
- static const IntType kCanonicalNaN = 0x7ff8'0000'0000'0000ULL;
- static bool IsNaN(T value) { return std::isnan(value); }
-};
-
-// Templated helper function for classifying fp numbers.
-template <typename T>
-typename FPTypeInfo<T>::IntType VfclassVHelper(T val) {
- auto fp_class = fpclassify(val);
- switch (fp_class) {
- case FP_INFINITE:
- return std::signbit(val) ? 1 : 1 << 7;
- case FP_NAN: {
- auto uint_val =
- *reinterpret_cast<typename FPTypeInfo<T>::IntType *>(&val);
- bool quiet_nan = (uint_val >> (FPTypeInfo<T>::kSigSize - 1)) & 1;
- return quiet_nan ? 1 << 9 : 1 << 8;
- }
- case FP_ZERO:
- return std::signbit(val) ? 1 << 3 : 1 << 4;
- case FP_SUBNORMAL:
- return std::signbit(val) ? 1 << 2 : 1 << 5;
- case FP_NORMAL:
- return std::signbit(val) ? 1 << 1 : 1 << 6;
- }
- return 0;
-}
-
-// These templated functions allow for comparison of values with a tolerance
-// given for floating point types. The tolerance is stated as the bit position
-// in the mantissa of the op, with 0 being the msb of the mantissa. If the
-// bit position is beyond the mantissa, a comparison of equal is performed.
-template <typename T>
-inline void FPCompare(T op, T reg, int, absl::string_view str) {
- EXPECT_EQ(reg, op) << str;
-}
-
-template <>
-inline void FPCompare<float>(float op, float reg, int delta_position,
- absl::string_view str) {
- using T = float;
- using UInt = typename FPTypeInfo<T>::IntType;
- UInt u_op = *reinterpret_cast<UInt *>(&op);
- UInt u_reg = *reinterpret_cast<UInt *>(®);
- if (!std::isnan(op) && !std::isinf(op) &&
- delta_position < FPTypeInfo<T>::kSigSize) {
- T delta;
- UInt exp = FPTypeInfo<T>::kExpMask >> FPTypeInfo<T>::kSigSize;
- if (exp > delta_position) {
- exp -= delta_position;
- UInt udelta = exp << FPTypeInfo<T>::kSigSize;
- delta = *reinterpret_cast<T *>(&udelta);
- } else {
- // Becomes a denormal
- int diff = delta_position - exp;
- UInt udelta = 1ULL << (FPTypeInfo<T>::kSigSize - 1 - diff);
- delta = *reinterpret_cast<T *>(&udelta);
- }
- EXPECT_THAT(reg, testing::NanSensitiveFloatNear(op, delta))
- << str << " op: " << std::hex << u_op << " reg: " << std::hex
- << u_reg;
- } else {
- EXPECT_THAT(reg, testing::NanSensitiveFloatEq(op))
- << str << " op: " << std::hex << u_op << " reg: " << std::hex
- << u_reg;
- }
-}
-
-template <>
-inline void FPCompare<double>(double op, double reg, int delta_position,
- absl::string_view str) {
- using T = double;
- using UInt = typename FPTypeInfo<T>::IntType;
- UInt u_op = *reinterpret_cast<UInt *>(&op);
- UInt u_reg = *reinterpret_cast<UInt *>(®);
- if (!std::isnan(op) && !std::isinf(op) &&
- delta_position < FPTypeInfo<T>::kSigSize) {
- T delta;
- UInt exp = FPTypeInfo<T>::kExpMask >> FPTypeInfo<T>::kSigSize;
- if (exp > delta_position) {
- exp -= delta_position;
- UInt udelta = exp << FPTypeInfo<T>::kSigSize;
- delta = *reinterpret_cast<T *>(&udelta);
- } else {
- // Becomes a denormal
- int diff = delta_position - exp;
- UInt udelta = 1ULL << (FPTypeInfo<T>::kSigSize - 1 - diff);
- delta = *reinterpret_cast<T *>(&udelta);
- }
- EXPECT_THAT(reg, testing::NanSensitiveDoubleNear(op, delta))
- << str << " op: " << std::hex << u_op << " reg: " << std::hex
- << u_reg;
- } else {
- EXPECT_THAT(reg, testing::NanSensitiveDoubleEq(op))
- << str << " op: " << std::hex << u_op << " reg: " << std::hex
- << u_reg;
- }
-}
-
-template <typename FP>
-FP OptimizationBarrier(FP op) {
- asm volatile("" : "+X"(op));
- return op;
-}
-
-namespace internal {
-
-// These are predicates used in the following NaNBox function definitions, as
-// part of the enable_if construct.
-template <typename S, typename D>
-struct EqualSize {
- static const bool value = sizeof(S) == sizeof(D) &&
- std::is_floating_point<S>::value &&
- std::is_integral<D>::value;
-};
-
-template <typename S, typename D>
-struct GreaterSize {
- static const bool value =
- sizeof(S) > sizeof(D) &&
- std::is_floating_point<S>::value &&std::is_integral<D>::value;
-};
-
-template <typename S, typename D>
-struct LessSize {
- static const bool value = sizeof(S) < sizeof(D) &&
- std::is_floating_point<S>::value &&
- std::is_integral<D>::value;
-};
-
-} // namespace internal
-
-// Template functions to NaN box a floating point value when being assigned
-// to a wider register. The first version places a smaller floating point value
-// in a NaN box (all upper bits in the word are set to 1).
-
-// Enable_if is used to select the proper implementation for different S and D
-// type combinations. It uses the SFINAE (substitution failure is not an error)
-// "feature" of C++ to hide the implementation that don't match the predicate
-// from being resolved.
-
-template <typename S, typename D>
-inline typename std::enable_if<internal::LessSize<S, D>::value, D>::type NaNBox(
- S value) {
- using SInt = typename FPTypeInfo<S>::IntType;
- SInt sval = *reinterpret_cast<SInt *>(&value);
- D dval = (~static_cast<D>(0) << (sizeof(S) * 8)) | sval;
- return *reinterpret_cast<D *>(&dval);
-}
-
-// This version does a straight copy - as the data types are the same size.
-template <typename S, typename D>
-inline typename std::enable_if<internal::EqualSize<S, D>::value, D>::type
-NaNBox(S value) {
- return *reinterpret_cast<D *>(&value);
-}
-
-// Signal error if the register is smaller than the floating point value.
-template <typename S, typename D>
-inline typename std::enable_if<internal::GreaterSize<S, D>::value, D>::type
-NaNBox(S value) {
- // No return statement, so error will be reported.
-}
-
-class RiscVFPInstructionTestBase : public testing::Test {
- public:
- RiscVFPInstructionTestBase() {
- memory_ = new TaggedFlatDemandMemory(8);
- state_ = new CheriotState("test", memory_);
- rv_fp_ = new RiscVCheriotFPState(state_);
- state_->set_rv_fp(rv_fp_);
- instruction_ = new Instruction(kInstAddress, state_);
- instruction_->set_size(4);
- child_instruction_ = new Instruction(kInstAddress, state_);
- child_instruction_->set_size(4);
- // Initialize a portion of memory with a known pattern.
- auto *db = state_->db_factory()->Allocate(8192);
- auto span = db->Get<uint8_t>();
- for (int i = 0; i < 8192; i++) {
- span[i] = i & 0xff;
- }
- memory_->Store(kDataLoadAddress - 4096, db);
- db->DecRef();
- for (int i = 1; i < 32; i++) {
- creg_[i] =
- state_->GetRegister<CheriotRegister>(absl::StrCat("c", i)).first;
- }
- for (int i = 1; i < 32; i++) {
- freg_[i] = state_->GetRegister<RVFpRegister>(absl::StrCat("f", i)).first;
- }
- for (int i = 1; i < 32; i++) {
- dreg_[i] = state_->GetRegister<RVFpRegister>(absl::StrCat("d", i)).first;
- }
- }
- ~RiscVFPInstructionTestBase() override {
- delete rv_fp_;
- rv_fp_ = nullptr;
- state_->set_rv_fp(nullptr);
- delete state_;
- state_ = nullptr;
- if (instruction_ != nullptr) instruction_->DecRef();
- instruction_ = nullptr;
- if (child_instruction_ != nullptr) child_instruction_->DecRef();
- child_instruction_ = nullptr;
- delete memory_;
- memory_ = nullptr;
- }
-
- // Clear the instruction instance and allocate a new one.
- void ResetInstruction() {
- instruction_->DecRef();
- instruction_ = new Instruction(kInstAddress, state_);
- instruction_->set_size(4);
- }
-
- // Creates source and destination scalar register operands for the registers
- // named in the two vectors and append them to the given instruction.
- void AppendRegisterOperands(Instruction *inst,
- const std::vector<std::string> &sources,
- const std::vector<std::string> &destinations) {
- for (auto ®_name : sources) {
- auto *reg = state_->GetRegister<CheriotRegister>(reg_name).first;
- inst->AppendSource(reg->CreateSourceOperand());
- }
- for (auto ®_name : destinations) {
- auto *reg = state_->GetRegister<CheriotRegister>(reg_name).first;
- inst->AppendDestination(reg->CreateDestinationOperand(0));
- }
- }
-
- // Creates source and destination scalar register operands for the registers
- // named in the two vectors and append them to the default instruction.
- void AppendRegisterOperands(const std::vector<std::string> &sources,
- const std::vector<std::string> &destinations) {
- AppendRegisterOperands(instruction_, sources, destinations);
- }
-
- // named register and sets it to the corresponding value.
- template <typename T, typename RegisterType = CheriotRegister>
- void SetRegisterValues(
- const std::vector<std::tuple<std::string, const T>> &values) {
- for (auto &[reg_name, value] : values) {
- auto *reg = state_->GetRegister<RegisterType>(reg_name).first;
- auto *db =
- state_->db_factory()->Allocate<typename RegisterType::ValueType>(1);
- db->template Set<T>(0, value);
- reg->SetDataBuffer(db);
- db->DecRef();
- }
- }
-
- // Initializes the semantic function of the instruction object.
- void SetSemanticFunction(Instruction *inst,
- Instruction::SemanticFunction fcn) {
- inst->set_semantic_function(fcn);
- }
-
- // Initializes the semantic function for the default instruction.
- void SetSemanticFunction(Instruction::SemanticFunction fcn) {
- instruction_->set_semantic_function(fcn);
- }
-
- // Sets the default child instruction as the child of the default instruction.
- void SetChildInstruction() { instruction_->AppendChild(child_instruction_); }
-
- // Initializes the semantic function for the default child instruction.
- void SetChildSemanticFunction(Instruction::SemanticFunction fcn) {
- child_instruction_->set_semantic_function(fcn);
- }
-
- // Construct a random FP value by separately generating integer values for
- // sign, exponent and mantissa.
- template <typename T>
- T RandomFPValue() {
- using UInt = typename FPTypeInfo<T>::IntType;
- UInt sign = absl::Uniform(absl::IntervalClosed, bitgen_, 0ULL, 1ULL);
- UInt exp = absl::Uniform(absl::IntervalClosedOpen, bitgen_, 0ULL,
- 1ULL << FPTypeInfo<T>::kExpSize);
- UInt sig = absl::Uniform(absl::IntervalClosedOpen, bitgen_, 0ULL,
- 1ULL << FPTypeInfo<T>::kSigSize);
- UInt value = (sign & 1) << (FPTypeInfo<T>::kBitSize - 1) |
- (exp << FPTypeInfo<T>::kSigSize) | sig;
- T val = *reinterpret_cast<T *>(&value);
- return val;
- }
-
- // This method uses random values for each field in the fp number.
- template <typename T>
- void FillArrayWithRandomFPValues(absl::Span<T> span) {
- for (auto &val : span) {
- val = RandomFPValue<T>();
- }
- }
-
- template <typename R, typename LHS>
- void UnaryOpFPTestHelper(absl::string_view name, Instruction *inst,
- absl::Span<const absl::string_view> reg_prefixes,
- int delta_position,
- std::function<R(LHS)> operation) {
- using LhsRegisterType = RVFpRegister;
- using DestRegisterType = RVFpRegister;
- LHS lhs_values[kTestValueLength];
- auto lhs_span = absl::Span<LHS>(lhs_values);
- const std::string kR1Name = absl::StrCat(reg_prefixes[0], 1);
- const std::string kRdName = absl::StrCat(reg_prefixes[1], 5);
- // This is used for the rounding mode operand.
- const std::string kRmName = absl::StrCat("x", 10);
- AppendRegisterOperands({kR1Name, kRmName}, {kRdName});
- FillArrayWithRandomFPValues<LHS>(lhs_span);
- using LhsInt = typename FPTypeInfo<LHS>::IntType;
- *reinterpret_cast<LhsInt *>(&lhs_span[0]) = FPTypeInfo<LHS>::kQNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[1]) = FPTypeInfo<LHS>::kSNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[2]) = FPTypeInfo<LHS>::kPosInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[3]) = FPTypeInfo<LHS>::kNegInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[4]) = FPTypeInfo<LHS>::kPosZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[5]) = FPTypeInfo<LHS>::kNegZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[6]) = FPTypeInfo<LHS>::kPosDenorm;
- *reinterpret_cast<LhsInt *>(&lhs_span[7]) = FPTypeInfo<LHS>::kNegDenorm;
- for (int i = 0; i < kTestValueLength; i++) {
- SetRegisterValues<LHS, LhsRegisterType>({{kR1Name, lhs_span[i]}});
-
- for (int rm : {0, 1, 2, 3, 4}) {
- rv_fp_->SetRoundingMode(static_cast<FPRoundingMode>(rm));
- SetRegisterValues<int, CheriotRegister>({{kRmName, rm}});
- SetRegisterValues<R, DestRegisterType>({{kRdName, 0}});
-
- inst->Execute(nullptr);
-
- R op_val;
- {
- ScopedFPStatus set_fpstatus(rv_fp_->host_fp_interface());
- op_val = operation(lhs_span[i]);
- }
- auto reg_val = state_->GetRegister<DestRegisterType>(kRdName)
- .first->data_buffer()
- ->template Get<R>(0);
- FPCompare<R>(op_val, reg_val, delta_position,
- absl::StrCat(name, " ", i, ": ", lhs_span[i]));
- }
- }
- }
-
- // Tester for unary instructions that produce an exception flag value.
- template <typename R, typename LHS>
- void UnaryOpWithFflagsFPTestHelper(
- absl::string_view name, Instruction *inst,
- absl::Span<const absl::string_view> reg_prefixes, int delta_position,
- std::function<std::tuple<R, uint32_t>(LHS)> operation) {
- using LhsRegisterType = RVFpRegister;
- using DestRegisterType = RVFpRegister;
- using LhsInt = typename FPTypeInfo<LHS>::IntType;
- using RInt = typename FPTypeInfo<R>::IntType;
- LHS lhs_values[kTestValueLength];
- auto lhs_span = absl::Span<LHS>(lhs_values);
- const std::string kR1Name = absl::StrCat(reg_prefixes[0], 1);
- const std::string kRdName = absl::StrCat(reg_prefixes[1], 5);
- // This is used for the rounding mode operand.
- const std::string kRmName = absl::StrCat("x", 10);
- AppendRegisterOperands({kR1Name, kRmName}, {kRdName});
- auto *flag_op = rv_fp_->fflags()->CreateSetDestinationOperand(0, "fflags");
- instruction_->AppendDestination(flag_op);
- FillArrayWithRandomFPValues<LHS>(lhs_span);
- *reinterpret_cast<LhsInt *>(&lhs_span[0]) = FPTypeInfo<LHS>::kQNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[1]) = FPTypeInfo<LHS>::kSNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[2]) = FPTypeInfo<LHS>::kPosInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[3]) = FPTypeInfo<LHS>::kNegInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[4]) = FPTypeInfo<LHS>::kPosZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[5]) = FPTypeInfo<LHS>::kNegZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[6]) = FPTypeInfo<LHS>::kPosDenorm;
- *reinterpret_cast<LhsInt *>(&lhs_span[7]) = FPTypeInfo<LHS>::kNegDenorm;
- for (int i = 0; i < kTestValueLength; i++) {
- SetRegisterValues<LHS, LhsRegisterType>({{kR1Name, lhs_span[i]}});
-
- for (int rm : {0, 1, 2, 3, 4}) {
- rv_fp_->SetRoundingMode(static_cast<FPRoundingMode>(rm));
- rv_fp_->fflags()->Write(static_cast<uint32_t>(0));
- SetRegisterValues<int, CheriotRegister>({{kRmName, rm}, {}});
- SetRegisterValues<R, DestRegisterType>({{kRdName, 0}});
-
- inst->Execute(nullptr);
- auto fflags = rv_fp_->fflags()->GetUint32();
-
- R op_val;
- uint32_t flag;
- {
- ScopedFPRoundingMode scoped_rm(rv_fp_->host_fp_interface(), rm);
- std::tie(op_val, flag) = operation(lhs_span[i]);
- }
-
- auto reg_val = state_->GetRegister<DestRegisterType>(kRdName)
- .first->data_buffer()
- ->template Get<R>(0);
- FPCompare<R>(
- op_val, reg_val, delta_position,
- absl::StrCat(name, " ", i, ": ", lhs_span[i], " rm: ", rm));
- auto lhs_uint = *reinterpret_cast<LhsInt *>(&lhs_span[i]);
- auto op_val_uint = *reinterpret_cast<RInt *>(&op_val);
- EXPECT_EQ(flag, fflags)
- << name << "(" << lhs_span[i] << ") " << std::hex << name << "(0x"
- << lhs_uint << ") == " << op_val << std::hex << " 0x"
- << op_val_uint << " rm: " << rm;
- }
- }
- }
-
- // Test helper for binary fp instructions.
- template <typename R, typename LHS, typename RHS>
- void BinaryOpFPTestHelper(absl::string_view name, Instruction *inst,
- absl::Span<const absl::string_view> reg_prefixes,
- int delta_position,
- std::function<R(LHS, RHS)> operation) {
- using LhsRegisterType = RVFpRegister;
- using RhsRegisterType = RVFpRegister;
- using DestRegisterType = RVFpRegister;
- LHS lhs_values[kTestValueLength];
- RHS rhs_values[kTestValueLength];
- auto lhs_span = absl::Span<LHS>(lhs_values);
- auto rhs_span = absl::Span<RHS>(rhs_values);
- const std::string kR1Name = absl::StrCat(reg_prefixes[0], 1);
- const std::string kR2Name = absl::StrCat(reg_prefixes[1], 2);
- const std::string kRdName = absl::StrCat(reg_prefixes[2], 5);
- // This is used for the rounding mode operand.
- const std::string kRmName = absl::StrCat("x", 10);
- AppendRegisterOperands({kR1Name, kR2Name, kRmName}, {kRdName});
- auto *flag_op = rv_fp_->fflags()->CreateSetDestinationOperand(0, "fflags");
- instruction_->AppendDestination(flag_op);
- FillArrayWithRandomFPValues<LHS>(lhs_span);
- FillArrayWithRandomFPValues<RHS>(rhs_span);
- using LhsInt = typename FPTypeInfo<LHS>::IntType;
- *reinterpret_cast<LhsInt *>(&lhs_span[0]) = FPTypeInfo<LHS>::kQNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[1]) = FPTypeInfo<LHS>::kSNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[2]) = FPTypeInfo<LHS>::kPosInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[3]) = FPTypeInfo<LHS>::kNegInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[4]) = FPTypeInfo<LHS>::kPosZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[5]) = FPTypeInfo<LHS>::kNegZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[6]) = FPTypeInfo<LHS>::kPosDenorm;
- *reinterpret_cast<LhsInt *>(&lhs_span[7]) = FPTypeInfo<LHS>::kNegDenorm;
- for (int i = 0; i < kTestValueLength; i++) {
- SetRegisterValues<LHS, LhsRegisterType>({{kR1Name, lhs_span[i]}});
- SetRegisterValues<RHS, RhsRegisterType>({{kR2Name, rhs_span[i]}});
-
- for (int rm : {0, 1, 2, 3, 4}) {
- rv_fp_->SetRoundingMode(static_cast<FPRoundingMode>(rm));
- SetRegisterValues<int, CheriotRegister>({{kRmName, rm}});
- SetRegisterValues<R, DestRegisterType>({{kRdName, 0}});
-
- inst->Execute(nullptr);
-
- R op_val;
- {
- ScopedFPStatus set_fpstatus(rv_fp_->host_fp_interface());
- op_val = operation(lhs_span[i], rhs_span[i]);
- }
- auto reg_val = state_->GetRegister<DestRegisterType>(kRdName)
- .first->data_buffer()
- ->template Get<R>(0);
- FPCompare<R>(op_val, reg_val, delta_position,
- absl::StrCat(name, " ", i, ": ", lhs_span[i], " ",
- rhs_span[i], " rm: ", rm));
- }
- if (HasFailure()) return;
- }
- }
-
- // Test helper for binary instructions that also produce an exception flag
- // value.
- template <typename R, typename LHS, typename RHS>
- void BinaryOpWithFflagsFPTestHelper(
- absl::string_view name, Instruction *inst,
- absl::Span<const absl::string_view> reg_prefixes, int delta_position,
- std::function<std::tuple<R, uint32_t>(LHS, RHS)> operation) {
- using LhsRegisterType = RVFpRegister;
- using RhsRegisterType = RVFpRegister;
- using DestRegisterType = RVFpRegister;
- using LhsUInt = typename FPTypeInfo<LHS>::IntType;
- using RhsUInt = typename FPTypeInfo<RHS>::IntType;
- LHS lhs_values[kTestValueLength];
- RHS rhs_values[kTestValueLength];
- auto lhs_span = absl::Span<LHS>(lhs_values);
- auto rhs_span = absl::Span<RHS>(rhs_values);
- const std::string kR1Name = absl::StrCat(reg_prefixes[0], 1);
- const std::string kR2Name = absl::StrCat(reg_prefixes[1], 2);
- const std::string kRdName = absl::StrCat(reg_prefixes[2], 5);
- // This is used for the rounding mode operand.
- const std::string kRmName = absl::StrCat("x", 10);
- AppendRegisterOperands({kR1Name, kR2Name, kRmName}, {kRdName});
- auto *flag_op = rv_fp_->fflags()->CreateSetDestinationOperand(0, "fflags");
- instruction_->AppendDestination(flag_op);
- FillArrayWithRandomFPValues<LHS>(lhs_span);
- FillArrayWithRandomFPValues<RHS>(rhs_span);
- using LhsInt = typename FPTypeInfo<LHS>::IntType;
- *reinterpret_cast<LhsInt *>(&lhs_span[0]) = FPTypeInfo<LHS>::kQNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[1]) = FPTypeInfo<LHS>::kSNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[2]) = FPTypeInfo<LHS>::kPosInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[3]) = FPTypeInfo<LHS>::kNegInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[4]) = FPTypeInfo<LHS>::kPosZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[5]) = FPTypeInfo<LHS>::kNegZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[6]) = FPTypeInfo<LHS>::kPosDenorm;
- *reinterpret_cast<LhsInt *>(&lhs_span[7]) = FPTypeInfo<LHS>::kNegDenorm;
- for (int i = 0; i < kTestValueLength; i++) {
- SetRegisterValues<LHS, LhsRegisterType>({{kR1Name, lhs_span[i]}});
- SetRegisterValues<RHS, RhsRegisterType>({{kR2Name, rhs_span[i]}});
-
- for (int rm : {0, 1, 2, 3, 4}) {
- rv_fp_->SetRoundingMode(static_cast<FPRoundingMode>(rm));
- rv_fp_->fflags()->Write(static_cast<uint32_t>(0));
- SetRegisterValues<int, CheriotRegister>({{kRmName, rm}, {}});
- SetRegisterValues<R, DestRegisterType>({{kRdName, 0}});
-
- inst->Execute(nullptr);
-
- R op_val;
- uint32_t flag;
- {
- ScopedFPStatus set_fpstatus(rv_fp_->host_fp_interface());
- std::tie(op_val, flag) = operation(lhs_span[i], rhs_span[i]);
- }
- auto reg_val = state_->GetRegister<DestRegisterType>(kRdName)
- .first->data_buffer()
- ->template Get<R>(0);
- FPCompare<R>(
- op_val, reg_val, delta_position,
- absl::StrCat(name, " ", i, ": ", lhs_span[i], " ", rhs_span[i]));
- auto lhs_uint = *reinterpret_cast<LhsUInt *>(&lhs_span[i]);
- auto rhs_uint = *reinterpret_cast<RhsUInt *>(&rhs_span[i]);
- auto fflags = rv_fp_->fflags()->GetUint32();
- EXPECT_EQ(flag, fflags)
- << std::hex << name << "(" << lhs_uint << ", " << rhs_uint << ")";
- }
- }
- }
-
- template <typename R, typename LHS, typename MHS, typename RHS>
- void TernaryOpFPTestHelper(absl::string_view name, Instruction *inst,
- absl::Span<const absl::string_view> reg_prefixes,
- int delta_position,
- std::function<R(LHS, MHS, RHS)> operation) {
- using LhsRegisterType = RVFpRegister;
- using MhsRegisterType = RVFpRegister;
- using RhsRegisterType = RVFpRegister;
- using DestRegisterType = RVFpRegister;
- LHS lhs_values[kTestValueLength];
- MHS mhs_values[kTestValueLength];
- RHS rhs_values[kTestValueLength];
- auto lhs_span = absl::Span<LHS>(lhs_values);
- auto mhs_span = absl::Span<MHS>(mhs_values);
- auto rhs_span = absl::Span<RHS>(rhs_values);
- const std::string kR1Name = absl::StrCat(reg_prefixes[0], 1);
- const std::string kR2Name = absl::StrCat(reg_prefixes[1], 2);
- const std::string kR3Name = absl::StrCat(reg_prefixes[2], 3);
- const std::string kRdName = absl::StrCat(reg_prefixes[3], 5);
- // This is used for the rounding mode operand.
- const std::string kRmName = absl::StrCat("x", 10);
- AppendRegisterOperands({kR1Name, kR2Name, kR3Name, kRmName}, {kRdName});
- FillArrayWithRandomFPValues<LHS>(lhs_span);
- FillArrayWithRandomFPValues<MHS>(mhs_span);
- FillArrayWithRandomFPValues<RHS>(rhs_span);
- using LhsInt = typename FPTypeInfo<LHS>::IntType;
- *reinterpret_cast<LhsInt *>(&lhs_span[0]) = FPTypeInfo<LHS>::kQNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[1]) = FPTypeInfo<LHS>::kSNaN;
- *reinterpret_cast<LhsInt *>(&lhs_span[2]) = FPTypeInfo<LHS>::kPosInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[3]) = FPTypeInfo<LHS>::kNegInf;
- *reinterpret_cast<LhsInt *>(&lhs_span[4]) = FPTypeInfo<LHS>::kPosZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[5]) = FPTypeInfo<LHS>::kNegZero;
- *reinterpret_cast<LhsInt *>(&lhs_span[6]) = FPTypeInfo<LHS>::kPosDenorm;
- *reinterpret_cast<LhsInt *>(&lhs_span[7]) = FPTypeInfo<LHS>::kNegDenorm;
- for (int i = 0; i < kTestValueLength; i++) {
- SetRegisterValues<LHS, LhsRegisterType>({{kR1Name, lhs_span[i]}});
- SetRegisterValues<MHS, MhsRegisterType>({{kR2Name, mhs_span[i]}});
- SetRegisterValues<RHS, RhsRegisterType>({{kR3Name, rhs_span[i]}});
-
- for (int rm : {0, 1, 2, 3, 4}) {
- rv_fp_->SetRoundingMode(static_cast<FPRoundingMode>(rm));
- SetRegisterValues<int, CheriotRegister>({{kRmName, rm}});
- SetRegisterValues<R, DestRegisterType>({{kRdName, 0}});
-
- inst->Execute(nullptr);
-
- R op_val;
- {
- ScopedFPStatus set_fpstatus(rv_fp_->host_fp_interface());
- op_val = operation(lhs_span[i], mhs_span[i], rhs_span[i]);
- }
- auto reg_val = state_->GetRegister<DestRegisterType>(kRdName)
- .first->data_buffer()
- ->template Get<R>(0);
- FPCompare<R>(
- op_val, reg_val, delta_position,
- absl::StrCat(name, " ", i, ": ", lhs_span[i], " ", rhs_span[i]));
- }
- }
- }
-
- absl::Span<CheriotRegister *> creg() {
- return absl::Span<CheriotRegister *>(creg_);
- }
-
- absl::Span<RVFpRegister *> freg() {
- return absl::Span<RVFpRegister *>(freg_);
- }
-
- absl::Span<RV64Register *> dreg() {
- return absl::Span<RV64Register *>(dreg_);
- }
- absl::BitGen &bitgen() { return bitgen_; }
- Instruction *instruction() { return instruction_; }
-
- template <typename T>
- T RoundToInteger(T val) {
- using FromUint = typename FPTypeInfo<T>::IntType;
- auto constexpr kBias = FPTypeInfo<T>::kExpBias;
- auto constexpr kExpMask = FPTypeInfo<T>::kExpMask;
- auto constexpr kSigSize = FPTypeInfo<T>::kSigSize;
- auto constexpr kSigMask = FPTypeInfo<T>::kSigMask;
- FromUint val_u = *reinterpret_cast<FromUint *>(&val);
- FromUint exp = kExpMask & val_u;
- FromUint sign = val_u & (1ULL << (FPTypeInfo<T>::kBitSize - 1));
- int exp_value = exp >> kSigSize;
- FromUint sig = kSigMask & val_u;
- // Turn the value into a denormal.
- constexpr FromUint hidden = 1ULL << (kSigSize - 1);
- FromUint tmp_u = sign | ((exp != 0) ? hidden : 0ULL) | (sig >> 1);
- T tmp = *reinterpret_cast<T *>(&tmp_u);
- if ((exp_value >= kBias) && (exp_value - kBias + 1 < kSigSize)) {
- // Divide so that only the bits we care about are left in the significand.
- int shift = kBias + kSigSize - exp_value - 1;
- FromUint div_exp = shift + kBias;
- FromUint div_u = div_exp << kSigSize;
- T div = *reinterpret_cast<T *>(&div_u);
- tmp /= div;
- // Convert back to normalized number, by using the original sign
- // and exponent, and the normalized and significand from the division.
- tmp_u = *reinterpret_cast<FromUint *>(&tmp);
- val_u = sign | exp | ((tmp_u << (shift + 1)) & kSigMask);
- val = *reinterpret_cast<T *>(&val_u);
- }
- return val;
- }
-
- protected:
- CheriotRegister *creg_[32];
- RV64Register *dreg_[32];
- RVFpRegister *freg_[32];
- CheriotState *state_;
- Instruction *instruction_;
- Instruction *child_instruction_;
- TaggedFlatDemandMemory *memory_;
- RiscVCheriotFPState *rv_fp_;
- absl::BitGen bitgen_;
-};
-
-} // namespace test
-} // namespace cheriot
-} // namespace sim
-} // namespace mpact
-
-#endif // MPACT_CHERIOT___TEST_RISCV_CHERIOT_FP_TEST_BASE_H_
diff --git a/cheriot/test/riscv_cheriot_i_instructions_test.cc b/cheriot/test/riscv_cheriot_i_instructions_test.cc
index 93dbd41..d5ab010 100644
--- a/cheriot/test/riscv_cheriot_i_instructions_test.cc
+++ b/cheriot/test/riscv_cheriot_i_instructions_test.cc
@@ -28,6 +28,7 @@
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/instruction.h"
#include "mpact/sim/generic/type_helpers.h"
+#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
// This file contains tests for individual RiscV32I instructions.
@@ -38,6 +39,7 @@
using ::mpact::sim::cheriot::CheriotState;
using ::mpact::sim::generic::ImmediateOperand;
using ::mpact::sim::generic::Instruction;
+using ::mpact::sim::util::TaggedFlatDemandMemory;
using CH_EC = ::mpact::sim::cheriot::ExceptionCode;
using PB = CheriotRegister::PermissionBits;
@@ -62,7 +64,8 @@
class RVCheriotIInstructionTest : public testing::Test {
public:
RVCheriotIInstructionTest() {
- state_ = new CheriotState("test");
+ mem_ = new TaggedFlatDemandMemory(8);
+ state_ = new CheriotState("test", mem_, nullptr);
instruction_ = new Instruction(kInstAddress, state_);
instruction_->set_size(4);
creg_1_ = state_->GetRegister<CheriotRegister>(kC1).first;
@@ -76,6 +79,7 @@
}
~RVCheriotIInstructionTest() override {
+ delete mem_;
delete state_;
delete instruction_;
}
@@ -135,6 +139,7 @@
uint64_t exception_code, uint64_t epc,
const Instruction *inst);
+ TaggedFlatDemandMemory *mem_;
CheriotState *state_;
Instruction *instruction_;
CheriotRegister *creg_1_;
diff --git a/cheriot/test/riscv_cheriot_m_instructions_test.cc b/cheriot/test/riscv_cheriot_m_instructions_test.cc
index 4874485..ec23951 100644
--- a/cheriot/test/riscv_cheriot_m_instructions_test.cc
+++ b/cheriot/test/riscv_cheriot_m_instructions_test.cc
@@ -28,6 +28,7 @@
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/instruction.h"
#include "mpact/sim/generic/type_helpers.h"
+#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
// This file contains tests for individual CHERIoT RiscV32M instructions.
@@ -38,6 +39,7 @@
using ::mpact::sim::cheriot::CheriotState;
using ::mpact::sim::generic::ImmediateOperand;
using ::mpact::sim::generic::Instruction;
+using ::mpact::sim::util::TaggedFlatDemandMemory;
using CH_EC = ::mpact::sim::cheriot::ExceptionCode;
using PB = CheriotRegister::PermissionBits;
@@ -64,7 +66,8 @@
class RVCheriotMInstructionTest : public testing::Test {
public:
RVCheriotMInstructionTest() {
- state_ = new CheriotState("test");
+ mem_ = new TaggedFlatDemandMemory(8);
+ state_ = new CheriotState("test", mem_, nullptr);
instruction_ = new Instruction(kInstAddress, state_);
instruction_->set_size(4);
creg_1_ = state_->GetRegister<CheriotRegister>(kC1).first;
@@ -73,6 +76,7 @@
}
~RVCheriotMInstructionTest() override {
+ delete mem_;
delete state_;
delete instruction_;
}
@@ -128,6 +132,7 @@
return reg->address();
}
+ TaggedFlatDemandMemory *mem_;
CheriotState *state_;
Instruction *instruction_;
CheriotRegister *creg_1_;
diff --git a/cheriot/test/riscv_cheriot_zicsr_instructions_test.cc b/cheriot/test/riscv_cheriot_zicsr_instructions_test.cc
index a1792af..6d75d87 100644
--- a/cheriot/test/riscv_cheriot_zicsr_instructions_test.cc
+++ b/cheriot/test/riscv_cheriot_zicsr_instructions_test.cc
@@ -28,6 +28,7 @@
#include "googlemock/include/gmock/gmock.h"
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/instruction.h"
+#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
#include "riscv//riscv_csr.h"
// This file contains tests for individual Zicsr instructions.
@@ -42,6 +43,7 @@
using ::mpact::sim::generic::ImmediateOperand;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::riscv::RiscV32SimpleCsr;
+using ::mpact::sim::util::TaggedFlatDemandMemory;
constexpr uint32_t kInstAddress = 0x2468;
@@ -59,7 +61,8 @@
class ZicsrInstructionsTest : public testing::Test {
protected:
ZicsrInstructionsTest() {
- state_ = new CheriotState("test");
+ mem_ = new TaggedFlatDemandMemory(8);
+ state_ = new CheriotState("test", mem_, nullptr);
instruction_ = new Instruction(kInstAddress, state_);
instruction_->set_size(4);
state_->set_on_trap([this](bool is_interrupt, uint64_t trap_value,
@@ -71,6 +74,7 @@
~ZicsrInstructionsTest() override {
delete instruction_;
+ delete mem_;
delete state_;
}
@@ -130,6 +134,7 @@
uint64_t exception_code, uint64_t epc,
const Instruction *inst);
+ TaggedFlatDemandMemory *mem_;
RiscV32SimpleCsr *csr_;
CheriotState *state_;
Instruction *instruction_;