Skip to content

File instr_branch.h

File List > projects > simtix > src > simtix > sm > instr_branch.h

Go to the documentation of this file

#pragma once

#include <cstdint>
#include <vector>

#include "sm/instr.h"
#include "sm/warp.h"

namespace simtix {

class InstrBranch : public Instr {
 public:
  using Op = void (InstrBranch::*)();

  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_; }

  bool may_change_ctrl_flow() const override { return true; }

  // Helper functions
  static inline int64_t DecodeImmBtype(uint32_t iword) {
    // (((iword & 0x80000000) >> 31 << 12) + ((iword & 0x80) >> 7 << 11) +
    // ((iword & 0x7e000000) >> 25 << 5) + ((iword & 0xf00) >> 8 << 1))
    return ((int32_t(iword & 0x80000000) >> 19) + (int32_t(iword & 0x80) << 4) +
            (int32_t(iword & 0x7e000000) >> 20) +
            (int32_t(iword & 0xf00) >> 7));
  }

 protected:
  InstrBranch(Warp *warp, uint32_t iword, uint64_t wpc);

  void Reinitialize(Warp *warp, uint32_t iword, uint64_t wpc) override;

  Op op_ = nullptr;

  bool rs1_data_ready_ = false;
  bool rs2_data_ready_ = false;
  bool executed_ = false;
  bool committed_ = false;

  int64_t imm_ = 0;

  // Register data
  std::vector<int64_t> rs1_data_;
  std::vector<int64_t> rs2_data_;
  // Next PC
  std::vector<uint64_t> next_pc_;

 private:
  //   Operations defined in this Opcode
  void beq_() {
    for (Thread *t : active_threads_) {
      uint32_t tid = t->tid();
      next_pc_[tid] =
          (rs1_data_[tid] == rs2_data_[tid]) ? wpc_ + imm_ : wpc_ + 4;
    }
  }
  void bne_() {
    for (Thread *t : active_threads_) {
      uint32_t tid = t->tid();
      next_pc_[tid] =
          (rs1_data_[tid] != rs2_data_[tid]) ? wpc_ + imm_ : wpc_ + 4;
    }
  }
  void blt_() {
    for (Thread *t : active_threads_) {
      uint32_t tid = t->tid();
      next_pc_[tid] =
          (rs1_data_[tid] < rs2_data_[tid]) ? wpc_ + imm_ : wpc_ + 4;
    }
  }
  void bge_() {
    for (Thread *t : active_threads_) {
      uint32_t tid = t->tid();
      next_pc_[tid] =
          (rs1_data_[tid] >= rs2_data_[tid]) ? wpc_ + imm_ : wpc_ + 4;
    }
  }
  void bltu_() {
    for (Thread *t : active_threads_) {
      uint32_t tid = t->tid();
      next_pc_[tid] = (uint64_t(rs1_data_[tid]) < uint64_t(rs2_data_[tid]))
                          ? wpc_ + imm_
                          : wpc_ + 4;
    }
  }
  void bgeu_() {
    for (Thread *t : active_threads_) {
      uint32_t tid = t->tid();
      next_pc_[tid] = (uint64_t(rs1_data_[tid]) >= uint64_t(rs2_data_[tid]))
                          ? wpc_ + imm_
                          : wpc_ + 4;
    }
  }

  void nop_() {}

  // Make InstrPool friend so that they can call our protected constructor
  template <class InstrType>
  friend class InstrPool;
};
}  // namespace simtix