blob: 27e5785ce2dbe0e4303c2d173b7cfc2611634cd9 [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.
#ifndef MPACT_SIM_UTIL_MEMORY_SINGLE_INITIATOR_ROUTER_H_
#define MPACT_SIM_UTIL_MEMORY_SINGLE_INITIATOR_ROUTER_H_
#include <cstdint>
#include <string>
#include <string_view>
#include "absl/container/btree_map.h"
#include "absl/status/status.h"
#include "mpact/sim/util/memory/memory_interface.h"
#include "mpact/sim/util/memory/tagged_memory_interface.h"
// This file defines a single initiator router class that routes memory accesses
// from an initiator to a set of targets based on memory address. The class
// implements both the Tagged and Atomic memory interfaces, so all memory
// accesses can be routed. Targets are added according to which memory interface
// they support (MemoryInterface, TaggedMemoryInterface, and
// AtomicMemoryOpInterface). A target that supports both a
// (Tagged)MemoryInterface and the AtomicMemoryOpInterface needs to be added
// twice: once for the baseline memory accesses, and then for the atomic memory
// interface.
namespace mpact {
namespace sim {
namespace util {
class SingleInitiatorRouter : public TaggedMemoryInterface,
public AtomicMemoryOpInterface {
public:
// Class local struct for handling address ranges.
// Base is the address of the first byte in the range. Top is the address of
// the last byte in the range.
struct AddressRange {
uint64_t base;
uint64_t top;
};
// Comparator for address ranges.
struct AddressRangeLess {
bool operator()(const AddressRange& lhs, const AddressRange& rhs) const {
return (lhs.top < rhs.base);
}
};
// Map type convenience template.
template <typename Interface>
using InterfaceMap =
absl::btree_map<SingleInitiatorRouter::AddressRange, Interface*,
SingleInitiatorRouter::AddressRangeLess>;
// Constructor and destructor.
explicit SingleInitiatorRouter(std::string name);
SingleInitiatorRouter(const SingleInitiatorRouter&) = delete;
SingleInitiatorRouter& operator=(const SingleInitiatorRouter&) = delete;
~SingleInitiatorRouter();
// Add 'memory' target interface with given range. Only three interface types
// are supported: MemoryInterface, TaggedMemoryInterface, and
// AtomicMemoryOpInterface.
template <typename Interface>
absl::Status AddTarget(Interface* memory, uint64_t base, uint64_t top);
// Add 'memory' target interface as default target, that is, if no other
// interface matches, it is the fallback interface. Only three interface types
// are supported: MemoryInterface, TaggedMemoryInterface, and
// AtomicMemoryOpInterface.
template <typename Interface>
absl::Status AddDefaultTarget(Interface* memory);
// Memory interface methods.
// Plain load.
void Load(uint64_t address, DataBuffer* db, Instruction* inst,
ReferenceCount* context) override;
// Vector load.
void Load(DataBuffer* address_db, DataBuffer* mask_db, int el_size,
DataBuffer* db, Instruction* inst,
ReferenceCount* context) override;
// Tagged load.
void Load(uint64_t address, DataBuffer* db, DataBuffer* tags,
Instruction* inst, ReferenceCount* context) override;
// Plain store.
void Store(uint64_t address, DataBuffer* db) override;
// Vector store.
void Store(DataBuffer* address_db, DataBuffer* mask_db, int el_size,
DataBuffer* db) override;
// Tagged store.
void Store(uint64_t address, DataBuffer* db, DataBuffer* tags) override;
// Atomic memory operation.
absl::Status PerformMemoryOp(uint64_t address, Operation op, DataBuffer* db,
Instruction* inst,
ReferenceCount* context) override;
// Accessors.
std::string_view name() const { return name_; }
private:
std::string name_;
// These maps are used to look up target interfaces based on addresses.
InterfaceMap<MemoryInterface> memory_targets_;
MemoryInterface* default_memory_target_ = nullptr;
InterfaceMap<TaggedMemoryInterface> tagged_targets_;
TaggedMemoryInterface* default_tagged_target_ = nullptr;
InterfaceMap<AtomicMemoryOpInterface> atomic_targets_;
AtomicMemoryOpInterface* default_atomic_target_ = nullptr;
};
} // namespace util
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_UTIL_MEMORY_SINGLE_INITIATOR_ROUTER_H_