From d12ba42a741464d410773471813d0a78a7ae1db2 Mon Sep 17 00:00:00 2001 From: Jeff Wang Date: Mon, 3 Feb 2020 01:12:24 -0500 Subject: [PATCH] add attributes for enumerated values in ilang - information also useful for strongly-typed enums (not implemented) - resolves enum values in ilang part of #1594 - still need to output enums to VCD (or better yet FST) files --- frontends/ast/ast.cc | 1 + frontends/ast/simplify.cc | 68 +++++++++++++++++++++++++++++- frontends/verilog/verilog_parser.y | 9 +++- tests/svtypes/enum_simple.sv | 4 +- tests/svtypes/typedef_scopes.sv | 2 +- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 135750837..239813810 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1222,6 +1222,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } 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()); } } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 95c50cda0..b9fb37d50 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -413,6 +413,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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) { @@ -862,6 +863,63 @@ 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++) @@ -908,6 +966,7 @@ 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; @@ -1104,10 +1163,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } 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 %s to scope\n", str.c_str()); + //log("\nadding enum item %s to scope\n", str.c_str()); current_scope[str] = enum_node; } } @@ -2577,6 +2637,10 @@ 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); @@ -3109,6 +3173,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma 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) @@ -3872,6 +3937,7 @@ void AstNode::allocateDefaultEnumValues() 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: diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index ea0a09599..f25a8de28 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1243,9 +1243,12 @@ single_defparam_decl: }; enum_type: TOK_ENUM { + static int enum_count; // create parent node for the enum astbuf2 = new AstNode(AST_ENUM); ast_stack.back()->children.push_back(astbuf2); + astbuf2->str = std::string("$enum"); + astbuf2->str += std::to_string(enum_count++); // create the template for the names astbuf1 = new AstNode(AST_ENUM_ITEM); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); @@ -1254,6 +1257,7 @@ enum_type: TOK_ENUM { delete astbuf1; astbuf1 = tnode; tnode->type = AST_WIRE; + tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str); // drop constant but keep any range delete tnode->children[0]; tnode->children.erase(tnode->children.begin()); } @@ -1311,7 +1315,10 @@ enum_var: TOK_ID { } ; -enum_decl: enum_type enum_var_list ';' { delete astbuf1; } +enum_decl: enum_type enum_var_list ';' { + //enum_type creates astbuf1 for use by typedef only + delete astbuf1; + } ; wire_decl: diff --git a/tests/svtypes/enum_simple.sv b/tests/svtypes/enum_simple.sv index 0c3f55c34..ccaf50da0 100644 --- a/tests/svtypes/enum_simple.sv +++ b/tests/svtypes/enum_simple.sv @@ -6,7 +6,7 @@ module enum_simple(input clk, input rst); ts0, ts1, ts2, ts3 } states_t; (states_t) state; - (states_t) enum_const = s1; + (states_t) enum_const = ts1; always @(posedge clk) begin if (rst) begin @@ -41,7 +41,7 @@ module enum_simple(input clk, input rst); assert(state != 2'h3); assert(s0 == '0); assert(ts0 == '0); - assert(enum_const == s1); + assert(enum_const == ts1); end endmodule diff --git a/tests/svtypes/typedef_scopes.sv b/tests/svtypes/typedef_scopes.sv index 9b3331c60..1c45c7057 100644 --- a/tests/svtypes/typedef_scopes.sv +++ b/tests/svtypes/typedef_scopes.sv @@ -27,7 +27,7 @@ module top; end (inner_type) inner_i2 = 8'h42; - (inner_type) inner_enum2 = s4; + (inner_enum_t) inner_enum2 = s4; always @(*) assert(inner_i2 == 4'h2); always @(*) assert(inner_enum2 == 3'h4); -- 2.30.2