File sm.h
File List > include > simtix > sm.h
Go to the documentation of this file
#pragma once
#include <simtix/clocked.h>
#include <simtix/mem.h>
#include <simtix/opencl.h>
#include <simtix/param.h>
#include <simtix/statistics.h>
#include <simtix/trace.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
namespace simtix {
class BaseSM : public sim::Clocked {
public:
enum class Status : uint8_t { kIdle = 0, kRunning, kCompleted, kFault };
// Fault status, only valid when status_ == kFault
struct FaultStatus {
uint32_t ewid; // Exception wid
uint64_t mcause;
uint64_t mepc;
uint64_t mtval;
};
explicit BaseSM(const std::string &name)
: sim::Clocked(name, sim::kSmTickPri) {}
virtual ~BaseSM() = default;
virtual void AttachIMem(mem::MemoryInterface *imem) = 0;
virtual void AttachDMem(mem::MemoryInterface *dmem) = 0;
virtual int Process(const opencl::WorkGroup &wg) = 0;
virtual void Reset() = 0;
virtual uint32_t cid() const = 0;
virtual uint64_t mcycle() const = 0;
virtual const std::vector<uint64_t> &minstrets() const = 0;
virtual Status status() const = 0;
virtual FaultStatus fault_status() const = 0;
const virtual std::shared_ptr<stat::Group> stat() const = 0;
};
class AtomicSM : public BaseSM {
public:
explicit AtomicSM(const std::string &name, uint32_t cid,
const ArchParam &p = kDefaultArchParam);
~AtomicSM();
void AttachIMem(mem::MemoryInterface *imem) override;
void AttachDMem(mem::MemoryInterface *dmem) override;
int Process(const opencl::WorkGroup &wg) override;
void Reset() override;
uint32_t cid() const override;
uint64_t mcycle() const override;
const std::vector<uint64_t> &minstrets() const override;
Status status() const override;
FaultStatus fault_status() const override;
const std::shared_ptr<stat::Group> stat() const override;
protected:
void Tick() override;
bool HasPendingTasks() override;
class Impl;
std::unique_ptr<Impl> impl_;
};
namespace pipelined {
class PipelinedSM : public BaseSM {
public:
class ParamBuilder;
class Param {
public:
static ParamBuilder Build();
friend class ParamBuilder;
DECL_PARAM_W_GETTER(size_t, kInstrQueueCapacity);
DECL_PARAM_W_GETTER(size_t, kInstrBufferCapacity);
DECL_PARAM_W_GETTER(size_t, kOutstandingInstrFetches);
DECL_PARAM_W_GETTER(size_t, kOutstandingLoadStores);
DECL_PARAM_W_GETTER(size_t, kOperandCollectBufferSize);
DECL_PARAM_W_GETTER(size_t, kCommitBufferSize);
DECL_PARAM_W_GETTER(uint32_t, kFetchWidth);
DECL_PARAM_W_GETTER(uint32_t, kDecodeWidth);
DECL_PARAM_W_GETTER(uint32_t, kScheduleWidth);
DECL_PARAM_W_GETTER(uint32_t, kOperandCollectWidth);
DECL_PARAM_W_GETTER(uint32_t, kExecuteWidth);
DECL_PARAM_W_GETTER(uint32_t, kCommitWidth);
DECL_PARAM_W_GETTER(uint32_t, kMemPorts);
DECL_PARAM_W_GETTER(size_t, kCoalescingGranularity);
DECL_PARAM_W_GETTER(uint32_t, kIAluLatency);
DECL_PARAM_W_GETTER(uint32_t, kIMulLatency);
DECL_PARAM_W_GETTER(uint32_t, kIDivLatency);
DECL_PARAM_W_GETTER(bool, kSwizzle);
DECL_PARAM_W_GETTER(size_t, kSharedPorts);
DECL_PARAM_W_GETTER(size_t, kReadPorts);
DECL_PARAM_W_GETTER(size_t, kWritePorts);
DECL_PARAM_W_GETTER(uint32_t, kRegfileBanks);
DECL_PARAM_W_GETTER(std::optional<mem::NBHBCache::Param>, kICacheParam);
DECL_PARAM_W_GETTER(std::optional<mem::NBHBCache::Param>, kDCacheParam);
private:
Param()
: kInstrQueueCapacity_(2),
kInstrBufferCapacity_(4),
kOutstandingInstrFetches_(8),
kOutstandingLoadStores_(8),
kOperandCollectBufferSize_(4),
kCommitBufferSize_(4),
kFetchWidth_(2),
kDecodeWidth_(2),
kScheduleWidth_(2),
kOperandCollectWidth_(2),
kExecuteWidth_(2),
kCommitWidth_(2),
kMemPorts_(4),
kCoalescingGranularity_(64),
kIAluLatency_(1),
kIMulLatency_(2),
kIDivLatency_(8),
kSwizzle_(true),
kSharedPorts_(1),
kReadPorts_(0),
kWritePorts_(0),
kRegfileBanks_(4),
kICacheParam_(std::nullopt),
kDCacheParam_(std::nullopt) {}
};
class ParamBuilder {
private:
Param param_;
public:
ParamBuilder &instr_queue_capacity(size_t v) {
param_.kInstrQueueCapacity_ = v;
return *this;
}
ParamBuilder &instr_buffer_capacity(size_t v) {
param_.kInstrBufferCapacity_ = v;
return *this;
}
ParamBuilder &outstanding_instr_fetches(size_t v) {
param_.kOutstandingInstrFetches_ = v;
return *this;
}
ParamBuilder &outstanding_load_stores(size_t v) {
param_.kOutstandingLoadStores_ = v;
return *this;
}
ParamBuilder &operand_collect_buffer_size(size_t v) {
param_.kOperandCollectBufferSize_ = v;
return *this;
}
ParamBuilder &commit_buffer_size(size_t v) {
param_.kCommitBufferSize_ = v;
return *this;
}
ParamBuilder &fetch_width(uint32_t v) {
param_.kFetchWidth_ = v;
return *this;
}
ParamBuilder &decode_width(uint32_t v) {
param_.kDecodeWidth_ = v;
return *this;
}
ParamBuilder &schedule_width(uint32_t v) {
param_.kScheduleWidth_ = v;
return *this;
}
ParamBuilder &operand_collect_width(uint32_t v) {
param_.kOperandCollectWidth_ = v;
return *this;
}
ParamBuilder &execute_width(uint32_t v) {
param_.kExecuteWidth_ = v;
return *this;
}
ParamBuilder &commit_width(uint32_t v) {
param_.kCommitWidth_ = v;
return *this;
}
ParamBuilder &mem_ports(uint32_t v) {
param_.kMemPorts_ = v;
return *this;
}
ParamBuilder &coalescing_granularity(size_t v) {
param_.kCoalescingGranularity_ = v;
return *this;
}
ParamBuilder &ialu_latency(uint32_t v) {
param_.kIAluLatency_ = v;
return *this;
}
ParamBuilder &imul_latency(uint32_t v) {
param_.kIMulLatency_ = v;
return *this;
}
ParamBuilder &idiv_latency(uint32_t v) {
param_.kIDivLatency_ = v;
return *this;
}
ParamBuilder &swizzle(bool v) {
param_.kSwizzle_ = v;
return *this;
}
ParamBuilder &shared_ports(size_t v) {
param_.kSharedPorts_ = v;
return *this;
}
ParamBuilder &read_ports(size_t v) {
param_.kReadPorts_ = v;
return *this;
}
ParamBuilder &write_ports(size_t v) {
param_.kWritePorts_ = v;
return *this;
}
ParamBuilder ®file_banks(uint32_t v) {
param_.kRegfileBanks_ = v;
return *this;
}
ParamBuilder &icache_param(std::optional<mem::NBHBCache::Param> v) {
param_.kICacheParam_ = v;
return *this;
}
ParamBuilder &dcache_param(std::optional<mem::NBHBCache::Param> v) {
param_.kDCacheParam_ = v;
return *this;
}
operator Param() {
if (param_.kInstrQueueCapacity_ < param_.kFetchWidth_) {
DPRINTF(Pipelined,
"Warning: InstrQueueCapacity(%zu) is less than FetchWidth(%u). "
"Adjusting InstrQueueCapacity to %u.\n",
param_.kInstrQueueCapacity_, param_.kFetchWidth_,
param_.kFetchWidth_);
param_.kInstrQueueCapacity_ = param_.kFetchWidth_;
}
if (param_.kInstrBufferCapacity_ < param_.kFetchWidth_ * 2) {
DPRINTF(Pipelined,
"Warning: InstrBufferCapacity(%zu) is less than 2 * "
"FetchWidth(%u). "
"Adjusting InstrBufferCapacity to %u.\n",
param_.kInstrBufferCapacity_, param_.kFetchWidth_,
param_.kFetchWidth_ * 2);
param_.kInstrBufferCapacity_ = param_.kFetchWidth_ * 2;
}
return param_;
}
};
inline static const Param kDefaultParam = Param::Build();
explicit PipelinedSM(const std::string &name, uint32_t cid,
const ArchParam &p = kDefaultArchParam,
const Param &pp = kDefaultParam);
~PipelinedSM();
void AttachICache(std::shared_ptr<mem::CacheInterface> icache);
void AttachDCache(std::shared_ptr<mem::CacheInterface> dcache);
void AttachIMem(mem::MemoryInterface *imem) override;
void AttachDMem(mem::MemoryInterface *dmem) override;
int Process(const opencl::WorkGroup &wg) override;
void Reset() override;
uint32_t cid() const override;
uint64_t mcycle() const override;
const std::vector<uint64_t> &minstrets() const override;
Status status() const override;
FaultStatus fault_status() const override;
const std::shared_ptr<stat::Group> stat() const override;
protected:
void Tick() override;
bool HasPendingTasks() override;
class Impl;
std::unique_ptr<Impl> impl_;
};
inline PipelinedSM::ParamBuilder PipelinedSM::Param::Build() {
return PipelinedSM::ParamBuilder();
}
} // namespace pipelined
} // namespace simtix
namespace fmt {
// fmt support for BaseSM::Status
template <>
struct formatter<simtix::BaseSM::Status> : formatter<string_view> {
template <typename FormatContext>
auto format(simtix::BaseSM::Status s, FormatContext &ctx) const { // NOLINT
string_view name = "Unknown";
switch (s) {
case simtix::BaseSM::Status::kIdle:
name = "Idle";
break;
case simtix::BaseSM::Status::kRunning:
name = "Running";
break;
case simtix::BaseSM::Status::kCompleted:
name = "Completed";
break;
case simtix::BaseSM::Status::kFault:
name = "Fault";
break;
}
return formatter<string_view>::format(name, ctx);
}
};
} // namespace fmt