blob: b8f0416ec88dbbc41033ab4d66b99c5952cb819e [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_GENERIC_STATUS_REGISTER_H_
#define MPACT_SIM_GENERIC_STATUS_REGISTER_H_
#include <any>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/generic/operand_interface.h"
#include "mpact/sim/generic/state_item.h"
#include "mpact/sim/generic/state_item_base.h"
// This file declares a class that implements a generic read-only status
// register.
namespace mpact {
namespace sim {
namespace generic {
// The Status register class implements a read-only view of conditions that
// are evaluated dynamically when the register is read. Each bit is computed
// by calling a bool() function associated with each bit position in the value
// type. If the function returns true, the bit is set to 1, otherwise it is a 0.
// By default the functions are initialized to return false (i.e., set the bit
// to 0). The default functions can be overridden by calling the
// SetEvaluateFunction for individual bit positions with the appropriate
// evaluation functions (including lambdas).
template <typename T>
class StatusRegisterBase : public StateItemBase {
static_assert(std::is_integral<T>::value, "Type must be integral");
public:
using Evaluate = absl::AnyInvocable<bool()>;
// The constructor is in the protected section below. Others are deleted.
StatusRegisterBase() = delete;
StatusRegisterBase(const StatusRegisterBase &) = delete;
StatusRegisterBase &operator=(const StatusRegisterBase &) = delete;
T Read();
T Read(T mask);
void SetDataBuffer(DataBuffer *db) override {
// Read only state item, so just decrement the ref count and ignore.
db->DecRef();
}
void SetEvaluateFunction(int position, Evaluate eval) {
evaluate_[position] = std::move(eval);
}
protected:
// The constructor is called from StateItem<>
StatusRegisterBase(ArchState *state, absl::string_view name,
const std::vector<int> &shape, int unit_size);
private:
std::vector<Evaluate> evaluate_;
int size_;
};
template <typename T>
StatusRegisterBase<T>::StatusRegisterBase(ArchState *state,
absl::string_view name,
const std::vector<int> &shape,
int unit_size)
: StateItemBase(state, name, shape, unit_size), size_(sizeof(T) * 8) {
// Initialize the evaluate functions to lambdas that return false.
for (int i = 0; i < size_; i++) {
evaluate_.push_back([]() -> bool { return false; });
}
}
// Call the evaluation function for each bit position, starting at the high
// (msb) position.
template <typename T>
T StatusRegisterBase<T>::Read() {
T value = 0;
for (int i = size_ - 1; i >= 0; i--) {
value <<= 1;
value |= (evaluate_[i]() ? 1 : 0);
}
return value;
}
// Call the evaluation function only for the bits that are set in the mask,
// starting at the (msb) position.
template <typename T>
T StatusRegisterBase<T>::Read(T mask) {
T value = 0;
for (int i = size_ - 1; i >= 0; i--) {
value <<= 1;
if (mask & (static_cast<T>(1) << i)) {
value |= (evaluate_[i]() ? 1 : 0);
}
}
return value;
}
// The source operand type for StatusRegisters.
template <typename T>
class StatusRegisterSourceOperand : public SourceOperandInterface {
public:
// Construtor. Note, default constructor deleted.
StatusRegisterSourceOperand(StatusRegisterBase<T> *status_reg,
std::string op_name)
: status_register_(status_reg), op_name_(op_name) {}
explicit StatusRegisterSourceOperand(StatusRegisterBase<T> *status_reg)
: StatusRegisterSourceOperand(status_reg, status_reg->name()) {}
StatusRegisterSourceOperand() = delete;
// Return the value cast to the given type.
bool AsBool(int i) override {
return static_cast<bool>(status_register_->Read());
}
int8_t AsInt8(int i) override {
return static_cast<int8_t>(status_register_->Read());
}
uint8_t AsUint8(int i) override {
return static_cast<uint8_t>(status_register_->Read());
}
int16_t AsInt16(int i) override {
return static_cast<int16_t>(status_register_->Read());
}
uint16_t AsUint16(int i) override {
return static_cast<uint16_t>(status_register_->Read());
}
int32_t AsInt32(int i) override {
return static_cast<int32_t>(status_register_->Read());
}
uint32_t AsUint32(int i) override {
return static_cast<uint32_t>(status_register_->Read());
}
int64_t AsInt64(int i) override {
return static_cast<int64_t>(status_register_->Read());
}
uint64_t AsUint64(int i) override {
return static_cast<uint64_t>(status_register_->Read());
}
// Return the register object.
std::any GetObject() const override { return std::any(status_register_); }
// Returns the shape of the register.
std::vector<int> shape() const override { return status_register_->shape(); }
std::string AsString() const override { return op_name_; }
private:
StatusRegisterBase<T> *status_register_;
std::string op_name_;
};
// Adding a deduction guide, so that the StatusRegisterSourceOperand can be
// used without template arguments, deducing the type from the constructor
// argument instead.
template <typename T>
StatusRegisterSourceOperand(StatusRegisterBase<T> *)
-> StatusRegisterSourceOperand<T>;
template <typename ElementType>
using StatusRegister =
StateItem<StatusRegisterBase<ElementType>, ElementType,
StatusRegisterSourceOperand<ElementType>, void>;
} // namespace generic
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_GENERIC_STATUS_REGISTER_H_