mirror of https://github.com/YosysHQ/yosys.git
tidy up generic functional backend, add generic scope class, tidy up c++ functional backend
This commit is contained in:
parent
39bf4f04f7
commit
eb2bb8c45b
|
@ -23,6 +23,7 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
const char illegal_characters[] = "!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ";
|
||||||
const char *reserved_keywords[] = {
|
const char *reserved_keywords[] = {
|
||||||
"alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit",
|
"alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit",
|
||||||
"atomic_noexcept","auto","bitand","bitor","bool","break","case",
|
"atomic_noexcept","auto","bitand","bitor","bool","break","case",
|
||||||
|
@ -41,45 +42,6 @@ const char *reserved_keywords[] = {
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CxxScope {
|
|
||||||
pool<std::string> used_names;
|
|
||||||
dict<IdString, std::string> name_map;
|
|
||||||
|
|
||||||
CxxScope() {
|
|
||||||
for(const char **p = reserved_keywords; *p != nullptr; p++)
|
|
||||||
reserve(*p);
|
|
||||||
}
|
|
||||||
void reserve(std::string name) {
|
|
||||||
used_names.insert(name);
|
|
||||||
}
|
|
||||||
std::string insert(IdString id) {
|
|
||||||
std::string str = RTLIL::unescape_id(id);
|
|
||||||
for(size_t i = 0; i < str.size(); i++)
|
|
||||||
if(strchr("!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ", str[i]))
|
|
||||||
str[i] = '_';
|
|
||||||
if(used_names.count(str) == 0){
|
|
||||||
used_names.insert(str);
|
|
||||||
name_map.insert({id, str});
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
for (int idx = 0 ; ; idx++){
|
|
||||||
std::string suffixed = str + "_" + std::to_string(idx);
|
|
||||||
if (used_names.count(suffixed) == 0) {
|
|
||||||
used_names.insert(suffixed);
|
|
||||||
if(name_map.count(id) == 0)
|
|
||||||
name_map.insert({id, suffixed});
|
|
||||||
return suffixed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::string operator[](IdString id) {
|
|
||||||
if(name_map.count(id) > 0)
|
|
||||||
return name_map[id];
|
|
||||||
else
|
|
||||||
return insert(id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CxxType {
|
struct CxxType {
|
||||||
FunctionalIR::Sort sort;
|
FunctionalIR::Sort sort;
|
||||||
CxxType(FunctionalIR::Sort sort) : sort(sort) {}
|
CxxType(FunctionalIR::Sort sort) : sort(sort) {}
|
||||||
|
@ -109,66 +71,30 @@ struct CxxWriter {
|
||||||
struct CxxStruct {
|
struct CxxStruct {
|
||||||
std::string name;
|
std::string name;
|
||||||
dict<IdString, CxxType> types;
|
dict<IdString, CxxType> types;
|
||||||
CxxScope scope;
|
FunctionalTools::Scope scope;
|
||||||
bool generate_methods;
|
CxxStruct(std::string name)
|
||||||
CxxStruct(std::string name, bool generate_methods = false)
|
: name(name), scope(illegal_characters, reserved_keywords) {
|
||||||
: name(name), generate_methods(generate_methods) {
|
|
||||||
scope.reserve("out");
|
scope.reserve("out");
|
||||||
scope.reserve("dump");
|
scope.reserve("dump");
|
||||||
}
|
}
|
||||||
void insert(IdString name, CxxType type) {
|
void insert(IdString name, CxxType type) {
|
||||||
scope.insert(name);
|
scope(name);
|
||||||
types.insert({name, type});
|
types.insert({name, type});
|
||||||
}
|
}
|
||||||
void print(CxxWriter &f) {
|
void print(CxxWriter &f) {
|
||||||
f.printf("struct %s {\n", name.c_str());
|
f.printf("\tstruct %s {\n", name.c_str());
|
||||||
for (auto p : types) {
|
for (auto p : types) {
|
||||||
f.printf("\t%s %s;\n", p.second.to_string().c_str(), scope[p.first].c_str());
|
f.printf("\t\t%s %s;\n", p.second.to_string().c_str(), scope(p.first).c_str());
|
||||||
}
|
}
|
||||||
f.printf("\n\ttemplate <typename T> void dump(T &out) const {\n");
|
f.printf("\n\t\ttemplate <typename T> void visit(T &fn) {\n");
|
||||||
for (auto p : types) {
|
for (auto p : types) {
|
||||||
f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str());
|
f.printf("\t\t\tfn(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope(p.first).c_str());
|
||||||
}
|
}
|
||||||
f.printf("\t}\n\n");
|
f.printf("\t\t}\n");
|
||||||
|
f.printf("\t};\n\n");
|
||||||
if (generate_methods) {
|
|
||||||
// Add size method
|
|
||||||
f.printf("\tint size() const {\n");
|
|
||||||
f.printf("\t\treturn %d;\n", types.size());
|
|
||||||
f.printf("\t}\n\n");
|
|
||||||
|
|
||||||
// Add get_input method
|
|
||||||
f.printf("\tstd::variant<%s> get_input(const int index) {\n", generate_variant_types().c_str());
|
|
||||||
f.printf("\t\tswitch (index) {\n");
|
|
||||||
int idx = 0;
|
|
||||||
for (auto p : types) {
|
|
||||||
f.printf("\t\t\tcase %d: return std::ref(%s);\n", idx, scope[p.first].c_str());
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
f.printf("\t\t\tdefault: throw std::out_of_range(\"Invalid input index\");\n");
|
|
||||||
f.printf("\t\t}\n");
|
|
||||||
f.printf("\t}\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
f.printf("};\n\n");
|
|
||||||
};
|
};
|
||||||
std::string operator[](IdString field) {
|
std::string operator[](IdString field) {
|
||||||
return scope[field];
|
return scope(field);
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::string generate_variant_types() const {
|
|
||||||
std::set<std::string> unique_types;
|
|
||||||
for (const auto& p : types) {
|
|
||||||
unique_types.insert("std::reference_wrapper<" + p.second.to_string() + ">");
|
|
||||||
}
|
|
||||||
std::ostringstream oss;
|
|
||||||
for (auto it = unique_types.begin(); it != unique_types.end(); ++it) {
|
|
||||||
if (it != unique_types.begin()) {
|
|
||||||
oss << ", ";
|
|
||||||
}
|
|
||||||
oss << *it;
|
|
||||||
}
|
|
||||||
return oss.str();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,6 +181,54 @@ template<class NodeNames> struct CxxPrintVisitor {
|
||||||
std::string undriven(Node, int width) { return format("$const<%0>(0)", width); }
|
std::string undriven(Node, int width) { return format("$const<%0>(0)", width); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CxxModule {
|
||||||
|
FunctionalIR ir;
|
||||||
|
CxxStruct input_struct, output_struct, state_struct;
|
||||||
|
std::string module_name;
|
||||||
|
|
||||||
|
explicit CxxModule(Module *module) :
|
||||||
|
ir(FunctionalIR::from_module(module)),
|
||||||
|
input_struct("Inputs"),
|
||||||
|
output_struct("Outputs"),
|
||||||
|
state_struct("State")
|
||||||
|
{
|
||||||
|
for (auto [name, sort] : ir.inputs())
|
||||||
|
input_struct.insert(name, sort);
|
||||||
|
for (auto [name, sort] : ir.outputs())
|
||||||
|
output_struct.insert(name, sort);
|
||||||
|
for (auto [name, sort] : ir.state())
|
||||||
|
state_struct.insert(name, sort);
|
||||||
|
module_name = FunctionalTools::Scope(illegal_characters, reserved_keywords)(module->name);
|
||||||
|
}
|
||||||
|
void write_header(CxxWriter &f) {
|
||||||
|
f.printf("#include \"sim.h\"\n\n");
|
||||||
|
}
|
||||||
|
void write_struct_def(CxxWriter &f) {
|
||||||
|
f.printf("struct %s {\n", module_name.c_str());
|
||||||
|
input_struct.print(f);
|
||||||
|
output_struct.print(f);
|
||||||
|
state_struct.print(f);
|
||||||
|
f.printf("\tstatic void eval(Inputs const &, Outputs &, State const &, State &);\n");
|
||||||
|
f.printf("};\n\n");
|
||||||
|
}
|
||||||
|
void write_eval_def(CxxWriter &f) {
|
||||||
|
f.printf("void %s::eval(%s::Inputs const &input, %s::Outputs &output, %s::State const ¤t_state, %s::State &next_state)\n{\n", module_name.c_str(), module_name.c_str(), module_name.c_str(), module_name.c_str(), module_name.c_str());
|
||||||
|
FunctionalTools::Scope locals(illegal_characters, reserved_keywords);
|
||||||
|
locals.reserve("input");
|
||||||
|
locals.reserve("output");
|
||||||
|
locals.reserve("current_state");
|
||||||
|
locals.reserve("next_state");
|
||||||
|
auto node_name = [&](FunctionalIR::Node n) { return locals(n.id(), n.name()); };
|
||||||
|
for (auto node : ir)
|
||||||
|
f.printf("\t%s %s = %s;\n", CxxType(node.sort()).to_string().c_str(), node_name(node).c_str(), node.visit(CxxPrintVisitor(node_name, input_struct, state_struct)).c_str());
|
||||||
|
for (auto [name, sort] : ir.state())
|
||||||
|
f.printf("\tnext_state.%s = %s;\n", state_struct[name].c_str(), node_name(ir.get_state_next_node(name)).c_str());
|
||||||
|
for (auto [name, sort] : ir.outputs())
|
||||||
|
f.printf("\toutput.%s = %s;\n", output_struct[name].c_str(), node_name(ir.get_output_node(name)).c_str());
|
||||||
|
f.printf("}\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct FunctionalCxxBackend : public Backend
|
struct FunctionalCxxBackend : public Backend
|
||||||
{
|
{
|
||||||
FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {}
|
FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {}
|
||||||
|
@ -265,47 +239,13 @@ struct FunctionalCxxBackend : public Backend
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printCxx(std::ostream &stream, std::string, std::string const & name, Module *module)
|
void printCxx(std::ostream &stream, std::string, Module *module)
|
||||||
{
|
{
|
||||||
auto ir = FunctionalIR::from_module(module);
|
|
||||||
CxxWriter f(stream);
|
CxxWriter f(stream);
|
||||||
|
CxxModule mod(module);
|
||||||
f.printf("#include \"sim.h\"\n");
|
mod.write_header(f);
|
||||||
f.printf("#include <variant>\n");
|
mod.write_struct_def(f);
|
||||||
CxxStruct input_struct(name + "_Inputs", true);
|
mod.write_eval_def(f);
|
||||||
for (auto [name, sort] : ir.inputs())
|
|
||||||
input_struct.insert(name, sort);
|
|
||||||
CxxStruct output_struct(name + "_Outputs");
|
|
||||||
for (auto [name, sort] : ir.outputs())
|
|
||||||
output_struct.insert(name, sort);
|
|
||||||
CxxStruct state_struct(name + "_State");
|
|
||||||
for (auto [name, sort] : ir.state())
|
|
||||||
state_struct.insert(name, sort);
|
|
||||||
|
|
||||||
dict<int, std::string> node_names;
|
|
||||||
CxxScope locals;
|
|
||||||
|
|
||||||
input_struct.print(f);
|
|
||||||
output_struct.print(f);
|
|
||||||
state_struct.print(f);
|
|
||||||
|
|
||||||
f.printf("void %s(%s_Inputs const &input, %s_Outputs &output, %s_State const ¤t_state, %s_State &next_state)\n{\n", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str());
|
|
||||||
locals.reserve("input");
|
|
||||||
locals.reserve("output");
|
|
||||||
locals.reserve("current_state");
|
|
||||||
locals.reserve("next_state");
|
|
||||||
auto node_to_string = [&](FunctionalIR::Node n) { return node_names.at(n.id()); };
|
|
||||||
for (auto node : ir)
|
|
||||||
{
|
|
||||||
std::string name = locals.insert(node.name());
|
|
||||||
node_names.emplace(node.id(), name);
|
|
||||||
f.printf("\t%s %s = %s;\n", CxxType(node.sort()).to_string().c_str(), name.c_str(), node.visit(CxxPrintVisitor(node_to_string, input_struct, state_struct)).c_str());
|
|
||||||
}
|
|
||||||
for (auto [name, sort] : ir.state())
|
|
||||||
f.printf("\tnext_state.%s = %s;\n", state_struct[name].c_str(), node_to_string(ir.get_state_next_node(name)).c_str());
|
|
||||||
for (auto [name, sort] : ir.outputs())
|
|
||||||
f.printf("\toutput.%s = %s;\n", output_struct[name].c_str(), node_to_string(ir.get_output_node(name)).c_str());
|
|
||||||
f.printf("}\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
@ -317,7 +257,7 @@ struct FunctionalCxxBackend : public Backend
|
||||||
|
|
||||||
for (auto module : design->selected_modules()) {
|
for (auto module : design->selected_modules()) {
|
||||||
log("Dumping module `%s'.\n", module->name.c_str());
|
log("Dumping module `%s'.\n", module->name.c_str());
|
||||||
printCxx(*f, filename, RTLIL::unescape_id(module->name), module);
|
printCxx(*f, filename, module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} FunctionalCxxBackend;
|
} FunctionalCxxBackend;
|
||||||
|
|
|
@ -33,7 +33,7 @@ class CellSimplifier {
|
||||||
} else {
|
} else {
|
||||||
reduced_b_width = new_width;
|
reduced_b_width = new_width;
|
||||||
T lower_b = factory.slice(b, b_width, 0, new_width);
|
T lower_b = factory.slice(b, b_width, 0, new_width);
|
||||||
T overflow = factory.ugt(b, factory.constant(RTLIL::Const(y_width, b_width)), b_width);
|
T overflow = factory.unsigned_greater_than(b, factory.constant(RTLIL::Const(y_width, b_width)), b_width);
|
||||||
return factory.mux(lower_b, factory.constant(RTLIL::Const(y_width, new_width)), overflow, new_width);
|
return factory.mux(lower_b, factory.constant(RTLIL::Const(y_width, new_width)), overflow, new_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,17 +102,17 @@ public:
|
||||||
T a = extend(inputs.at(ID(A)), a_width, width, is_signed);
|
T a = extend(inputs.at(ID(A)), a_width, width, is_signed);
|
||||||
T b = extend(inputs.at(ID(B)), b_width, width, is_signed);
|
T b = extend(inputs.at(ID(B)), b_width, width, is_signed);
|
||||||
if(cellType.in({ID($eq), ID($eqx)}))
|
if(cellType.in({ID($eq), ID($eqx)}))
|
||||||
return extend(factory.eq(a, b, width), 1, y_width, false);
|
return extend(factory.equal(a, b, width), 1, y_width, false);
|
||||||
else if(cellType.in({ID($ne), ID($nex)}))
|
else if(cellType.in({ID($ne), ID($nex)}))
|
||||||
return extend(factory.ne(a, b, width), 1, y_width, false);
|
return extend(factory.not_equal(a, b, width), 1, y_width, false);
|
||||||
else if(cellType == ID($lt))
|
else if(cellType == ID($lt))
|
||||||
return extend(is_signed ? factory.gt(b, a, width) : factory.ugt(b, a, width), 1, y_width, false);
|
return extend(is_signed ? factory.signed_greater_than(b, a, width) : factory.unsigned_greater_than(b, a, width), 1, y_width, false);
|
||||||
else if(cellType == ID($le))
|
else if(cellType == ID($le))
|
||||||
return extend(is_signed ? factory.ge(b, a, width) : factory.uge(b, a, width), 1, y_width, false);
|
return extend(is_signed ? factory.signed_greater_equal(b, a, width) : factory.unsigned_greater_equal(b, a, width), 1, y_width, false);
|
||||||
else if(cellType == ID($gt))
|
else if(cellType == ID($gt))
|
||||||
return extend(is_signed ? factory.gt(a, b, width) : factory.ugt(a, b, width), 1, y_width, false);
|
return extend(is_signed ? factory.signed_greater_than(a, b, width) : factory.unsigned_greater_than(a, b, width), 1, y_width, false);
|
||||||
else if(cellType == ID($ge))
|
else if(cellType == ID($ge))
|
||||||
return extend(is_signed ? factory.ge(a, b, width) : factory.uge(a, b, width), 1, y_width, false);
|
return extend(is_signed ? factory.signed_greater_equal(a, b, width) : factory.unsigned_greater_equal(a, b, width), 1, y_width, false);
|
||||||
else
|
else
|
||||||
log_abort();
|
log_abort();
|
||||||
}else if(cellType.in({ID($logic_or), ID($logic_and)})){
|
}else if(cellType.in({ID($logic_or), ID($logic_and)})){
|
||||||
|
@ -127,7 +127,7 @@ public:
|
||||||
return extend(inputs.at(ID(A)), a_width, y_width, a_signed);
|
return extend(inputs.at(ID(A)), a_width, y_width, a_signed);
|
||||||
}else if(cellType == ID($neg)){
|
}else if(cellType == ID($neg)){
|
||||||
T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed);
|
T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed);
|
||||||
return factory.neg(a, y_width);
|
return factory.unary_minus(a, y_width);
|
||||||
}else if(cellType == ID($logic_not)){
|
}else if(cellType == ID($logic_not)){
|
||||||
T a = reduce_or(inputs.at(ID(A)), a_width);
|
T a = reduce_or(inputs.at(ID(A)), a_width);
|
||||||
T y = factory.bitwise_not(a, 1);
|
T y = factory.bitwise_not(a, 1);
|
||||||
|
@ -161,7 +161,7 @@ public:
|
||||||
T shr = logical_shift_right(a, b, width, b_width);
|
T shr = logical_shift_right(a, b, width, b_width);
|
||||||
if(b_signed) {
|
if(b_signed) {
|
||||||
T sign_b = factory.slice(b, b_width, b_width - 1, 1);
|
T sign_b = factory.slice(b, b_width, b_width - 1, 1);
|
||||||
T shl = logical_shift_left(a, factory.neg(b, b_width), width, b_width);
|
T shl = logical_shift_left(a, factory.unary_minus(b, b_width), width, b_width);
|
||||||
T y = factory.mux(shr, shl, sign_b, width);
|
T y = factory.mux(shr, shl, sign_b, width);
|
||||||
return extend(y, width, y_width, false);
|
return extend(y, width, y_width, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -237,10 +237,10 @@ public:
|
||||||
if(results.size() == 0)
|
if(results.size() == 0)
|
||||||
return factory.undriven(0);
|
return factory.undriven(0);
|
||||||
T node = results[0];
|
T node = results[0];
|
||||||
int size = results[0].size();
|
int size = results[0].width();
|
||||||
for(size_t i = 1; i < results.size(); i++) {
|
for(size_t i = 1; i < results.size(); i++) {
|
||||||
node = factory.concat(node, size, results[i], results[i].size());
|
node = factory.concat(node, size, results[i], results[i].width());
|
||||||
size += results[i].size();
|
size += results[i].width();
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -405,6 +405,13 @@ void FunctionalIR::topological_sort() {
|
||||||
if(scc) log_error("combinational loops, aborting\n");
|
if(scc) log_error("combinational loops, aborting\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdString merge_name(IdString a, IdString b) {
|
||||||
|
if(a[0] == '$' && b[0] == '\\')
|
||||||
|
return b;
|
||||||
|
else
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
void FunctionalIR::forward_buf() {
|
void FunctionalIR::forward_buf() {
|
||||||
std::vector<int> perm, alias;
|
std::vector<int> perm, alias;
|
||||||
perm.clear();
|
perm.clear();
|
||||||
|
@ -416,10 +423,15 @@ void FunctionalIR::forward_buf() {
|
||||||
{
|
{
|
||||||
int target_index = alias[node.arg(0).index()];
|
int target_index = alias[node.arg(0).index()];
|
||||||
auto target_node = _graph[perm[target_index]];
|
auto target_node = _graph[perm[target_index]];
|
||||||
if(!target_node.has_sparse_attr() && node.has_sparse_attr()){
|
if(node.has_sparse_attr()) {
|
||||||
IdString id = node.sparse_attr();
|
if(target_node.has_sparse_attr()) {
|
||||||
target_node.sparse_attr() = id;
|
IdString id = merge_name(node.sparse_attr(), target_node.sparse_attr());
|
||||||
}
|
target_node.sparse_attr() = id;
|
||||||
|
} else {
|
||||||
|
IdString id = node.sparse_attr();
|
||||||
|
target_node.sparse_attr() = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
alias.push_back(target_index);
|
alias.push_back(target_index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -29,6 +29,58 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace FunctionalTools {
|
||||||
|
class Scope {
|
||||||
|
const char *_illegal_characters;
|
||||||
|
pool<std::string> _used_names;
|
||||||
|
dict<int, std::string> _by_id;
|
||||||
|
dict<IdString, std::string> _by_name;
|
||||||
|
std::string allocate_name(IdString suggestion) {
|
||||||
|
std::string str = RTLIL::unescape_id(suggestion);
|
||||||
|
for(size_t i = 0; i < str.size(); i++)
|
||||||
|
if(strchr(_illegal_characters, str[i]))
|
||||||
|
str[i] = '_';
|
||||||
|
if(_used_names.count(str) == 0) {
|
||||||
|
_used_names.insert(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
for (int idx = 0 ; ; idx++){
|
||||||
|
std::string suffixed = str + "_" + std::to_string(idx);
|
||||||
|
if(_used_names.count(suffixed) == 0) {
|
||||||
|
_used_names.insert(suffixed);
|
||||||
|
return suffixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Scope(const char *illegal_characters = "", const char **keywords = nullptr) {
|
||||||
|
_illegal_characters = illegal_characters;
|
||||||
|
if(keywords != nullptr)
|
||||||
|
for(const char **p = keywords; *p != nullptr; p++)
|
||||||
|
reserve(*p);
|
||||||
|
}
|
||||||
|
void reserve(std::string name) {
|
||||||
|
_used_names.insert(std::move(name));
|
||||||
|
}
|
||||||
|
std::string operator()(int id, IdString suggestion) {
|
||||||
|
auto it = _by_id.find(id);
|
||||||
|
if(it != _by_id.end())
|
||||||
|
return it->second;
|
||||||
|
std::string str = allocate_name(suggestion);
|
||||||
|
_by_id.insert({id, str});
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
std::string operator()(IdString idstring) {
|
||||||
|
auto it = _by_name.find(idstring);
|
||||||
|
if(it != _by_name.end())
|
||||||
|
return it->second;
|
||||||
|
std::string str = allocate_name(idstring);
|
||||||
|
_by_name.insert({idstring, str});
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class FunctionalIR {
|
class FunctionalIR {
|
||||||
enum class Fn {
|
enum class Fn {
|
||||||
invalid,
|
invalid,
|
||||||
|
@ -133,7 +185,7 @@ public:
|
||||||
friend class Factory;
|
friend class Factory;
|
||||||
friend class FunctionalIR;
|
friend class FunctionalIR;
|
||||||
Graph::Ref _ref;
|
Graph::Ref _ref;
|
||||||
Node(Graph::Ref ref) : _ref(ref) { }
|
explicit Node(Graph::Ref ref) : _ref(ref) { }
|
||||||
operator Graph::Ref() { return _ref; }
|
operator Graph::Ref() { return _ref; }
|
||||||
template<class NodePrinter> struct PrintVisitor {
|
template<class NodePrinter> struct PrintVisitor {
|
||||||
NodePrinter np;
|
NodePrinter np;
|
||||||
|
@ -225,7 +277,6 @@ public:
|
||||||
{
|
{
|
||||||
return visit(PrintVisitor(np));
|
return visit(PrintVisitor(np));
|
||||||
}
|
}
|
||||||
/* TODO: delete */ int size() const { return sort().width(); }
|
|
||||||
};
|
};
|
||||||
class Factory {
|
class Factory {
|
||||||
FunctionalIR &_ir;
|
FunctionalIR &_ir;
|
||||||
|
@ -235,7 +286,7 @@ public:
|
||||||
Graph::Ref ref = _ir._graph.add(std::move(fn), {std::move(sort)});
|
Graph::Ref ref = _ir._graph.add(std::move(fn), {std::move(sort)});
|
||||||
for (auto arg : args)
|
for (auto arg : args)
|
||||||
ref.append_arg(Graph::Ref(arg));
|
ref.append_arg(Graph::Ref(arg));
|
||||||
return ref;
|
return Node(ref);
|
||||||
}
|
}
|
||||||
void check_basic_binary(Node const &a, Node const &b) { log_assert(a.sort().is_signal() && a.sort() == b.sort()); }
|
void check_basic_binary(Node const &a, Node const &b) { log_assert(a.sort().is_signal() && a.sort() == b.sort()); }
|
||||||
void check_shift(Node const &a, Node const &b) { log_assert(a.sort().is_signal() && b.sort().is_signal()); }
|
void check_shift(Node const &a, Node const &b) { log_assert(a.sort().is_signal() && b.sort().is_signal()); }
|
||||||
|
@ -341,39 +392,30 @@ public:
|
||||||
void suggest_name(Node node, IdString name) {
|
void suggest_name(Node node, IdString name) {
|
||||||
node._ref.sparse_attr() = name;
|
node._ref.sparse_attr() = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO delete this later*/
|
|
||||||
Node eq(Node a, Node b, int) { return equal(a, b, 0); }
|
|
||||||
Node ne(Node a, Node b, int) { return not_equal(a, b, 0); }
|
|
||||||
Node gt(Node a, Node b, int) { return signed_greater_than(a, b, 0); }
|
|
||||||
Node ge(Node a, Node b, int) { return signed_greater_equal(a, b, 0); }
|
|
||||||
Node ugt(Node a, Node b, int) { return unsigned_greater_than(a, b, 0); }
|
|
||||||
Node uge(Node a, Node b, int) { return unsigned_greater_equal(a, b, 0); }
|
|
||||||
Node neg(Node a, int) { return unary_minus(a, 0); }
|
|
||||||
};
|
};
|
||||||
static FunctionalIR from_module(Module *module);
|
static FunctionalIR from_module(Module *module);
|
||||||
Factory factory() { return Factory(*this); }
|
Factory factory() { return Factory(*this); }
|
||||||
int size() const { return _graph.size(); }
|
int size() const { return _graph.size(); }
|
||||||
Node operator[](int i) { return _graph[i]; }
|
Node operator[](int i) { return Node(_graph[i]); }
|
||||||
void topological_sort();
|
void topological_sort();
|
||||||
void forward_buf();
|
void forward_buf();
|
||||||
dict<IdString, Sort> inputs() const { return _inputs; }
|
dict<IdString, Sort> inputs() const { return _inputs; }
|
||||||
dict<IdString, Sort> outputs() const { return _outputs; }
|
dict<IdString, Sort> outputs() const { return _outputs; }
|
||||||
dict<IdString, Sort> state() const { return _state; }
|
dict<IdString, Sort> state() const { return _state; }
|
||||||
Node get_output_node(IdString name) { return _graph({name, false}); }
|
Node get_output_node(IdString name) { return Node(_graph({name, false})); }
|
||||||
Node get_state_next_node(IdString name) { return _graph({name, true}); }
|
Node get_state_next_node(IdString name) { return Node(_graph({name, true})); }
|
||||||
class Iterator {
|
class Iterator {
|
||||||
friend class FunctionalIR;
|
friend class FunctionalIR;
|
||||||
FunctionalIR &_ir;
|
FunctionalIR *_ir;
|
||||||
int _index;
|
int _index;
|
||||||
Iterator(FunctionalIR &ir, int index) : _ir(ir), _index(index) {}
|
Iterator(FunctionalIR *ir, int index) : _ir(ir), _index(index) {}
|
||||||
public:
|
public:
|
||||||
Node operator*() { return _ir._graph[_index]; }
|
Node operator*() { return Node(_ir->_graph[_index]); }
|
||||||
Iterator &operator++() { _index++; return *this; }
|
Iterator &operator++() { _index++; return *this; }
|
||||||
bool operator!=(Iterator const &other) const { return _index != other._index; }
|
bool operator!=(Iterator const &other) const { return _index != other._index; }
|
||||||
};
|
};
|
||||||
Iterator begin() { return Iterator(*this, 0); }
|
Iterator begin() { return Iterator(this, 0); }
|
||||||
Iterator end() { return Iterator(*this, _graph.size()); }
|
Iterator end() { return Iterator(this, _graph.size()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
Loading…
Reference in New Issue