blob: e90a376602b79f5804284c1387114ab97cec8a7b [file]
// 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_MEMORY_WATCHER_H_
#define MPACT_SIM_UTIL_MEMORY_MEMORY_WATCHER_H_
#include <cstdint>
#include "absl/container/btree_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/util/memory/memory_interface.h"
// This file declares a class that is used to create data watchpoints. Since it
// implements the memory interface, it can easily be inserted between a memory
// requestor and the memory.
namespace mpact {
namespace sim {
namespace util {
using ::mpact::sim::generic::DataBuffer;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::generic::ReferenceCount;
class MemoryWatcher : public MemoryInterface {
public:
// Address range struct used as key in maps from range to callback function.
struct AddressRange {
uint64_t start;
uint64_t end;
explicit AddressRange(uint64_t address) : start(address), end(address) {}
AddressRange(uint64_t start_address, uint64_t end_address)
: start(start_address), end(end_address) {}
};
// Callback types. The load callback does not pass the load data, as that is
// not available in the memory Load call. The call passes the address and the
// data size.
using Callback = absl::AnyInvocable<void(uint64_t, int)>;
// Constructor - default constructor is disabled. Use default destructor.
explicit MemoryWatcher(MemoryInterface *memory);
MemoryWatcher() = delete;
MemoryWatcher(const MemoryWatcher &) = delete; // no copy constructor.
MemoryWatcher &operator=(const MemoryWatcher &) = delete; // no assignment.
~MemoryWatcher() override = default;
// Methods to set/clear watch ranges. No new store (load) range can overlap an
// existing store (load) range. The address range has to have the start < end.
// Since there cannot be any overlapping ranges, it is only necessary to
// specify a single address for the clear call, as it will map to the range
// that contains it.
absl::Status SetStoreWatchCallback(const AddressRange &range,
Callback callback);
absl::Status ClearStoreWatchCallback(uint64_t address);
absl::Status SetLoadWatchCallback(const AddressRange &range,
Callback callback);
absl::Status ClearLoadWatchCallback(uint64_t address);
// The memory interface methods.
void Load(uint64_t address, DataBuffer *db, Instruction *inst,
ReferenceCount *context) override;
void Load(DataBuffer *address_db, DataBuffer *mask_db, int el_size,
DataBuffer *db, Instruction *inst,
ReferenceCount *context) override;
void Store(uint64_t address, DataBuffer *db) override;
void Store(DataBuffer *address_db, DataBuffer *mask_db, int el_size,
DataBuffer *db) override;
private:
// Comparator used to compare two address ranges. A range is less than another
// if they do (a) not overlap and (b) the addresses of the first are less than
// the other.
struct AddressRangeLess {
constexpr bool operator()(const AddressRange &lhs,
const AddressRange &rhs) const {
return lhs.end < rhs.start;
}
};
// The memory interface to forward the loads/stores to.
MemoryInterface *memory_;
absl::btree_multimap<AddressRange, Callback, AddressRangeLess>
ld_watch_actions_;
absl::btree_multimap<AddressRange, Callback, AddressRangeLess>
st_watch_actions_;
};
} // namespace util
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_UTIL_MEMORY_MEMORY_WATCHER_H_