| // 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. |
| |
| #ifndef MPACT_SIM_UTIL_MEMORY_ATOMIC_MEMORY_H_ |
| #define MPACT_SIM_UTIL_MEMORY_ATOMIC_MEMORY_H_ |
| |
| #include <cstdint> |
| |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/status/status.h" |
| #include "mpact/sim/generic/data_buffer.h" |
| #include "mpact/sim/generic/instruction.h" |
| #include "mpact/sim/generic/ref_count.h" |
| #include "mpact/sim/util/memory/memory_interface.h" |
| |
| namespace mpact { |
| namespace sim { |
| namespace util { |
| |
| using ::mpact::sim::generic::DataBufferFactory; |
| using ::mpact::sim::generic::Instruction; |
| using ::mpact::sim::generic::ReferenceCount; |
| |
| // This class builds upon the flat demand memory class to provide atomic |
| // memory operations on top of memory loads/stores. |
| |
| class AtomicMemory : public MemoryInterface, public AtomicMemoryOpInterface { |
| public: |
| using Operation = AtomicMemoryOpInterface::Operation; |
| |
| AtomicMemory() = delete; |
| explicit AtomicMemory(MemoryInterface* memory); |
| ~AtomicMemory() override; |
| |
| // Load data from address into the DataBuffer, then schedule the Instruction |
| // inst (if not nullptr) to be executed (using the function delay line) with |
| // context. The size of the data access is based on size of the data buffer. |
| void Load(uint64_t address, DataBuffer* db, Instruction* inst, |
| ReferenceCount* context) override; |
| // Load data from N addresses stored in address_db (uint64), using mask_db |
| // (bool) to mask out the corresponding loads from taking place (if false). |
| // Each access is el_size bytes long, and is stored into the DataBuffer. |
| // Once done, the Instruction inst (if not nullptr) is scheduled to be |
| // executed (using the function delay line) with context. It's the |
| // responsibility of the caller to ensure that all DataBuffer instances passed |
| // in are appropriately sized. |
| void Load(DataBuffer* address_db, DataBuffer* mask_db, int el_size, |
| DataBuffer* db, Instruction* inst, |
| ReferenceCount* context) override; |
| // Stores data from the DataBuffer instance to memory starting at address. |
| void Store(uint64_t address, DataBuffer* db) override; |
| // Stores data starting at each of the N addresses stored in address_db, |
| // (uint64) using mask_db (bool) to mask out stores from taking place (if |
| // false). Each store is el_size bytes long. It's the responsibility of the |
| // caller to ensure that all DataBuffer instances that are passed in are |
| // appropriately sized. |
| void Store(DataBuffer* address_db, DataBuffer* mask_db, int el_size, |
| DataBuffer* db) override; |
| |
| absl::Status PerformMemoryOp(uint64_t address, Operation op, DataBuffer* db, |
| Instruction* inst, |
| ReferenceCount* context) override; |
| |
| private: |
| static constexpr int kTagShift = 3; |
| // Write back the result. |
| void WriteBack(Instruction* inst, ReferenceCount* context, DataBuffer* db); |
| // Returns the db of the given size. |
| DataBuffer* GetDb(int size) const; |
| MemoryInterface* memory_ = nullptr; |
| // Tag store for load linked operations. This is used to track if there is an |
| // intervening store between the ll and the sc instruction. The addresses used |
| // are the memory address shifted right by three. For byte addressable |
| // memories, this means that the address is effectively a uint64_t address, |
| // and that the ll/sc tracking granule is 8 bytes. |
| absl::flat_hash_set<uint64_t> ll_tag_set_; |
| // Support accesses of 1 through 8 byte integer types. |
| DataBuffer* db1_; |
| DataBuffer* db2_; |
| DataBuffer* db4_; |
| DataBuffer* db8_; |
| DataBufferFactory db_factory_; |
| }; |
| |
| } // namespace util |
| } // namespace sim |
| } // namespace mpact |
| |
| #endif // MPACT_SIM_UTIL_MEMORY_ATOMIC_MEMORY_H_ |