blob: 99db44fad6b8a065b92fee0044b2c44aefed5825 [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_INTERFACE_H_
#define MPACT_SIM_UTIL_MEMORY_MEMORY_INTERFACE_H_
#include <cstdint>
#include <functional>
#include <type_traits>
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/generic/instruction.h"
#include "mpact/sim/generic/ref_count.h"
namespace mpact {
namespace sim {
namespace util {
using ::mpact::sim::generic::DataBuffer;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::generic::ReferenceCount;
// This class defines the interface to perform load/store from memory.
// There are two base methods each for Loads and Stores, as well as a
// pair of templated convience methods.
//
// Load operations take part in two steps: Mem and Writeback. The Load call
// itself constitutes the Mem step, which is when the values in memory are
// read and copied to the DataBuffer. Once done, the Mem step is responsible
// for scheduling the Instruction to be executed with the given context with
// the latency associated with the DataBuffer.
//
// This interface does not do any inter-access ordering, for instance performing
// loads before stores. That is the responsibility of the calling entity.
class MemoryInterface {
public:
// Default destructor.
virtual ~MemoryInterface() = default;
// 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.
virtual void Load(uint64_t address, DataBuffer *db, Instruction *inst,
ReferenceCount *context) = 0;
// Load data from 1 or 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. Use the DataBuffer size<uint64_t> to determine
// the number of addresses availalble. The following summarizes the parameter
// requirements:
virtual void Load(DataBuffer *address_db, DataBuffer *mask_db, int el_size,
DataBuffer *db, Instruction *inst,
ReferenceCount *context) = 0;
// Convenience template function that calls the above function with the
// element size as the sizeof() the template parameter type.
template <typename T>
void Load(DataBuffer *address_db, DataBuffer *mask_db, DataBuffer *db,
Instruction *inst, ReferenceCount *context) {
Load(address_db, mask_db, sizeof(T), db, inst, context);
}
// Stores data from the DataBuffer instance to memory starting at address.
virtual void Store(uint64_t address, DataBuffer *db) = 0;
// Stores data starting at each of the 1 or 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. The following summarizes the parameter
// requirements:
// address_db->size<uint64_t>)() is either 1 or N
// mask_db->size<bool>() is N
// db->size<uint8_t>()/el_size = N.
virtual void Store(DataBuffer *address, DataBuffer *mask, int el_size,
DataBuffer *db) = 0;
// Convenience template function that calls the above function with the
// element size as the sizeof() the template parameter type.
template <typename T>
void Store(DataBuffer *address_db, DataBuffer *mask_db, DataBuffer *db) {
Store(address_db, mask_db, sizeof(T), db);
}
};
// This an additional memory interface that can be used to to perform atomic
// operations in memory. It supports LL/SC as well as atomic operations
// performed in (or near) memory. No implementation is required, or even
// expected to support all the operations. For unsupported operations the
// implementation should return absl::UnimplementedError().
class AtomicMemoryOpInterface {
public:
// Default destructor.
virtual ~AtomicMemoryOpInterface() = default;
enum class Operation {
// Load linked and store conditional combines to implement an atomic op.
kLoadLinked,
kStoreConditional,
// Atomically swap MEM[address] and db->Get<T>(0).
kAtomicSwap,
// Individual atomic operations implemented in/near memory. More may be
// added in the future. The exact implementation of the operations is up
// to the implementation. One example is RiscV atomic memory operations
// that operatle like the following:
//
// tmp = MEM[address]
// MEM[address] = op(MEM[ADDRESS], db->Get<T>(0))
// db->Set<T>(tmp)
//
// where T corresponds to the integer size corresponding to the element
// size.
kAtomicAdd,
kAtomicSub,
kAtomicAnd,
kAtomicOr,
kAtomicXor,
kAtomicMax,
kAtomicMaxu,
kAtomicMin,
kAtomicMinu,
};
// Perform atomic memory operation 'op' at location 'address', using the value
// in 'db', and returning the result in DataBuffer 'db'. The element size for
// is inferred from the size of 'db' and is the same for both the source value
// as well as the result of the atomic operation. The size of the data buffer
// db->size<uint8_t>() must be equal to sizeof(T) for some integer type, i.e.,
// 1, 2, 4, or 8.
virtual absl::Status PerformMemoryOp(uint64_t address, Operation op,
DataBuffer *db, Instruction *inst,
ReferenceCount *context) = 0;
};
} // namespace util
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_UTIL_MEMORY_MEMORY_INTERFACE_H_