diff options
Diffstat (limited to 'frontends/rtlil')
| -rw-r--r-- | frontends/rtlil/.gitignore | 4 | ||||
| -rw-r--r-- | frontends/rtlil/Makefile.inc | 19 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_frontend.cc | 115 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_frontend.h | 51 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_lexer.l | 150 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_parser.y | 484 | 
6 files changed, 823 insertions, 0 deletions
diff --git a/frontends/rtlil/.gitignore b/frontends/rtlil/.gitignore new file mode 100644 index 000000000..d4a322756 --- /dev/null +++ b/frontends/rtlil/.gitignore @@ -0,0 +1,4 @@ +rtlil_lexer.cc +rtlil_parser.output +rtlil_parser.tab.cc +rtlil_parser.tab.hh diff --git a/frontends/rtlil/Makefile.inc b/frontends/rtlil/Makefile.inc new file mode 100644 index 000000000..d0c0cfcf8 --- /dev/null +++ b/frontends/rtlil/Makefile.inc @@ -0,0 +1,19 @@ + +GENFILES += frontends/rtlil/rtlil_parser.tab.cc +GENFILES += frontends/rtlil/rtlil_parser.tab.hh +GENFILES += frontends/rtlil/rtlil_parser.output +GENFILES += frontends/rtlil/rtlil_lexer.cc + +frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y +	$(Q) mkdir -p $(dir $@) +	$(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $< + +frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc + +frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l +	$(Q) mkdir -p $(dir $@) +	$(P) flex -o frontends/rtlil/rtlil_lexer.cc $< + +OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o +OBJS += frontends/rtlil/rtlil_frontend.o + diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc new file mode 100644 index 000000000..00c34175e --- /dev/null +++ b/frontends/rtlil/rtlil_frontend.cc @@ -0,0 +1,115 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + * + *  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. + * + *  --- + * + *  A very simple and straightforward frontend for the RTLIL text + *  representation. + * + */ + +#include "rtlil_frontend.h" +#include "kernel/register.h" +#include "kernel/log.h" + +void rtlil_frontend_yyerror(char const *s) +{ +	YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s); +} + +YOSYS_NAMESPACE_BEGIN + +struct RTLILFrontend : public Frontend { +	RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { } +	void help() override +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("    read_rtlil [filename]\n"); +		log("\n"); +		log("Load modules from an RTLIL file to the current design. (RTLIL is a text\n"); +		log("representation of a design in yosys's internal format.)\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 blackbox\n"); +		log("        module, and overwrite the existing module if it is a blackbox module.)\n"); +		log("\n"); +		log("    -overwrite\n"); +		log("        overwrite existing modules with the same name\n"); +		log("\n"); +		log("    -lib\n"); +		log("        only create empty blackbox modules\n"); +		log("\n"); +	} +	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override +	{ +		RTLIL_FRONTEND::flag_nooverwrite = false; +		RTLIL_FRONTEND::flag_overwrite = false; +		RTLIL_FRONTEND::flag_lib = false; + +		log_header(design, "Executing RTLIL frontend.\n"); + +		size_t argidx; +		for (argidx = 1; argidx < args.size(); argidx++) { +			std::string arg = args[argidx]; +			if (arg == "-nooverwrite") { +				RTLIL_FRONTEND::flag_nooverwrite = true; +				RTLIL_FRONTEND::flag_overwrite = false; +				continue; +			} +			if (arg == "-overwrite") { +				RTLIL_FRONTEND::flag_nooverwrite = false; +				RTLIL_FRONTEND::flag_overwrite = true; +				continue; +			} +			if (arg == "-lib") { +				RTLIL_FRONTEND::flag_lib = true; +				continue; +			} +			break; +		} +		extra_args(f, filename, args, argidx); + +		log("Input filename: %s\n", filename.c_str()); + +		RTLIL_FRONTEND::lexin = f; +		RTLIL_FRONTEND::current_design = design; +		rtlil_frontend_yydebug = false; +		rtlil_frontend_yyrestart(NULL); +		rtlil_frontend_yyparse(); +		rtlil_frontend_yylex_destroy(); +	} +} RTLILFrontend; + +struct IlangFrontend : public Frontend { +	IlangFrontend() : Frontend("ilang", "(deprecated) alias of read_rtlil") { } +	void help() override +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("See `help read_rtlil`.\n"); +		log("\n"); +	} +	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override +	{ +		RTLILFrontend.execute(f, filename, args, design); +	} +} IlangFrontend; + +YOSYS_NAMESPACE_END + diff --git a/frontends/rtlil/rtlil_frontend.h b/frontends/rtlil/rtlil_frontend.h new file mode 100644 index 000000000..a420778b0 --- /dev/null +++ b/frontends/rtlil/rtlil_frontend.h @@ -0,0 +1,51 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + * + *  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. + * + *  --- + * + *  A very simple and straightforward frontend for the RTLIL text + *  representation. + * + */ + +#ifndef RTLIL_FRONTEND_H +#define RTLIL_FRONTEND_H + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +namespace RTLIL_FRONTEND { +	extern std::istream *lexin; +	extern RTLIL::Design *current_design; +	extern bool flag_nooverwrite; +	extern bool flag_overwrite; +	extern bool flag_lib; +} + +YOSYS_NAMESPACE_END + +extern int rtlil_frontend_yydebug; +int rtlil_frontend_yylex(void); +void rtlil_frontend_yyerror(char const *s); +void rtlil_frontend_yyrestart(FILE *f); +int rtlil_frontend_yyparse(void); +int rtlil_frontend_yylex_destroy(void); +int rtlil_frontend_yyget_lineno(void); + +#endif + diff --git a/frontends/rtlil/rtlil_lexer.l b/frontends/rtlil/rtlil_lexer.l new file mode 100644 index 000000000..295455f53 --- /dev/null +++ b/frontends/rtlil/rtlil_lexer.l @@ -0,0 +1,150 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + * + *  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. + * + *  --- + * + *  A very simple and straightforward frontend for the RTLIL text + *  representation. + * + */ + +%{ + +#ifdef __clang__ +// bison generates code using the 'register' storage class specifier +#pragma clang diagnostic ignored "-Wdeprecated-register" +#endif + +#include <cstdlib> +#include "frontends/rtlil/rtlil_frontend.h" +#include "rtlil_parser.tab.hh" + +USING_YOSYS_NAMESPACE + +#define YY_INPUT(buf,result,max_size) \ +	result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size) + +%} + +%option yylineno +%option noyywrap +%option nounput +%option prefix="rtlil_frontend_yy" + +%x STRING + +%% + +"autoidx"	{ return TOK_AUTOIDX; } +"module"	{ return TOK_MODULE; } +"attribute"	{ return TOK_ATTRIBUTE; } +"parameter"	{ return TOK_PARAMETER; } +"signed"	{ return TOK_SIGNED; } +"real"		{ return TOK_REAL; } +"wire"		{ return TOK_WIRE; } +"memory"	{ return TOK_MEMORY; } +"width"		{ return TOK_WIDTH; } +"upto"		{ return TOK_UPTO; } +"offset"	{ return TOK_OFFSET; } +"size"		{ return TOK_SIZE; } +"input"		{ return TOK_INPUT; } +"output"	{ return TOK_OUTPUT; } +"inout"		{ return TOK_INOUT; } +"cell"		{ return TOK_CELL; } +"connect"	{ return TOK_CONNECT; } +"switch"	{ return TOK_SWITCH; } +"case"		{ return TOK_CASE; } +"assign"	{ return TOK_ASSIGN; } +"sync"		{ return TOK_SYNC; } +"low"		{ return TOK_LOW; } +"high"		{ return TOK_HIGH; } +"posedge"	{ return TOK_POSEDGE; } +"negedge"	{ return TOK_NEGEDGE; } +"edge"		{ return TOK_EDGE; } +"always"	{ return TOK_ALWAYS; } +"global"	{ return TOK_GLOBAL; } +"init"		{ return TOK_INIT; } +"update"	{ return TOK_UPDATE; } +"process"	{ return TOK_PROCESS; } +"end"		{ return TOK_END; } + +[a-z]+		{ return TOK_INVALID; } + +"\\"[^ \t\r\n]+		{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } +"$"[^ \t\r\n]+		{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } +"."[0-9]+		{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } + +[0-9]+'[01xzm-]*	{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; } +-?[0-9]+		{ +	char *end = nullptr; +	errno = 0; +	long value = strtol(yytext, &end, 10); +	log_assert(end == yytext + strlen(yytext)); +	if (errno == ERANGE) +		return TOK_INVALID; // literal out of range of long +	if (value < INT_MIN || value > INT_MAX) +		return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) +	rtlil_frontend_yylval.integer = value; +	return TOK_INT; +} + +\"		{ BEGIN(STRING); } +<STRING>\\.	{ yymore(); } +<STRING>\"	{ +	BEGIN(0); +	char *yystr = strdup(yytext); +	yystr[strlen(yytext) - 1] = 0; +	int i = 0, j = 0; +	while (yystr[i]) { +		if (yystr[i] == '\\' && yystr[i + 1]) { +			i++; +			if (yystr[i] == 'n') +				yystr[i] = '\n'; +			else if (yystr[i] == 't') +				yystr[i] = '\t'; +			else if ('0' <= yystr[i] && yystr[i] <= '7') { +				yystr[i] = yystr[i] - '0'; +				if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { +					yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; +					i++; +				} +				if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { +					yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; +					i++; +				} +			} +		} +		yystr[j++] = yystr[i++]; +	} +	yystr[j] = 0; +	rtlil_frontend_yylval.string = yystr; +	return TOK_STRING; +} +<STRING>.	{ yymore(); } + +"#"[^\n]*	/* ignore comments */ +[ \t]		/* ignore non-newline whitespaces */ +[\r\n]+		{ return TOK_EOL; } + +.               { return *yytext; } + +%% + +// this is a hack to avoid the 'yyinput defined but not used' error msgs +void *rtlil_frontend_avoid_input_warnings() { +	return (void*)&yyinput; +} diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y new file mode 100644 index 000000000..646489196 --- /dev/null +++ b/frontends/rtlil/rtlil_parser.y @@ -0,0 +1,484 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + * + *  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. + * + *  --- + * + *  A very simple and straightforward frontend for the RTLIL text + *  representation. + * + */ + +%{ +#include <list> +#include "frontends/rtlil/rtlil_frontend.h" +YOSYS_NAMESPACE_BEGIN +namespace RTLIL_FRONTEND { +	std::istream *lexin; +	RTLIL::Design *current_design; +	RTLIL::Module *current_module; +	RTLIL::Wire *current_wire; +	RTLIL::Memory *current_memory; +	RTLIL::Cell *current_cell; +	RTLIL::Process *current_process; +	std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack; +	std::vector<RTLIL::CaseRule*> case_stack; +	dict<RTLIL::IdString, RTLIL::Const> attrbuf; +	bool flag_nooverwrite, flag_overwrite, flag_lib; +	bool delete_current_module; +} +using namespace RTLIL_FRONTEND; +YOSYS_NAMESPACE_END +USING_YOSYS_NAMESPACE +%} + +%define api.prefix {rtlil_frontend_yy} + +/* The union is defined in the header, so we need to provide all the + * includes it requires + */ +%code requires { +#include <string> +#include <vector> +#include "frontends/rtlil/rtlil_frontend.h" +} + +%union { +	char *string; +	int integer; +	YOSYS_NAMESPACE_PREFIX RTLIL::Const *data; +	YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; +	std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec; +} + +%token <string> TOK_ID TOK_VALUE TOK_STRING +%token <integer> TOK_INT +%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT +%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC +%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT +%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET +%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO + +%type <rsigspec> sigspec_list_reversed +%type <sigspec> sigspec sigspec_list +%type <integer> sync_type +%type <data> constant + +%expect 0 +%debug + +%% + +input: +	optional_eol { +		attrbuf.clear(); +	} design { +		if (attrbuf.size() != 0) +			rtlil_frontend_yyerror("dangling attribute"); +	}; + +EOL: +	optional_eol TOK_EOL; + +optional_eol: +	optional_eol TOK_EOL | /* empty */; + +design: +	design module | +	design attr_stmt | +	design autoidx_stmt | +	/* empty */; + +module: +	TOK_MODULE TOK_ID EOL { +		delete_current_module = false; +		if (current_design->has($2)) { +			RTLIL::Module *existing_mod = current_design->module($2); +			if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { +				log("Ignoring blackbox re-definition of module %s.\n", $2); +				delete_current_module = true; +			} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { +				rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str()); +			} else if (flag_nooverwrite) { +				log("Ignoring re-definition of module %s.\n", $2); +				delete_current_module = true; +			} else { +				log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); +				current_design->remove(existing_mod); +			} +		} +		current_module = new RTLIL::Module; +		current_module->name = $2; +		current_module->attributes = attrbuf; +		if (!delete_current_module) +			current_design->add(current_module); +		attrbuf.clear(); +		free($2); +	} module_body TOK_END { +		if (attrbuf.size() != 0) +			rtlil_frontend_yyerror("dangling attribute"); +		current_module->fixup_ports(); +		if (delete_current_module) +			delete current_module; +		else if (flag_lib) +			current_module->makeblackbox(); +		current_module = nullptr; +	} EOL; + +module_body: +	module_body module_stmt | +	/* empty */; + +module_stmt: +	param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; + +param_stmt: +	TOK_PARAMETER TOK_ID EOL { +		current_module->avail_parameters($2); +		free($2); +	}; + +param_defval_stmt: +	TOK_PARAMETER TOK_ID constant EOL { +		current_module->avail_parameters($2); +		current_module->parameter_default_values[$2] = *$3; +		free($2); +	}; + +attr_stmt: +	TOK_ATTRIBUTE TOK_ID constant EOL { +		attrbuf[$2] = *$3; +		delete $3; +		free($2); +	}; + +autoidx_stmt: +	TOK_AUTOIDX TOK_INT EOL { +		autoidx = max(autoidx, $2); +	}; + +wire_stmt: +	TOK_WIRE { +		current_wire = current_module->addWire("$__rtlil_frontend_tmp__"); +		current_wire->attributes = attrbuf; +		attrbuf.clear(); +	} wire_options TOK_ID EOL { +		if (current_module->wire($4) != nullptr) +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str()); +		current_module->rename(current_wire, $4); +		free($4); +	}; + +wire_options: +	wire_options TOK_WIDTH TOK_INT { +		current_wire->width = $3; +	} | +	wire_options TOK_WIDTH TOK_INVALID { +		rtlil_frontend_yyerror("RTLIL error: invalid wire width"); +	} | +	wire_options TOK_UPTO { +		current_wire->upto = true; +	} | +	wire_options TOK_SIGNED { +		current_wire->is_signed = true; +	} | +	wire_options TOK_OFFSET TOK_INT { +		current_wire->start_offset = $3; +	} | +	wire_options TOK_INPUT TOK_INT { +		current_wire->port_id = $3; +		current_wire->port_input = true; +		current_wire->port_output = false; +	} | +	wire_options TOK_OUTPUT TOK_INT { +		current_wire->port_id = $3; +		current_wire->port_input = false; +		current_wire->port_output = true; +	} | +	wire_options TOK_INOUT TOK_INT { +		current_wire->port_id = $3; +		current_wire->port_input = true; +		current_wire->port_output = true; +	} | +	/* empty */; + +memory_stmt: +	TOK_MEMORY { +		current_memory = new RTLIL::Memory; +		current_memory->attributes = attrbuf; +		attrbuf.clear(); +	} memory_options TOK_ID EOL { +		if (current_module->memories.count($4) != 0) +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str()); +		current_memory->name = $4; +		current_module->memories[$4] = current_memory; +		free($4); +	}; + +memory_options: +	memory_options TOK_WIDTH TOK_INT { +		current_memory->width = $3; +	} | +	memory_options TOK_SIZE TOK_INT { +		current_memory->size = $3; +	} | +	memory_options TOK_OFFSET TOK_INT { +		current_memory->start_offset = $3; +	} | +	/* empty */; + +cell_stmt: +	TOK_CELL TOK_ID TOK_ID EOL { +		if (current_module->cell($3) != nullptr) +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str()); +		current_cell = current_module->addCell($3, $2); +		current_cell->attributes = attrbuf; +		attrbuf.clear(); +		free($2); +		free($3); +	} cell_body TOK_END EOL; + +cell_body: +	cell_body TOK_PARAMETER TOK_ID constant EOL { +		current_cell->parameters[$3] = *$4; +		free($3); +		delete $4; +	} | +	cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL { +		current_cell->parameters[$4] = *$5; +		current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED; +		free($4); +		delete $5; +	} | +	cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { +		current_cell->parameters[$4] = *$5; +		current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; +		free($4); +		delete $5; +	} | +	cell_body TOK_CONNECT TOK_ID sigspec EOL { +		if (current_cell->hasPort($3)) +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str()); +		current_cell->setPort($3, *$4); +		delete $4; +		free($3); +	} | +	/* empty */; + +proc_stmt: +	TOK_PROCESS TOK_ID EOL { +		if (current_module->processes.count($2) != 0) +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str()); +		current_process = new RTLIL::Process; +		current_process->name = $2; +		current_process->attributes = attrbuf; +		current_module->processes[$2] = current_process; +		switch_stack.clear(); +		switch_stack.push_back(¤t_process->root_case.switches); +		case_stack.clear(); +		case_stack.push_back(¤t_process->root_case); +		attrbuf.clear(); +		free($2); +	} case_body sync_list TOK_END EOL; + +switch_stmt: +	TOK_SWITCH sigspec EOL { +		RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; +		rule->signal = *$2; +		rule->attributes = attrbuf; +		switch_stack.back()->push_back(rule); +		attrbuf.clear(); +		delete $2; +	} attr_list switch_body TOK_END EOL; + +attr_list: +	/* empty */ | +	attr_list attr_stmt; + +switch_body: +	switch_body TOK_CASE { +		RTLIL::CaseRule *rule = new RTLIL::CaseRule; +		rule->attributes = attrbuf; +		switch_stack.back()->back()->cases.push_back(rule); +		switch_stack.push_back(&rule->switches); +		case_stack.push_back(rule); +		attrbuf.clear(); +	} compare_list EOL case_body { +		switch_stack.pop_back(); +		case_stack.pop_back(); +	} | +	/* empty */; + +compare_list: +	sigspec { +		case_stack.back()->compare.push_back(*$1); +		delete $1; +	} | +	compare_list ',' sigspec { +		case_stack.back()->compare.push_back(*$3); +		delete $3; +	} | +	/* empty */; + +case_body: +	case_body attr_stmt | +	case_body switch_stmt | +	case_body assign_stmt | +	/* empty */; + +assign_stmt: +	TOK_ASSIGN sigspec sigspec EOL { +		if (attrbuf.size() != 0) +			rtlil_frontend_yyerror("dangling attribute"); +		case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); +		delete $2; +		delete $3; +	}; + +sync_list: +	sync_list TOK_SYNC sync_type sigspec EOL { +		RTLIL::SyncRule *rule = new RTLIL::SyncRule; +		rule->type = RTLIL::SyncType($3); +		rule->signal = *$4; +		current_process->syncs.push_back(rule); +		delete $4; +	} update_list | +	sync_list TOK_SYNC TOK_ALWAYS EOL { +		RTLIL::SyncRule *rule = new RTLIL::SyncRule; +		rule->type = RTLIL::SyncType::STa; +		rule->signal = RTLIL::SigSpec(); +		current_process->syncs.push_back(rule); +	} update_list | +	sync_list TOK_SYNC TOK_GLOBAL EOL { +		RTLIL::SyncRule *rule = new RTLIL::SyncRule; +		rule->type = RTLIL::SyncType::STg; +		rule->signal = RTLIL::SigSpec(); +		current_process->syncs.push_back(rule); +	} update_list | +	sync_list TOK_SYNC TOK_INIT EOL { +		RTLIL::SyncRule *rule = new RTLIL::SyncRule; +		rule->type = RTLIL::SyncType::STi; +		rule->signal = RTLIL::SigSpec(); +		current_process->syncs.push_back(rule); +	} update_list | +	/* empty */; + +sync_type: +	TOK_LOW { $$ = RTLIL::ST0; } | +	TOK_HIGH { $$ = RTLIL::ST1; } | +	TOK_POSEDGE { $$ = RTLIL::STp; } | +	TOK_NEGEDGE { $$ = RTLIL::STn; } | +	TOK_EDGE { $$ = RTLIL::STe; }; + +update_list: +	update_list TOK_UPDATE sigspec sigspec EOL { +		current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4)); +		delete $3; +		delete $4; +	} | +	/* empty */; + +constant: +	TOK_VALUE { +		char *ep; +		int width = strtol($1, &ep, 10); +		std::list<RTLIL::State> bits; +		while (*(++ep) != 0) { +			RTLIL::State bit = RTLIL::Sx; +			switch (*ep) { +			case '0': bit = RTLIL::S0; break; +			case '1': bit = RTLIL::S1; break; +			case 'x': bit = RTLIL::Sx; break; +			case 'z': bit = RTLIL::Sz; break; +			case '-': bit = RTLIL::Sa; break; +			case 'm': bit = RTLIL::Sm; break; +			} +			bits.push_front(bit); +		} +		if (bits.size() == 0) +			bits.push_back(RTLIL::Sx); +		while ((int)bits.size() < width) { +			RTLIL::State bit = bits.back(); +			if (bit == RTLIL::S1) +				bit = RTLIL::S0; +			bits.push_back(bit); +		} +		while ((int)bits.size() > width) +			bits.pop_back(); +		$$ = new RTLIL::Const; +		for (auto it = bits.begin(); it != bits.end(); it++) +			$$->bits.push_back(*it); +		free($1); +	} | +	TOK_INT { +		$$ = new RTLIL::Const($1, 32); +	} | +	TOK_STRING { +		$$ = new RTLIL::Const($1); +		free($1); +	}; + +sigspec: +	constant { +		$$ = new RTLIL::SigSpec(*$1); +		delete $1; +	} | +	TOK_ID { +		if (current_module->wire($1) == nullptr) +			rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str()); +		$$ = new RTLIL::SigSpec(current_module->wire($1)); +		free($1); +	} | +	sigspec '[' TOK_INT ']' { +		if ($3 >= $1->size() || $3 < 0) +			rtlil_frontend_yyerror("bit index out of range"); +		$$ = new RTLIL::SigSpec($1->extract($3)); +		delete $1; +	} | +	sigspec '[' TOK_INT ':' TOK_INT ']' { +		if ($3 >= $1->size() || $3 < 0 || $3 < $5) +			rtlil_frontend_yyerror("invalid slice"); +		$$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); +		delete $1; +	} | +	'{' sigspec_list '}' { +		$$ = $2; +	}; + +sigspec_list_reversed: +	sigspec_list_reversed sigspec { +		$$->push_back(*$2); +		delete $2; +	} | +	/* empty */ { +		$$ = new std::vector<RTLIL::SigSpec>; +	}; + +sigspec_list: sigspec_list_reversed { +		$$ = new RTLIL::SigSpec; +		for (auto it = $1->rbegin(); it != $1->rend(); it++) +			$$->append(*it); +		delete $1; +	}; + +conn_stmt: +	TOK_CONNECT sigspec sigspec EOL { +		if (attrbuf.size() != 0) +			rtlil_frontend_yyerror("dangling attribute"); +		current_module->connect(*$2, *$3); +		delete $2; +		delete $3; +	};  | 
