File instr_op.h
File List > projects > simtix > src > simtix > sm > instr_op.h
Go to the documentation of this file
#pragma once
#include <cstdint>
#include <vector>
#include "sm/instr.h"
#include "sm/thread.h"
#include "sm/warp.h"
namespace simtix {
class InstrOp : public Instr {
public:
using Op = void (InstrOp::*)();
// Implementation of Instr's virtual methods
void Decode() override;
void Issue() override;
void OperandCollect() override;
void Execute() override;
void Commit() override;
void Reset() override;
void Assign(const Instr *other) override;
bool CanIssue() const override;
bool CanExecute() const override {
return rs1_data_ready_ && rs2_data_ready_;
}
bool CanCommit() const override { return executed_; }
bool CanRetire() const override { return committed_; }
protected:
InstrOp(Warp *warp, uint32_t iword, uint64_t wpc);
void Reinitialize(Warp *warp, uint32_t iword, uint64_t wpc) override;
int64_t imm_ = 0;
Op op_ = nullptr;
bool rs1_data_ready_ = false;
bool rs2_data_ready_ = false;
bool executed_ = false;
bool committed_ = false;
// Register data
std::vector<int64_t> rs1_data_;
std::vector<int64_t> rs2_data_;
std::vector<int64_t> rd_data_;
private:
// Operations defined in this Opcode
void add_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = (rs1_data_[tid] + rs2_data_[tid]);
}
}
void sub_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = (rs1_data_[tid] - rs2_data_[tid]);
}
}
void slt_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = (rs1_data_[tid] < rs2_data_[tid]) ? 1 : 0;
}
}
void sltu_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] =
(uint64_t(rs1_data_[tid]) < uint64_t(rs2_data_[tid])) ? 1 : 0;
}
}
void xor_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = rs1_data_[tid] ^ rs2_data_[tid];
}
}
void or_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = rs1_data_[tid] | rs2_data_[tid];
}
}
void and_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = rs1_data_[tid] & rs2_data_[tid];
}
}
void sll_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = rs1_data_[tid] << (rs2_data_[tid] & 0x3f);
}
}
void srl_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = uint64_t(rs1_data_[tid]) >> (rs2_data_[tid] & 0x3f);
}
}
void sra_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = rs1_data_[tid] >> (rs2_data_[tid] & 0x3f);
}
}
void czero_eqz_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = (rs2_data_[tid] == 0) ? 0 : rs1_data_[tid];
}
}
void czero_nez_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = (rs2_data_[tid] != 0) ? 0 : rs1_data_[tid];
}
}
void mul_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
rd_data_[tid] = rs1_data_[tid] * rs2_data_[tid];
}
}
void mulh_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
__int128_t mul_res =
(__int128_t)rs1_data_[tid] * (__int128_t)rs2_data_[tid];
rd_data_[tid] = (int64_t)(mul_res >> 64);
}
}
void mulhsu_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
uint64_t rs2_unsigned = (uint64_t)rs2_data_[tid];
__int128_t mul_res =
(__int128_t)rs1_data_[tid] * (__uint128_t)rs2_unsigned;
rd_data_[tid] = (int64_t)(mul_res >> 64);
}
}
void mulhu_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
uint64_t rs1_unsigned = (uint64_t)rs1_data_[tid];
uint64_t rs2_unsigned = (uint64_t)rs2_data_[tid];
__uint128_t mul_res =
(__uint128_t)rs1_unsigned * (__uint128_t)rs2_unsigned;
rd_data_[tid] = (int64_t)(mul_res >> 64);
}
}
void div_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
if (rs2_data_[tid] == 0) {
rd_data_[tid] = -1;
} else if ((rs1_data_[tid] == INT64_MIN) && (rs2_data_[tid] == -1)) {
rd_data_[tid] = rs1_data_[tid];
} else {
rd_data_[tid] = rs1_data_[tid] / rs2_data_[tid];
}
}
}
void divu_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
if (rs2_data_[tid] == 0) {
rd_data_[tid] = -1;
} else {
rd_data_[tid] =
(int64_t)((uint64_t)rs1_data_[tid] / (uint64_t)rs2_data_[tid]);
}
}
}
void rem_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
if (rs2_data_[tid] == 0) {
rd_data_[tid] = rs1_data_[tid];
} else if ((rs1_data_[tid] == INT64_MIN) && (rs2_data_[tid] == -1)) {
rd_data_[tid] = 0;
} else {
rd_data_[tid] = rs1_data_[tid] % rs2_data_[tid];
}
}
}
void remu_() {
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
if (rs2_data_[tid] == 0) {
rd_data_[tid] = rs1_data_[tid];
} else {
rd_data_[tid] =
(int64_t)((uint64_t)rs1_data_[tid] % (uint64_t)rs2_data_[tid]);
}
}
}
void nop_() {}
// Make InstrPool friend so that they can call our protected constructor
template <class InstrType>
friend class InstrPool;
};
} // namespace simtix