mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge pull request #1803 from Grazfather/typedef
Support standard typedef grammar (Fixed)
This commit is contained in:
		
						commit
						b86905d952
					
				
					 12 changed files with 124 additions and 40 deletions
				
			
		|  | @ -1179,12 +1179,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump | |||
| 			for (auto n : design->verilog_globals) | ||||
| 				(*it)->children.push_back(n->clone()); | ||||
| 
 | ||||
| 			for (auto n : design->verilog_packages){ | ||||
| 				for (auto o : n->children) { | ||||
| 			// append nodes from previous packages using package-qualified names
 | ||||
| 			for (auto &n : design->verilog_packages) { | ||||
| 				for (auto &o : n->children) { | ||||
| 					AstNode *cloned_node = o->clone(); | ||||
| 					log("cloned node %s\n", type2str(cloned_node->type).c_str()); | ||||
| 					if (cloned_node->type == AST_ENUM){ | ||||
| 						for (auto e : cloned_node->children){ | ||||
| 					// 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); | ||||
| 						} | ||||
|  | @ -1220,6 +1221,8 @@ 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) { | ||||
| 			// process enum/other declarations
 | ||||
| 			(*it)->simplify(true, false, false, 1, -1, false, false); | ||||
| 			design->verilog_packages.push_back((*it)->clone()); | ||||
| 		} | ||||
| 		else { | ||||
|  |  | |||
|  | @ -47,6 +47,22 @@ static void error_on_dpi_function(AST::AstNode *node) | |||
| 		error_on_dpi_function(child); | ||||
| } | ||||
| 
 | ||||
| static void add_package_types(std::map<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) | ||||
| { | ||||
| 	// prime the parser's user type lookup table with the package qualified names
 | ||||
| 	// of typedefed names in the packages seen so far.
 | ||||
| 	user_types.clear(); | ||||
| 	for (const auto &pkg : package_list) { | ||||
| 		log_assert(pkg->type==AST::AST_PACKAGE); | ||||
| 		for (const auto &node: pkg->children) { | ||||
| 			if (node->type == AST::AST_TYPEDEF) { | ||||
| 				std::string s = pkg->str + "::" + node->str.substr(1); | ||||
| 				user_types[s] = node; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct VerilogFrontend : public Frontend { | ||||
| 	VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } | ||||
| 	void help() YS_OVERRIDE | ||||
|  | @ -450,6 +466,9 @@ struct VerilogFrontend : public Frontend { | |||
| 			lexin = new std::istringstream(code_after_preproc); | ||||
| 		} | ||||
| 
 | ||||
| 		// make package typedefs available to parser
 | ||||
| 		add_package_types(pkg_user_types, design->verilog_packages); | ||||
| 
 | ||||
| 		frontend_verilog_yyset_lineno(1); | ||||
| 		frontend_verilog_yyrestart(NULL); | ||||
| 		frontend_verilog_yyparse(); | ||||
|  | @ -468,6 +487,7 @@ struct VerilogFrontend : public Frontend { | |||
| 		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, | ||||
| 				flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); | ||||
| 
 | ||||
| 
 | ||||
| 		if (!flag_nopp) | ||||
| 			delete lexin; | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,6 +45,12 @@ namespace VERILOG_FRONTEND | |||
| 	// 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); | ||||
| 
 | ||||
| 	// names of locally typedef'ed types
 | ||||
| 	extern std::map<std::string, AST::AstNode*> user_types; | ||||
| 
 | ||||
| 	// names of package typedef'ed types
 | ||||
| 	extern std::map<std::string, AST::AstNode*> pkg_user_types; | ||||
| 
 | ||||
| 	// state of `default_nettype
 | ||||
| 	extern bool default_nettype_wire; | ||||
| 
 | ||||
|  |  | |||
|  | @ -372,9 +372,33 @@ supply1 { return TOK_SUPPLY1; } | |||
| "$signed"   { return TOK_TO_SIGNED; } | ||||
| "$unsigned" { return TOK_TO_UNSIGNED; } | ||||
| 
 | ||||
| [a-zA-Z_$][a-zA-Z0-9_$]* { | ||||
| [a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* { | ||||
| 	// package qualifier | ||||
| 	auto s = std::string("\\") + yytext; | ||||
| 	if (pkg_user_types.count(s) > 0) { | ||||
| 		// found it | ||||
| 		yylval->string = new std::string(s); | ||||
| 		return TOK_USER_TYPE; | ||||
| 	} | ||||
| 	else { | ||||
| 		// backup before :: just return first part | ||||
| 		size_t len = strchr(yytext, ':') - yytext; | ||||
| 		yyless(len); | ||||
| 		yylval->string = new std::string(std::string("\\") + yytext); | ||||
| 		return TOK_ID; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| [a-zA-Z_$][a-zA-Z0-9_$]* { | ||||
| 	auto s = std::string("\\") + yytext; | ||||
| 	if (user_types.count(s) > 0) { | ||||
| 		yylval->string = new std::string(s); | ||||
| 		return TOK_USER_TYPE; | ||||
| 	} | ||||
| 	else { | ||||
| 		yylval->string = new std::string(std::string("\\") + yytext); | ||||
| 		return TOK_ID; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| [a-zA-Z_$][a-zA-Z0-9_$\.]* { | ||||
|  |  | |||
|  | @ -54,6 +54,8 @@ namespace VERILOG_FRONTEND { | |||
| 	std::map<std::string, AstNode*> *attr_list, default_attr_list; | ||||
| 	std::stack<std::map<std::string, AstNode*> *> attr_list_stack; | ||||
| 	std::map<std::string, AstNode*> *albuf; | ||||
| 	std::map<std::string, AstNode*> user_types; | ||||
| 	std::map<std::string, AstNode*> pkg_user_types; | ||||
| 	std::vector<AstNode*> ast_stack; | ||||
| 	struct AstNode *astbuf1, *astbuf2, *astbuf3; | ||||
| 	struct AstNode *current_function_or_task; | ||||
|  | @ -125,6 +127,26 @@ struct specify_rise_fall { | |||
| 	specify_triple fall; | ||||
| }; | ||||
| 
 | ||||
| static void addTypedefNode(std::string *name, AstNode *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); | ||||
| 	tnode->str = *name; | ||||
| 	user_types[*name] = tnode; | ||||
| 	if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { | ||||
| 		// typedef inside a package so we need the qualified name | ||||
| 		auto qname = current_ast_mod->str + "::" + (*name).substr(1); | ||||
| 		pkg_user_types[qname] = tnode; | ||||
| 	} | ||||
| 	delete name; | ||||
| 	ast_stack.back()->children.push_back(tnode); | ||||
| } | ||||
| 
 | ||||
| static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true) | ||||
| { | ||||
| 	auto range = new AstNode(AST_RANGE); | ||||
|  | @ -167,6 +189,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_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS | ||||
| %token <string> TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL | ||||
| %token <string> TOK_USER_TYPE | ||||
| %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL | ||||
| %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END | ||||
| %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM | ||||
|  | @ -190,6 +213,7 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = | |||
| %type <ast> range range_or_multirange  non_opt_range non_opt_multirange range_or_signed_int | ||||
| %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list | ||||
| %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number | ||||
| %type <string> type_name | ||||
| %type <ast> opt_enum_init | ||||
| %type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff | ||||
| %type <al> attr case_attr | ||||
|  | @ -330,7 +354,9 @@ hierarchical_id: | |||
| 	}; | ||||
| 
 | ||||
| hierarchical_type_id: | ||||
| 	'(' hierarchical_id ')' { $$ = $2; }; | ||||
| 	TOK_USER_TYPE | ||||
| 	| '(' TOK_USER_TYPE ')'	{ $$ = $2; }		// non-standard grammar | ||||
| 	; | ||||
| 
 | ||||
| module: | ||||
| 	attr TOK_MODULE TOK_ID { | ||||
|  | @ -352,6 +378,7 @@ module: | |||
| 		ast_stack.pop_back(); | ||||
| 		log_assert(ast_stack.size() == 1); | ||||
| 		current_ast_mod = NULL; | ||||
| 		user_types.clear(); | ||||
| 	}; | ||||
| 
 | ||||
| module_para_opt: | ||||
|  | @ -465,6 +492,7 @@ package: | |||
| 	} ';' package_body TOK_ENDPACKAGE { | ||||
| 		ast_stack.pop_back(); | ||||
| 		current_ast_mod = NULL; | ||||
| 		user_types.clear(); | ||||
| 	}; | ||||
| 
 | ||||
| package_body: | ||||
|  | @ -494,6 +522,7 @@ interface: | |||
| 		ast_stack.pop_back(); | ||||
| 		log_assert(ast_stack.size() == 1); | ||||
| 		current_ast_mod = NULL; | ||||
| 		user_types.clear(); | ||||
| 	}; | ||||
| 
 | ||||
| interface_body: | ||||
|  | @ -1591,8 +1620,12 @@ assign_expr: | |||
| 		ast_stack.back()->children.push_back(node); | ||||
| 	}; | ||||
| 
 | ||||
| type_name: TOK_ID		// first time seen | ||||
| 	 | TOK_USER_TYPE	// redefinition | ||||
| 	 ; | ||||
| 
 | ||||
| typedef_decl: | ||||
| 	TOK_TYPEDEF wire_type range TOK_ID range_or_multirange ';' { | ||||
| 	TOK_TYPEDEF wire_type range type_name range_or_multirange ';' { | ||||
| 		astbuf1 = $2; | ||||
| 		astbuf2 = $3; | ||||
| 		if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { | ||||
|  | @ -1625,13 +1658,10 @@ typedef_decl: | |||
| 			} | ||||
| 			astbuf1->children.push_back(rangeNode); | ||||
| 		} | ||||
| 
 | ||||
| 		ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); | ||||
| 		ast_stack.back()->children.back()->str = *$4; | ||||
| 		addTypedefNode($4, astbuf1); | ||||
| 	} | | ||||
| 	TOK_TYPEDEF enum_type TOK_ID ';' { | ||||
| 		ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); | ||||
| 		ast_stack.back()->children.back()->str = *$3; | ||||
| 	TOK_TYPEDEF enum_type type_name ';' { | ||||
| 		addTypedefNode($3, astbuf1); | ||||
| 	} | ||||
| 	; | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,8 +5,9 @@ module enum_simple(input clk, input rst); | |||
| 	typedef enum logic [1:0] { | ||||
| 		ts0, ts1, ts2, ts3 | ||||
| 	} states_t; | ||||
| 	(states_t) state; | ||||
| 	(states_t) enum_const = ts1; | ||||
| 	states_t state; | ||||
| 	(states_t) state1; | ||||
| 	states_t enum_const = ts1; | ||||
| 
 | ||||
| 	always @(posedge clk) begin | ||||
| 		if (rst) begin | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| module top(input [3:0] addr, wdata, input clk, wen, output reg [3:0] rdata); | ||||
| 	typedef logic [3:0] ram16x4_t[0:15]; | ||||
| 
 | ||||
| 	(ram16x4_t) mem; | ||||
| 	ram16x4_t mem; | ||||
| 
 | ||||
| 	always @(posedge clk) begin | ||||
| 		if (wen) mem[addr] <= wdata; | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| module top(input [3:0] addr, wdata, input clk, wen, output reg [3:0] rdata); | ||||
| 	typedef logic [3:0] nibble; | ||||
| 
 | ||||
| 	(nibble) mem[0:15]; | ||||
| 	nibble mem[0:15]; | ||||
| 
 | ||||
| 	always @(posedge clk) begin | ||||
| 		if (wen) mem[addr] <= wdata; | ||||
|  |  | |||
|  | @ -5,8 +5,8 @@ endpackage | |||
| 
 | ||||
| module top; | ||||
| 
 | ||||
| 	(* keep *) (pkg::uint8_t) a = 8'hAA; | ||||
| 	(* keep *) (pkg::enum8_t) b_enum = pkg::bb; | ||||
| 	(* keep *) pkg::uint8_t a = 8'hAA; | ||||
| 	(* keep *) pkg::enum8_t b_enum = pkg::bb; | ||||
| 
 | ||||
| 	always @* assert(a == 8'hAA); | ||||
| 	always @* assert(b_enum == 8'hBB); | ||||
|  |  | |||
|  | @ -6,12 +6,12 @@ module top; | |||
| 	typedef logic [1:0] uint2_t; | ||||
| 	typedef logic signed [3:0] int4_t; | ||||
| 	typedef logic signed [7:0] int8_t; | ||||
| 	typedef (int8_t) char_t; | ||||
| 	typedef int8_t char_t; | ||||
| 
 | ||||
| 	parameter (uint2_t) int2 = 2'b10; | ||||
| 	localparam (int4_t) int4 = -1; | ||||
| 	localparam (int8_t) int8 = int4; | ||||
| 	localparam (char_t) ch = int8; | ||||
| 	parameter uint2_t int2 = 2'b10; | ||||
| 	localparam int4_t int4 = -1; | ||||
| 	localparam int8_t int8 = int4; | ||||
| 	localparam char_t ch = int8; | ||||
| 
 | ||||
| 
 | ||||
| 	`STATIC_ASSERT(int2 == 2'b10); | ||||
|  |  | |||
|  | @ -4,30 +4,30 @@ typedef enum logic {s0, s1} outer_enum_t; | |||
| 
 | ||||
| module top; | ||||
| 
 | ||||
| 	(outer_uint4_t) u4_i = 8'hA5; | ||||
| 	(outer_enum_t) enum4_i = s0; | ||||
| 	outer_uint4_t u4_i = 8'hA5; | ||||
| 	outer_enum_t enum4_i = s0; | ||||
| 	always @(*) assert(u4_i == 4'h5); | ||||
| 	always @(*) assert(enum4_i == 1'b0); | ||||
| 
 | ||||
| 	typedef logic [3:0] inner_type; | ||||
| 	typedef enum logic [2:0] {s2=2, s3, s4} inner_enum_t; | ||||
| 	(inner_type) inner_i1 = 8'h5A; | ||||
| 	(inner_enum_t) inner_enum1 = s3; | ||||
| 	inner_type inner_i1 = 8'h5A; | ||||
| 	inner_enum_t inner_enum1 = s3; | ||||
| 	always @(*) assert(inner_i1 == 4'hA); | ||||
| 	always @(*) assert(inner_enum1 == 3'h3); | ||||
| 
 | ||||
| 	if (1) begin: genblock | ||||
| 		typedef logic [7:0] inner_type; | ||||
| 		parameter (inner_type) inner_const = 8'hA5; | ||||
| 		parameter inner_type inner_const = 8'hA5; | ||||
|  		typedef enum logic [2:0] {s5=5, s6, s7} inner_enum_t; | ||||
| 		(inner_type) inner_gb_i = inner_const; //8'hA5;
 | ||||
|  		(inner_enum_t) inner_gb_enum1 = s7; | ||||
| 		inner_type inner_gb_i = inner_const; //8'hA5;
 | ||||
|  		inner_enum_t inner_gb_enum1 = s7; | ||||
| 		always @(*) assert(inner_gb_i == 8'hA5); | ||||
|  		always @(*) assert(inner_gb_enum1 == 3'h7); | ||||
| 	end | ||||
| 
 | ||||
| 	(inner_type) inner_i2 = 8'h42; | ||||
| 	(inner_enum_t) inner_enum2 = s4; | ||||
| 	inner_type inner_i2 = 8'h42; | ||||
| 	inner_enum_t inner_enum2 = s4; | ||||
| 	always @(*) assert(inner_i2 == 4'h2); | ||||
| 	always @(*) assert(inner_enum2 == 3'h4); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,12 +3,12 @@ module top; | |||
| 	typedef logic [1:0] uint2_t; | ||||
| 	typedef logic signed [3:0] int4_t; | ||||
| 	typedef logic signed [7:0] int8_t; | ||||
| 	typedef (int8_t) char_t; | ||||
| 	typedef int8_t char_t; | ||||
| 
 | ||||
| 	(* keep *) (uint2_t) int2 = 2'b10; | ||||
| 	(* keep *) (int4_t) int4 = -1; | ||||
| 	(* keep *) (int8_t) int8 = int4; | ||||
| 	(* keep *) (char_t) ch = int8; | ||||
| 	(* keep *) uint2_t int2 = 2'b10; | ||||
| 	(* keep *) int4_t int4 = -1; | ||||
| 	(* keep *) int8_t int8 = int4; | ||||
| 	(* keep *) char_t ch = int8; | ||||
| 
 | ||||
| 
 | ||||
| 	always @* assert(int2 == 2'b10); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue