blob: 6b9b39abe135bce8cd8fa341b3efa3f044a970d4 [file]
// 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
//
// 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 "mpact/sim/util/renode/renode_memory_access.h"
#include <cstdint>
#include <cstring>
#include "absl/log/log.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/generic/instruction.h"
#include "mpact/sim/generic/ref_count.h"
namespace mpact::sim::util::renode {
using ::mpact::sim::generic::DataBuffer;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::generic::ReferenceCount;
// Process the load using the interface to the ReNode system bus to fetch data.
void RenodeMemoryAccess::Load(uint64_t address, DataBuffer* db,
Instruction* inst, ReferenceCount* context) {
if (read_fcn_ == nullptr) {
LOG(WARNING) << "RenodeMemoryAccess: read_fcn_ is null";
std::memset(db->raw_ptr(), 0, db->size<uint8_t>());
FinishLoad(db->latency(), inst, context);
return;
}
int32_t size = db->size<uint8_t>();
// Call the C# function delegate.
auto bytes_read = read_fcn_(address, static_cast<char*>(db->raw_ptr()), size);
if (size != bytes_read) {
LOG(ERROR) << "Failed to read " << size - bytes_read << " bytes of "
<< size;
}
FinishLoad(db->latency(), inst, context);
}
// TODO(torerik): add vector load functionality.
void RenodeMemoryAccess::Load(DataBuffer* address_db, DataBuffer* mask_db,
int el_size, DataBuffer* db, Instruction* inst,
ReferenceCount* context) {
LOG(ERROR) << "RenodeMemoryAccess: Vector loads are not supported";
}
// Complete the load by writing back (or scheduling the write back of) the
// fetched data.
void RenodeMemoryAccess::FinishLoad(int latency, Instruction* inst,
ReferenceCount* context) {
if (inst == nullptr) return;
// If the latency is 0, execute the instruction immediately.
if (latency == 0) {
inst->Execute(context);
return;
}
// If the latency is not zero, increment the reference counts of the
// instruction and context
inst->IncRef();
if (context != nullptr) context->IncRef();
// Schedule the instruction to be executed in the future in a lambda.
inst->state()->function_delay_line()->Add(latency, [inst, context]() {
inst->Execute(context);
// Decrement the reference counts.
if (context != nullptr) context->DecRef();
inst->DecRef();
});
}
// Process the store using the interface to the ReNode system bus to store data.
void RenodeMemoryAccess::Store(uint64_t address, DataBuffer* db) {
if (write_fcn_ == nullptr) {
LOG(WARNING) << "RenodeMemoryAccess: write_fcn_ is null";
return;
}
int32_t size = db->size<uint8_t>();
// Call the C# function delegate.
auto bytes_written =
write_fcn_(address, static_cast<char*>(db->raw_ptr()), size);
if (size != bytes_written) {
LOG(ERROR) << "Failed to write " << size - bytes_written << " bytes of "
<< size;
}
}
// TODO(torerik): add vector store functionality.
void RenodeMemoryAccess::Store(DataBuffer* address, DataBuffer* mask,
int el_size, DataBuffer* db) {
LOG(ERROR) << "RenodeMemoryAccess: Vector stores are not supported";
}
} // namespace mpact::sim::util::renode