diff options
Diffstat (limited to 'frontends/ast')
-rw-r--r-- | frontends/ast/ast.cc | 54 | ||||
-rw-r--r-- | frontends/ast/ast.h | 9 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 57 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 214 |
4 files changed, 287 insertions, 47 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 5bbea0faf..3254012bd 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -88,6 +88,8 @@ std::string AST::type2str(AstNodeType type) X(AST_LIVE) X(AST_FAIR) X(AST_COVER) + X(AST_ENUM) + X(AST_ENUM_ITEM) X(AST_FCALL) X(AST_TO_BITS) X(AST_TO_SIGNED) @@ -202,6 +204,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch is_logic = false; is_signed = false; is_string = false; + is_enum = false; is_wand = false; is_wor = false; is_unsized = false; @@ -321,6 +324,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const fprintf(f, " %d", v); fprintf(f, " ]"); } + if (is_enum) { + fprintf(f, " type=enum"); + } fprintf(f, "\n"); for (auto &it : attributes) { @@ -933,14 +939,15 @@ RTLIL::Const AstNode::realAsConst(int width) } // create a new AstModule from an AST_MODULE AST node -static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL) +static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) { log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); if (defer) log("Storing AST representation for module `%s'.\n", ast->str.c_str()); - else + else if (!quiet) { log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str()); + } current_module = new AstModule; current_module->ast = NULL; @@ -1174,7 +1181,15 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump for (auto n : design->verilog_packages){ for (auto o : n->children) { AstNode *cloned_node = o->clone(); - cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); + log("cloned node %s\n", type2str(cloned_node->type).c_str()); + if (cloned_node->type == AST_ENUM){ + for (auto e : cloned_node->children){ + log_assert(e->type == AST_ENUM_ITEM); + e->str = n->str + std::string("::") + e->str.substr(1); + } + } else { + cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); + } (*it)->children.push_back(cloned_node); } } @@ -1203,10 +1218,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump design->add(process_module(*it, defer)); } - else if ((*it)->type == AST_PACKAGE) + else if ((*it)->type == AST_PACKAGE) { design->verilog_packages.push_back((*it)->clone()); - else + } + else { + // must be global definition + (*it)->simplify(false, false, false, 1, -1, false, false); //process enum/other declarations design->verilog_globals.push_back((*it)->clone()); + } } } @@ -1466,14 +1485,16 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R // create a new parametric module (when needed) and return the name of the generated module - without support for interfaces RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool /*mayfail*/) { + bool quiet = lib || attributes.count(ID(blackbox)) || attributes.count(ID(whitebox)); + AstNode *new_ast = NULL; - std::string modname = derive_common(design, parameters, &new_ast); + std::string modname = derive_common(design, parameters, &new_ast, quiet); if (!design->has(modname)) { new_ast->str = modname; - design->add(process_module(new_ast, false)); + design->add(process_module(new_ast, false, NULL, quiet)); design->module(modname)->check(); - } else { + } else if (!quiet) { log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); } @@ -1482,7 +1503,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R } // create a new parametric module (when needed) and return the name of the generated module -std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out) +std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool quiet) { std::string stripped_name = name.str(); @@ -1498,13 +1519,15 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString para_counter++; std::string para_id = child->str; if (parameters.count(para_id) > 0) { - log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str]))); + if (!quiet) + log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str]))); para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); continue; } para_id = stringf("$%d", para_counter); if (parameters.count(para_id) > 0) { - log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); + if (!quiet) + log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); continue; } @@ -1521,7 +1544,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString if (design->has(modname)) return modname; - log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); + if (!quiet) + log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); loadconfig(); AstNode *new_ast = ast->clone(); @@ -1532,12 +1556,14 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString para_counter++; std::string para_id = child->str; if (parameters.count(para_id) > 0) { - log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str]))); + if (!quiet) + log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str]))); goto rewrite_parameter; } para_id = stringf("$%d", para_counter); if (parameters.count(para_id) > 0) { - log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); + if (!quiet) + log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); goto rewrite_parameter; } continue; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 14e1cec5e..59e6058a7 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -68,6 +68,8 @@ namespace AST AST_LIVE, AST_FAIR, AST_COVER, + AST_ENUM, + AST_ENUM_ITEM, AST_FCALL, AST_TO_BITS, @@ -181,6 +183,8 @@ namespace AST int port_id, range_left, range_right; uint32_t integer; double realvalue; + // set for IDs typed to an enumeration, not used + bool is_enum; // if this is a multirange memory then this vector contains offset and length of each dimension std::vector<int> multirange_dimensions; @@ -286,6 +290,9 @@ namespace AST int isConst() const; // return '1' for AST_CONSTANT and '2' for AST_REALVALUE double asReal(bool is_signed); RTLIL::Const realAsConst(int width); + + // helpers for enum + void allocateDefaultEnumValues(); }; // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code @@ -300,7 +307,7 @@ namespace AST ~AstModule() YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE; - std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out); + std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool quiet = false); void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE; RTLIL::Module *clone() const YS_OVERRIDE; void loadconfig() const; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 94f5c0a04..1dfcf3e0e 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -595,6 +595,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun switch (type) { + case AST_NONE: + // unallocated enum, ignore + break; case AST_CONSTANT: width_hint = max(width_hint, int(bits.size())); if (!is_signed) @@ -612,7 +615,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun id_ast = current_scope.at(str); if (!id_ast) log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str()); - if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) { + if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) { if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) { this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; } else @@ -861,6 +864,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_GENIF: case AST_GENCASE: case AST_PACKAGE: + case AST_ENUM: case AST_MODPORT: case AST_MODPORTMEMBER: case AST_TYPEDEF: @@ -1022,7 +1026,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) else log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } - else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) { + else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM || id2ast->type == AST_ENUM_ITEM) { if (id2ast->children[0]->type != AST_CONSTANT) log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str()); chunk = RTLIL::Const(id2ast->children[0]->bits); @@ -1334,18 +1338,31 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) detectSignWidth(width_hint, sign_hint); RTLIL::SigSpec cond = children[0]->genRTLIL(); - RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint); + RTLIL::SigSpec sig; + if (cond.is_fully_const()) { + if (cond.as_bool()) { + sig = children[1]->genRTLIL(width_hint, sign_hint); + widthExtend(this, sig, sig.size(), children[1]->is_signed); + } + else { + sig = children[2]->genRTLIL(width_hint, sign_hint); + widthExtend(this, sig, sig.size(), children[2]->is_signed); + } + } + else { + RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint); + RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint); - if (cond.size() > 1) - cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false); + if (cond.size() > 1) + cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false); - int width = max(val1.size(), val2.size()); - is_signed = children[1]->is_signed && children[2]->is_signed; - widthExtend(this, val1, width, is_signed); - widthExtend(this, val2, width, is_signed); + int width = max(val1.size(), val2.size()); + is_signed = children[1]->is_signed && children[2]->is_signed; + widthExtend(this, val1, width, is_signed); + widthExtend(this, val2, width, is_signed); - RTLIL::SigSpec sig = mux2rtlil(this, cond, val1, val2); + sig = mux2rtlil(this, cond, val1, val2); + } if (sig.size() < width_hint) sig.extend_u0(width_hint, sign_hint); @@ -1559,21 +1576,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } - if (cell->type.in("$specify2", "$specify3")) { + if (cell->type == "$specify2") { int src_width = GetSize(cell->getPort("\\SRC")); int dst_width = GetSize(cell->getPort("\\DST")); bool full = cell->getParam("\\FULL").as_bool(); if (!full && src_width != dst_width) log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n"); - if (cell->type == "$specify3") { - int dat_width = GetSize(cell->getPort("\\DAT")); - if (dat_width != dst_width) - log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); - } cell->setParam("\\SRC_WIDTH", Const(src_width)); cell->setParam("\\DST_WIDTH", Const(dst_width)); } - if (cell->type == "$specrule") { + else if (cell->type == "$specify3") { + int dat_width = GetSize(cell->getPort("\\DAT")); + int dst_width = GetSize(cell->getPort("\\DST")); + if (dat_width != dst_width) + log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); + int src_width = GetSize(cell->getPort("\\SRC")); + cell->setParam("\\SRC_WIDTH", Const(src_width)); + cell->setParam("\\DST_WIDTH", Const(dst_width)); + } + else if (cell->type == "$specrule") { int src_width = GetSize(cell->getPort("\\SRC")); int dst_width = GetSize(cell->getPort("\\DST")); cell->setParam("\\SRC_WIDTH", Const(src_width)); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 36ae831b8..9a8150ebf 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -323,9 +323,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.) - if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF) + if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF) const_fold = true; - if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) + if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) const_fold = true; // in certain cases a function must be evaluated constant. this is what in_param controls. @@ -410,18 +410,35 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } this_wire_scope[node->str] = node; } + // these nodes appear at the top level in a module and can define names if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL || node->type == AST_TYPEDEF) { backup_scope[node->str] = current_scope[node->str]; current_scope[node->str] = node; } + if (node->type == AST_ENUM) { + current_scope[node->str] = node; + for (auto enode : node->children) { + log_assert(enode->type==AST_ENUM_ITEM); + if (current_scope.count(enode->str) == 0) { + current_scope[enode->str] = enode; + } + } + } } for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF) while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) did_something = true; + if (node->type == AST_ENUM) { + for (auto enode : node->children){ + log_assert(enode->type==AST_ENUM_ITEM); + while (node->simplify(true, false, false, 1, -1, false, in_param)) + did_something = true; + } + } } } @@ -497,6 +514,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } break; + case AST_ENUM: + //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); + if (!basic_prep) { + for (auto item_node : children) { + while (!item_node->basic_prep && item_node->simplify(false, false, false, stage, -1, false, in_param)) + did_something = true; + } + // allocate values (called more than once) + allocateDefaultEnumValues(); + } + break; + case AST_PARAMETER: case AST_LOCALPARAM: while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true) @@ -510,6 +539,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1); } break; + case AST_ENUM_ITEM: + while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, in_param)) + did_something = true; + children[0]->detectSignWidth(width_hint, sign_hint); + if (children.size() > 1 && children[1]->type == AST_RANGE) { + while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, in_param)) + did_something = true; + if (!children[1]->range_valid) + log_file_error(filename, linenum, "Non-constant width range on enum item decl.\n"); + width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1); + } + break; case AST_TO_BITS: case AST_TO_SIGNED: @@ -827,11 +868,68 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = templ->range_swapped; range_left = templ->range_left; range_right = templ->range_right; + attributes["\\wiretype"] = mkconst_str(resolved_type->str); + //check if enum + if (templ->attributes.count("\\enum_type")){ + //get reference to enum node: + std::string enum_type = templ->attributes["\\enum_type"]->str.c_str(); + // log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type)); + // log("current scope:\n"); + // for (auto &it : current_scope) + // log(" %s\n", it.first.c_str()); + log_assert(current_scope.count(enum_type) == 1); + AstNode *enum_node = current_scope.at(enum_type); + log_assert(enum_node->type == AST_ENUM); + //get width from 1st enum item: + log_assert(enum_node->children.size() >= 1); + AstNode *enum_item0 = enum_node->children[0]; + log_assert(enum_item0->type == AST_ENUM_ITEM); + int width; + if (!enum_item0->range_valid) + width = 1; + else if (enum_item0->range_swapped) + width = enum_item0->range_right - enum_item0->range_left + 1; + else + width = enum_item0->range_left - enum_item0->range_right + 1; + log_assert(width > 0); + //add declared enum items: + for (auto enum_item : enum_node->children){ + log_assert(enum_item->type == AST_ENUM_ITEM); + //get is_signed + bool is_signed; + if (enum_item->children.size() == 1){ + is_signed = false; + } else if (enum_item->children.size() == 2){ + log_assert(enum_item->children[1]->type == AST_RANGE); + is_signed = enum_item->children[1]->is_signed; + } else { + log_error("enum_item children size==%lu, expected 1 or 2 for %s (%s)\n", + enum_item->children.size(), + enum_item->str.c_str(), enum_node->str.c_str() + ); + } + //start building attribute string + std::string enum_item_str = "\\enum_"; + enum_item_str.append(std::to_string(width)); + enum_item_str.append("_"); + //get enum item value + if(enum_item->children[0]->type != AST_CONSTANT){ + log_error("expected const, got %s for %s (%s)\n", + type2str(enum_item->children[0]->type).c_str(), + enum_item->str.c_str(), enum_node->str.c_str() + ); + } + int val = enum_item->children[0]->asInt(is_signed); + enum_item_str.append(std::to_string(val)); + //set attribute for available val to enum item name mappings + attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); + } + } // Insert clones children from template at beginning for (int i = 0; i < GetSize(templ->children); i++) children.insert(children.begin() + i, templ->children[i]->clone()); - + if (type == AST_MEMORY && GetSize(children) == 1) { // Single-bit memories must have [0:0] range AstNode *rng = new AstNode(AST_RANGE); @@ -873,12 +971,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = templ->range_swapped; range_left = templ->range_left; range_right = templ->range_right; + attributes["\\wiretype"] = mkconst_str(resolved_type->str); for (auto template_child : templ->children) children.push_back(template_child->clone()); did_something = true; } log_assert(!is_custom_type); - } + } // resolve constant prefixes if (type == AST_PREFIX) { @@ -1010,7 +1109,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // trim/extend parameters - if (type == AST_PARAMETER || type == AST_LOCALPARAM) { + if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM) { if (children.size() > 1 && children[1]->type == AST_RANGE) { if (!children[1]->range_valid) log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); @@ -1051,9 +1150,34 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_IDENTIFIER) { if (current_scope.count(str) == 0) { for (auto node : current_ast_mod->children) { - if ((node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || - node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION) && str == node->str) { + //log("looking at mod scope child %s\n", type2str(node->type).c_str()); + switch (node->type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_WIRE: + case AST_AUTOWIRE: + case AST_GENVAR: + case AST_MEMORY: + case AST_FUNCTION: + case AST_TASK: + case AST_DPI_FUNCTION: + //log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str()); + if (str == node->str) { + //log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str()); + current_scope[node->str] = node; + } + break; + case AST_ENUM: current_scope[node->str] = node; + for (auto enum_node : node->children) { + log_assert(enum_node->type==AST_ENUM_ITEM); + if (str == enum_node->str) { + //log("\nadding enum item %s to scope\n", str.c_str()); + current_scope[str] = enum_node; + } + } + break; + default: break; } } @@ -1285,7 +1409,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (buf->type != AST_CONSTANT) - log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); + log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant (%s)!\n", type2str(buf->type).c_str()); delete varbuf->children[0]; varbuf->children[0] = buf; @@ -2504,7 +2628,7 @@ skip_dynamic_range_lvalue_expansion:; } for (auto child : decl->children) - if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) + if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_ENUM_ITEM) { AstNode *wire = nullptr; @@ -2535,6 +2659,9 @@ skip_dynamic_range_lvalue_expansion:; wire->is_output = false; wire->is_reg = true; wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + if (child->type == AST_ENUM_ITEM) + wire->attributes["\\enum_base_type"] = child->attributes["\\enum_base_type"]; + wire_cache[child->str] = wire; current_ast_mod->children.push_back(wire); @@ -2610,7 +2737,7 @@ replace_fcall_later:; switch (type) { case AST_IDENTIFIER: - if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) { + if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) { if (current_scope[str]->children[0]->type == AST_CONSTANT) { if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) { std::vector<RTLIL::State> data; @@ -2909,9 +3036,19 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m std::ifstream f; f.open(mem_filename.c_str()); - yosys_input_files.insert(mem_filename); - - if (f.fail()) + if (f.fail()) { +#ifdef _WIN32 + char slash = '\\'; +#else + char slash = '/'; +#endif + std::string path = filename.substr(0, filename.find_last_of(slash)+1); + f.open(path + mem_filename.c_str()); + yosys_input_files.insert(path + mem_filename); + } else { + yosys_input_files.insert(mem_filename); + } + if (f.fail() || GetSize(mem_filename) == 0) log_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str()); log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid); @@ -3039,7 +3176,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma for (size_t i = 0; i < children.size(); i++) { AstNode *child = children[i]; if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || - child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF) { + child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF || child->type == AST_ENUM_ITEM) { if (backup_name_map.size() == 0) backup_name_map = name_map; std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; @@ -3058,6 +3195,27 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma child->str = new_name; current_scope[new_name] = child; } + if (child->type == AST_ENUM){ + current_scope[child->str] = child; + for (auto enode : child->children){ + log_assert(enode->type == AST_ENUM_ITEM); + if (backup_name_map.size() == 0) + backup_name_map = name_map; + std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; + size_t pos = enode->str.rfind('.'); + if (pos == std::string::npos) + pos = enode->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0; + else + pos = pos + 1; + new_name = enode->str.substr(0, pos) + new_name + enode->str.substr(pos); + if (new_name[0] != '$' && new_name[0] != '\\') + new_name = prefix[0] + new_name; + name_map[enode->str] = new_name; + + enode->str = new_name; + current_scope[new_name] = enode; + } + } } for (size_t i = 0; i < children.size(); i++) { @@ -3796,4 +3954,32 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed); } +void AstNode::allocateDefaultEnumValues() +{ + log_assert(type==AST_ENUM); + int last_enum_int = -1; + for (auto node : children) { + log_assert(node->type==AST_ENUM_ITEM); + node->attributes["\\enum_base_type"] = mkconst_str(str); + for (size_t i = 0; i < node->children.size(); i++) { + switch (node->children[i]->type) { + case AST_NONE: + // replace with auto-incremented constant + delete node->children[i]; + node->children[i] = AstNode::mkconst_int(++last_enum_int, true); + break; + case AST_CONSTANT: + // explicit constant (or folded expression) + // TODO: can't extend 'x or 'z item + last_enum_int = node->children[i]->integer; + break; + default: + // ignore ranges + break; + } + // TODO: range check + } + } +} + YOSYS_NAMESPACE_END |