Skip to content

File instr.h

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

Go to the documentation of this file

#pragma once

#include <stdint.h>

#include <cassert>
#include <cstdint>
#include <string>
#include <vector>

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

// Execution latency
#ifndef LATENCY_IMUL
#define LATENCY_IMUL 2
#endif

#ifndef LATENCY_IDIV
#define LATENCY_IDIV 8
#endif

#ifndef SUBWARP_INTERLEAVING
#define SUBWARP_INTERLEAVING 1
#endif

namespace simtix {

class Instr {
 public:
  enum Opcode : uint8_t {
    // clang-format off
    kLoad    = 0b0000011,
    kStore   = 0b0100011,
    kBranch  = 0b1100011,
    kCustom1 = 0b0101011,
    kOpImm   = 0b0010011,
    kOp      = 0b0110011,
    kSystem  = 0b1110011,
    kAuipc   = 0b0010111,
    kLui     = 0b0110111,
    kOpImm32 = 0b0011011,
    kOp32    = 0b0111011,
    kFmadd   = 0b1000011,
    kFmsub   = 0b1000111,
    kFnmsub  = 0b1001011,
    kFnmadd  = 0b1001111,
    kOpFp    = 0b1010011,
    kJal     = 0b1101111,
    kJalr    = 0b1100111
    // clang-format on
  };

  enum ExecutionUnit : uint8_t { kALU = 0, kLSU, kMul, kDiv, kFPU };

  // Operations for different pipeline stage
  virtual void Decode();

  virtual void Issue();

  virtual void OperandCollect() = 0;

  virtual void Execute() = 0;

  virtual void Commit() = 0;

  virtual void Reset();

  virtual void Assign(const Instr *other);

  // Check scoreboard
  virtual bool CanIssue() const = 0;

  virtual bool CanExecute() const = 0;

  virtual bool CanCommit() const = 0;

  virtual bool CanRetire() const = 0;

  void set_ssw(std::optional<uint32_t> ssw) { ssw_ = ssw; }

  // Public getters
  uint32_t wid() const {
    return (warp_ == nullptr) ? UINT32_MAX : warp_->wid();
  }
  uint32_t iword() const { return iword_; }
  uint64_t wpc() const { return wpc_; }
  uint8_t opcode() const { return opcode_; }
  bool illegal() const { return illegal_; }
  uint8_t tswid() const { return tswid_; }
  uint32_t sswid() const { return ssw_.value_or(0); }
  ExecutionUnit execution_unit() const { return execution_unit_; }

  // implement by each instruction
  virtual bool may_change_ctrl_flow() const { return false; }
  virtual bool barrier_valid() const { return false; }
  virtual bool exception_valid() const { return illegal_; }

  // Helper functions for decoding common bit fields
  static constexpr uint32_t BitMask(uint32_t width) { return (1 << width) - 1; }

  static inline uint8_t DecodeOpcode(uint32_t iword) {
    return iword & BitMask(7);
  }
  static inline uint8_t DecodeRd(uint32_t iword) {
    return (iword >> 7) & BitMask(5);
  }
  static inline uint8_t DecodeFunct3(uint32_t iword) {
    return (iword >> 12) & BitMask(3);
  }
  static inline uint8_t DecodeRs1(uint32_t iword) {
    return (iword >> 15) & BitMask(5);
  }
  static inline uint8_t DecodeRs2(uint32_t iword) {
    return (iword >> 20) & BitMask(5);
  }
  static inline uint8_t DecodeFunct7(uint32_t iword) {
    return (iword >> 25) & BitMask(7);
  }

 protected:
  // Protected constructor
  Instr(Warp *warp, uint32_t iword, uint64_t wpc)
      : warp_(warp), iword_(iword), wpc_(wpc) {}

  virtual ~Instr() = default;

  // Protected function to reinitialize the instruction
  virtual void Reinitialize(Warp *warp, uint32_t iword, uint64_t wpc) {
    warp_ = warp;
    iword_ = iword;
    wpc_ = wpc;
  }

  // Reference to the warp
  Warp *warp_;

  // The instruction word
  uint32_t iword_;

  // Instruction PC (warp PC)
  uint64_t wpc_;

  // Opcode
  uint8_t opcode_ = 0;

  // Function code
  uint8_t funct3_ = 0, funct7_ = 0;

  // Registers
  uint8_t rs1_ = 0, rs2_ = 0, rd_ = 0;

  // Is illegal instruction or not
  bool illegal_ = false;

  // Execution unit
  ExecutionUnit execution_unit_ = kALU;

  // Instruction mnemonic
  std::string mnemonic_;

  std::optional<uint32_t> ssw_;

  uint8_t tswid_ = 0;
  std::vector<Thread *> active_threads_;

 private:
  template <class InstrType>
  friend class InstrPool;

  friend class InstrPtr;
};

}  // namespace simtix