mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #1811 from PeterCrozier/typedef_scope
Support module/package/interface/block scope for typedef names.
This commit is contained in:
commit
d5e2061687
|
@ -541,8 +541,6 @@ from SystemVerilog:
|
||||||
SystemVerilog files being read into the same design afterwards.
|
SystemVerilog files being read into the same design afterwards.
|
||||||
|
|
||||||
- typedefs are supported (including inside packages)
|
- typedefs are supported (including inside packages)
|
||||||
- type identifiers must currently be enclosed in (parentheses) when declaring
|
|
||||||
signals of that type (this is syntactically incorrect SystemVerilog)
|
|
||||||
- type casts are currently not supported
|
- type casts are currently not supported
|
||||||
|
|
||||||
- enums are supported (including inside packages)
|
- enums are supported (including inside packages)
|
||||||
|
|
|
@ -52,7 +52,6 @@ static void add_package_types(std::map<std::string, AST::AstNode *> &user_types,
|
||||||
{
|
{
|
||||||
// prime the parser's user type lookup table with the package qualified names
|
// prime the parser's user type lookup table with the package qualified names
|
||||||
// of typedefed names in the packages seen so far.
|
// of typedefed names in the packages seen so far.
|
||||||
user_types.clear();
|
|
||||||
for (const auto &pkg : package_list) {
|
for (const auto &pkg : package_list) {
|
||||||
log_assert(pkg->type==AST::AST_PACKAGE);
|
log_assert(pkg->type==AST::AST_PACKAGE);
|
||||||
for (const auto &node: pkg->children) {
|
for (const auto &node: pkg->children) {
|
||||||
|
@ -62,6 +61,8 @@ static void add_package_types(std::map<std::string, AST::AstNode *> &user_types,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
user_type_stack.clear();
|
||||||
|
user_type_stack.push_back(new UserTypeMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VerilogFrontend : public Frontend {
|
struct VerilogFrontend : public Frontend {
|
||||||
|
|
|
@ -45,8 +45,9 @@ namespace VERILOG_FRONTEND
|
||||||
// this function converts a Verilog constant to an AST_CONSTANT node
|
// this function converts a Verilog constant to an AST_CONSTANT node
|
||||||
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
|
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
|
||||||
|
|
||||||
// names of locally typedef'ed types
|
// names of locally typedef'ed types in a stack
|
||||||
extern std::map<std::string, AST::AstNode*> user_types;
|
typedef std::map<std::string, AST::AstNode*> UserTypeMap;
|
||||||
|
extern std::vector<UserTypeMap *> user_type_stack;
|
||||||
|
|
||||||
// names of package typedef'ed types
|
// names of package typedef'ed types
|
||||||
extern std::map<std::string, AST::AstNode*> pkg_user_types;
|
extern std::map<std::string, AST::AstNode*> pkg_user_types;
|
||||||
|
|
|
@ -99,6 +99,18 @@ YYLTYPE old_location;
|
||||||
#define YY_BUF_SIZE 65536
|
#define YY_BUF_SIZE 65536
|
||||||
|
|
||||||
extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
|
extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
|
||||||
|
|
||||||
|
static bool isUserType(std::string &s)
|
||||||
|
{
|
||||||
|
// check current scope then outer scopes for a name
|
||||||
|
for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) {
|
||||||
|
if ((*it)->count(s) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%option yylineno
|
%option yylineno
|
||||||
|
@ -376,9 +388,9 @@ supply1 { return TOK_SUPPLY1; }
|
||||||
// package qualifier
|
// package qualifier
|
||||||
auto s = std::string("\\") + yytext;
|
auto s = std::string("\\") + yytext;
|
||||||
if (pkg_user_types.count(s) > 0) {
|
if (pkg_user_types.count(s) > 0) {
|
||||||
// found it
|
// package qualified typedefed name
|
||||||
yylval->string = new std::string(s);
|
yylval->string = new std::string(s);
|
||||||
return TOK_USER_TYPE;
|
return TOK_PKG_USER_TYPE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// backup before :: just return first part
|
// backup before :: just return first part
|
||||||
|
@ -391,7 +403,8 @@ supply1 { return TOK_SUPPLY1; }
|
||||||
|
|
||||||
[a-zA-Z_$][a-zA-Z0-9_$]* {
|
[a-zA-Z_$][a-zA-Z0-9_$]* {
|
||||||
auto s = std::string("\\") + yytext;
|
auto s = std::string("\\") + yytext;
|
||||||
if (user_types.count(s) > 0) {
|
if (isUserType(s)) {
|
||||||
|
// previously typedefed name
|
||||||
yylval->string = new std::string(s);
|
yylval->string = new std::string(s);
|
||||||
return TOK_USER_TYPE;
|
return TOK_USER_TYPE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace VERILOG_FRONTEND {
|
||||||
std::map<std::string, AstNode*> *attr_list, default_attr_list;
|
std::map<std::string, AstNode*> *attr_list, default_attr_list;
|
||||||
std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
|
std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
|
||||||
std::map<std::string, AstNode*> *albuf;
|
std::map<std::string, AstNode*> *albuf;
|
||||||
std::map<std::string, AstNode*> user_types;
|
std::vector<UserTypeMap*> user_type_stack;
|
||||||
std::map<std::string, AstNode*> pkg_user_types;
|
std::map<std::string, AstNode*> pkg_user_types;
|
||||||
std::vector<AstNode*> ast_stack;
|
std::vector<AstNode*> ast_stack;
|
||||||
struct AstNode *astbuf1, *astbuf2, *astbuf3;
|
struct AstNode *astbuf1, *astbuf2, *astbuf3;
|
||||||
|
@ -130,14 +130,10 @@ struct specify_rise_fall {
|
||||||
static void addTypedefNode(std::string *name, AstNode *node)
|
static void addTypedefNode(std::string *name, AstNode *node)
|
||||||
{
|
{
|
||||||
log_assert(node);
|
log_assert(node);
|
||||||
// seems to be support for local scoped typedefs in simplify()
|
|
||||||
// and tests redefine types.
|
|
||||||
//if (user_types.count(*name) > 0) {
|
|
||||||
// frontend_verilog_yyerror("Type already defined.");
|
|
||||||
//}
|
|
||||||
auto *tnode = new AstNode(AST_TYPEDEF, node);
|
auto *tnode = new AstNode(AST_TYPEDEF, node);
|
||||||
tnode->str = *name;
|
tnode->str = *name;
|
||||||
user_types[*name] = tnode;
|
auto user_types = user_type_stack.back();
|
||||||
|
(*user_types)[*name] = tnode;
|
||||||
if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) {
|
if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) {
|
||||||
// typedef inside a package so we need the qualified name
|
// typedef inside a package so we need the qualified name
|
||||||
auto qname = current_ast_mod->str + "::" + (*name).substr(1);
|
auto qname = current_ast_mod->str + "::" + (*name).substr(1);
|
||||||
|
@ -147,6 +143,24 @@ static void addTypedefNode(std::string *name, AstNode *node)
|
||||||
ast_stack.back()->children.push_back(tnode);
|
ast_stack.back()->children.push_back(tnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void enterTypeScope()
|
||||||
|
{
|
||||||
|
auto user_types = new UserTypeMap();
|
||||||
|
user_type_stack.push_back(user_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exitTypeScope()
|
||||||
|
{
|
||||||
|
user_type_stack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isInLocalScope(const std::string *name)
|
||||||
|
{
|
||||||
|
// tests if a name was declared in the current block scope
|
||||||
|
auto user_types = user_type_stack.back();
|
||||||
|
return (user_types->count(*name) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
|
static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
|
||||||
{
|
{
|
||||||
auto range = new AstNode(AST_RANGE);
|
auto range = new AstNode(AST_RANGE);
|
||||||
|
@ -189,7 +203,7 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned =
|
||||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||||
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS
|
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS
|
||||||
%token <string> TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL
|
%token <string> TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL
|
||||||
%token <string> TOK_USER_TYPE
|
%token <string> TOK_USER_TYPE TOK_PKG_USER_TYPE
|
||||||
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
|
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
|
||||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||||
|
@ -355,11 +369,14 @@ hierarchical_id:
|
||||||
|
|
||||||
hierarchical_type_id:
|
hierarchical_type_id:
|
||||||
TOK_USER_TYPE
|
TOK_USER_TYPE
|
||||||
|
| TOK_PKG_USER_TYPE // package qualified type name
|
||||||
| '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar
|
| '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar
|
||||||
;
|
;
|
||||||
|
|
||||||
module:
|
module:
|
||||||
attr TOK_MODULE TOK_ID {
|
attr TOK_MODULE {
|
||||||
|
enterTypeScope();
|
||||||
|
} TOK_ID {
|
||||||
do_not_require_port_stubs = false;
|
do_not_require_port_stubs = false;
|
||||||
AstNode *mod = new AstNode(AST_MODULE);
|
AstNode *mod = new AstNode(AST_MODULE);
|
||||||
ast_stack.back()->children.push_back(mod);
|
ast_stack.back()->children.push_back(mod);
|
||||||
|
@ -367,9 +384,9 @@ module:
|
||||||
current_ast_mod = mod;
|
current_ast_mod = mod;
|
||||||
port_stubs.clear();
|
port_stubs.clear();
|
||||||
port_counter = 0;
|
port_counter = 0;
|
||||||
mod->str = *$3;
|
mod->str = *$4;
|
||||||
append_attr(mod, $1);
|
append_attr(mod, $1);
|
||||||
delete $3;
|
delete $4;
|
||||||
} module_para_opt module_args_opt ';' module_body TOK_ENDMODULE {
|
} module_para_opt module_args_opt ';' module_body TOK_ENDMODULE {
|
||||||
if (port_stubs.size() != 0)
|
if (port_stubs.size() != 0)
|
||||||
frontend_verilog_yyerror("Missing details for module port `%s'.",
|
frontend_verilog_yyerror("Missing details for module port `%s'.",
|
||||||
|
@ -378,7 +395,7 @@ module:
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
log_assert(ast_stack.size() == 1);
|
log_assert(ast_stack.size() == 1);
|
||||||
current_ast_mod = NULL;
|
current_ast_mod = NULL;
|
||||||
user_types.clear();
|
exitTypeScope();
|
||||||
};
|
};
|
||||||
|
|
||||||
module_para_opt:
|
module_para_opt:
|
||||||
|
@ -482,17 +499,19 @@ module_arg:
|
||||||
};
|
};
|
||||||
|
|
||||||
package:
|
package:
|
||||||
attr TOK_PACKAGE TOK_ID {
|
attr TOK_PACKAGE {
|
||||||
|
enterTypeScope();
|
||||||
|
} TOK_ID {
|
||||||
AstNode *mod = new AstNode(AST_PACKAGE);
|
AstNode *mod = new AstNode(AST_PACKAGE);
|
||||||
ast_stack.back()->children.push_back(mod);
|
ast_stack.back()->children.push_back(mod);
|
||||||
ast_stack.push_back(mod);
|
ast_stack.push_back(mod);
|
||||||
current_ast_mod = mod;
|
current_ast_mod = mod;
|
||||||
mod->str = *$3;
|
mod->str = *$4;
|
||||||
append_attr(mod, $1);
|
append_attr(mod, $1);
|
||||||
} ';' package_body TOK_ENDPACKAGE {
|
} ';' package_body TOK_ENDPACKAGE {
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
current_ast_mod = NULL;
|
current_ast_mod = NULL;
|
||||||
user_types.clear();
|
exitTypeScope();
|
||||||
};
|
};
|
||||||
|
|
||||||
package_body:
|
package_body:
|
||||||
|
@ -505,7 +524,9 @@ package_body_stmt:
|
||||||
localparam_decl;
|
localparam_decl;
|
||||||
|
|
||||||
interface:
|
interface:
|
||||||
TOK_INTERFACE TOK_ID {
|
TOK_INTERFACE {
|
||||||
|
enterTypeScope();
|
||||||
|
} TOK_ID {
|
||||||
do_not_require_port_stubs = false;
|
do_not_require_port_stubs = false;
|
||||||
AstNode *intf = new AstNode(AST_INTERFACE);
|
AstNode *intf = new AstNode(AST_INTERFACE);
|
||||||
ast_stack.back()->children.push_back(intf);
|
ast_stack.back()->children.push_back(intf);
|
||||||
|
@ -513,8 +534,8 @@ interface:
|
||||||
current_ast_mod = intf;
|
current_ast_mod = intf;
|
||||||
port_stubs.clear();
|
port_stubs.clear();
|
||||||
port_counter = 0;
|
port_counter = 0;
|
||||||
intf->str = *$2;
|
intf->str = *$3;
|
||||||
delete $2;
|
delete $3;
|
||||||
} module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
|
} module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
|
||||||
if (port_stubs.size() != 0)
|
if (port_stubs.size() != 0)
|
||||||
frontend_verilog_yyerror("Missing details for module port `%s'.",
|
frontend_verilog_yyerror("Missing details for module port `%s'.",
|
||||||
|
@ -522,7 +543,7 @@ interface:
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
log_assert(ast_stack.size() == 1);
|
log_assert(ast_stack.size() == 1);
|
||||||
current_ast_mod = NULL;
|
current_ast_mod = NULL;
|
||||||
user_types.clear();
|
exitTypeScope();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface_body:
|
interface_body:
|
||||||
|
@ -1621,7 +1642,7 @@ assign_expr:
|
||||||
};
|
};
|
||||||
|
|
||||||
type_name: TOK_ID // first time seen
|
type_name: TOK_ID // first time seen
|
||||||
| TOK_USER_TYPE // redefinition
|
| TOK_USER_TYPE { if (isInLocalScope($1)) frontend_verilog_yyerror("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
typedef_decl:
|
typedef_decl:
|
||||||
|
@ -2210,20 +2231,21 @@ behavioral_stmt:
|
||||||
} opt_arg_list ';'{
|
} opt_arg_list ';'{
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
attr TOK_BEGIN opt_label {
|
attr TOK_BEGIN {
|
||||||
|
enterTypeScope();
|
||||||
|
} opt_label {
|
||||||
AstNode *node = new AstNode(AST_BLOCK);
|
AstNode *node = new AstNode(AST_BLOCK);
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
ast_stack.push_back(node);
|
ast_stack.push_back(node);
|
||||||
append_attr(node, $1);
|
append_attr(node, $1);
|
||||||
if ($3 != NULL)
|
if ($4 != NULL)
|
||||||
node->str = *$3;
|
node->str = *$4;
|
||||||
} behavioral_stmt_list TOK_END opt_label {
|
} behavioral_stmt_list TOK_END opt_label {
|
||||||
if ($3 != NULL && $7 != NULL && *$3 != *$7)
|
exitTypeScope();
|
||||||
frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
|
if ($4 != NULL && $8 != NULL && *$4 != *$8)
|
||||||
if ($3 != NULL)
|
frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1);
|
||||||
delete $3;
|
delete $4;
|
||||||
if ($7 != NULL)
|
delete $8;
|
||||||
delete $7;
|
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
attr TOK_FOR '(' {
|
attr TOK_FOR '(' {
|
||||||
|
@ -2301,6 +2323,8 @@ behavioral_stmt:
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
unique_case_attr:
|
unique_case_attr:
|
||||||
/* empty */ {
|
/* empty */ {
|
||||||
$$ = false;
|
$$ = false;
|
||||||
|
@ -2516,16 +2540,17 @@ gen_stmt:
|
||||||
case_type_stack.pop_back();
|
case_type_stack.pop_back();
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
TOK_BEGIN opt_label {
|
TOK_BEGIN {
|
||||||
|
enterTypeScope();
|
||||||
|
} opt_label {
|
||||||
AstNode *node = new AstNode(AST_GENBLOCK);
|
AstNode *node = new AstNode(AST_GENBLOCK);
|
||||||
node->str = $2 ? *$2 : std::string();
|
node->str = $3 ? *$3 : std::string();
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
ast_stack.push_back(node);
|
ast_stack.push_back(node);
|
||||||
} module_gen_body TOK_END opt_label {
|
} module_gen_body TOK_END opt_label {
|
||||||
if ($2 != NULL)
|
exitTypeScope();
|
||||||
delete $2;
|
delete $3;
|
||||||
if ($6 != NULL)
|
delete $7;
|
||||||
delete $6;
|
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
TOK_MSG_TASKS {
|
TOK_MSG_TASKS {
|
||||||
|
|
|
@ -31,5 +31,12 @@ module top;
|
||||||
always @(*) assert(inner_i2 == 4'h2);
|
always @(*) assert(inner_i2 == 4'h2);
|
||||||
always @(*) assert(inner_enum2 == 3'h4);
|
always @(*) assert(inner_enum2 == 3'h4);
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
typedef logic[7:0] between_t;
|
||||||
|
|
||||||
|
module other;
|
||||||
|
between_t a = 8'h42;
|
||||||
|
always @(*) assert(a == 8'h42);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue