| // 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_ |