feat: fix compile error and update demo

This commit is contained in:
Wankupi
2024-07-23 20:04:41 +08:00
parent 80ff0d5682
commit 2fc44f14c9
7 changed files with 130 additions and 121 deletions

View File

@ -1,131 +1,111 @@
#include "../include/tools.h" #include "tools.h"
#include <iostream> #include <iostream>
#include <unordered_map>
bool reset;
bool ready;
// RISC-V // RISC-V
enum class Opcode : dark::max_size_t { enum class Opcode : dark::max_size_t {
ADD, ADD,
SUB, SUB,
SLL, SLL,
SRL, SRL,
SRA, SRA,
AND, AND,
OR, OR,
XOR, XOR,
SLT, SLT,
SLTU, SLTU,
SGE, SGE,
SGEU, SGEU,
SEQ, SEQ,
SNEQ SNEQ
}; };
// Normally, only wire can be used in the input. // Normally, only wire can be used in the input.
struct AluInput { struct AluInput {
Wire <8> opcode; Wire<8> opcode;
Wire <1> issue; Wire<1> issue;
Wire <32> rs1; Wire<32> rs1;
Wire <32> rs2; Wire<32> rs2;
}; };
struct AluOutput { struct AluOutput {
Register <32> out; Register<32> out;
Register <1> done; Register<1> done;
}; };
struct AluModule : AluInput, AluOutput { struct AluModule : dark::Module<AluInput, AluOutput> {
using Tags = SyncTags<AluInput, AluOutput>; void work() override {
if (issue) {
void work() { switch (static_cast<Opcode>(static_cast<unsigned>(opcode))) {
if (reset) { using enum Opcode;
done <= 0; case ADD: out <= (rs1 + rs2); break;
} else if(ready && issue) { case SUB: out <= (rs1 - rs2); break;
switch (static_cast <Opcode> (static_cast <unsigned> (opcode))) { case SLL: out <= (rs1 << rs2); break;
using enum Opcode; case SRL: out <= (rs1 >> rs2); break;
case ADD: out <= (rs1 + rs2); break; case SRA: out <= (to_signed(rs1) >> to_unsigned(rs2));
case SUB: out <= (rs1 - rs2); break; case AND: out <= (rs1 & rs2); break;
case SLL: out <= (rs1 << rs2); break; case OR: out <= (rs1 | rs2); break;
case SRL: out <= (rs1 >> rs2); break; case XOR: out <= (rs1 ^ rs2); break;
case SRA: out <= (to_signed(rs1) >> to_unsigned(rs2)); case SLT: out <= (to_signed(rs1) < to_signed(rs2)); break;
case AND: out <= (rs1 & rs2); break; case SLTU: out <= (rs1 < rs2); break;
case OR: out <= (rs1 | rs2); break; case SGE: out <= (to_signed(rs1) >= to_signed(rs2)); break;
case XOR: out <= (rs1 ^ rs2); break; case SGEU: out <= (rs1 >= rs2); break;
case SLT: out <= (to_signed(rs1) < to_signed(rs2)); break; case SEQ: out <= (rs1 == rs2); break;
case SLTU: out <= (rs1 < rs2); break; case SNEQ: out <= (rs1 != rs2); break;
case SGE: out <= (to_signed(rs1) >= to_signed(rs2)); break; default: dark::debug::assert(false, "Invalid opcode");
case SGEU: out <= (rs1 >= rs2); break; }
case SEQ: out <= (rs1 == rs2); break; done <= 1;
case SNEQ: out <= (rs1 != rs2); break; }
default: dark::debug::assert(false, "Invalid opcode"); else {
} done <= 0;
done <= 1; }
} else { }
done <= 0;
}
}
}; };
signed main() { int main() {
AluModule alu; std::string opstring;
std::string opstring; max_size_t opcode;
max_size_t issue;
max_size_t rs1;
max_size_t rs2;
max_size_t opcode; dark::CPU cpu;
max_size_t issue; AluModule alu;
max_size_t rs1; alu.opcode = [&]() { return opcode; };
max_size_t rs2; alu.issue = [&]() { return issue; };
alu.rs1 = [&]() { return rs1; };
ready = 1; alu.rs2 = [&]() { return rs2; };
cpu.add_module(&alu);
alu.opcode = [&]() { return opcode; };
alu.issue = [&]() { return issue; };
alu.rs1 = [&]() { return rs1; };
alu.rs2 = [&]() { return rs2; };
while (std::cin >> opstring) {
issue = 1;
std::cin >> rs1 >> rs2;
if (opstring == "add") {
opcode = static_cast <max_size_t> (Opcode::ADD);
} else if (opstring == "sub") {
opcode = static_cast <max_size_t> (Opcode::SUB);
} else if (opstring == "sll") {
opcode = static_cast <max_size_t> (Opcode::SLL);
} else if (opstring == "srl") {
opcode = static_cast <max_size_t> (Opcode::SRL);
} else if (opstring == "sra") {
opcode = static_cast <max_size_t> (Opcode::SRA);
} else if (opstring == "and") {
opcode = static_cast <max_size_t> (Opcode::AND);
} else if (opstring == "or") {
opcode = static_cast <max_size_t> (Opcode::OR);
} else if (opstring == "xor") {
opcode = static_cast <max_size_t> (Opcode::XOR);
} else if (opstring == "slt") {
opcode = static_cast <max_size_t> (Opcode::SLT);
} else if (opstring == "sltu") {
opcode = static_cast <max_size_t> (Opcode::SLTU);
} else if (opstring == "sge") {
opcode = static_cast <max_size_t> (Opcode::SGE);
} else if (opstring == "sgeu") {
opcode = static_cast <max_size_t> (Opcode::SGEU);
} else if (opstring == "seq") {
opcode = static_cast <max_size_t> (Opcode::SEQ);
} else if (opstring == "sneq") {
opcode = static_cast <max_size_t> (Opcode::SNEQ);
} else {
std::cout << "Invalid opcode" << std::endl;
issue = 0;
}
alu.work();
std::cout << to_unsigned(alu.out) << std::endl;
sync_member(alu);
}
std::unordered_map<std::string, Opcode> cmd2op = {
{"add", Opcode::ADD},
{"sub", Opcode::SUB},
{"sll", Opcode::SLL},
{"src", Opcode::SRL},
{"sra", Opcode::SRA},
{"and", Opcode::AND},
{"or", Opcode::OR},
{"xor", Opcode::XOR},
{"slt", Opcode::SLT},
{"sltu", Opcode::SLTU},
{"sge", Opcode::SGE},
{"sgeu", Opcode::SGEU},
{"seq", Opcode::SEQ},
{"sneq", Opcode::SNEQ}};
while (std::cin >> opstring) {
if (cmd2op.find(opstring) == cmd2op.end()) {
std::cout << "Invalid opcode" << std::endl;
issue = 0;
}
else {
issue = 1;
std::cin >> rs1 >> rs2;
}
opcode = static_cast<max_size_t>(cmd2op[opstring]);
cpu.run_once();
std::cout << "out: " << static_cast<unsigned int>(alu.out) << std::endl;
std::cout << "done: " << static_cast<unsigned int>(alu.done) << std::endl;
}
return 0;
} }

View File

@ -43,7 +43,9 @@ concept int_type = !has_length<_Tp> && implicit_convertible_to<_Tp, max_size_t>;
template<typename _Lhs, typename _Rhs> template<typename _Lhs, typename _Rhs>
concept bit_match = concept bit_match =
(bit_type<_Lhs> && bit_type<_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len) || (int_type<_Lhs> || int_type<_Rhs>); (bit_type<_Lhs> && bit_type<_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len) // prevent format
|| (int_type<_Lhs> && bit_type<_Rhs>) //
|| (bit_type<_Lhs> && int_type<_Rhs>);
template<typename _Tp, std::size_t _Len> template<typename _Tp, std::size_t _Len>
concept bit_convertible = concept bit_convertible =

View File

@ -1,4 +1,6 @@
#pragma once
#include "module.h" #include "module.h"
#include <algorithm>
#include <memory> #include <memory>
#include <random> #include <random>
#include <vector> #include <vector>
@ -7,7 +9,8 @@ namespace dark {
class CPU { class CPU {
private: private:
std::vector<std::unique_ptr<ModuleBase>> modules; std::vector<std::unique_ptr<ModuleBase>> mod_owned;
std::vector<ModuleBase *> modules;
public: public:
unsigned long long cycles = 0; unsigned long long cycles = 0;
@ -19,9 +22,21 @@ private:
} }
public: public:
void add_module(std::unique_ptr<ModuleBase> module) { /// @attention the pointer will be moved. you SHOULD NOT use it after calling this function.
modules.push_back(std::move(module)); template<typename _Tp>
requires std::derived_from<_Tp, ModuleBase>
void add_module(std::unique_ptr<_Tp> &module) {
modules.push_back(module.get());
mod_owned.emplace_back(std::move(module));
} }
void add_module(std::unique_ptr<ModuleBase> module) {
modules.push_back(module.get());
mod_owned.emplace_back(std::move(module));
}
void add_module(ModuleBase *module) {
modules.push_back(module);
}
void run_once() { void run_once() {
++cycles; ++cycles;
for (auto &module: modules) for (auto &module: modules)
@ -30,10 +45,7 @@ public:
} }
void run_once_shuffle() { void run_once_shuffle() {
static std::default_random_engine engine; static std::default_random_engine engine;
std::vector<ModuleBase *> shuffled; std::vector<ModuleBase *> shuffled = modules;
shuffled.reserve(modules.size());
for (auto &module: modules)
shuffled.push_back(module.get());
std::shuffle(shuffled.begin(), shuffled.end(), engine); std::shuffle(shuffled.begin(), shuffled.end(), engine);
++cycles; ++cycles;

View File

@ -1,13 +1,21 @@
#pragma once
#include "synchronize.h" #include "synchronize.h"
namespace dark { namespace dark {
namespace details {
struct empty_class {
void sync() { /* do nothing */ }
};
} // namespace details
struct ModuleBase { struct ModuleBase {
virtual void work() = 0; virtual void work() = 0;
virtual void sync() = 0; virtual void sync() = 0;
virtual ~ModuleBase() = default; virtual ~ModuleBase() = default;
}; };
template<typename _Tinput, typename _Toutput, typename _Tprivate> template<typename _Tinput, typename _Toutput, typename _Tprivate = details::empty_class>
requires std::is_aggregate_v<_Tinput> && std::is_aggregate_v<_Toutput> && std::is_aggregate_v<_Tprivate>
struct Module : public ModuleBase, public _Tinput, public _Toutput, protected _Tprivate { struct Module : public ModuleBase, public _Tinput, public _Toutput, protected _Tprivate {
void sync() override final { void sync() override final {
sync_member(static_cast<_Tinput &>(*this)); sync_member(static_cast<_Tinput &>(*this));

View File

@ -41,6 +41,7 @@ public:
} }
explicit operator max_size_t() const { return this->_M_old; } explicit operator max_size_t() const { return this->_M_old; }
explicit operator bool() const { return this->_M_old; }
}; };
} // namespace dark } // namespace dark

View File

@ -5,6 +5,8 @@
#include "register.h" #include "register.h"
#include "synchronize.h" #include "synchronize.h"
#include "wire.h" #include "wire.h"
#include "module.h"
#include "cpu.h"
using dark::Bit; using dark::Bit;
using dark::sign_extend; using dark::sign_extend;

View File

@ -107,6 +107,10 @@ public:
this->_M_func.reset(_M_new_func(std::forward<_Fn>(fn))); this->_M_func.reset(_M_new_func(std::forward<_Fn>(fn)));
this->sync(); this->sync();
} }
explicit operator bool() const {
return static_cast<max_size_t>(*this);
}
}; };