blob: 17116cc061418292b27b8beb65fd95159b662c18 [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_STATE_ITEM_H_
#define MPACT_SIM_GENERIC_STATE_ITEM_H_
#include <string>
#include <type_traits>
#include "absl/strings/string_view.h"
#include "mpact/sim/generic/operand_interface.h"
namespace mpact {
namespace sim {
namespace generic {
// Forward declarations
// ArchState is a class that holds the architectural (processor) state.
// This class is not used in the StateItem class, other than passing on a
// pointer to the BaseType. Even in the BaseClass it is only used as a
// property with a getter function.
class ArchState;
// This file contains a templated helper class used to create types for
// registers and other machine state. As such, this class doesn't have its
// own test class, but is effectively tested where those resulting types
// are defined, e.g., test/register_test.cc for register.{h,cc} where the
// register types are defined.
// Variadically templated base class for machine state classes. The
// templatization is done to enable creation of scalar, vector and array
// value typed instances of a base class such as a register or fifo.
// The base template cannot be instantiated since the constructor is
// deleted, only the partially specialized versions of the template can be
// instantiated.
template <typename BaseType, typename ElementType, typename SourceOperandType,
typename DestinationOperandType, int... Ns>
class StateItem : public BaseType {
public:
StateItem() = delete;
};
// The following partial specializations of the State class are used to
// model scalar, vector and array structured values. Each has a templated
// constructor that takes a name and an optional pack of additional
// parameters. The constructor calls the BaseType class constructor
// with the name, order of the state based on scalar value, vector or array
// size, the size of the unit type and the pack of additional parameters.
// Partial specialization for a scalar state class of ElementType.
template <typename BaseType, typename ElementType, typename SourceOperandType,
typename DestinationOperandType>
class StateItem<BaseType, ElementType, SourceOperandType,
DestinationOperandType> : public BaseType {
public:
using ValueType = ElementType;
template <typename... Ps>
explicit StateItem(ArchState *arch_state, absl::string_view name, Ps... pargs)
: BaseType(arch_state, name, {1}, sizeof(ElementType), pargs...) {}
virtual SourceOperandInterface *CreateSourceOperand() {
return new SourceOperandType(this);
}
virtual DestinationOperandInterface *CreateDestinationOperand(int latency) {
return new DestinationOperandType(this, latency);
}
virtual SourceOperandInterface *CreateSourceOperand(std::string op_name) {
return new SourceOperandType(this, op_name);
}
virtual DestinationOperandInterface *CreateDestinationOperand(
int latency, std::string op_name) {
return new DestinationOperandType(this, latency, op_name);
}
};
// Partial specialization for a longer "scalar" register using an array of
// element type. The element type should be uint8_t (so it is a byte array).
template <typename BaseType, typename ElementType, typename SourceOperandType,
typename DestinationOperandType>
class StateItem<BaseType, ElementType *, SourceOperandType,
DestinationOperandType> : public BaseType {
public:
using ValueType = ElementType;
template <typename... Ps>
explicit StateItem(ArchState *arch_state, absl::string_view name, int width,
Ps... pargs)
: BaseType(arch_state, name, {width}, sizeof(ElementType), pargs...) {
static_assert(std::is_same<ElementType, uint8_t>::value,
"Element type must be 'uint8_t'");
}
virtual SourceOperandInterface *CreateSourceOperand() {
return new SourceOperandType(this);
}
virtual SourceOperandInterface *CreateSourceOperand(std::string op_name) {
return new SourceOperandType(this, op_name);
}
virtual DestinationOperandInterface *CreateDestinationOperand(
int latency, std::string op_name) {
return new DestinationOperandType(this, latency, op_name);
}
virtual DestinationOperandInterface *CreateDestinationOperand(int latency) {
return new DestinationOperandType(this, latency);
}
};
// Specialization used when there is no Destination operand type (i.e., it is
// void).
template <typename BaseType, typename ElementType, typename SourceOperandType>
class StateItem<BaseType, ElementType, SourceOperandType, void>
: public BaseType {
public:
using ValueType = ElementType;
template <typename... Ps>
explicit StateItem(ArchState *arch_state, absl::string_view name, Ps... pargs)
: BaseType(arch_state, name, {1}, sizeof(ElementType), pargs...) {}
virtual SourceOperandInterface *CreateSourceOperand() {
return new SourceOperandType(this);
}
virtual SourceOperandInterface *CreateSourceOperand(std::string op_name) {
return new SourceOperandType(this, op_name);
}
};
// Partial specialization for a N length vector state class of ElementType.
template <typename BaseType, typename ElementType, typename SourceOperandType,
typename DestinationOperandType, int N>
class StateItem<BaseType, ElementType, SourceOperandType,
DestinationOperandType, N> : public BaseType {
public:
using ValueType = ElementType;
static constexpr int kNumDimensions = 1;
static constexpr int kShape[] = {N};
template <typename... Ps>
explicit StateItem(ArchState *arch_state, absl::string_view name, Ps... pargs)
: BaseType(arch_state, name, {N}, sizeof(ElementType), pargs...) {}
// Source/destination operand creation interface.
virtual SourceOperandInterface *CreateSourceOperand() {
return new SourceOperandType(this);
}
virtual DestinationOperandInterface *CreateDestinationOperand(int latency) {
return new DestinationOperandType(this, latency);
}
virtual SourceOperandInterface *CreateSourceOperand(std::string op_name) {
return new SourceOperandType(this, op_name);
}
virtual DestinationOperandInterface *CreateDestinationOperand(
int latency, std::string op_name) {
return new DestinationOperandType(this, latency, op_name);
}
};
// Partial specialization for a MxN size matrix state class of ElementType.
template <typename BaseType, typename ElementType, typename SourceOperandType,
typename DestinationOperandType, int M, int N>
class StateItem<BaseType, ElementType, SourceOperandType,
DestinationOperandType, M, N> : public BaseType {
public:
using ValueType = ElementType;
static constexpr int kNumDimensions = 2;
static constexpr int kShape[] = {M, N};
template <typename... Ps>
explicit StateItem(ArchState *arch_state, absl::string_view name, Ps... pargs)
: BaseType(arch_state, name, {M, N}, sizeof(ElementType), pargs...) {}
virtual SourceOperandInterface *CreateSourceOperand() {
return new SourceOperandType(this);
}
virtual DestinationOperandInterface *CreateDestinationOperand(int latency) {
return new DestinationOperandType(this, latency);
}
virtual SourceOperandInterface *CreateSourceOperand(std::string op_name) {
return new SourceOperandType(this, op_name);
}
virtual DestinationOperandInterface *CreateDestinationOperand(
int latency, std::string op_name) {
return new DestinationOperandType(this, latency, op_name);
}
};
} // namespace generic
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_GENERIC_STATE_ITEM_H_