Renamed simX to simx

This commit is contained in:
Santosh Srivatsan 2021-12-10 16:57:29 -05:00
parent be499d6f38
commit e7bc436b52
17 changed files with 3962 additions and 0 deletions

50
sim/simx/Makefile Normal file
View file

@ -0,0 +1,50 @@
RTL_DIR = ../hw/rtl
CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Werror -g
CXXFLAGS += -fPIC -Wno-maybe-uninitialized
CXXFLAGS += -I. -I../common -I../../hw
CXXFLAGS += -I../common/softfloat/source/include
CXXFLAGS += $(CONFIGS)
LDFLAGS += ../common/softfloat/build/Linux-x86_64-GCC/softfloat.a
TOP = vx_cache_sim
SRCS = ../common/util.cpp ../common/mem.cpp ../common/rvfloats.cpp
SRCS += args.cpp pipeline.cpp warp.cpp core.cpp decode.cpp execute.cpp main.cpp
OBJS := $(patsubst %.cpp, obj_dir/%.o, $(notdir $(SRCS)))
VPATH := $(sort $(dir $(SRCS)))
#$(info OBJS is $(OBJS))
#$(info VPATH is $(VPATH))
# Debugigng
ifdef DEBUG
CXXFLAGS += -g -O0 -DDEBUG_LEVEL=$(DEBUG)
else
CXXFLAGS += -O2 -DNDEBUG
endif
PROJECT = simX
all: $(PROJECT)
$(PROJECT): $(SRCS)
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
obj_dir/%.o: %.cpp
mkdir -p obj_dir
$(CXX) $(CXXFLAGS) -c $< -o $@
static: $(OBJS)
$(AR) rcs lib$(PROJECT).a $(OBJS) ../common/softfloat/build/Linux-x86_64-GCC/*.o
.depend: $(SRCS)
$(CXX) $(CXXFLAGS) -MM $^ > .depend;
clean-static:
rm -rf lib$(PROJECT).a obj_dir .depend
clean: clean-static
rm -rf $(PROJECT)

73
sim/simx/archdef.h Normal file
View file

@ -0,0 +1,73 @@
#pragma once
#include <string>
#include <sstream>
#include <cstdlib>
#include <stdio.h>
#include "types.h"
namespace vortex {
class ArchDef {
public:
ArchDef(const std::string &/*arch*/,
int num_cores,
int num_warps,
int num_threads) {
// simx64
wsize_ = 8;
vsize_ = 16;
num_regs_ = 32;
num_csrs_ = 4096;
num_barriers_= NUM_BARRIERS;
num_cores_ = num_cores;
num_warps_ = num_warps;
num_threads_ = num_threads;
}
int wsize() const {
return wsize_;
}
int vsize() const {
return vsize_;
}
int num_regs() const {
return num_regs_;
}
int num_csrs() const {
return num_csrs_;
}
int num_barriers() const {
return num_barriers_;
}
int num_threads() const {
return num_threads_;
}
int num_warps() const {
return num_warps_;
}
int num_cores() const {
return num_cores_;
}
private:
int wsize_;
int vsize_;
int num_regs_;
int num_csrs_;
int num_barriers_;
int num_threads_;
int num_warps_;
int num_cores_;
};
}

47
sim/simx/args.cpp Normal file
View file

@ -0,0 +1,47 @@
#include <iostream>
#include <string>
#include "args.h"
using namespace vortex;
using std::string;
std::string CommandLineArg::helpString_;
std::unordered_map<string, CommandLineArg *> CommandLineArg::longArgs_;
std::unordered_map<string, CommandLineArg *> CommandLineArg::shortArgs_;
CommandLineArg::CommandLineArg(string s, string l, const char *helpText) {
helpString_ += helpText;
longArgs_[l] = this;
shortArgs_[s] = this;
}
CommandLineArg::CommandLineArg(string l, const char *helpText) {
helpString_ += helpText;
longArgs_[l] = this;
}
void CommandLineArg::readArgs(int argc, char **argv) {
for (int i = 0; i < argc; i++) {
std::unordered_map<string, CommandLineArg *>::iterator
s = shortArgs_.find(std::string(argv[i])),
l = longArgs_.find(std::string(argv[i]));
if (s != shortArgs_.end()) {
i += s->second->read(argc - i, &argv[i]);
} else if (l != longArgs_.end()) {
i += l->second->read(argc - i, &argv[i]);
} else {
throw BadArg(string(argv[i]));
}
}
}
void CommandLineArg::clearArgs() {
shortArgs_.clear();
longArgs_.clear();
helpString_ = "";
}
void CommandLineArg::showHelp(std::ostream &os) {
os << helpString_;
}

64
sim/simx/args.h Normal file
View file

@ -0,0 +1,64 @@
#pragma once
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <util.h>
namespace vortex {
struct BadArg { BadArg(std::string s) : arg(s) {} std::string arg; };
class CommandLineArg {
public:
CommandLineArg(std::string s, std::string l, const char *helpText);
CommandLineArg(std::string l, const char *helpText);
virtual int read(int argc, char** argv) = 0;
static void readArgs(int argc, char **argv);
static void clearArgs();
static void showHelp(std::ostream &os);
private:
static std::string helpString_;
static std::unordered_map<std::string, CommandLineArg *> longArgs_;
static std::unordered_map<std::string, CommandLineArg *> shortArgs_;
};
template <typename T> class CommandLineArgSetter : public CommandLineArg {
public:
CommandLineArgSetter(std::string s, std::string l, const char *ht, T &x) :
CommandLineArg(s, l, ht), arg_(x) {}
CommandLineArgSetter(std::string l, const char *ht, T &x) :
CommandLineArg(l, ht), arg_(x) {}
int read(int argc, char **argv) {
__unused(argc);
std::istringstream iss(argv[1]);
iss >> arg_;
return 1;
}
private:
T &arg_;
};
class CommandLineArgFlag : public CommandLineArg {
public:
CommandLineArgFlag(std::string s, std::string l, const char *ht, bool &x) :
CommandLineArg(s, l, ht), arg_(x) { arg_ = false; }
CommandLineArgFlag(std::string l, const char *ht, bool &x) :
CommandLineArg(l, ht), arg_(x) { arg_ = false; }
int read(int argc, char **argv) {
__unused(argc, argv);
arg_ = true;
return 0;
}
private:
bool &arg_;
};
}

395
sim/simx/core.cpp Normal file
View file

@ -0,0 +1,395 @@
#include <iostream>
#include <iomanip>
#include <string.h>
#include <assert.h>
#include <util.h>
#include "types.h"
#include "archdef.h"
#include "mem.h"
#include "decode.h"
#include "core.h"
#include "debug.h"
using namespace vortex;
Core::Core(const ArchDef &arch, Decoder &decoder, MemoryUnit &mem, Word id)
: id_(id)
, arch_(arch)
, decoder_(decoder)
, mem_(mem)
, shared_mem_(1, SMEM_SIZE)
, inst_in_schedule_("schedule")
, inst_in_fetch_("fetch")
, inst_in_decode_("decode")
, inst_in_issue_("issue")
, inst_in_execute_("execute")
, inst_in_writeback_("writeback") {
in_use_iregs_.resize(arch.num_warps(), 0);
in_use_fregs_.resize(arch.num_warps(), 0);
in_use_vregs_.reset();
csrs_.resize(arch_.num_csrs(), 0);
fcsrs_.resize(arch_.num_warps(), 0);
barriers_.resize(arch_.num_barriers(), 0);
warps_.resize(arch_.num_warps());
for (int i = 0; i < arch_.num_warps(); ++i) {
warps_[i] = std::make_shared<Warp>(this, i);
}
this->clear();
}
Core::~Core() {
for (auto& buf : print_bufs_) {
auto str = buf.second.str();
if (!str.empty()) {
std::cout << "#" << buf.first << ": " << str << std::endl;
}
}
}
void Core::clear() {
for (int w = 0; w < arch_.num_warps(); ++w) {
in_use_iregs_[w].reset();
in_use_fregs_[w].reset();
}
stalled_warps_.reset();
in_use_vregs_.reset();
for (auto& csr : csrs_) {
csr = 0;
}
for (auto& fcsr : fcsrs_) {
fcsr = 0;
}
for (auto& barrier : barriers_) {
barrier.reset();
}
for (auto warp : warps_) {
warp->clear();
}
inst_in_schedule_.clear();
inst_in_fetch_.clear();
inst_in_decode_.clear();
inst_in_issue_.clear();
inst_in_execute_.clear();
inst_in_writeback_.clear();
print_bufs_.clear();
steps_ = 0;
insts_ = 0;
loads_ = 0;
stores_ = 0;
inst_in_schedule_.valid = true;
warps_[0]->setTmask(0, true);
ebreak_ = false;
}
void Core::step() {
D(2, "###########################################################");
steps_++;
D(2, std::dec << "Core" << id_ << ": cycle: " << steps_);
this->writeback();
this->execute();
this->issue();
this->decode();
this->fetch();
this->schedule();
DPN(2, std::flush);
}
void Core::schedule() {
if (!inst_in_schedule_.enter(&inst_in_fetch_))
return;
bool foundSchedule = false;
int scheduled_warp = inst_in_schedule_.wid;
for (size_t wid = 0; wid < warps_.size(); ++wid) {
// round robin scheduling
scheduled_warp = (scheduled_warp + 1) % warps_.size();
bool is_active = warps_[scheduled_warp]->active();
bool stalled = stalled_warps_[scheduled_warp];
if (is_active && !stalled) {
foundSchedule = true;
break;
}
}
if (!foundSchedule)
return;
D(2, "Schedule: wid=" << scheduled_warp);
inst_in_schedule_.wid = scheduled_warp;
// advance pipeline
inst_in_schedule_.next(&inst_in_fetch_);
}
void Core::fetch() {
if (!inst_in_fetch_.enter(&inst_in_issue_))
return;
int wid = inst_in_fetch_.wid;
auto active_threads_b = warps_[wid]->getActiveThreads();
warps_[wid]->step(&inst_in_fetch_);
auto active_threads_a = warps_[wid]->getActiveThreads();
insts_ += active_threads_b;
if (active_threads_b != active_threads_a) {
D(3, "*** warp#" << wid << " active threads changed to " << active_threads_a);
}
if (inst_in_fetch_.stall_warp) {
D(3, "*** warp#" << wid << " fetch stalled");
stalled_warps_[wid] = true;
}
D(4, inst_in_fetch_);
// advance pipeline
inst_in_fetch_.next(&inst_in_issue_);
}
void Core::decode() {
if (!inst_in_decode_.enter(&inst_in_issue_))
return;
// advance pipeline
inst_in_decode_.next(&inst_in_issue_);
}
void Core::issue() {
if (!inst_in_issue_.enter(&inst_in_execute_))
return;
bool in_use_regs = (inst_in_issue_.used_iregs & in_use_iregs_[inst_in_issue_.wid]) != 0
|| (inst_in_issue_.used_fregs & in_use_fregs_[inst_in_issue_.wid]) != 0
|| (inst_in_issue_.used_vregs & in_use_vregs_) != 0;
if (in_use_regs) {
D(3, "*** Issue: registers not ready!");
inst_in_issue_.stalled = true;
return;
}
switch (inst_in_issue_.rdest_type) {
case 1:
if (inst_in_issue_.rdest)
in_use_iregs_[inst_in_issue_.wid][inst_in_issue_.rdest] = 1;
break;
case 2:
in_use_fregs_[inst_in_issue_.wid][inst_in_issue_.rdest] = 1;
break;
case 3:
in_use_vregs_[inst_in_issue_.rdest] = 1;
break;
default:
break;
}
// advance pipeline
inst_in_issue_.next(&inst_in_execute_);
}
void Core::execute() {
if (!inst_in_execute_.enter(&inst_in_writeback_))
return;
// advance pipeline
inst_in_execute_.next(&inst_in_writeback_);
}
void Core::writeback() {
if (!inst_in_writeback_.enter(NULL))
return;
switch (inst_in_writeback_.rdest_type) {
case 1:
in_use_iregs_[inst_in_writeback_.wid][inst_in_writeback_.rdest] = 0;
break;
case 2:
in_use_fregs_[inst_in_writeback_.wid][inst_in_writeback_.rdest] = 0;
break;
case 3:
in_use_vregs_[inst_in_writeback_.rdest] = 0;
break;
default:
break;
}
if (inst_in_writeback_.stall_warp) {
stalled_warps_[inst_in_writeback_.wid] = false;
D(3, "*** warp#" << inst_in_writeback_.wid << " fetch released");
}
// advance pipeline
inst_in_writeback_.next(NULL);
}
DoubleWord Core::get_csr(Addr addr, int tid, int wid) {
if (addr == CSR_FFLAGS) {
return fcsrs_.at(wid) & 0x1F;
} else if (addr == CSR_FRM) {
return (fcsrs_.at(wid) >> 5);
} else if (addr == CSR_FCSR) {
return fcsrs_.at(wid);
} else if (addr == CSR_WTID) {
// Warp threadID
return tid;
} else if (addr == CSR_LTID) {
// Core threadID
return tid + (wid * arch_.num_threads());
} else if (addr == CSR_GTID) {
// Processor threadID
return tid + (wid * arch_.num_threads()) +
(arch_.num_threads() * arch_.num_warps() * id_);
} else if (addr == CSR_LWID) {
// Core warpID
return wid;
} else if (addr == CSR_GWID) {
// Processor warpID
return wid + (arch_.num_warps() * id_);
} else if (addr == CSR_GCID) {
// Processor coreID
return id_;
} else if (addr == CSR_TMASK) {
// Processor coreID
return warps_.at(wid)->getTmask();
} else if (addr == CSR_NT) {
// Number of threads per warp
return arch_.num_threads();
} else if (addr == CSR_NW) {
// Number of warps per core
return arch_.num_warps();
} else if (addr == CSR_NC) {
// Number of cores
return arch_.num_cores();
} else if (addr == CSR_MINSTRET) {
// NumInsts
return insts_;
} else if (addr == CSR_MINSTRET_H) {
// NumInsts
return (DoubleWord)(insts_ >> 32);
} else if (addr == CSR_MCYCLE) {
// NumCycles
return (DoubleWord)steps_;
} else if (addr == CSR_MCYCLE_H) {
// NumCycles
return (DoubleWord)(steps_ >> 32);
} else {
return csrs_.at(addr);
}
}
void Core::set_csr(Addr addr, DoubleWord value, int /*tid*/, int wid) {
if (addr == CSR_FFLAGS) {
fcsrs_.at(wid) = (fcsrs_.at(wid) & ~0x1F) | (value & 0x1F);
} else if (addr == CSR_FRM) {
fcsrs_.at(wid) = (fcsrs_.at(wid) & ~0xE0) | (value << 5);
} else if (addr == CSR_FCSR) {
fcsrs_.at(wid) = value & 0xff;
} else {
csrs_.at(addr) = value;
}
}
void Core::barrier(int bar_id, int count, int warp_id) {
auto& barrier = barriers_.at(bar_id);
barrier.set(warp_id);
if (barrier.count() < (size_t)count)
return;
for (int i = 0; i < arch_.num_warps(); ++i) {
if (barrier.test(i)) {
warps_.at(i)->activate();
}
}
barrier.reset();
}
// simx64
Word Core::icache_fetch(Addr addr) {
Word data;
mem_.read(&data, addr, sizeof(Word), 0);
return data;
}
// simx64
DoubleWord Core::dcache_read(Addr addr, Size size) {
++loads_;
DoubleWord data = 0;
#ifdef SM_ENABLE
if ((addr >= (SMEM_BASE_ADDR - SMEM_SIZE))
&& ((addr + 3) < SMEM_BASE_ADDR)) {
shared_mem_.read(&data, addr & (SMEM_SIZE-1), size);
return data;
}
#endif
mem_.read(&data, addr, size, 0);
return data;
}
void Core::dcache_write(Addr addr, DoubleWord data, Size size) {
++stores_;
#ifdef SM_ENABLE
if ((addr >= (SMEM_BASE_ADDR - SMEM_SIZE))
&& ((addr + 3) < SMEM_BASE_ADDR)) {
shared_mem_.write(&data, addr & (SMEM_SIZE-1), size);
return;
}
#endif
if (addr >= IO_COUT_ADDR
&& addr <= (IO_COUT_ADDR + IO_COUT_SIZE - 1)) {
this->writeToStdOut(addr, data);
return;
}
mem_.write(&data, addr, size, 0);
}
bool Core::running() const {
return inst_in_fetch_.valid
|| inst_in_decode_.valid
|| inst_in_issue_.valid
|| inst_in_execute_.valid
|| inst_in_writeback_.valid;
}
void Core::printStats() const {
std::cout << "Steps : " << steps_ << std::endl
<< "Insts : " << insts_ << std::endl
<< "Loads : " << loads_ << std::endl
<< "Stores: " << stores_ << std::endl;
}
void Core::writeToStdOut(Addr addr, DoubleWord data) {
uint32_t tid = (addr - IO_COUT_ADDR) & (IO_COUT_SIZE-1);
auto& ss_buf = print_bufs_[tid];
char c = (char)data;
ss_buf << c;
if (c == '\n') {
std::cout << std::dec << "#" << tid << ": " << ss_buf.str() << std::flush;
ss_buf.str("");
}
}
void Core::trigger_ebreak() {
ebreak_ = true;
}
bool Core::check_ebreak() const {
return ebreak_;
}

123
sim/simx/core.h Normal file
View file

@ -0,0 +1,123 @@
#pragma once
#include <string>
#include <vector>
#include <list>
#include <stack>
#include <unordered_map>
#include <memory>
#include <set>
#include "debug.h"
#include "types.h"
#include "archdef.h"
#include "decode.h"
#include "mem.h"
#include "warp.h"
#include "pipeline.h"
namespace vortex {
class Core {
public:
Core(const ArchDef &arch, Decoder &decoder, MemoryUnit &mem, Word id);
~Core();
void clear();
bool running() const;
void step();
void printStats() const;
Word id() const {
return id_;
}
Warp& warp(int i) {
return *warps_.at(i);
}
Decoder& decoder() {
return decoder_;
}
const ArchDef& arch() const {
return arch_;
}
unsigned long num_insts() const {
return insts_;
}
unsigned long num_steps() const {
return steps_;
}
Word getIRegValue(int reg) const {
return warps_[0]->getIRegValue(reg);
}
DoubleWord get_csr(Addr addr, int tid, int wid);
void set_csr(Addr addr, DoubleWord value, int tid, int wid);
void barrier(int bar_id, int count, int warp_id);
// simx64
Word icache_fetch(Addr);
// simx64
DoubleWord dcache_read(Addr, Size);
// simx64
void dcache_write(Addr, DoubleWord, Size);
void trigger_ebreak();
bool check_ebreak() const;
private:
void schedule();
void fetch();
void decode();
void issue();
void execute();
void writeback();
void writeToStdOut(Addr addr, DoubleWord data);
std::vector<RegMask> in_use_iregs_;
std::vector<RegMask> in_use_fregs_;
RegMask in_use_vregs_;
WarpMask stalled_warps_;
std::vector<std::shared_ptr<Warp>> warps_;
std::vector<WarpMask> barriers_;
std::vector<DoubleWord> csrs_;
std::vector<Byte> fcsrs_;
std::unordered_map<int, std::stringstream> print_bufs_;
Word id_;
const ArchDef &arch_;
Decoder &decoder_;
MemoryUnit &mem_;
#ifdef SM_ENABLE
RAM shared_mem_;
#endif
bool ebreak_;
Pipeline inst_in_schedule_;
Pipeline inst_in_fetch_;
Pipeline inst_in_decode_;
Pipeline inst_in_issue_;
Pipeline inst_in_execute_;
Pipeline inst_in_writeback_;
uint64_t steps_;
uint64_t insts_;
uint64_t loads_;
uint64_t stores_;
};
} // namespace vortex

43
sim/simx/debug.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 4
#endif
#define DEBUG_HEADER << "DEBUG "
//#define DEBUG_HEADER << "DEBUG " << __FILE__ << ':' << std::dec << __LINE__ << ": "
#ifndef NDEBUG
#include <iostream>
#include <iomanip>
#define DX(x) x
#define D(lvl, x) do { \
if ((lvl) <= DEBUG_LEVEL) { \
std::cout DEBUG_HEADER << x << std::endl; \
} \
} while(0)
#define DPH(lvl, x) do { \
if ((lvl) <= DEBUG_LEVEL) { \
std::cout DEBUG_HEADER << x; \
} \
} while(0)
#define DPN(lvl, x) do { \
if ((lvl) <= DEBUG_LEVEL) { \
std::cout << x; \
} \
} while(0)
#else
#define DX(x)
#define D(lvl, x) do {} while(0)
#define DPH(lvl, x) do {} while(0)
#define DPN(lvl, x) do {} while(0)
#define D_RAW(x) do {} while(0)
#endif

600
sim/simx/decode.cpp Normal file
View file

@ -0,0 +1,600 @@
#include <iostream>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <vector>
#include <unordered_map>
#include <util.h>
#include "debug.h"
#include "types.h"
#include "decode.h"
#include "archdef.h"
#include "instr.h"
using namespace vortex;
struct InstTableEntry_t {
bool controlFlow;
InstType iType;
};
static const std::unordered_map<int, struct InstTableEntry_t> sc_instTable = {
{Opcode::NOP, {false, InstType::N_TYPE}},
{Opcode::R_INST, {false, InstType::R_TYPE}},
{Opcode::L_INST, {false, InstType::I_TYPE}},
{Opcode::I_INST, {false, InstType::I_TYPE}},
{Opcode::S_INST, {false, InstType::S_TYPE}},
{Opcode::B_INST, {true , InstType::B_TYPE}},
{Opcode::LUI_INST, {false, InstType::U_TYPE}},
{Opcode::AUIPC_INST, {false, InstType::U_TYPE}},
{Opcode::JAL_INST, {true , InstType::J_TYPE}},
{Opcode::JALR_INST, {true , InstType::I_TYPE}},
{Opcode::SYS_INST, {true , InstType::I_TYPE}},
{Opcode::FENCE, {true , InstType::I_TYPE}},
{Opcode::FL, {false, InstType::I_TYPE}},
{Opcode::FS, {false, InstType::S_TYPE}},
{Opcode::FCI, {false, InstType::R_TYPE}},
{Opcode::FMADD, {false, InstType::R4_TYPE}},
{Opcode::FMSUB, {false, InstType::R4_TYPE}},
{Opcode::FMNMADD, {false, InstType::R4_TYPE}},
{Opcode::FMNMSUB, {false, InstType::R4_TYPE}},
{Opcode::VSET, {false, InstType::V_TYPE}},
{Opcode::GPGPU, {false, InstType::R_TYPE}},
{Opcode::R_INST_64, {false, InstType::R_TYPE}},
{Opcode::I_INST_64, {false, InstType::I_TYPE}},
};
static const char* op_string(const Instr &instr) {
// simx64
Word func2 = instr.getFunc2();
Word func3 = instr.getFunc3();
Word func7 = instr.getFunc7();
Word rs2 = instr.getRSrc(1);
DoubleWord imm = instr.getImm();
switch (instr.getOpcode()) {
case Opcode::NOP: return "NOP";
case Opcode::LUI_INST: return "LUI";
case Opcode::AUIPC_INST: return "AUIPC";
case Opcode::R_INST:
if (func7 & 0x1) {
switch (func3) {
case 0: return "MUL";
case 1: return "MULH";
case 2: return "MULHSU";
case 3: return "MULHU";
case 4: return "DIV";
case 5: return "DIVU";
case 6: return "REM";
case 7: return "REMU";
}
} else {
switch (func3) {
case 0: return func7 ? "SUB" : "ADD";
case 1: return "SLL";
case 2: return "SLT";
case 3: return "SLTU";
case 4: return "XOR";
case 5: return func7 ? "SRA" : "SRL";
case 6: return "OR";
case 7: return "AND";
}
}
case Opcode::I_INST:
switch (func3) {
case 0: return "ADDI";
case 1: return "SLLI";
case 2: return "SLTI";
case 3: return "SLTIU";
case 4: return "XORI";
case 5: return func7 ? "SRAI" : "SRLI";
case 6: return "ORI";
case 7: return "ANDI";
}
case Opcode::B_INST:
switch (func3) {
case 0: return "BEQ";
case 1: return "BNE";
case 4: return "BLT";
case 5: return "BGE";
case 6: return "BLTU";
case 7: return "BGEU";
default:
std::abort();
}
case Opcode::JAL_INST: return "JAL";
case Opcode::JALR_INST: return "JALR";
case Opcode::L_INST:
switch (func3) {
case 0: return "LBI";
case 1: return "LHI";
case 2: return "LW";
// simx64
case 3: return "LD";
case 4: return "LBU";
case 5: return "LHU";
// simx64
case 6: return "LWU";
default:
std::abort();
}
case Opcode::S_INST:
switch (func3) {
case 0: return "SB";
case 1: return "SH";
case 2: return "SW";
// simx64
case 3: return "SD";
default:
std::abort();
}
// simx64
case Opcode::R_INST_64:
if (func7 & 0x1){
switch (func3) {
case 0: return func7 ? "SUBW" : "ADDW";
case 1: return "SLLW";
case 5: return func7 ? "SRAW" : "SRLW";
default:
std::abort();
}
} else {
switch (func3) {
case 0: return "MULW";
case 4: return "DIVW";
case 5: return "DIVUW";
case 6: return "REMW";
case 7: return "REMUW";
default:
std::abort();
}
}
// simx64
case Opcode::I_INST_64:
switch (func3) {
case 0: return "ADDIW";
case 1: return "SLLIW";
case 5: return func7 ? "SRAIW" : "SRLIW";
default:
std::abort();
}
case Opcode::SYS_INST:
switch (func3) {
case 0: return imm ? "EBREAK" : "ECALL";
case 1: return "CSRRW";
case 2: return "CSRRS";
case 3: return "CSRRC";
case 5: return "CSRRWI";
case 6: return "CSRRSI";
case 7: return "CSRRCI";
default:
std::abort();
}
case Opcode::FENCE: return "FENCE";
// simx64
case Opcode::FL:
switch (func3) {
case 0x1: return "VL";
case 0x2: return "FLW";
case 0x3: return "FLD";
default:
std::abort();
}
case Opcode::FS:
switch (func3) {
case 0x1: return "VS";
case 0x2: return "FSW";
case 0x3: return "FSD";
default:
std::abort();
}
case Opcode::FCI:
switch (func7) {
case 0x00: return "FADD.S";
case 0x01: return "FADD.D";
case 0x04: return "FSUB.S";
case 0x05: return "FSUB.D";
case 0x08: return "FMUL.S";
case 0x09: return "FMUL.D";
case 0x0c: return "FDIV.S";
case 0x0d: return "FDIV.D";
case 0x2c: return "FSQRT.S";
case 0x2d: return "FSQRT.D";
case 0x10:
switch (func3) {
case 0: return "FSGNJ.S";
case 1: return "FSGNJN.S";
case 2: return "FSGNJX.S";
default:
std::abort();
}
case 0x11:
switch (func3) {
case 0: return "FSGNJ.D";
case 1: return "FSGNJN.D";
case 2: return "FSGNJX.D";
default:
std::abort();
}
case 0x14:
switch (func3) {
case 0: return "FMIN.S";
case 1: return "FMAX.S";
default:
std::abort();
}
case 0x15:
switch (func3) {
case 0: return "FMIN.D";
case 1: return "FMAX.D";
default:
std::abort();
}
case 0x20: return "FCVT.S.D";
case 0x21: return "FCVT.D.S";
case 0x50:
switch (func3) {
case 0: return "FLE.S";
case 1: return "FLT.S";
case 2: return "FEQ.S";
default:
std::abort();
}
case 0x51:
switch (func3) {
case 0: return "FLE.D";
case 1: return "FLT.D";
case 2: return "FEQ.D";
default:
std::abort();
}
// simx64
case 0x60:
switch (rs2) {
case 0: return "FCVT.W.S";
case 1: return "FCVT.WU.S";
case 2: return "FCVT.L.S";
case 3: return "FCVT.LU.S";
default:
std::abort();
}
case 0x61:
switch (rs2) {
case 0: return "FCVT.W.D";
case 1: return "FCVT.WU.D";
case 2: return "FCVT.L.D";
case 3: return "FCVT.LU.D";
default:
std::abort();
}
case 0x68:
switch (rs2) {
case 0: return "FCVT.S.W";
case 1: return "FCVT.S.WU";
case 2: return "FCVT.S.L";
case 3: return "FCVT.S.LU";
default:
std::abort();
}
case 0x69:
switch (rs2) {
case 0: return "FCVT.D.W";
case 1: return "FCVT.D.WU";
case 2: return "FCVT.D.L";
case 3: return "FCVT.D.LU";
default:
std::abort();
}
case 0x70: return func3 ? "FCLASS.S" : "FMV.X.W";
case 0x71: return func3 ? "FCLASS.D" : "FMV.X.D";
case 0x78: return "FMV.W.X";
case 0x79: return "FMV.D.X";
default:
std::abort();
}
case Opcode::FMADD: return func2 ? "FMADD.D" : "FMADD.S";
case Opcode::FMSUB: return func2 ? "FMSUB.D" : "FMSUB.S";
case Opcode::FMNMADD: return func2 ? "FNMADD.D" : "FNMADD.S";
case Opcode::FMNMSUB: return func2 ? "FNMSUB.D" : "FNMSUB.S";
case Opcode::VSET: return "VSET";
case Opcode::GPGPU:
switch (func3) {
case 0: return "TMC";
case 1: return "WSPAWN";
case 2: return "SPLIT";
case 3: return "JOIN";
case 4: return "BAR";
case 6: return "PREFETCH";
default:
std::abort();
}
default:
std::abort();
}
}
namespace vortex {
std::ostream &operator<<(std::ostream &os, const Instr &instr) {
os << op_string(instr) << ": ";
auto opcode = instr.getOpcode();
auto rd_to_string = [&]() {
int rdt = instr.getRDType();
int rd = instr.getRDest();
switch (rdt) {
case 1: os << "r" << std::dec << rd << " <- "; break;
case 2: os << "fr" << std::dec << rd << " <- "; break;
case 3: os << "vr" << std::dec << rd << " <- "; break;
default: break;
}
};
auto rs_to_string = [&](int i) {
int rst = instr.getRSType(i);
int rs = instr.getRSrc(i);
switch (rst) {
case 1: os << "r" << std::dec << rs; break;
case 2: os << "fr" << std::dec << rs; break;
case 3: os << "vr" << std::dec << rs; break;
default: break;
}
};
if (opcode == S_INST
|| opcode == FS
|| opcode == VS) {
os << "M[r" << std::dec << instr.getRSrc(0) << " + 0x" << std::hex << instr.getImm() << "] <- ";
rs_to_string(1);
} else
if (opcode == L_INST
|| opcode == FL
|| opcode == VL) {
rd_to_string();
os << "M[r" << std::dec << instr.getRSrc(0) << " + 0x" << std::hex << instr.getImm() << "]";
} else {
rd_to_string();
int i = 0;
for (; i < instr.getNRSrc(); ++i) {
if (i) os << ", ";
rs_to_string(i);
}
if (instr.hasImm()) {
if (i) os << ", ";
os << "imm=0x" << std::hex << instr.getImm();
}
}
return os;
}
}
Decoder::Decoder(const ArchDef &arch) {
// simx64
inst_s_ = arch.wsize() * 4;
opcode_s_ = 7;
reg_s_ = 5;
func2_s_ = 2;
func3_s_ = 3;
mop_s_ = 3;
vmask_s_ = 1;
shift_opcode_ = 0;
shift_rd_ = opcode_s_;
shift_func3_ = shift_rd_ + reg_s_;
shift_rs1_ = shift_func3_ + func3_s_;
shift_rs2_ = shift_rs1_ + reg_s_;
shift_func7_ = shift_rs2_ + reg_s_;
shift_rs3_ = shift_func7_ + func2_s_;
shift_vmop_ = shift_func7_ + vmask_s_;
shift_vnf_ = shift_vmop_ + mop_s_;
shift_func6_ = shift_func7_ + 1;
shift_vset_ = shift_func7_ + 6;
reg_mask_ = 0x1f;
// simx64
func2_mask_ = 0x3;
func3_mask_ = 0x7;
func6_mask_ = 0x3f;
func7_mask_ = 0x7f;
opcode_mask_ = 0x7f;
i_imm_mask_ = 0xfff;
s_imm_mask_ = 0xfff;
b_imm_mask_ = 0x1fff;
u_imm_mask_ = 0xfffff;
j_imm_mask_ = 0xfffff;
v_imm_mask_ = 0x7ff;
}
// simx64
std::shared_ptr<Instr> Decoder::decode(Word code, Word PC) {
auto instr = std::make_shared<Instr>();
Opcode op = (Opcode)((code >> shift_opcode_) & opcode_mask_);
instr->setOpcode(op);
// simx64
Word func2 = (code >> shift_func7_) & func2_mask_;
Word func3 = (code >> shift_func3_) & func3_mask_;
Word func6 = (code >> shift_func6_) & func6_mask_;
Word func7 = (code >> shift_func7_) & func7_mask_;
int rd = (code >> shift_rd_) & reg_mask_;
int rs1 = (code >> shift_rs1_) & reg_mask_;
int rs2 = (code >> shift_rs2_) & reg_mask_;
int rs3 = (code >> shift_rs3_) & reg_mask_;
auto op_it = sc_instTable.find(op);
if (op_it == sc_instTable.end()) {
std::cout << std::hex << "invalid opcode: 0x" << op << ", instruction=0x" << code << ", PC=" << PC << std::endl;
std::abort();
}
auto iType = op_it->second.iType;
if (op == Opcode::FL || op == Opcode::FS) {
// simx64
if (func3 != 0x2 && func3 != 0x3) {
iType = InstType::V_TYPE;
}
}
switch (iType) {
case InstType::N_TYPE:
break;
case InstType::R_TYPE:
if (op == Opcode::FCI) {
switch (func7) {
case 0x68: // FCVT.S.W, FCVT.S.WU, FCVT.S.L, FCVT.S.LU
case 0x69: // FCVT.D.W, FCVT.D.WU, FCVT.D.L, FCVT.D.LU
case 0x78: // FMV.W.X
case 0x79: // FMV.D.X
instr->setSrcReg(rs1);
break;
default:
instr->setSrcFReg(rs1);
}
instr->setSrcFReg(rs2);
switch (func7) {
case 0x50: // FLE.S, FLT.S, FEQ.S
case 0x51: // FLE.D, FLT.D, FEQ.D
case 0x60: // FCVT.WU.S, FCVT.W.S, FCVT.L.S, FCVT.LU.S
case 0x61: // FCVT.W.D, FCVT.WU.D, FCVT.L.D, FCVT.LU.D
case 0x70: // FLASS.S, FMV.X.W
case 0x71: // FCLASS.D, FMV.X.D
instr->setDestReg(rd);
break;
default:
instr->setDestFReg(rd);
}
} else {
instr->setDestReg(rd);
instr->setSrcReg(rs1);
instr->setSrcReg(rs2);
}
instr->setFunc3(func3);
instr->setFunc7(func7);
break;
case InstType::I_TYPE: {
instr->setSrcReg(rs1);
if (op == Opcode::FL) {
instr->setDestFReg(rd);
} else {
instr->setDestReg(rd);
}
instr->setFunc3(func3);
instr->setFunc7(func7);
if ((func3 == 5) && (op != L_INST) && (op != Opcode::FL)) {
instr->setImm(signExt(rs2, 6, 0x3F));
} else {
instr->setImm(signExt(code >> shift_rs2_, 12, i_imm_mask_));
}
} break;
case InstType::S_TYPE: {
instr->setSrcReg(rs1);
if (op == Opcode::FS) {
instr->setSrcFReg(rs2);
} else {
instr->setSrcReg(rs2);
}
instr->setFunc3(func3);
DoubleWord imeed = (func7 << reg_s_) | rd;
instr->setImm(signExt(imeed, 12, s_imm_mask_));
} break;
case InstType::B_TYPE: {
instr->setSrcReg(rs1);
instr->setSrcReg(rs2);
instr->setFunc3(func3);
Word bit_11 = rd & 0x1;
Word bits_4_1 = rd >> 1;
Word bit_10_5 = func7 & 0x3f;
Word bit_12 = func7 >> 6;
DoubleWord imeed = (bits_4_1 << 1) | (bit_10_5 << 5) | (bit_11 << 11) | (bit_12 << 12);
instr->setImm(signExt(imeed, 13, b_imm_mask_));
} break;
case InstType::U_TYPE:
instr->setDestReg(rd);
instr->setImm(signExt(code >> shift_func3_, 20, u_imm_mask_));
break;
case InstType::J_TYPE: {
instr->setDestReg(rd);
Word unordered = code >> shift_func3_;
Word bits_19_12 = unordered & 0xff;
Word bit_11 = (unordered >> 8) & 0x1;
Word bits_10_1 = (unordered >> 9) & 0x3ff;
Word bit_20 = (unordered >> 19) & 0x1;
DoubleWord imeed = 0 | (bits_10_1 << 1) | (bit_11 << 11) | (bits_19_12 << 12) | (bit_20 << 20);
if (bit_20) {
imeed |= ~j_imm_mask_;
}
instr->setImm(imeed);
} break;
case InstType::V_TYPE:
switch (op) {
case Opcode::VSET: {
instr->setDestVReg(rd);
instr->setSrcVReg(rs1);
instr->setFunc3(func3);
if (func3 == 7) {
instr->setImm(!(code >> shift_vset_));
if (instr->getImm()) {
Word immed = (code >> shift_rs2_) & v_imm_mask_;
instr->setImm(immed);
instr->setVlmul(immed & 0x3);
instr->setVediv((immed >> 4) & 0x3);
instr->setVsew((immed >> 2) & 0x3);
} else {
instr->setSrcVReg(rs2);
}
} else {
instr->setSrcVReg(rs2);
instr->setVmask((code >> shift_func7_) & 0x1);
instr->setFunc6(func6);
}
} break;
case Opcode::VL:
instr->setDestVReg(rd);
instr->setSrcVReg(rs1);
instr->setVlsWidth(func3);
instr->setSrcVReg(rs2);
instr->setVmask(code >> shift_func7_);
instr->setVmop((code >> shift_vmop_) & func3_mask_);
instr->setVnf((code >> shift_vnf_) & func3_mask_);
break;
case Opcode::VS:
instr->setVs3(rd);
instr->setSrcVReg(rs1);
instr->setVlsWidth(func3);
instr->setSrcVReg(rs2);
instr->setVmask(code >> shift_func7_);
instr->setVmop((code >> shift_vmop_) & func3_mask_);
instr->setVnf((code >> shift_vnf_) & func3_mask_);
break;
default:
std::abort();
}
break;
case R4_TYPE:
instr->setDestFReg(rd);
instr->setSrcFReg(rs1);
instr->setSrcFReg(rs2);
instr->setSrcFReg(rs3);
instr->setFunc3(func3);
// simx64
instr->setFunc2(func2);
break;
default:
std::abort();
}
D(2, "Instr 0x" << std::hex << code << ": " << *instr << std::flush);
return instr;
}

61
sim/simx/decode.h Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include <vector>
#include <memory>
namespace vortex {
class ArchDef;
class Instr;
class Pipeline;
class Decoder {
public:
Decoder(const ArchDef &);
std::shared_ptr<Instr> decode(Word code, Word PC);
private:
Word inst_s_;
Word opcode_s_;
Word reg_s_;
Word func2_s_;
Word func3_s_;
Word shift_opcode_;
Word shift_rd_;
Word shift_rs1_;
Word shift_rs2_;
Word shift_rs3_;
Word shift_func2_;
Word shift_func3_;
Word shift_func7_;
Word shift_j_u_immed_;
Word shift_s_b_immed_;
Word shift_i_immed_;
Word reg_mask_;
Word func2_mask_;
Word func3_mask_;
Word func6_mask_;
Word func7_mask_;
Word opcode_mask_;
Word i_imm_mask_;
Word s_imm_mask_;
Word b_imm_mask_;
Word u_imm_mask_;
Word j_imm_mask_;
Word v_imm_mask_;
//Vector
Word shift_vset_;
Word shift_vset_immed_;
Word shift_vmask_;
Word shift_vmop_;
Word shift_vnf_;
Word shift_func6_;
Word vmask_s_;
Word mop_s_;
};
}

1902
sim/simx/execute.cpp Normal file

File diff suppressed because it is too large Load diff

147
sim/simx/instr.h Normal file
View file

@ -0,0 +1,147 @@
#pragma once
#include "types.h"
namespace vortex {
class Warp;
enum Opcode {
NOP = 0,
R_INST = 0x33,
L_INST = 0x3,
I_INST = 0x13,
S_INST = 0x23,
B_INST = 0x63,
LUI_INST = 0x37,
AUIPC_INST= 0x17,
JAL_INST = 0x6f,
JALR_INST = 0x67,
SYS_INST = 0x73,
FENCE = 0x0f,
// F Extension
FL = 0x7,
FS = 0x27,
FCI = 0x53,
FMADD = 0x43,
FMSUB = 0x47,
FMNMSUB = 0x4b,
FMNMADD = 0x4f,
// Vector Extension
VSET = 0x57,
VL = 0x7,
VS = 0x27,
// GPGPU Extension
GPGPU = 0x6b,
// simx64
// RV64 Standard Extensions
R_INST_64 = 0x3b,
I_INST_64 = 0x1b,
};
enum InstType {
N_TYPE,
R_TYPE,
I_TYPE,
S_TYPE,
B_TYPE,
U_TYPE,
J_TYPE,
V_TYPE,
R4_TYPE
};
class Instr {
public:
Instr()
: opcode_(Opcode::NOP)
, num_rsrcs_(0)
, has_imm_(false)
, rdest_(0)
, func3_(0)
, func7_(0) {
for (int i = 0; i < MAX_REG_SOURCES; ++i) {
rsrc_type_[i] = 0;
}
}
/* Setters used to "craft" the instruction. */
void setOpcode(Opcode opcode) { opcode_ = opcode; }
void setDestReg(int destReg) { rdest_type_ = 1; rdest_ = destReg; }
void setSrcReg(int srcReg) { rsrc_type_[num_rsrcs_] = 1; rsrc_[num_rsrcs_++] = srcReg; }
void setDestFReg(int destReg) { rdest_type_ = 2; rdest_ = destReg; }
void setSrcFReg(int srcReg) { rsrc_type_[num_rsrcs_] = 2; rsrc_[num_rsrcs_++] = srcReg; }
void setDestVReg(int destReg) { rdest_type_ = 3; rdest_ = destReg; }
void setSrcVReg(int srcReg) { rsrc_type_[num_rsrcs_] = 3; rsrc_[num_rsrcs_++] = srcReg; }
void setFunc2(Word func2) { func2_ = func2;}
void setFunc3(Word func3) { func3_ = func3; }
void setFunc7(Word func7) { func7_ = func7; }
void setImm(DoubleWord imm) { has_imm_ = true; imm_ = imm; }
void setVlsWidth(Word width) { vlsWidth_ = width; }
void setVmop(Word mop) { vMop_ = mop; }
void setVnf(Word nf) { vNf_ = nf; }
void setVmask(Word mask) { vmask_ = mask; }
void setVs3(Word vs) { vs3_ = vs; }
void setVlmul(Word lmul) { vlmul_ = 1 << lmul; }
void setVsew(Word sew) { vsew_ = 1 << (3+sew); }
void setVediv(Word ediv) { vediv_ = 1 << ediv; }
void setFunc6(Word func6) { func6_ = func6; }
/* Getters used by encoders. */
Opcode getOpcode() const { return opcode_; }
Word getFunc2() const { return func2_; }
Word getFunc3() const { return func3_; }
Word getFunc6() const { return func6_; }
Word getFunc7() const { return func7_; }
int getNRSrc() const { return num_rsrcs_; }
int getRSrc(int i) const { return rsrc_[i]; }
int getRSType(int i) const { return rsrc_type_[i]; }
int getRDest() const { return rdest_; }
int getRDType() const { return rdest_type_; }
bool hasImm() const { return has_imm_; }
DoubleWord getImm() const { return imm_; }
Word getVlsWidth() const { return vlsWidth_; }
Word getVmop() const { return vMop_; }
Word getvNf() const { return vNf_; }
Word getVmask() const { return vmask_; }
Word getVs3() const { return vs3_; }
Word getVlmul() const { return vlmul_; }
Word getVsew() const { return vsew_; }
Word getVediv() const { return vediv_; }
private:
enum {
MAX_REG_SOURCES = 3
};
Opcode opcode_;
int num_rsrcs_;
bool has_imm_;
int rdest_type_;
int isrc_mask_;
int fsrc_mask_;
int vsrc_mask_;
DoubleWord imm_;
int rsrc_type_[MAX_REG_SOURCES];
int rsrc_[MAX_REG_SOURCES];
int rdest_;
Word func2_;
Word func3_;
Word func7_;
//Vector
Word vmask_;
Word vlsWidth_;
Word vMop_;
Word vNf_;
Word vs3_;
Word vlmul_;
Word vsew_;
Word vediv_;
Word func6_;
friend std::ostream &operator<<(std::ostream &, const Instr&);
};
}

109
sim/simx/main.cpp Normal file
View file

@ -0,0 +1,109 @@
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <sys/stat.h>
#include "debug.h"
#include "types.h"
#include "core.h"
#include "args.h"
using namespace vortex;
int main(int argc, char **argv) {
std::string archString("rv32imf");
int num_cores(NUM_CORES * NUM_CLUSTERS);
int num_warps(NUM_WARPS);
int num_threads(NUM_THREADS);
std::string imgFileName;
bool showHelp(false);
bool showStats(false);
bool riscv_test(false);
/* Read the command line arguments. */
CommandLineArgFlag fh("-h", "--help", "", showHelp);
CommandLineArgSetter<std::string> fa("-a", "--arch", "", archString);
CommandLineArgSetter<std::string> fi("-i", "--image", "", imgFileName);
CommandLineArgSetter<int> fc("-c", "--cores", "", num_cores);
CommandLineArgSetter<int> fw("-w", "--warps", "", num_warps);
CommandLineArgSetter<int> ft("-t", "--threads", "", num_threads);
CommandLineArgFlag fr("-r", "--riscv", "", riscv_test);
CommandLineArgFlag fs("-s", "--stats", "", showStats);
CommandLineArg::readArgs(argc - 1, argv + 1);
if (showHelp || imgFileName.empty()) {
std::cout << "Vortex emulator command line arguments:\n"
" -i, --image <filename> Program RAM image\n"
" -c, --cores <num> Number of cores\n"
" -w, --warps <num> Number of warps\n"
" -t, --threads <num> Number of threads\n"
" -a, --arch <arch string> Architecture string\n"
" -r, --riscv riscv test\n"
" -s, --stats Print stats on exit.\n";
return 0;
}
ArchDef arch(archString, num_cores, num_warps, num_threads);
Decoder decoder(arch);
MemoryUnit mu(0, arch.wsize(), true);
RAM ram((1<<12), (1<<20));
std::string program_ext(fileExtension(imgFileName.c_str()));
if (program_ext == "bin") {
ram.loadBinImage(imgFileName.c_str(), STARTUP_ADDR);
} else if (program_ext == "hex") {
ram.loadHexImage(imgFileName.c_str());
} else {
std::cout << "*** error: only *.bin or *.hex images supported." << std::endl;
return -1;
}
mu.attach(ram, 0, 0xFFFFFFFF);
struct stat hello;
fstat(0, &hello);
std::vector<std::shared_ptr<Core>> cores(num_cores);
for (int i = 0; i < num_cores; ++i) {
cores[i] = std::make_shared<Core>(arch, decoder, mu, i);
}
bool running;
int exitcode = 0;
do {
running = false;
for (auto& core : cores) {
core->step();
if (core->running()) {
running = true;
}
if (core->check_ebreak()) {
exitcode = core->getIRegValue(3);
running = false;
break;
}
}
} while (running);
if (riscv_test) {
if (1 == exitcode) {
std::cout << "Passed." << std::endl;
exitcode = 0;
} else {
std::cout << "Failed." << std::endl;
}
} else {
if (exitcode != 0) {
std::cout << "*** error: exitcode=" << exitcode << std::endl;
}
}
return exitcode;
}

63
sim/simx/pipeline.cpp Normal file
View file

@ -0,0 +1,63 @@
#include <iostream>
#include "pipeline.h"
using namespace vortex;
namespace vortex {
std::ostream &operator<<(std::ostream &os, const Pipeline& pipeline) {
os << pipeline.name_ << ": valid=" << pipeline.valid << std::endl;
os << pipeline.name_ << ": stalled=" << pipeline.stalled << std::endl;
os << pipeline.name_ << ": stall_warp=" << pipeline.stall_warp << std::endl;
os << pipeline.name_ << ": wid=" << pipeline.wid << std::endl;
os << pipeline.name_ << ": PC=" << std::hex << pipeline.PC << std::endl;
os << pipeline.name_ << ": used_iregs=" << pipeline.used_iregs << std::endl;
os << pipeline.name_ << ": used_fregs=" << pipeline.used_fregs << std::endl;
os << pipeline.name_ << ": used_vregs=" << pipeline.used_vregs << std::endl;
return os;
}
}
Pipeline::Pipeline(const char* name)
: name_(name) {
this->clear();
}
void Pipeline::clear() {
valid = false;
stalled = false;
stall_warp = false;
wid = 0;
PC = 0;
used_iregs.reset();
used_fregs.reset();
used_vregs.reset();
}
bool Pipeline::enter(Pipeline *drain) {
if (drain) {
if (drain->stalled) {
this->stalled = true;
return false;
}
drain->valid = false;
}
this->stalled = false;
if (!this->valid)
return false;
return true;
}
void Pipeline::next(Pipeline *drain) {
if (drain) {
drain->valid = this->valid;
drain->stalled = this->stalled;
drain->stall_warp = this->stall_warp;
drain->wid = this->wid;
drain->PC = this->PC;
drain->rdest = this->rdest;
drain->rdest_type = this->rdest_type;
drain->used_iregs = this->used_iregs;
drain->used_fregs = this->used_fregs;
drain->used_vregs = this->used_vregs;
}
}

48
sim/simx/pipeline.h Normal file
View file

@ -0,0 +1,48 @@
#pragma once
#include <memory>
#include <util.h>
#include "types.h"
#include "debug.h"
namespace vortex {
class Instr;
class Pipeline {
public:
Pipeline(const char* name);
void clear();
bool enter(Pipeline* drain);
void next(Pipeline* drain);
//--
bool valid;
//--
bool stalled;
bool stall_warp;
//--
int wid;
DoubleWord PC;
//--
int rdest_type;
int rdest;
RegMask used_iregs;
RegMask used_fregs;
RegMask used_vregs;
private:
const char* name_;
friend std::ostream &operator<<(std::ostream &, const Pipeline&);
};
}

27
sim/simx/types.h Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include <bitset>
#include <VX_config.h>
namespace vortex {
typedef uint8_t Byte;
typedef uint32_t Word;
typedef int32_t WordI;
// simx64
typedef uint64_t DoubleWord;
typedef int64_t DoubleWordI;
// simx64
typedef uint64_t Addr;
typedef uint64_t Size;
typedef std::bitset<32> RegMask;
typedef std::bitset<32> ThreadMask;
typedef std::bitset<32> WarpMask;
}

97
sim/simx/warp.cpp Normal file
View file

@ -0,0 +1,97 @@
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <assert.h>
#include <util.h>
#include "instr.h"
#include "core.h"
using namespace vortex;
Warp::Warp(Core *core, Word id)
: id_(id)
, core_(core) {
// simx64
iRegFile_.resize(core_->arch().num_threads(), std::vector<DoubleWord>(core_->arch().num_regs(), 0));
fRegFile_.resize(core_->arch().num_threads(), std::vector<DoubleWord>(core_->arch().num_regs(), 0));
vRegFile_.resize(core_->arch().num_regs(), std::vector<Byte>(core_->arch().vsize(), 0));
this->clear();
}
void Warp::clear() {
PC_ = STARTUP_ADDR;
tmask_.reset();
active_ = false;
}
void Warp::step(Pipeline *pipeline) {
assert(tmask_.any());
DPH(2, "Step: wid=" << id_ << ", PC=0x" << std::hex << PC_ << ", tmask=");
for (int i = 0, n = core_->arch().num_threads(); i < n; ++i)
DPN(2, tmask_[n-i-1]);
DPN(2, "\n");
/* Fetch and decode. */
Word fetched = core_->icache_fetch(PC_);
auto instr = core_->decoder().decode(fetched, PC_);
// Update pipeline
pipeline->valid = true;
pipeline->PC = PC_;
pipeline->rdest = instr->getRDest();
pipeline->rdest_type = instr->getRDType();
pipeline->used_iregs.reset();
pipeline->used_fregs.reset();
pipeline->used_vregs.reset();
switch (pipeline->rdest_type) {
case 1:
pipeline->used_iregs[pipeline->rdest] = 1;
break;
case 2:
pipeline->used_fregs[pipeline->rdest] = 1;
break;
case 3:
pipeline->used_vregs[pipeline->rdest] = 1;
break;
default:
break;
}
for (int i = 0; i < instr->getNRSrc(); ++i) {
int type = instr->getRSType(i);
int reg = instr->getRSrc(i);
switch (type) {
case 1:
pipeline->used_iregs[reg] = 1;
break;
case 2:
pipeline->used_fregs[reg] = 1;
break;
case 3:
pipeline->used_vregs[reg] = 1;
break;
default:
break;
}
}
// Execute
this->execute(*instr, pipeline);
D(4, "Register state:");
for (int i = 0; i < core_->arch().num_regs(); ++i) {
DPN(4, " %r" << std::setfill('0') << std::setw(2) << std::dec << i << ':');
// for (int j = 0; j < core_->arch().num_threads(); ++j) {
// // simx64
// DPN(4, ' ' << std::setfill('0') << std::setw(16) << std::hex << iRegFile_[j][i] << std::setfill(' ') << ' ');
// }
DPN(4, ' ' << std::setfill('0') << std::setw(16) << std::hex << iRegFile_[0][i] << std::setfill(' ') << ' ');
DPN(4, ' ' << std::setfill('0') << std::setw(16) << std::hex << fRegFile_[0][i] << std::setfill(' ') << ' ');
DPN(4, std::endl);
}
}

113
sim/simx/warp.h Normal file
View file

@ -0,0 +1,113 @@
#ifndef __WARP_H
#define __WARP_H
#include <vector>
#include <stack>
#include "types.h"
namespace vortex {
class Core;
class Instr;
class Pipeline;
struct DomStackEntry {
DomStackEntry(const ThreadMask &tmask, DoubleWord PC)
: tmask(tmask)
, PC(PC)
, fallThrough(false)
, unanimous(false)
{}
DomStackEntry(const ThreadMask &tmask)
: tmask(tmask)
, PC(0)
, fallThrough(true)
, unanimous(false)
{}
ThreadMask tmask;
DoubleWord PC;
bool fallThrough;
bool unanimous;
};
struct vtype {
int vill;
int vediv;
int vsew;
int vlmul;
};
class Warp {
public:
Warp(Core *core, Word id);
void clear();
bool active() const {
return active_;
}
void activate() {
active_ = true;
}
std::size_t getActiveThreads() const {
if (active_)
return tmask_.count();
return 0;
}
Word id() const {
return id_;
}
DoubleWord getPC() const {
return PC_;
}
void setPC(DoubleWord PC) {
PC_ = PC;
}
void setTmask(size_t index, bool value) {
tmask_[index] = value;
active_ = tmask_.any();
}
Word getTmask() const {
if (active_)
return tmask_.to_ulong();
return 0;
}
Word getIRegValue(int reg) const {
return iRegFile_[0][reg];
}
void step(Pipeline *);
private:
void execute(const Instr &instr, Pipeline *);
Word id_;
bool active_;
Core *core_;
DoubleWord PC_;
ThreadMask tmask_;
// simx64
std::vector<std::vector<DoubleWord>> iRegFile_;
std::vector<std::vector<DoubleWord>> fRegFile_;
std::vector<std::vector<Byte>> vRegFile_;
std::stack<DomStackEntry> domStack_;
struct vtype vtype_;
int vl_;
};
}
#endif