mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			796 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			796 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  *  yosys -- Yosys Open SYnthesis Suite
 | |
|  *
 | |
|  *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 | |
|  *
 | |
|  *  Permission to use, copy, modify, and/or distribute this software for any
 | |
|  *  purpose with or without fee is hereby granted, provided that the above
 | |
|  *  copyright notice and this permission notice appear in all copies.
 | |
|  *
 | |
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | |
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | |
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | |
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | |
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  *  ---
 | |
|  *
 | |
|  *  The Verilog frontend.
 | |
|  *
 | |
|  *  This frontend is using the AST frontend library (see frontends/ast/).
 | |
|  *  Thus this frontend does not generate RTLIL code directly but creates an
 | |
|  *  AST directly from the Verilog parse tree and then passes this AST to
 | |
|  *  the AST frontend library.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #if !defined(__wasm)
 | |
| #include <filesystem>
 | |
| #endif
 | |
| 
 | |
| #include "verilog_frontend.h"
 | |
| #include "verilog_lexer.h"
 | |
| #include "verilog_error.h"
 | |
| #include "verilog_location.h"
 | |
| #include "preproc.h"
 | |
| #include "kernel/yosys.h"
 | |
| #include "libs/sha1/sha1.h"
 | |
| #include <stdarg.h>
 | |
| #include <list>
 | |
| 
 | |
| YOSYS_NAMESPACE_BEGIN
 | |
| using namespace VERILOG_FRONTEND;
 | |
| 
 | |
| // use the Verilog bison/flex parser to generate an AST and use AST::process() to convert it to RTLIL
 | |
| 
 | |
| static std::vector<std::string> verilog_defaults;
 | |
| static std::list<std::vector<std::string>> verilog_defaults_stack;
 | |
| 
 | |
| static void error_on_dpi_function(AST::AstNode *node)
 | |
| {
 | |
|     if (node->type == AST::AST_DPI_FUNCTION)
 | |
|         err_at_loc(node->location, "Found DPI function %s.\n", node->str);
 | |
|     for (auto& child : node->children)
 | |
|         error_on_dpi_function(child.get());
 | |
| }
 | |
| 
 | |
| static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<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.
 | |
| 	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.get();
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| struct VerilogFrontend : public Frontend {
 | |
| 	VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { }
 | |
| 	void help() override
 | |
| 	{
 | |
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
| 		log("\n");
 | |
| 		log("    read_verilog [options] [filename]\n");
 | |
| 		log("\n");
 | |
| 		log("Load modules from a Verilog file to the current design. A large subset of\n");
 | |
| 		log("Verilog-2005 is supported.\n");
 | |
| 		log("\n");
 | |
| 		log("    -sv\n");
 | |
| 		log("        enable support for SystemVerilog features. (only a small subset\n");
 | |
| 		log("        of SystemVerilog is supported)\n");
 | |
| 		log("\n");
 | |
| 		log("    -formal\n");
 | |
| 		log("        enable support for SystemVerilog assertions and some Yosys extensions\n");
 | |
| 		log("        replace the implicit -D SYNTHESIS with -D FORMAL\n");
 | |
| 		log("\n");
 | |
| 		log("    -nosynthesis\n");
 | |
| 		log("        don't add implicit -D SYNTHESIS\n");
 | |
| 		log("\n");
 | |
| 		log("    -noassert\n");
 | |
| 		log("        ignore assert() statements\n");
 | |
| 		log("\n");
 | |
| 		log("    -noassume\n");
 | |
| 		log("        ignore assume() statements\n");
 | |
| 		log("\n");
 | |
| 		log("    -norestrict\n");
 | |
| 		log("        ignore restrict() statements\n");
 | |
| 		log("\n");
 | |
| 		log("    -assume-asserts\n");
 | |
| 		log("        treat all assert() statements like assume() statements\n");
 | |
| 		log("\n");
 | |
| 		log("    -assert-assumes\n");
 | |
| 		log("        treat all assume() statements like assert() statements\n");
 | |
| 		log("\n");
 | |
| 		log("    -nodisplay\n");
 | |
| 		log("        suppress output from display system tasks ($display et. al).\n");
 | |
| 		log("        This does not affect the output from a later 'sim' command.\n");
 | |
| 		log("\n");
 | |
| 		log("    -debug\n");
 | |
| 		log("        alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
 | |
| 		log("\n");
 | |
| 		log("    -dump_ast1\n");
 | |
| 		log("        dump abstract syntax tree (before simplification)\n");
 | |
| 		log("\n");
 | |
| 		log("    -dump_ast2\n");
 | |
| 		log("        dump abstract syntax tree (after simplification)\n");
 | |
| 		log("\n");
 | |
| 		log("    -no_dump_ptr\n");
 | |
| 		log("        do not include hex memory addresses in dump (easier to diff dumps)\n");
 | |
| 		log("\n");
 | |
| 		log("    -dump_vlog1\n");
 | |
| 		log("        dump ast as Verilog code (before simplification)\n");
 | |
| 		log("\n");
 | |
| 		log("    -dump_vlog2\n");
 | |
| 		log("        dump ast as Verilog code (after simplification)\n");
 | |
| 		log("\n");
 | |
| 		log("    -dump_rtlil\n");
 | |
| 		log("        dump generated RTLIL netlist\n");
 | |
| 		log("\n");
 | |
| 		log("    -yydebug\n");
 | |
| 		log("        enable parser debug output\n");
 | |
| 		log("\n");
 | |
| 		log("    -nolatches\n");
 | |
| 		log("        usually latches are synthesized into logic loops\n");
 | |
| 		log("        this option prohibits this and sets the output to 'x'\n");
 | |
| 		log("        in what would be the latches hold condition\n");
 | |
| 		log("\n");
 | |
| 		log("        this behavior can also be achieved by setting the\n");
 | |
| 		log("        'nolatches' attribute on the respective module or\n");
 | |
| 		log("        always block.\n");
 | |
| 		log("\n");
 | |
| 		log("    -nomem2reg\n");
 | |
| 		log("        under certain conditions memories are converted to registers\n");
 | |
| 		log("        early during simplification to ensure correct handling of\n");
 | |
| 		log("        complex corner cases. this option disables this behavior.\n");
 | |
| 		log("\n");
 | |
| 		log("        this can also be achieved by setting the 'nomem2reg'\n");
 | |
| 		log("        attribute on the respective module or register.\n");
 | |
| 		log("\n");
 | |
| 		log("        This is potentially dangerous. Usually the front-end has good\n");
 | |
| 		log("        reasons for converting an array to a list of registers.\n");
 | |
| 		log("        Prohibiting this step will likely result in incorrect synthesis\n");
 | |
| 		log("        results.\n");
 | |
| 		log("\n");
 | |
| 		log("    -mem2reg\n");
 | |
| 		log("        always convert memories to registers. this can also be\n");
 | |
| 		log("        achieved by setting the 'mem2reg' attribute on the respective\n");
 | |
| 		log("        module or register.\n");
 | |
| 		log("\n");
 | |
| 		log("    -nomeminit\n");
 | |
| 		log("        do not infer $meminit cells and instead convert initialized\n");
 | |
| 		log("        memories to registers directly in the front-end.\n");
 | |
| 		log("\n");
 | |
| 		log("    -ppdump\n");
 | |
| 		log("        dump Verilog code after pre-processor\n");
 | |
| 		log("\n");
 | |
| 		log("    -nopp\n");
 | |
| 		log("        do not run the pre-processor\n");
 | |
| 		log("\n");
 | |
| 		log("    -nodpi\n");
 | |
| 		log("        disable DPI-C support\n");
 | |
| 		log("\n");
 | |
| 		log("    -noblackbox\n");
 | |
| 		log("        do not automatically add a (* blackbox *) attribute to an\n");
 | |
| 		log("        empty module.\n");
 | |
| 		log("\n");
 | |
| 		log("    -lib\n");
 | |
| 		log("        only create empty blackbox modules. This implies -DBLACKBOX.\n");
 | |
| 		log("        modules with the (* whitebox *) attribute will be preserved.\n");
 | |
| 		log("        (* lib_whitebox *) will be treated like (* whitebox *).\n");
 | |
| 		log("\n");
 | |
| 		log("    -nowb\n");
 | |
| 		log("        delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
 | |
| 		log("        all modules.\n");
 | |
| 		log("\n");
 | |
| 		log("    -specify\n");
 | |
| 		log("        parse and import specify blocks\n");
 | |
| 		log("\n");
 | |
| 		log("    -noopt\n");
 | |
| 		log("        don't perform basic optimizations (such as const folding) in the\n");
 | |
| 		log("        high-level front-end.\n");
 | |
| 		log("\n");
 | |
| 		log("    -icells\n");
 | |
| 		log("        interpret cell types starting with '$' as internal cell types\n");
 | |
| 		log("\n");
 | |
| 		log("    -pwires\n");
 | |
| 		log("        add a wire for each module parameter\n");
 | |
| 		log("\n");
 | |
| 		log("    -nooverwrite\n");
 | |
| 		log("        ignore re-definitions of modules. (the default behavior is to\n");
 | |
| 		log("        create an error message if the existing module is not a black box\n");
 | |
| 		log("        module, and overwrite the existing module otherwise.)\n");
 | |
| 		log("\n");
 | |
| 		log("    -overwrite\n");
 | |
| 		log("        overwrite existing modules with the same name\n");
 | |
| 		log("\n");
 | |
| 		log("    -defer\n");
 | |
| 		log("        only read the abstract syntax tree and defer actual compilation\n");
 | |
| 		log("        to a later 'hierarchy' command. Useful in cases where the default\n");
 | |
| 		log("        parameters of modules yield invalid or not synthesizable code.\n");
 | |
| 		log("\n");
 | |
| 		log("    -noautowire\n");
 | |
| 		log("        make the default of `default_nettype be \"none\" instead of \"wire\".\n");
 | |
| 		log("\n");
 | |
| 		log("    -setattr <attribute_name>\n");
 | |
| 		log("        set the specified attribute (to the value 1) on all loaded modules\n");
 | |
| 		log("\n");
 | |
| 		log("    -Dname[=definition]\n");
 | |
| 		log("        define the preprocessor symbol 'name' and set its optional value\n");
 | |
| 		log("        'definition'\n");
 | |
| 		log("\n");
 | |
| 		log("    -Idir\n");
 | |
| 		log("        add 'dir' to the directories which are used when searching include\n");
 | |
| 		log("        files\n");
 | |
| 		log("\n");
 | |
| 		log("    -relativeshare\n");
 | |
| 		log("        use paths relative to share directory for source locations\n");
 | |
| 		log("        where possible (experimental).\n");
 | |
| 		log("\n");
 | |
| 		log("The command 'verilog_defaults' can be used to register default options for\n");
 | |
| 		log("subsequent calls to 'read_verilog'.\n");
 | |
| 		log("\n");
 | |
| 		log("Note that the Verilog frontend does a pretty good job of processing valid\n");
 | |
| 		log("verilog input, but has not very good error reporting. It generally is\n");
 | |
| 		log("recommended to use a simulator (for example Icarus Verilog) for checking\n");
 | |
| 		log("the syntax of the code, rather than to rely on read_verilog for that.\n");
 | |
| 		log("\n");
 | |
| 		log("Depending on if read_verilog is run in -formal mode, either the macro\n");
 | |
| 		log("SYNTHESIS or FORMAL is defined automatically, unless -nosynthesis is used.\n");
 | |
| 		log("In addition, read_verilog always defines the macro YOSYS.\n");
 | |
| 		log("\n");
 | |
| 		log("See the Yosys README file for a list of non-standard Verilog features\n");
 | |
| 		log("supported by the Yosys Verilog front-end.\n");
 | |
| 		log("\n");
 | |
| 	}
 | |
| 	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
 | |
| 	{
 | |
| 		bool flag_nodisplay = false;
 | |
| 		bool flag_dump_ast1 = false;
 | |
| 		bool flag_dump_ast2 = false;
 | |
| 		bool flag_no_dump_ptr = false;
 | |
| 		bool flag_dump_vlog1 = false;
 | |
| 		bool flag_dump_vlog2 = false;
 | |
| 		bool flag_dump_rtlil = false;
 | |
| 		bool flag_debug_lexer = false;
 | |
| 		bool flag_debug_parser = false;
 | |
| 		bool flag_nolatches = false;
 | |
| 		bool flag_nomeminit = false;
 | |
| 		bool flag_nomem2reg = false;
 | |
| 		bool flag_mem2reg = false;
 | |
| 		bool flag_ppdump = false;
 | |
| 		bool flag_nopp = false;
 | |
| 		bool flag_nodpi = false;
 | |
| 		bool flag_noopt = false;
 | |
| 		bool flag_icells = false;
 | |
| 		bool flag_pwires = false;
 | |
| 		bool flag_nooverwrite = false;
 | |
| 		bool flag_overwrite = false;
 | |
| 		bool flag_defer = false;
 | |
| 		bool flag_noblackbox = false;
 | |
| 		bool flag_nowb = false;
 | |
| 		bool flag_nosynthesis = false;
 | |
| 		bool flag_yydebug = false;
 | |
| 		bool flag_relative_share = false;
 | |
| 		define_map_t defines_map;
 | |
| 
 | |
| 		std::list<std::string> include_dirs;
 | |
| 		std::list<std::string> attributes;
 | |
| 
 | |
| 		ParseMode parse_mode = {};
 | |
| 		ParseState parse_state = {};
 | |
| 		parse_mode.sv = false;
 | |
| 		parse_mode.formal = false;
 | |
| 		parse_mode.noassert = false;
 | |
| 		parse_mode.noassume = false;
 | |
| 		parse_mode.norestrict = false;
 | |
| 		parse_mode.assume_asserts = false;
 | |
| 		parse_mode.assert_assumes = false;
 | |
| 		parse_mode.lib = false;
 | |
| 		parse_mode.specify = false;
 | |
| 		parse_state.default_nettype_wire = true;
 | |
| 
 | |
| 		args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
 | |
| 
 | |
| 		size_t argidx;
 | |
| 		for (argidx = 1; argidx < args.size(); argidx++) {
 | |
| 			std::string arg = args[argidx];
 | |
| 			if (arg == "-sv") {
 | |
| 				parse_mode.sv = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-formal") {
 | |
| 				parse_mode.formal = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nosynthesis") {
 | |
| 				flag_nosynthesis = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-noassert") {
 | |
| 				parse_mode.noassert = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-noassume") {
 | |
| 				parse_mode.noassume = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-norestrict") {
 | |
| 				parse_mode.norestrict = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-assume-asserts") {
 | |
| 				parse_mode.assume_asserts = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-assert-assumes") {
 | |
| 				parse_mode.assert_assumes = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nodisplay") {
 | |
| 				flag_nodisplay = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-debug") {
 | |
| 				flag_dump_ast1 = true;
 | |
| 				flag_dump_ast2 = true;
 | |
| 				flag_dump_vlog1 = true;
 | |
| 				flag_dump_vlog2 = true;
 | |
| 				flag_debug_lexer = true;
 | |
| 				flag_debug_parser = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-dump_ast1") {
 | |
| 				flag_dump_ast1 = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-dump_ast2") {
 | |
| 				flag_dump_ast2 = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-no_dump_ptr") {
 | |
| 				flag_no_dump_ptr = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-dump_vlog1") {
 | |
| 				flag_dump_vlog1 = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-dump_vlog2") {
 | |
| 				flag_dump_vlog2 = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-dump_rtlil") {
 | |
| 				flag_dump_rtlil = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-yydebug") {
 | |
| 				flag_yydebug = true;
 | |
| 				flag_debug_lexer = true;
 | |
| 				flag_debug_parser = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nolatches") {
 | |
| 				flag_nolatches = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nomeminit") {
 | |
| 				flag_nomeminit = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nomem2reg") {
 | |
| 				flag_nomem2reg = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-mem2reg") {
 | |
| 				flag_mem2reg = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-ppdump") {
 | |
| 				flag_ppdump = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nopp") {
 | |
| 				flag_nopp = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nodpi") {
 | |
| 				flag_nodpi = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-noblackbox") {
 | |
| 				flag_noblackbox = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-lib") {
 | |
| 				parse_mode.lib = true;
 | |
| 				defines_map.add("BLACKBOX", "");
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-nowb") {
 | |
| 				flag_nowb = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-specify") {
 | |
| 				parse_mode.specify = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-noopt") {
 | |
| 				flag_noopt = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-icells") {
 | |
| 				flag_icells = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-pwires") {
 | |
| 				flag_pwires = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-ignore_redef" || arg == "-nooverwrite") {
 | |
| 				flag_nooverwrite = true;
 | |
| 				flag_overwrite = false;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-overwrite") {
 | |
| 				flag_nooverwrite = false;
 | |
| 				flag_overwrite = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-defer") {
 | |
| 				flag_defer = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-noautowire") {
 | |
| 				parse_state.default_nettype_wire = false;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-setattr" && argidx+1 < args.size()) {
 | |
| 				attributes.push_back(RTLIL::escape_id(args[++argidx]));
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-relativeshare") {
 | |
| 				flag_relative_share = true;
 | |
| 				log_experimental("read_verilog -relativeshare");
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-D" && argidx+1 < args.size()) {
 | |
| 				std::string name = args[++argidx], value;
 | |
| 				size_t equal = name.find('=');
 | |
| 				if (equal != std::string::npos) {
 | |
| 					value = name.substr(equal+1);
 | |
| 					name = name.substr(0, equal);
 | |
| 				}
 | |
| 				defines_map.add(name, value);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg.compare(0, 2, "-D") == 0) {
 | |
| 				size_t equal = arg.find('=', 2);
 | |
| 				std::string name = arg.substr(2, equal-2);
 | |
| 				std::string value;
 | |
| 				if (equal != std::string::npos)
 | |
| 					value = arg.substr(equal+1);
 | |
| 				defines_map.add(name, value);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-I" && argidx+1 < args.size()) {
 | |
| 				include_dirs.push_back(args[++argidx]);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg.compare(0, 2, "-I") == 0) {
 | |
| 				include_dirs.push_back(arg.substr(2));
 | |
| 				continue;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if (parse_mode.formal || !flag_nosynthesis)
 | |
| 			defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1");
 | |
| 
 | |
| 		extra_args(f, filename, args, argidx);
 | |
| 
 | |
| 		log_header(design, "Executing Verilog-2005 frontend: %s\n", filename);
 | |
| 
 | |
| 		log("Parsing %s%s input from `%s' to AST representation.\n",
 | |
| 				parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
 | |
| 
 | |
| 		log("verilog frontend filename %s\n", filename.c_str());
 | |
| 		if (flag_relative_share) {
 | |
| 			auto share_path = proc_share_dirname();
 | |
| 			if (filename.substr(0, share_path.length()) == share_path)
 | |
| 				filename = std::string("+/") + filename.substr(share_path.length());
 | |
| 			log("new filename %s\n", filename.c_str());
 | |
| 		}
 | |
| 		AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
 | |
| 		std::string code_after_preproc;
 | |
| 
 | |
| 		parse_state.lexin = f;
 | |
| 		if (!flag_nopp) {
 | |
| 			code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode);
 | |
| 			if (flag_ppdump)
 | |
| 				log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc);
 | |
| 			parse_state.lexin = new std::istringstream(code_after_preproc);
 | |
| 		}
 | |
| 
 | |
| 		auto filename_shared = std::make_shared<std::string>(filename);
 | |
| 		auto top_loc = Location();
 | |
| 		top_loc.begin.filename = filename_shared;
 | |
| 		parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN);
 | |
| 		VerilogLexer lexer(&parse_state, &parse_mode, filename_shared);
 | |
| 		frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode);
 | |
| 		lexer.set_debug(flag_debug_lexer);
 | |
| 		parser.set_debug_level(flag_debug_parser ? 1 : 0);
 | |
| 
 | |
| 		// make package typedefs available to parser
 | |
| 		add_package_types(parse_state.pkg_user_types, design->verilog_packages);
 | |
| 
 | |
| 		UserTypeMap global_types_map;
 | |
| 		for (auto& def : design->verilog_globals) {
 | |
| 			if (def->type == AST::AST_TYPEDEF) {
 | |
| 				global_types_map[def->str] = def.get();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		log_assert(parse_state.user_type_stack.empty());
 | |
| 		// use previous global typedefs as bottom level of user type stack
 | |
| 		parse_state.user_type_stack.push_back(std::move(global_types_map));
 | |
| 		// add a new empty type map to allow overriding existing global definitions
 | |
| 		parse_state.user_type_stack.push_back(UserTypeMap());
 | |
| 
 | |
| 		if (flag_yydebug) {
 | |
| 			lexer.set_debug(true);
 | |
| 			parser.set_debug_level(1);
 | |
| 		}
 | |
| 		parser.parse();
 | |
| 		// frontend_verilog_yyset_lineno(1);
 | |
| 
 | |
| 		for (auto &child : parse_state.current_ast->children) {
 | |
| 			if (child->type == AST::AST_MODULE)
 | |
| 				for (auto &attr : attributes)
 | |
| 					if (child->attributes.count(attr) == 0)
 | |
| 						child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false);
 | |
| 		}
 | |
| 
 | |
| 		if (flag_nodpi)
 | |
| 			error_on_dpi_function(parse_state.current_ast);
 | |
| 
 | |
| 		AST::process(design, parse_state.current_ast, flag_nodisplay, 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, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire);
 | |
| 
 | |
| 
 | |
| 		if (!flag_nopp)
 | |
| 			delete parse_state.lexin;
 | |
| 
 | |
| 		// only the previous and new global type maps remain
 | |
| 		log_assert(parse_state.user_type_stack.size() == 2);
 | |
| 		parse_state.user_type_stack.clear();
 | |
| 
 | |
| 		delete parse_state.current_ast;
 | |
| 		parse_state.current_ast = NULL;
 | |
| 
 | |
| 		log("Successfully finished Verilog frontend.\n");
 | |
| 	}
 | |
| } VerilogFrontend;
 | |
| 
 | |
| struct VerilogDefaults : public Pass {
 | |
| 	VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
 | |
| 	void help() override
 | |
| 	{
 | |
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
| 		log("\n");
 | |
| 		log("    verilog_defaults -add [options]\n");
 | |
| 		log("\n");
 | |
| 		log("Add the specified options to the list of default options to read_verilog.\n");
 | |
| 		log("\n");
 | |
| 		log("\n");
 | |
| 		log("    verilog_defaults -clear\n");
 | |
| 		log("\n");
 | |
| 		log("Clear the list of Verilog default options.\n");
 | |
| 		log("\n");
 | |
| 		log("\n");
 | |
| 		log("    verilog_defaults -push\n");
 | |
| 		log("    verilog_defaults -pop\n");
 | |
| 		log("\n");
 | |
| 		log("Push or pop the list of default options to a stack. Note that -push does\n");
 | |
| 		log("not imply -clear.\n");
 | |
| 		log("\n");
 | |
| 	}
 | |
| 	void execute(std::vector<std::string> args, RTLIL::Design*) override
 | |
| 	{
 | |
| 		if (args.size() < 2)
 | |
| 			cmd_error(args, 1, "Missing argument.");
 | |
| 
 | |
| 		if (args[1] == "-add") {
 | |
| 			verilog_defaults.insert(verilog_defaults.end(), args.begin()+2, args.end());
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (args.size() != 2)
 | |
| 			cmd_error(args, 2, "Extra argument.");
 | |
| 
 | |
| 		if (args[1] == "-clear") {
 | |
| 			verilog_defaults.clear();
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (args[1] == "-push") {
 | |
| 			verilog_defaults_stack.push_back(verilog_defaults);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (args[1] == "-pop") {
 | |
| 			if (verilog_defaults_stack.empty()) {
 | |
| 				verilog_defaults.clear();
 | |
| 			} else {
 | |
| 				verilog_defaults.swap(verilog_defaults_stack.back());
 | |
| 				verilog_defaults_stack.pop_back();
 | |
| 			}
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| } VerilogDefaults;
 | |
| 
 | |
| struct VerilogDefines : public Pass {
 | |
| 	VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { }
 | |
| 	void help() override
 | |
| 	{
 | |
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
| 		log("\n");
 | |
| 		log("    verilog_defines [options]\n");
 | |
| 		log("\n");
 | |
| 		log("Define and undefine verilog preprocessor macros.\n");
 | |
| 		log("\n");
 | |
| 		log("    -Dname[=definition]\n");
 | |
| 		log("        define the preprocessor symbol 'name' and set its optional value\n");
 | |
| 		log("        'definition'\n");
 | |
| 		log("\n");
 | |
| 		log("    -Uname[=definition]\n");
 | |
| 		log("        undefine the preprocessor symbol 'name'\n");
 | |
| 		log("\n");
 | |
| 		log("    -reset\n");
 | |
| 		log("        clear list of defined preprocessor symbols\n");
 | |
| 		log("\n");
 | |
| 		log("    -list\n");
 | |
| 		log("        list currently defined preprocessor symbols\n");
 | |
| 		log("\n");
 | |
| 	}
 | |
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | |
| 	{
 | |
| 		size_t argidx;
 | |
| 		for (argidx = 1; argidx < args.size(); argidx++) {
 | |
| 			std::string arg = args[argidx];
 | |
| 			if (arg == "-D" && argidx+1 < args.size()) {
 | |
| 				std::string name = args[++argidx], value;
 | |
| 				size_t equal = name.find('=');
 | |
| 				if (equal != std::string::npos) {
 | |
| 					value = name.substr(equal+1);
 | |
| 					name = name.substr(0, equal);
 | |
| 				}
 | |
| 				design->verilog_defines->add(name, value);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg.compare(0, 2, "-D") == 0) {
 | |
| 				size_t equal = arg.find('=', 2);
 | |
| 				std::string name = arg.substr(2, equal-2);
 | |
| 				std::string value;
 | |
| 				if (equal != std::string::npos)
 | |
| 					value = arg.substr(equal+1);
 | |
| 				design->verilog_defines->add(name, value);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-U" && argidx+1 < args.size()) {
 | |
| 				std::string name = args[++argidx];
 | |
| 				design->verilog_defines->erase(name);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg.compare(0, 2, "-U") == 0) {
 | |
| 				std::string name = arg.substr(2);
 | |
| 				design->verilog_defines->erase(name);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-reset") {
 | |
| 				design->verilog_defines->clear();
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-list") {
 | |
| 				design->verilog_defines->log();
 | |
| 				continue;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if (args.size() != argidx)
 | |
| 			cmd_error(args, argidx, "Extra argument.");
 | |
| 	}
 | |
| } VerilogDefines;
 | |
| 
 | |
| #if !defined(__wasm)
 | |
| 
 | |
| static void parse_file_list(const std::string &file_list_path, RTLIL::Design *design, bool relative_to_file_list_path)
 | |
| {
 | |
| 	std::ifstream flist(file_list_path);
 | |
| 	if (!flist.is_open()) {
 | |
| 		log_error("Verilog file list file does not exist");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| 	std::filesystem::path file_list_parent_dir = std::filesystem::path(file_list_path).parent_path();
 | |
| 
 | |
| 	std::string v_file_name;
 | |
| 	while (std::getline(flist, v_file_name)) {
 | |
| 		if (v_file_name.empty()) {
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		std::filesystem::path verilog_file_path;
 | |
| 		if (relative_to_file_list_path) {
 | |
| 			verilog_file_path = file_list_parent_dir / v_file_name;
 | |
| 		} else {
 | |
| 			verilog_file_path = std::filesystem::current_path() / v_file_name;
 | |
| 		}
 | |
| 
 | |
| 		bool is_sv = (verilog_file_path.extension() == ".sv");
 | |
| 
 | |
| 		std::vector<std::string> read_verilog_cmd = {"read_verilog", "-defer"};
 | |
| 		if (is_sv) {
 | |
| 			read_verilog_cmd.push_back("-sv");
 | |
| 		}
 | |
| 		read_verilog_cmd.push_back(verilog_file_path.string());
 | |
| 		Pass::call(design, read_verilog_cmd);
 | |
| 	}
 | |
| 
 | |
| 	flist.close();
 | |
| }
 | |
| 
 | |
| struct VerilogFileList : public Pass {
 | |
| 	VerilogFileList() : Pass("read_verilog_file_list", "parse a Verilog file list") {}
 | |
| 	void help() override
 | |
| 	{
 | |
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
| 		log("\n");
 | |
| 		log("    read_verilog_file_list [options]\n");
 | |
| 		log("\n");
 | |
| 		log("Parse a Verilog file list, and pass the list of Verilog files to read_verilog\n");
 | |
| 		log("command\n");
 | |
| 		log("\n");
 | |
| 		log("    -F file_list_path\n");
 | |
| 		log("        File list file contains list of Verilog files to be parsed, any path is\n");
 | |
| 		log("        treated relative to the file list file\n");
 | |
| 		log("\n");
 | |
| 		log("    -f file_list_path\n");
 | |
| 		log("        File list file contains list of Verilog files to be parsed, any path is\n");
 | |
| 		log("        treated relative to current working directroy\n");
 | |
| 		log("\n");
 | |
| 	}
 | |
| 
 | |
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | |
| 	{
 | |
| 		size_t argidx;
 | |
| 		for (argidx = 1; argidx < args.size(); argidx++) {
 | |
| 			std::string arg = args[argidx];
 | |
| 			if (arg == "-F" && argidx + 1 < args.size()) {
 | |
| 				std::string file_list_path = args[++argidx];
 | |
| 				parse_file_list(file_list_path, design, true);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (arg == "-f" && argidx + 1 < args.size()) {
 | |
| 				std::string file_list_path = args[++argidx];
 | |
| 				parse_file_list(file_list_path, design, false);
 | |
| 				continue;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		extra_args(args, argidx, design, false);
 | |
| 	}
 | |
| } VerilogFilelist;
 | |
| 
 | |
| #endif
 | |
| 
 | |
| YOSYS_NAMESPACE_END
 |