| // 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 |