blob: 3f80efd254bff8560fbc36330d6b4e5ae23b11b4 [file] [edit]
// Copyright 2023 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
//
// https://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.
#include "other/riscv_simple_state.h"
#include <iostream>
#include <limits>
#include <string>
#include <vector>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "mpact/sim/generic/type_helpers.h"
#include "mpact/sim/util/memory/flat_demand_memory.h"
#include "other/riscv_register.h"
namespace mpact {
namespace sim {
namespace riscv {
RiscVState::RiscVState(absl::string_view id, RiscVXlen xlen,
util::MemoryInterface *memory,
util::AtomicMemoryOpInterface *atomic_memory)
: ArchState(id),
xlen_(xlen),
memory_(memory),
atomic_memory_(atomic_memory) {
if (memory_ == nullptr) {
memory_ = owned_memory_ = new util::FlatDemandMemory(0);
}
DataBuffer *db = nullptr;
switch (xlen_) {
case RiscVXlen::RV32: {
auto *pc32 = GetRegister<RV32Register>(kPcName).first;
pc_src_operand_ = pc32->CreateSourceOperand();
pc_dst_operand_ = pc32->CreateDestinationOperand(0);
pc_ = pc32;
db = db_factory()->Allocate<RV32Register::ValueType>(1);
db->Set<uint32_t>(0, 0);
break;
}
default:
LOG(ERROR) << "Unsupported xlen";
return;
}
set_pc_operand(pc_src_operand_);
pc_->SetDataBuffer(db);
db->DecRef();
}
RiscVState::~RiscVState() {
delete pc_src_operand_;
delete pc_dst_operand_;
delete owned_memory_;
}
void RiscVState::LoadMemory(const Instruction *inst, uint64_t address,
DataBuffer *db, Instruction *child_inst,
ReferenceCount *context) {
memory_->Load(address, db, child_inst, context);
}
void RiscVState::LoadMemory(const Instruction *inst, DataBuffer *address_db,
DataBuffer *mask_db, int el_size, DataBuffer *db,
Instruction *child_inst, ReferenceCount *context) {
memory_->Load(address_db, mask_db, el_size, db, child_inst, context);
}
void RiscVState::StoreMemory(const Instruction *inst, uint64_t address,
DataBuffer *db) {
memory_->Store(address, db);
}
void RiscVState::StoreMemory(const Instruction *inst, DataBuffer *address_db,
DataBuffer *mask_db, int el_size, DataBuffer *db) {
memory_->Store(address_db, mask_db, el_size, db);
}
void RiscVState::Fence(const Instruction *inst, int fm, int predecessor,
int successor) {
// TODO: Add fence operation once operations have non-zero latency.
}
void RiscVState::FenceI(const Instruction *inst) {
// TODO: Add instruction fence operation when needed.
}
void RiscVState::ECall(const Instruction *inst) {
if (on_ecall_ != nullptr) {
auto res = on_ecall_(inst);
if (res) return;
}
std::string where = (inst != nullptr)
? absl::StrCat(absl::Hex(inst->address()))
: "unknown location";
LOG(ERROR) << "ECall called without handler at address: " << where;
LOG(ERROR) << "Treating as nop";
}
void RiscVState::EBreak(const Instruction *inst) {
for (auto &handler : on_ebreak_) {
bool res = handler(inst);
if (res) return;
}
std::string where = (inst != nullptr)
? absl::StrCat(absl::Hex(inst->address()))
: "unknown location";
LOG(ERROR) << "EBreak called without handler at address: " << where;
LOG(ERROR) << "Treating as nop";
}
void RiscVState::WFI(const Instruction *inst) {
if (on_wfi_ != nullptr) {
bool res = on_wfi_(inst);
if (res) return;
}
std::string where = (inst != nullptr)
? absl::StrCat(absl::Hex(inst->address()))
: "unknown location";
LOG(INFO) << "No handler for wfi: treating as nop: " << where;
}
} // namespace riscv
} // namespace sim
} // namespace mpact