File instr_load.h
File List > projects > simtix > src > simtix > sm > instr_load.h
Go to the documentation of this file
#pragma once
#include <simtix/mem.h>
#include <cstdint>
#include <utility>
#include <vector>
#include "sm/fu/lsu/base.h"
#include "sm/instr.h"
#include "sm/thread.h"
#include "sm/warp.h"
namespace simtix {
class InstrLoad : public Instr {
public:
using Op = void (InstrLoad::*)();
// 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_; }
bool CanCommit() const override {
return executed_ && num_pending_load_ == 0;
}
bool CanRetire() const override { return committed_; }
bool exception_valid() const override { return illegal_ || access_fault_; }
protected:
// Protected constructor
InstrLoad(Warp *warp, uint32_t iword, uint64_t wpc);
void Reinitialize(Warp *warp, uint32_t iword, uint64_t wpc) override;
// Operation
Op op_ = nullptr;
bool rs1_data_ready_ = false;
bool executed_ = false;
bool committed_ = false;
int64_t imm_ = 0;
std::vector<int64_t> rs1_data_;
std::vector<int64_t> rd_data_;
std::vector<uint8_t> buf_;
uint32_t num_pending_load_ = 0;
bool access_fault_ = false;
uint64_t fault_addr_ = 0;
template <std::size_t N, bool Sext>
inline void VectorLoad() {
num_pending_load_ = active_threads_.size();
for (Thread *t : active_threads_) {
uint32_t tid = t->tid();
// Address calculation.
uint64_t addr = rs1_data_[tid] + imm_;
// Use tid to compute the buffer index.
uint8_t *bytes = buf_.data() + tid * 8;
auto on_resp = [tid, addr, bytes, this](auto status) -> bool {
// Ignore all responses if this load instruction has all requests
// finished.
if (num_pending_load_ == 0) {
return true;
}
// If the response status is not okay, halt all pending loads by
// reseting num_pending_load_.
if (status != mem::MemoryInterface::RespStatus::kOkay) {
access_fault_ = true;
fault_addr_ = addr;
num_pending_load_ = 0;
return true;
}
// Assemble bytes into a 64-bit int.
int64_t tmp = 0;
for (int j = N - 1; j >= 0; --j) {
tmp = tmp << 8;
tmp |= bytes[j];
}
// Do sign extension if needed.
if constexpr (Sext) {
if ((bytes[N - 1] & 0x80) != 0) {
constexpr int shamt = 64 - 8 * N;
tmp = tmp << shamt;
tmp = tmp >> shamt;
}
}
--num_pending_load_;
rd_data_[tid] = tmp;
return true;
};
MemoryInterface::Payload payload = {.id = {.wid = warp_->wid()},
.addr = addr,
.data = bytes,
.strb = nullptr,
.size = N};
// Read the data in the address of rs1_data from memory.
warp_->lsu()->PushReadRequest(tid, payload, std::move(on_resp));
}
}
private:
// Operations defined in this Opcode
void ld_() { VectorLoad<8, true>(); }
void lw_() { VectorLoad<4, true>(); }
void lwu_() { VectorLoad<4, false>(); }
void lh_() { VectorLoad<2, true>(); }
void lhu_() { VectorLoad<2, false>(); }
void lb_() { VectorLoad<1, true>(); }
void lbu_() { VectorLoad<1, false>(); }
void nop_() {}
// Make InstrPool friend so that they can call our protected constructor
template <class InstrType>
friend class InstrPool;
};
} // namespace simtix