Skip to content

File instr_system.h

File List > projects > simtix > src > simtix > sm > instr_system.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 InstrSystem : public Instr {
 public:
  using Op = void (InstrSystem::*)();

  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_; }
  bool CanCommit() const override { return true; }
  bool CanRetire() const override { return committed_; }

  bool exception_valid() const override {
    return illegal_ || op_ == &InstrSystem::ecall_;
  }

  static inline uint16_t DecodeCSR(uint32_t iword) {
    return (uint16_t)(iword >> 20);
  }

  static inline uint64_t DecodeUimm(uint32_t iword) {
    return (uint64_t)(iword >> 15) & (uint64_t)0x1f;
  }

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

  Op op_ = nullptr;
  uint16_t csr_ = 0;
  uint64_t uimm_ = 0;

  bool rs1_data_ready_ = false;
  bool committed_ = false;

  // Register data
  std::vector<int64_t> rs1_data_;
  std::vector<int64_t> rd_data_;

 private:
  void csrrw_() {
    for (Thread* t : active_threads_) {
      if (rd_) {
        // regfile[rd_] = csr[csr_]
        uint64_t csr_data;
        t->ReadCSR(csr_, &csr_data);
        rd_data_[t->tid()] = csr_data;
      }
      // csr[csr_] = regfile[rs1_]
      if (t->WriteCSR(csr_, rs1_data_[t->tid()]) == -1) {
        illegal_ = true;
        return;
      }
    }
  }

  void csrrs_() {
    for (Thread* t : active_threads_) {
      uint64_t csr_data;
      t->ReadCSR(csr_, &csr_data);
      if (rs1_) {
        // csr[csr_] = regfile[rs1_] | csr[csr_]
        uint64_t set_csr_data = csr_data | rs1_data_[t->tid()];
        if (t->WriteCSR(csr_, set_csr_data) == -1) {
          illegal_ = true;
          return;
        }
      }
      // regfile[rd_] = csr[csr_]
      rd_data_[t->tid()] = csr_data;
    }
  }

  void csrrc_() {
    for (Thread* t : active_threads_) {
      uint64_t csr_data;
      t->ReadCSR(csr_, &csr_data);
      if (rs1_) {
        // csr[csr_] = csr[csr_] & ~regfile[rs1_]
        uint64_t clear_csr_data = csr_data & ~rs1_data_[t->tid()];
        if (t->WriteCSR(csr_, clear_csr_data) == -1) {
          illegal_ = true;
          return;
        }
      }
      // regfile[rd_] = csr[csr_]
      rd_data_[t->tid()] = csr_data;
    }
  }

  void csrrwi_() {
    for (Thread* t : active_threads_) {
      if (rd_) {
        // regfile[rd_] = csr[csr_]
        uint64_t csr_data;
        t->ReadCSR(csr_, &csr_data);
        rd_data_[t->tid()] = csr_data;
      }
      // csr[csr_] = uimm_
      if (t->WriteCSR(csr_, uimm_) == -1) {
        illegal_ = true;
        return;
      }
    }
  }

  void csrrsi_() {
    for (Thread* t : active_threads_) {
      uint64_t csr_data;
      t->ReadCSR(csr_, &csr_data);
      // regfile[rd_] = csr[csr_]
      rd_data_[t->tid()] = csr_data;
      if (rs1_ & (uint8_t)0x1f) {
        // csr[csr_] = uimm_ | csr[csr_]
        uint64_t set_csr_data = csr_data | uimm_;
        if (t->WriteCSR(csr_, set_csr_data) == -1) {
          illegal_ = true;
          return;
        }
      }
    }
  }

  void csrrci_() {
    for (Thread* t : active_threads_) {
      uint64_t csr_data;
      t->ReadCSR(csr_, &csr_data);
      // regfile[rd_] = csr[csr_]
      rd_data_[t->tid()] = csr_data;
      if (rs1_ & (uint8_t)0x1f) {
        // csr[csr_] = csr[csr_] & ~uimm_
        uint64_t clear_csr_data = csr_data & ~uimm_;
        if (t->WriteCSR(csr_, clear_csr_data) == -1) {
          illegal_ = true;
          return;
        }
      }
    }
  }

  void ecall_() {
    warp_->set_mepc(wpc_);
    warp_->set_mcause(11);  // E-call from m mode
    warp_->set_mtval(0);
    illegal_ = false;
  }

  void nop_() {}

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

}  // namespace simtix